Skip to content

Commit 34f66a6

Browse files
Brian Coutinhofacebook-github-bot
authored andcommitted
add activity profiler plugin interface and test (#202)
Summary: Pull Request resolved: #202 # Activity Profiler Interface Adds the child Activiity profiler interface and implementation. This interface can be used by libraries and frameworks to supply trace events to Kineto. The first version only consolidates trace events and does not handle correlation yet. ## Details * Add Activity Profiler interface header that includes both profiler and the profiler session. A session manages all the trace event data captured by the respective profiler * Also had to move GenericTrace activity to includes dir as it used in the profiler session interface. * Creates sessions and starts and stops them in the primary ActivityProfilers flow. * First use-case is to integrate with Glow (Graph Lowering Compiler) , adding a glow_runtime event type for it. https://github.com/pytorch/glow/blob/master/docs/Tracing.md Reviewed By: gdankel Differential Revision: D27601906 fbshipit-source-id: 38e608a3a1a6e1b9e69f80d07312e388ed7ad339
1 parent 6f9c0ee commit 34f66a6

File tree

10 files changed

+370
-0
lines changed

10 files changed

+370
-0
lines changed

libkineto/include/ActivityType.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ enum class ActivityType {
2121
CONCURRENT_KERNEL, // on-device kernels
2222
EXTERNAL_CORRELATION,
2323
CUDA_RUNTIME, // host side cuda runtime events
24+
GLOW_RUNTIME, // host side glow runtime events
2425
CPU_INSTANT_EVENT, // host side point-like events
2526
ENUM_COUNT
2627
};
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
* All rights reserved.
4+
* This source code is licensed under the BSD-style license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#include <memory>
11+
#include <set>
12+
#include <vector>
13+
14+
#include "GenericTraceActivity.h"
15+
#include "ActivityTraceInterface.h"
16+
17+
/* This file includes an abstract base class for an activity profiler
18+
* that can be implemented by multiple tracing agents in the application.
19+
* The high level Kineto profiler can co-ordinate start and end of tracing
20+
* and combine together events from multiple such activity profilers.
21+
*/
22+
23+
namespace libkineto {
24+
25+
enum class TraceStatus {
26+
READY, // Accepting trace requests
27+
WARMUP, // Performing trace warmup
28+
RECORDING, // Actively collecting activities
29+
PROCESSING, // Recording is complete, preparing results
30+
ERROR, // One or more errors (and possibly also warnings) occurred.
31+
WARNING, // One or more warnings occurred.
32+
};
33+
34+
/* IActivityProfilerSession:
35+
* an opaque object that can be used by a high level profiler to
36+
* start/stop and return trace events.
37+
*/
38+
class IActivityProfilerSession {
39+
40+
public:
41+
virtual ~IActivityProfilerSession() {}
42+
43+
// start the trace collection synchronously
44+
virtual void start() = 0;
45+
46+
// stop the trace collection synchronously
47+
virtual void stop() = 0;
48+
49+
TraceStatus status() {
50+
return status_;
51+
}
52+
53+
// returns list of Trace Activities
54+
virtual std::vector<GenericTraceActivity>& activities() = 0;
55+
56+
// returns errors with this trace
57+
virtual std::vector<std::string> errors() = 0;
58+
59+
// processes trace activities using logger
60+
virtual void processTrace(ActivityLogger& logger) = 0;
61+
62+
// XXX define trace formats
63+
// virtual save(string name, TraceFormat format)
64+
65+
protected:
66+
TraceStatus status_ = TraceStatus::READY;
67+
};
68+
69+
70+
/* Activity Profiler Plugins:
71+
* These allow other frameworks to integrate into Kineto's primariy
72+
* activity profiler. While the primary activity profiler handles
73+
* timing the trace collections and correlating events the plugins
74+
* can become source of new trace activity types.
75+
*/
76+
class IActivityProfiler {
77+
78+
public:
79+
80+
virtual ~IActivityProfiler() {}
81+
82+
// name of profiler
83+
virtual const std::string& name() const = 0;
84+
85+
// returns activity types this profiler supports
86+
virtual const std::set<ActivityType>& availableActivities() const = 0;
87+
88+
// Calls prepare() on registered tracer providers passing in the relevant
89+
// activity types. Returns a profiler session handle (including uuid?).
90+
virtual std::unique_ptr<IActivityProfilerSession> configure(
91+
const std::set<ActivityType>& activity_types,
92+
const std::string& config="") = 0;
93+
94+
// asynchronous version of the above with future timestamp and duration.
95+
virtual std::unique_ptr<IActivityProfilerSession> configure(
96+
int64_t ts_ms,
97+
int64_t duration_ms,
98+
const std::set<ActivityType>& activity_types,
99+
const std::string& config = "") = 0;
100+
};
101+
102+
} // namespace libkineto

libkineto/libkineto_defs.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ def get_libkineto_public_headers():
5757
"include/ClientInterface.h",
5858
"include/GenericTraceActivity.h",
5959
"include/TraceActivity.h",
60+
"include/GenericTraceActivity.h",
61+
"include/IActivityProfiler.h",
6062
"include/TraceSpan.h",
6163
"include/ThreadUtil.h",
6264
"include/libkineto.h",

libkineto/src/ActivityProfiler.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ void ActivityProfiler::processTraceInternal(ActivityLogger& logger) {
159159
}
160160
#endif // HAS_CUPTI
161161

162+
for (const auto& session : sessions_){
163+
LOG(INFO) << "Processing child profiler trace";
164+
session->processTrace(logger);
165+
}
166+
162167
finalizeTrace(*config_, logger);
163168
}
164169

@@ -440,6 +445,24 @@ void ActivityProfiler::handleCuptiActivity(const CUpti_Activity* record, Activit
440445
}
441446
#endif // HAS_CUPTI
442447

448+
void ActivityProfiler::configureChildProfilers() {
449+
// If child profilers are enabled create profiler sessions
450+
for (auto& profiler: profilers_) {
451+
int64_t start_time_ms = duration_cast<milliseconds>(
452+
profileStartTime_.time_since_epoch()).count();
453+
LOG(INFO) << "Running child profiler " << profiler->name() << " for "
454+
<< config_->activitiesOnDemandDuration().count() << " ms";
455+
auto session = profiler->configure(
456+
start_time_ms,
457+
config_->activitiesOnDemandDuration().count(),
458+
std::set<ActivityType>{ActivityType::CPU_OP} // TODO make configurable
459+
);
460+
if (session) {
461+
sessions_.push_back(std::move(session));
462+
}
463+
}
464+
}
465+
443466
void ActivityProfiler::configure(
444467
const Config& config,
445468
const time_point<system_clock>& now) {
@@ -503,6 +526,11 @@ void ActivityProfiler::configure(
503526
if (profileStartTime_ < now) {
504527
profileStartTime_ = now + config_->activitiesWarmupDuration();
505528
}
529+
530+
if (profilers_.size() > 0) {
531+
configureChildProfilers();
532+
}
533+
506534
LOG(INFO) << "Tracing starting in "
507535
<< duration_cast<seconds>(profileStartTime_ - now).count() << "s";
508536

@@ -517,6 +545,10 @@ void ActivityProfiler::startTraceInternal(const time_point<system_clock>& now) {
517545
libkineto::api().client()->start();
518546
}
519547
VLOG(0) << "Warmup -> CollectTrace";
548+
for (auto& session: sessions_){
549+
LOG(INFO) << "Starting child profiler session";
550+
session->start();
551+
}
520552
currentRunloopState_ = RunloopState::CollectTrace;
521553
}
522554

@@ -545,6 +577,10 @@ void ActivityProfiler::stopTraceInternal(const time_point<system_clock>& now) {
545577
static_cast<std::underlying_type<RunloopState>::type>(
546578
currentRunloopState_.load());
547579
}
580+
for (auto& session: sessions_){
581+
LOG(INFO) << "Stopping child profiler session";
582+
session->stop();
583+
}
548584
currentRunloopState_ = RunloopState::ProcessTrace;
549585
}
550586

@@ -701,6 +737,7 @@ void ActivityProfiler::resetTraceData() {
701737
disabledTraceSpans_.clear();
702738
traceBuffers_ = nullptr;
703739
metadata_.clear();
740+
sessions_.clear();
704741
}
705742

706743

libkineto/src/ActivityProfiler.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "libkineto.h"
2727
#include "output_base.h"
2828
#include "GenericTraceActivity.h"
29+
#include "IActivityProfiler.h"
2930

3031
namespace KINETO_NAMESPACE {
3132

@@ -117,12 +118,19 @@ class ActivityProfiler {
117118
metadata_[key] = value;
118119
}
119120

121+
void addActivityProfiler(
122+
std::shared_ptr<IActivityProfiler> profiler) {
123+
std::lock_guard<std::mutex> guard(mutex_);
124+
profilers_.push_back(profiler);
125+
}
126+
120127
protected:
121128

122129
using CpuGpuSpanPair = std::pair<TraceSpan, TraceSpan>;
123130
static const CpuGpuSpanPair& defaultTraceSpan();
124131

125132
private:
133+
126134
class ExternalEventMap {
127135
public:
128136

@@ -203,6 +211,8 @@ class ActivityProfiler {
203211

204212
void finalizeTrace(const Config& config, ActivityLogger& logger);
205213

214+
void configureChildProfilers();
215+
206216
// Process a single CPU trace
207217
void processCpuTrace(
208218
libkineto::CpuTraceBuffer& cpuTrace,
@@ -357,6 +367,11 @@ class ActivityProfiler {
357367
// Trace metadata
358368
std::unordered_map<std::string, std::string> metadata_;
359369

370+
// child activity profilers
371+
std::vector<std::shared_ptr<IActivityProfiler>> profilers_;
372+
373+
// a vector of active profiler plugin sessions
374+
std::vector<std::unique_ptr<IActivityProfilerSession>> sessions_;
360375
};
361376

362377
} // namespace KINETO_NAMESPACE

libkineto/src/ActivityType.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ static constexpr std::array<ActivityTypeName, activityTypeCount + 1> map{{
2525
{"kernel", ActivityType::CONCURRENT_KERNEL},
2626
{"external_correlation", ActivityType::EXTERNAL_CORRELATION},
2727
{"cuda_runtime", ActivityType::CUDA_RUNTIME},
28+
{"glow_runtime", ActivityType::GLOW_RUNTIME},
2829
{"cpu_instant_event", ActivityType::CPU_INSTANT_EVENT},
2930
{"ENUM_COUNT", ActivityType::ENUM_COUNT}
3031
}};

libkineto/test/ActivityProfilerTest.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,21 @@
2828
#include "src/output_membuf.h"
2929

3030
#include "src/Logger.h"
31+
#include "test/MockActivitySubProfiler.h"
3132

3233
using namespace std::chrono;
3334
using namespace KINETO_NAMESPACE;
3435

3536
#define CUDA_LAUNCH_KERNEL CUPTI_RUNTIME_TRACE_CBID_cudaLaunchKernel_v7000
3637
#define CUDA_MEMCPY CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy_v3020
3738

39+
namespace {
40+
const TraceSpan& defaultTraceSpan() {
41+
static TraceSpan span(0, 0, "Unknown", "");
42+
return span;
43+
}
44+
}
45+
3846
// Provides ability to easily create a few test CPU-side ops
3947
struct MockCpuActivityBuffer : public CpuTraceBuffer {
4048
MockCpuActivityBuffer(int64_t startTime, int64_t endTime) {
@@ -375,6 +383,78 @@ TEST_F(ActivityProfilerTest, CorrelatedTimestampTest) {
375383
EXPECT_EQ(counts["launchKernel"], 1);
376384
}
377385

386+
TEST_F(ActivityProfilerTest, SubActivityProfilers) {
387+
using ::testing::Return;
388+
using ::testing::ByMove;
389+
390+
// Verbose logging is useful for debugging
391+
std::vector<std::string> log_modules(
392+
{"ActivityProfiler.cpp"});
393+
SET_LOG_VERBOSITY_LEVEL(2, log_modules);
394+
395+
// Setup example events to test
396+
GenericTraceActivity ev{defaultTraceSpan(), ActivityType::GLOW_RUNTIME, ""};
397+
ev.device = 1;
398+
ev.resource = 0;
399+
400+
int64_t start_time_us = 100;
401+
int64_t duration_us = 1000;
402+
auto start_time = time_point<system_clock>(microseconds(start_time_us));
403+
404+
std::vector<GenericTraceActivity> test_activities{3, ev};
405+
test_activities[0].startTime = start_time_us;
406+
test_activities[0].endTime = start_time_us + 5000;
407+
test_activities[0].activityName = "SubGraph A execution";
408+
test_activities[1].startTime = start_time_us;
409+
test_activities[1].endTime = start_time_us + 2000;
410+
test_activities[1].activityName = "Operator foo";
411+
test_activities[2].startTime = start_time_us + 2500;
412+
test_activities[2].endTime = start_time_us + 2900;
413+
test_activities[2].activityName = "Operator bar";
414+
415+
auto mock_activity_profiler =
416+
std::make_shared<MockActivityProfiler>(test_activities);
417+
418+
MockCuptiActivities activities;
419+
ActivityProfiler profiler(activities, /*cpu only*/ true);
420+
profiler.addActivityProfiler(mock_activity_profiler);
421+
422+
profiler.configure(*cfg_, start_time);
423+
profiler.startTrace(start_time);
424+
EXPECT_TRUE(profiler.isActive());
425+
426+
profiler.stopTrace(start_time + microseconds(duration_us));
427+
EXPECT_TRUE(profiler.isActive());
428+
429+
char filename[] = "/tmp/libkineto_testXXXXXX.json";
430+
mkstemps(filename, 5);
431+
LOG(INFO) << "Logging to tmp file " << filename;
432+
433+
// process trace
434+
auto logger = std::make_unique<MemoryTraceLogger>(*cfg_);
435+
profiler.processTrace(*logger);
436+
profiler.setLogger(logger.get());
437+
438+
ActivityTrace trace(std::move(logger), loggerFactory);
439+
trace.save(filename);
440+
const auto& traced_activites = trace.activities();
441+
442+
// Test we have all the events
443+
EXPECT_EQ(traced_activites->size(), test_activities.size());
444+
445+
// Check that the expected file was written and that it has some content
446+
int fd = open(filename, O_RDONLY);
447+
if (!fd) {
448+
perror(filename);
449+
}
450+
EXPECT_TRUE(fd);
451+
452+
// Should expect at least 100 bytes
453+
struct stat buf{};
454+
fstat(fd, &buf);
455+
EXPECT_GT(buf.st_size, 100);
456+
}
457+
378458
TEST_F(ActivityProfilerTest, BufferSizeLimitTestWarmup) {
379459
ActivityProfiler profiler(cuptiActivities_, /*cpu only*/ false);
380460

libkineto/test/ConfigTest.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ TEST(ParseTest, ActivityTypes) {
9292
ActivityType::GPU_MEMSET,
9393
ActivityType::CONCURRENT_KERNEL,
9494
ActivityType::EXTERNAL_CORRELATION,
95+
ActivityType::GLOW_RUNTIME,
9596
ActivityType::CUDA_RUNTIME}));
9697

9798
Config cfg2;

0 commit comments

Comments
 (0)