Skip to content

Commit 3085c25

Browse files
gdankelfacebook-github-bot
authored andcommitted
Invert ConfigLoader -> profiler dependency
Summary: Change direction of dependency from ConfigLoader -> profiler to profiler -> ConfigLoader. This way, the profiler is able to lazily initialize config loader and also move towards the pluggable profiler design. Reviewed By: xw285cornell Differential Revision: D28802798 fbshipit-source-id: 3825e2790ac11ce0dbb31b0756c52aafca61ebf5
1 parent cbae600 commit 3085c25

11 files changed

+176
-118
lines changed

libkineto/src/ActivityProfilerController.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,15 @@ namespace KINETO_NAMESPACE {
2626
constexpr milliseconds kProfilerIntervalMsecs(1000);
2727

2828
ActivityProfilerController::ActivityProfilerController(bool cpuOnly) {
29-
profiler_ = std::make_unique<ActivityProfiler>(CuptiActivityInterface::singleton(), cpuOnly);
29+
profiler_ = std::make_unique<ActivityProfiler>(
30+
CuptiActivityInterface::singleton(), cpuOnly);
31+
ConfigLoader::instance().addHandler(
32+
ConfigLoader::ConfigKind::ActivityProfiler, this);
3033
}
3134

3235
ActivityProfilerController::~ActivityProfilerController() {
36+
ConfigLoader::instance().removeHandler(
37+
ConfigLoader::ConfigKind::ActivityProfiler, this);
3338
if (profilerThread_) {
3439
// signaling termination of the profiler loop
3540
stopRunloop_ = true;
@@ -65,6 +70,17 @@ static std::unique_ptr<ActivityLogger> makeLogger(const Config& config) {
6570
return loggerFactory().makeLogger(config.activitiesLogUrl());
6671
}
6772

73+
bool ActivityProfilerController::canAcceptConfig() {
74+
return !profiler_->isActive();
75+
}
76+
77+
void ActivityProfilerController::acceptConfig(const Config& config) {
78+
VLOG(1) << "acceptConfig";
79+
if (config.activityProfilerEnabled()) {
80+
scheduleTrace(config);
81+
}
82+
}
83+
6884
void ActivityProfilerController::profilerLoop() {
6985
setThreadName("Kineto Activity Profiler");
7086
VLOG(0) << "Entering activity profiler loop";
@@ -107,6 +123,11 @@ void ActivityProfilerController::profilerLoop() {
107123
}
108124

109125
void ActivityProfilerController::scheduleTrace(const Config& config) {
126+
VLOG(1) << "scheduleTrace";
127+
if (profiler_->isActive()) {
128+
LOG(ERROR) << "Ignored request - profiler busy";
129+
return;
130+
}
110131
std::lock_guard<std::mutex> lock(asyncConfigLock_);
111132
asyncRequestConfig_ = config.clone();
112133
// start a profilerLoop() thread to handle request

libkineto/src/ActivityProfilerController.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,21 @@
99

1010
#include <atomic>
1111
#include <memory>
12+
#include <mutex>
1213
#include <thread>
1314

1415
#include "ActivityLoggerFactory.h"
1516
#include "ActivityProfiler.h"
1617
#include "ActivityProfilerInterface.h"
1718
#include "ActivityTraceInterface.h"
19+
#include "ConfigLoader.h"
1820
#include "CuptiActivityInterface.h"
1921

2022
namespace KINETO_NAMESPACE {
2123

2224
class Config;
2325

24-
class ActivityProfilerController {
26+
class ActivityProfilerController : public ConfigLoader::ConfigHandler {
2527
public:
2628
explicit ActivityProfilerController(bool cpuOnly);
2729
ActivityProfilerController(const ActivityProfilerController&) = delete;
@@ -34,6 +36,9 @@ class ActivityProfilerController {
3436
const std::string& protocol,
3537
ActivityLoggerFactory::FactoryFunc factory);
3638

39+
bool canAcceptConfig() override;
40+
void acceptConfig(const Config& config) override;
41+
3742
void scheduleTrace(const Config& config);
3843

3944
void prepareTrace(const Config& config);

libkineto/src/Config.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ Config::Config()
156156
kDefaultActivitiesExternalAPINetSizeThreshold),
157157
activitiesExternalAPIGpuOpCountThreshold_(
158158
kDefaultActivitiesExternalAPIGpuOpCountThreshold),
159+
activitiesOnDemandTimestamp_(milliseconds(0)),
159160
requestTimestamp_(milliseconds(0)),
160161
enableSigUsr2_(true),
161162
enableIpcFabric_(false) {

libkineto/src/Config.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ class Config : public AbstractConfig {
4545
}
4646

4747
bool activityProfilerEnabled() const {
48-
return activityProfilerEnabled_;
48+
return activityProfilerEnabled_ ||
49+
activitiesOnDemandTimestamp_.time_since_epoch().count() > 0;
4950
}
5051

5152
// Log activitiy trace to this file

libkineto/src/ConfigLoader.cpp

Lines changed: 12 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
#include <chrono>
1616
#include <fstream>
1717

18-
#include "libkineto.h"
19-
#include "ActivityProfilerProxy.h"
2018
#include "DaemonConfigLoader.h"
2119

2220
#include "Logger.h"
@@ -120,7 +118,7 @@ void ConfigLoader::setDaemonConfigLoaderFactory(
120118
}
121119

122120
ConfigLoader& ConfigLoader::instance() {
123-
static ConfigLoader config_loader(libkineto::api());
121+
static ConfigLoader config_loader;
124122
return config_loader;
125123
}
126124

@@ -130,9 +128,8 @@ std::string ConfigLoader::readOnDemandConfigFromDaemon(
130128
if (!daemonConfigLoader_) {
131129
return "";
132130
}
133-
bool events =
134-
now > onDemandEventProfilerConfig_->eventProfilerOnDemandEndTime();
135-
bool activities = !libkinetoApi_.activityProfiler().isActive();
131+
bool events = canHandlerAcceptConfig(ConfigKind::EventProfiler);
132+
bool activities = canHandlerAcceptConfig(ConfigKind::ActivityProfiler);
136133
return daemonConfigLoader_->readOnDemandConfig(events, activities);
137134
}
138135

@@ -144,10 +141,8 @@ int ConfigLoader::contextCountForGpu(uint32_t device) {
144141
return daemonConfigLoader_->gpuContextCount(device);
145142
}
146143

147-
ConfigLoader::ConfigLoader(LibkinetoApi& api)
148-
: libkinetoApi_(api),
149-
onDemandEventProfilerConfig_(new Config()),
150-
configUpdateIntervalSecs_(kConfigUpdateIntervalSecs),
144+
ConfigLoader::ConfigLoader()
145+
: configUpdateIntervalSecs_(kConfigUpdateIntervalSecs),
151146
onDemandConfigUpdateIntervalSecs_(kOnDemandConfigUpdateIntervalSecs),
152147
stopFlag_(false),
153148
onDemandSignal_(false) {
@@ -211,51 +206,23 @@ void ConfigLoader::configureFromSignal(
211206
if (daemonConfigLoader_) {
212207
daemonConfigLoader_->setCommunicationFabric(config_.ipcFabricEnabled());
213208
}
214-
if (eventProfilerRequest(config)) {
215-
if (now > onDemandEventProfilerConfig_->eventProfilerOnDemandEndTime()) {
216-
LOG(INFO) << "Starting on-demand event profiling from signal";
217-
std::lock_guard<std::mutex> lock(configLock_);
218-
onDemandEventProfilerConfig_ = config.clone();
219-
} else {
220-
LOG(ERROR) << "On-demand event profiler is busy";
221-
}
222-
}
223-
// Initiate a trace by default, even when not specified in the config.
224-
// Set trace duration and iterations to 0 to suppress.
225-
config.updateActivityProfilerRequestReceivedTime();
226-
try {
227-
auto& profiler = dynamic_cast<ActivityProfilerProxy&>(
228-
libkinetoApi_.activityProfiler());
229-
profiler.scheduleTrace(config);
230-
} catch (const std::exception& e) {
231-
LOG(ERROR) << "Failed to schedule profiler request (busy?)";
232-
}
209+
notifyHandlers(config);
233210
}
234211

235212
void ConfigLoader::configureFromDaemon(
236213
time_point<system_clock> now,
237214
Config& config) {
238215
const std::string config_str = readOnDemandConfigFromDaemon(now);
239-
LOG_IF(INFO, !config_str.empty()) << "Received config from dyno:\n"
240-
<< config_str;
216+
if (config_str.empty()) {
217+
return;
218+
}
219+
220+
LOG(INFO) << "Received config from dyno:\n" << config_str;
241221
config.parse(config_str);
242222
if (daemonConfigLoader_) {
243223
daemonConfigLoader_->setCommunicationFabric(config_.ipcFabricEnabled());
244224
}
245-
if (eventProfilerRequest(config)) {
246-
std::lock_guard<std::mutex> lock(configLock_);
247-
onDemandEventProfilerConfig_ = config.clone();
248-
}
249-
if (config_.activityProfilerEnabled() &&
250-
config.activityProfilerRequestReceivedTime() > now) {
251-
try {
252-
auto& profiler = dynamic_cast<ActivityProfilerProxy&>(
253-
libkinetoApi_.activityProfiler());
254-
profiler.scheduleTrace(config);
255-
} catch (const std::exception& e) {
256-
LOG(ERROR) << "Failed to schedule profiler request (busy?)";
257-
}
258-
}
225+
notifyHandlers(config);
259226
}
260227

261228
void ConfigLoader::updateConfigThread() {
@@ -313,10 +280,4 @@ bool ConfigLoader::hasNewConfig(const Config& oldConfig) {
313280
return config_.timestamp() > oldConfig.timestamp();
314281
}
315282

316-
bool ConfigLoader::hasNewEventProfilerOnDemandConfig(const Config& oldConfig) {
317-
std::lock_guard<std::mutex> lock(configLock_);
318-
return onDemandEventProfilerConfig_->eventProfilerOnDemandStartTime() >
319-
oldConfig.eventProfilerOnDemandStartTime();
320-
}
321-
322283
} // namespace KINETO_NAMESPACE

libkineto/src/ConfigLoader.h

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,56 @@ class DaemonConfigLoader;
2727

2828
class ConfigLoader {
2929
public:
30+
3031
static ConfigLoader& instance();
3132

32-
inline std::unique_ptr<Config> getConfigCopy() {
33-
std::lock_guard<std::mutex> lock(configLock_);
34-
return config_.clone();
33+
enum ConfigKind {
34+
ActivityProfiler = 0,
35+
EventProfiler,
36+
NumConfigKinds
37+
};
38+
39+
struct ConfigHandler {
40+
virtual ~ConfigHandler() {}
41+
virtual bool canAcceptConfig() = 0;
42+
virtual void acceptConfig(const Config& cfg) = 0;
43+
};
44+
45+
void addHandler(ConfigKind kind, ConfigHandler* handler) {
46+
handlers_[kind].push_back(handler);
47+
}
48+
49+
void removeHandler(ConfigKind kind, ConfigHandler* handler) {
50+
auto it = std::find(
51+
handlers_[kind].begin(), handlers_[kind].end(), handler);
52+
if (it != handlers_[kind].end()) {
53+
handlers_[kind].erase(it);
54+
}
3555
}
3656

37-
inline std::unique_ptr<Config> getEventProfilerOnDemandConfigCopy() {
57+
void notifyHandlers(const Config& cfg) {
58+
for (auto& key_val : handlers_) {
59+
for (ConfigHandler* handler : key_val.second) {
60+
handler->acceptConfig(cfg);
61+
}
62+
}
63+
}
64+
65+
bool canHandlerAcceptConfig(ConfigKind kind) {
66+
for (ConfigHandler* handler : handlers_[kind]) {
67+
if (!handler->canAcceptConfig()) {
68+
return false;
69+
}
70+
}
71+
return true;
72+
}
73+
74+
inline std::unique_ptr<Config> getConfigCopy() {
3875
std::lock_guard<std::mutex> lock(configLock_);
39-
return onDemandEventProfilerConfig_->clone();
76+
return config_.clone();
4077
}
4178

4279
bool hasNewConfig(const Config& oldConfig);
43-
bool hasNewEventProfilerOnDemandConfig(const Config& oldConfig);
4480
int contextCountForGpu(uint32_t gpu);
4581

4682
void handleOnDemandSignal();
@@ -49,7 +85,7 @@ class ConfigLoader {
4985
std::function<std::unique_ptr<DaemonConfigLoader>()> factory);
5086

5187
private:
52-
explicit ConfigLoader(libkineto::LibkinetoApi& api);
88+
ConfigLoader();
5389
~ConfigLoader();
5490

5591
void updateConfigThread();
@@ -65,21 +101,14 @@ class ConfigLoader {
65101
std::chrono::time_point<std::chrono::system_clock> now,
66102
Config& config);
67103

68-
inline bool eventProfilerRequest(const Config& config) {
69-
return (
70-
config.eventProfilerOnDemandStartTime() >
71-
onDemandEventProfilerConfig_->eventProfilerOnDemandStartTime());
72-
}
73-
74104
std::string readOnDemandConfigFromDaemon(
75105
std::chrono::time_point<std::chrono::system_clock> now);
76106

77-
LibkinetoApi& libkinetoApi_;
78107
std::mutex configLock_;
79108
const char* configFileName_;
80109
Config config_;
81-
std::unique_ptr<Config> onDemandEventProfilerConfig_;
82110
std::unique_ptr<DaemonConfigLoader> daemonConfigLoader_;
111+
std::map<ConfigKind, std::vector<ConfigHandler*>> handlers_;
83112

84113
std::chrono::seconds configUpdateIntervalSecs_;
85114
std::chrono::seconds onDemandConfigUpdateIntervalSecs_;

0 commit comments

Comments
 (0)