Skip to content

Commit f33afea

Browse files
[mlir] Add an Observer for profiling actions to a stream. (#67251)
The profile is stored in the Chrome trace event format. Added the --profile-action-to=<file> option to mlir-opt.
1 parent b116747 commit f33afea

File tree

6 files changed

+155
-0
lines changed

6 files changed

+155
-0
lines changed

mlir/include/mlir/Debug/CLOptionsSetup.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ class DebugConfig {
5151
/// Get the filename to use for logging actions.
5252
StringRef getLogActionsTo() const { return logActionsToFlag; }
5353

54+
/// Get the filename to use for profiling actions.
55+
StringRef getProfileActionsTo() const { return profileActionsToFlag; }
56+
5457
/// Set a location breakpoint manager to filter out action logging based on
5558
/// the attached IR location in the Action context. Ownership stays with the
5659
/// caller.
@@ -71,6 +74,9 @@ class DebugConfig {
7174
/// Log action execution to the given file (or "-" for stdout)
7275
std::string logActionsToFlag;
7376

77+
/// Profile action execution to the given file (or "-" for stdout)
78+
std::string profileActionsToFlag;
79+
7480
/// Location Breakpoints to filter the action logging.
7581
std::vector<tracing::BreakpointManager *> logActionLocationFilter;
7682
};
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===- ActionProfiler.h - Profiling Actions *- C++ -*-=======================//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef MLIR_TRACING_OBSERVERS_ACTIONPROFILER_H
10+
#define MLIR_TRACING_OBSERVERS_ACTIONPROFILER_H
11+
12+
#include "mlir/Debug/ExecutionContext.h"
13+
#include "llvm/ADT/StringRef.h"
14+
#include "llvm/Support/raw_ostream.h"
15+
16+
#include <chrono>
17+
#include <mutex>
18+
19+
namespace mlir {
20+
namespace tracing {
21+
22+
/// This class defines an observer that profiles events before and after
23+
/// execution on the provided stream. The events are stored in the Chrome trace
24+
/// event format.
25+
struct ActionProfiler : public ExecutionContext::Observer {
26+
ActionProfiler(raw_ostream &os)
27+
: os(os), startTime(std::chrono::steady_clock::now()) {
28+
os << "[";
29+
}
30+
31+
~ActionProfiler() override { os << "]"; }
32+
33+
void beforeExecute(const ActionActiveStack *action, Breakpoint *breakpoint,
34+
bool willExecute) override;
35+
void afterExecute(const ActionActiveStack *action) override;
36+
37+
private:
38+
void print(const ActionActiveStack *action, llvm::StringRef phase);
39+
40+
raw_ostream &os;
41+
std::chrono::time_point<std::chrono::steady_clock> startTime;
42+
bool printComma = false;
43+
44+
/// A mutex used to guard profiling.
45+
std::mutex mutex;
46+
};
47+
48+
} // namespace tracing
49+
} // namespace mlir
50+
51+
#endif // MLIR_TRACING_OBSERVERS_ACTIONPROFILER_H

mlir/lib/Debug/CLOptionsSetup.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "mlir/Debug/DebuggerExecutionContextHook.h"
1313
#include "mlir/Debug/ExecutionContext.h"
1414
#include "mlir/Debug/Observers/ActionLogging.h"
15+
#include "mlir/Debug/Observers/ActionProfiler.h"
1516
#include "mlir/IR/MLIRContext.h"
1617
#include "mlir/Support/FileUtilities.h"
1718
#include "llvm/Support/CommandLine.h"
@@ -30,6 +31,12 @@ struct DebugConfigCLOptions : public DebugConfig {
3031
" '-' is passed"),
3132
cl::location(logActionsToFlag)};
3233

34+
static cl::opt<std::string, /*ExternalStorage=*/true> profileActionsTo{
35+
"profile-actions-to",
36+
cl::desc("Profile action execution to a file, or stderr if "
37+
" '-' is passed"),
38+
cl::location(profileActionsToFlag)};
39+
3340
static cl::list<std::string> logActionLocationFilter(
3441
"log-mlir-actions-filter",
3542
cl::desc(
@@ -71,6 +78,7 @@ class InstallDebugHandler::Impl {
7178
public:
7279
Impl(MLIRContext &context, const DebugConfig &config) {
7380
if (config.getLogActionsTo().empty() &&
81+
config.getProfileActionsTo().empty() &&
7482
!config.isDebuggerActionHookEnabled()) {
7583
if (tracing::DebugCounter::isActivated())
7684
context.registerActionHandler(tracing::DebugCounter());
@@ -97,6 +105,24 @@ class InstallDebugHandler::Impl {
97105
actionLogger->addBreakpointManager(locationBreakpoint);
98106
executionContext.registerObserver(actionLogger.get());
99107
}
108+
109+
if (!config.getProfileActionsTo().empty()) {
110+
std::string errorMessage;
111+
profileActionsFile =
112+
openOutputFile(config.getProfileActionsTo(), &errorMessage);
113+
if (!profileActionsFile) {
114+
emitError(UnknownLoc::get(&context),
115+
"Opening file for --profile-actions-to failed: ")
116+
<< errorMessage << "\n";
117+
return;
118+
}
119+
profileActionsFile->keep();
120+
raw_fd_ostream &profileActionsStream = profileActionsFile->os();
121+
actionProfiler =
122+
std::make_unique<tracing::ActionProfiler>(profileActionsStream);
123+
executionContext.registerObserver(actionProfiler.get());
124+
}
125+
100126
if (config.isDebuggerActionHookEnabled()) {
101127
errs() << " (with Debugger hook)";
102128
setupDebuggerExecutionContextHook(executionContext);
@@ -111,6 +137,8 @@ class InstallDebugHandler::Impl {
111137
std::unique_ptr<tracing::ActionLogger> actionLogger;
112138
std::vector<std::unique_ptr<tracing::FileLineColLocBreakpoint>>
113139
locationBreakpoints;
140+
std::unique_ptr<ToolOutputFile> profileActionsFile;
141+
std::unique_ptr<tracing::ActionProfiler> actionProfiler;
114142
};
115143

116144
InstallDebugHandler::InstallDebugHandler(MLIRContext &context,
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//===- ActionProfiler.cpp - Profiling Actions *- C++ -*-=====================//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "mlir/Debug/Observers/ActionProfiler.h"
10+
#include "mlir/Debug/BreakpointManager.h"
11+
#include "mlir/IR/Action.h"
12+
#include "mlir/Rewrite/PatternApplicator.h"
13+
#include "llvm/Support/Casting.h"
14+
#include "llvm/Support/Threading.h"
15+
#include "llvm/Support/raw_ostream.h"
16+
#include <chrono>
17+
18+
using namespace mlir;
19+
using namespace mlir::tracing;
20+
21+
//===----------------------------------------------------------------------===//
22+
// ActionProfiler
23+
//===----------------------------------------------------------------------===//
24+
void ActionProfiler::beforeExecute(const ActionActiveStack *action,
25+
Breakpoint *breakpoint, bool willExecute) {
26+
print(action, "B"); // begin event.
27+
}
28+
29+
void ActionProfiler::afterExecute(const ActionActiveStack *action) {
30+
print(action, "E"); // end event.
31+
}
32+
33+
// Print an event in JSON format.
34+
void ActionProfiler::print(const ActionActiveStack *action,
35+
llvm::StringRef phase) {
36+
// Create the event.
37+
std::string str;
38+
llvm::raw_string_ostream event(str);
39+
event << "{";
40+
event << R"("name": ")" << action->getAction().getTag() << "\", ";
41+
event << R"("cat": "PERF", )";
42+
event << R"("ph": ")" << phase << "\", ";
43+
event << R"("pid": 0, )";
44+
event << R"("tid": )" << llvm::get_threadid() << ", ";
45+
auto ts = std::chrono::steady_clock::now() - startTime;
46+
event << R"("ts": )"
47+
<< std::chrono::duration_cast<std::chrono::microseconds>(ts).count();
48+
if (phase == "B") {
49+
event << R"(, "args": {)";
50+
event << R"("desc": ")";
51+
action->getAction().print(event);
52+
event << "\"}";
53+
}
54+
event << "}";
55+
56+
// Print the event.
57+
std::lock_guard<std::mutex> guard(mutex);
58+
if (printComma)
59+
os << ",\n";
60+
printComma = true;
61+
os << event.str();
62+
os.flush();
63+
}

mlir/lib/Debug/Observers/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
add_mlir_library(MLIRObservers
22
ActionLogging.cpp
3+
ActionProfiler.cpp
34

45
ADDITIONAL_HEADER_DIRS
56
${MLIR_MAIN_INCLUDE_DIR}/mlir/Debug/Observers

mlir/test/Pass/action-profiler.mlir

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: mlir-opt %s --profile-actions-to=- -test-stats-pass -test-module-pass | FileCheck %s
2+
3+
// CHECK: {"name": "pass-execution", "cat": "PERF", "ph": "B", "pid": 0, "tid": {{[0-9]+}}, "ts": {{[0-9]+}}, "args": {"desc": "`pass-execution` running `{{.*}}TestStatisticPass` on Operation `builtin.module`"}},
4+
// CHECK-NEXT: {"name": "pass-execution", "cat": "PERF", "ph": "E", "pid": 0, "tid": {{[0-9]+}}, "ts": {{[0-9]+}}},
5+
// CHECK-NEXT: {"name": "pass-execution", "cat": "PERF", "ph": "B", "pid": 0, "tid": {{[0-9]+}}, "ts": {{[0-9]+}}, "args": {"desc": "`pass-execution` running `{{.*}}TestModulePass` on Operation `builtin.module`"}},
6+
// CHECK-NEXT: {"name": "pass-execution", "cat": "PERF", "ph": "E", "pid": 0, "tid": {{[0-9]+}}, "ts": {{[0-9]+}}}

0 commit comments

Comments
 (0)