Skip to content

Commit 0c48a3b

Browse files
gdankelfacebook-github-bot
authored andcommitted
Invert ConfigLoader -> profiler dependency (#271)
Summary: Pull Request resolved: #271 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: bac82cf2b90716b9e19ab8aa401a26a3d06bbe31
1 parent cbae600 commit 0c48a3b

11 files changed

+177
-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: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#pragma once
99

10+
#include <algorithm>
1011
#include <atomic>
1112
#include <chrono>
1213
#include <condition_variable>
@@ -27,20 +28,56 @@ class DaemonConfigLoader;
2728

2829
class ConfigLoader {
2930
public:
31+
3032
static ConfigLoader& instance();
3133

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

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

4280
bool hasNewConfig(const Config& oldConfig);
43-
bool hasNewEventProfilerOnDemandConfig(const Config& oldConfig);
4481
int contextCountForGpu(uint32_t gpu);
4582

4683
void handleOnDemandSignal();
@@ -49,7 +86,7 @@ class ConfigLoader {
4986
std::function<std::unique_ptr<DaemonConfigLoader>()> factory);
5087

5188
private:
52-
explicit ConfigLoader(libkineto::LibkinetoApi& api);
89+
ConfigLoader();
5390
~ConfigLoader();
5491

5592
void updateConfigThread();
@@ -65,21 +102,14 @@ class ConfigLoader {
65102
std::chrono::time_point<std::chrono::system_clock> now,
66103
Config& config);
67104

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

77-
LibkinetoApi& libkinetoApi_;
78108
std::mutex configLock_;
79109
const char* configFileName_;
80110
Config config_;
81-
std::unique_ptr<Config> onDemandEventProfilerConfig_;
82111
std::unique_ptr<DaemonConfigLoader> daemonConfigLoader_;
112+
std::map<ConfigKind, std::vector<ConfigHandler*>> handlers_;
83113

84114
std::chrono::seconds configUpdateIntervalSecs_;
85115
std::chrono::seconds onDemandConfigUpdateIntervalSecs_;

0 commit comments

Comments
 (0)