Skip to content

Commit bd8fbc9

Browse files
authored
Add support for TimingManager (#219)
Introduces support for the TimingManager which was a part of LLVM 17. This enables time tracing of (parallel) compilation across target systems. For example this is a report from the mock target. ``` ===-------------------------------------------------------------------------=== ... Execution time report ... ===-------------------------------------------------------------------------=== Total Execution Time: 0.0089 seconds ----User Time---- ----Wall Time---- ----Name---- 0.0000 ( 0.1%) 0.0000 ( 0.2%) build-config 0.0001 ( 0.7%) 0.0001 ( 1.3%) build-target 0.0004 ( 2.7%) 0.0004 ( 4.7%) parse-mlir 0.0000 ( 0.1%) 0.0000 ( 0.1%) command-line-passes 0.0143 ( 91.6%) 0.0076 ( 85.3%) build-qem 0.0142 ( 91.0%) 0.0075 ( 84.2%) compile-payload 0.0011 ( 7.2%) 0.0011 ( 12.7%) build-target-pass-managers 0.0130 ( 83.5%) 0.0063 ( 71.0%) compile-system 0.0130 ( 83.5%) 0.0063 ( 71.0%) MockSystem 0.0019 ( 12.2%) 0.0010 ( 10.7%) passes 0.0001 ( 0.4%) 0.0001 ( 0.6%) Canonicalizer 0.0000 ( 0.2%) 0.0000 ( 0.3%) mlir::quir::BreakResetPass 0.0000 ( 0.1%) 0.0000 ( 0.1%) mlir::quir::SubroutineCloningPass 0.0000 ( 0.0%) 0.0000 ( 0.0%) mlir::quir::RemoveQubitOperandsPass 0.0000 ( 0.0%) 0.0000 ( 0.1%) mlir::quir::ClassicalOnlyDetectionPass 0.0001 ( 0.5%) 0.0001 ( 0.9%) qssc::targets::systems::mock::MockQubitLocalizationPass 0.0000 ( 0.0%) 0.0000 ( 0.0%) qssc::targets::systems::mock::SymbolTableBuildPass 0.0009 ( 6.1%) 0.0005 ( 5.4%) 'builtin.module' Pipeline 0.0007 ( 4.2%) 0.0004 ( 4.6%) qssc::targets::systems::mock::MockFunctionLocalizationPass 0.0000 ( 0.1%) 0.0000 ( 0.1%) mlir::quir::FunctionArgumentSpecializationPass 0.0000 ( 0.0%) 0.0000 ( 0.0%) emit-to-payload 0.0110 ( 70.7%) 0.0053 ( 59.3%) children 0.0052 ( 33.1%) 0.0052 ( 58.2%) MockController 0.0004 ( 2.5%) 0.0004 ( 4.5%) passes 0.0002 ( 1.3%) 0.0002 ( 2.3%) qssc::targets::systems::mock::conversion::MockQUIRToStdPass 0.0000 ( 0.1%) 0.0000 ( 0.2%) Canonicalizer 0.0000 ( 0.0%) 0.0000 ( 0.0%) LLVMLegalizeForExport 0.0048 ( 30.5%) 0.0048 ( 53.6%) emit-to-payload 0.0000 ( 0.0%) 0.0000 ( 0.0%) emit-to-payload-post-children 0.0002 ( 1.5%) 0.0002 ( 2.6%) MockDrive_0 0.0000 ( 0.0%) 0.0000 ( 0.1%) passes 0.0002 ( 1.4%) 0.0002 ( 2.4%) emit-to-payload 0.0000 ( 0.0%) 0.0000 ( 0.0%) emit-to-payload-post-children 0.0002 ( 1.4%) 0.0002 ( 2.5%) MockAcquire_0 0.0000 ( 0.0%) 0.0000 ( 0.0%) passes 0.0002 ( 1.3%) 0.0002 ( 2.3%) emit-to-payload 0.0000 ( 0.0%) 0.0000 ( 0.0%) emit-to-payload-post-children 0.0001 ( 1.0%) 0.0001 ( 1.7%) MockDrive_1 0.0000 ( 0.1%) 0.0000 ( 0.3%) passes 0.0001 ( 0.6%) 0.0001 ( 1.1%) emit-to-payload 0.0000 ( 0.0%) 0.0000 ( 0.0%) emit-to-payload-post-children 0.0000 ( 0.0%) 0.0000 ( 0.0%) emit-to-payload-post-children 0.0001 ( 0.6%) 0.0001 ( 1.0%) write-payload 0.0007 ( 4.8%) 0.0007 ( 8.4%) Rest 0.0156 (100.0%) 0.0089 (100.0%) Total ```
1 parent 5232bf9 commit bd8fbc9

File tree

13 files changed

+335
-96
lines changed

13 files changed

+335
-96
lines changed

include/Frontend/OpenQASM3/OpenQASM3Frontend.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "API/errors.h"
2626

2727
#include "mlir/IR/BuiltinOps.h"
28+
#include "mlir/Support/Timing.h"
2829

2930
#include "llvm/Support/Error.h"
3031

@@ -47,7 +48,8 @@ namespace qssc::frontend::openqasm3 {
4748
llvm::Error parse(std::string const &source, bool sourceIsFilename,
4849
bool emitRawAST, bool emitPrettyAST, bool emitMLIR,
4950
mlir::ModuleOp newModule,
50-
std::optional<DiagnosticCallback> diagnosticCb);
51+
std::optional<DiagnosticCallback> diagnosticCb,
52+
mlir::TimingScope &timing);
5153

5254
}; // namespace qssc::frontend::openqasm3
5355

include/HAL/Compile/TargetCompilationManager.h

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,18 @@ class TargetCompilationManager {
4343
TargetCompilationManager(hal::TargetSystem &target,
4444
mlir::MLIRContext *context);
4545

46-
using WalkTargetModulesFunction =
47-
std::function<llvm::Error(hal::Target *, mlir::ModuleOp)>;
48-
using WalkTargetFunction = std::function<llvm::Error(hal::Target *)>;
46+
using WalkTargetModulesFunction = std::function<llvm::Error(
47+
hal::Target *, mlir::ModuleOp, mlir::TimingScope &timing)>;
48+
using WalkTargetFunction =
49+
std::function<llvm::Error(hal::Target *, mlir::TimingScope &timing)>;
4950

5051
// Depth first walker for a target system
51-
llvm::Error walkTarget(Target *target, const WalkTargetFunction &walkFunc);
52+
llvm::Error walkTarget(Target *target, mlir::TimingScope &timing,
53+
const WalkTargetFunction &walkFunc);
5254
// Depth first walker for a target system modules
5355
llvm::Error
5456
walkTargetModules(Target *target, mlir::ModuleOp targetModuleOp,
57+
mlir::TimingScope &timing,
5558
const WalkTargetModulesFunction &walkFunc,
5659
const WalkTargetModulesFunction &postChildrenCallbackFunc);
5760

@@ -68,7 +71,8 @@ class TargetCompilationManager {
6871
/// @brief Compile only at the MLIR level for the full target
6972
/// system.
7073
/// @param moduleOp The root module operation to compile for.
71-
/// This must not be specialized to a system already.
74+
/// @param timing Root timing scope for tracking timing of payload
75+
/// compilation. This must not be specialized to a system already.
7276
virtual llvm::Error compileMLIR(mlir::ModuleOp moduleOp) = 0;
7377

7478
/// @brief Generate the full configured compilation pipeline
@@ -77,6 +81,8 @@ class TargetCompilationManager {
7781
/// @param moduleOp The root module operation to compile for.
7882
/// This must not be specialized to a system already.
7983
/// @param payload The payload to populate.
84+
/// @param timing Root timing scope for tracking timing of payload
85+
/// compilation.
8086
/// @param doCompileMLIR Whether to call compileMLIR prior to compiling the
8187
/// payload. Defaults to true.
8288
virtual llvm::Error compilePayload(mlir::ModuleOp moduleOp,
@@ -88,6 +94,9 @@ class TargetCompilationManager {
8894
bool printBeforeAllTargetPayload,
8995
bool printAfterTargetCompileFailure);
9096

97+
void enableTiming(mlir::TimingScope &timingScope);
98+
void disableTiming();
99+
91100
protected:
92101
bool getPrintBeforeAllTargetPasses() { return printBeforeAllTargetPasses; }
93102
bool getPrintAfterAllTargetPasses() { return printAfterAllTargetPasses; }
@@ -97,9 +106,13 @@ class TargetCompilationManager {
97106
}
98107

99108
/// Thread-safe implementation
100-
virtual void printIR(llvm::StringRef msg, mlir::Operation *op,
109+
virtual void printIR(llvm::Twine msg, mlir::Operation *op,
101110
llvm::raw_ostream &out);
102111

112+
/// @brief Get a nested timer instance from the root timer
113+
/// @param name The name of the timing span
114+
mlir::TimingScope getTimer(llvm::StringRef name);
115+
103116
private:
104117
hal::TargetSystem &target;
105118
mlir::MLIRContext *context;
@@ -109,6 +122,8 @@ class TargetCompilationManager {
109122
bool printBeforeAllTargetPayload = false;
110123
bool printAfterTargetCompileFailure = false;
111124

125+
mlir::TimingScope rootTimer;
126+
112127
}; // class TargetCompilationManager
113128

114129
/// Register a set of useful command-line options that can be used to configure

include/HAL/Compile/ThreadedCompilationManager.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,17 @@ class ThreadedCompilationManager : public TargetCompilationManager {
4646
/// Threaded depth first walker for a target system using the current
4747
/// MLIRContext's threadpool.
4848
llvm::Error walkTargetThreaded(
49-
Target *target,
49+
Target *target, mlir::TimingScope &timing,
5050
const TargetCompilationManager::WalkTargetFunction &walkFunc);
5151
/// Threaded depth first walker for a target system modules using the current
5252
/// MLIRContext's threadpool.
5353
llvm::Error walkTargetModulesThreaded(
54-
Target *target, mlir::ModuleOp targetModuleOp,
54+
Target *target, mlir::ModuleOp targetModuleOp, mlir::TimingScope &timing,
5555
const TargetCompilationManager::WalkTargetModulesFunction &walkFunc,
5656
const TargetCompilationManager::WalkTargetModulesFunction
5757
&postChildrenCallbackFunc);
5858

59-
virtual void printIR(llvm::StringRef msg, mlir::Operation *op,
59+
virtual void printIR(llvm::Twine msg, mlir::Operation *op,
6060
llvm::raw_ostream &out) override;
6161

6262
public:
@@ -93,7 +93,8 @@ class ThreadedCompilationManager : public TargetCompilationManager {
9393

9494
/// Prepare pass managers in a threaded way
9595
/// initializing them with the mlir context safely.
96-
llvm::Error buildTargetPassManagers_(Target &target);
96+
llvm::Error buildTargetPassManagers_(Target &target,
97+
mlir::TimingScope &timing);
9798
/// Threadsafe initialization of PM to work around
9899
/// non-threadsafe registration of dependent dialects.
99100
/// I (Thomas) believe this is related to the conversation here
@@ -106,11 +107,13 @@ class ThreadedCompilationManager : public TargetCompilationManager {
106107
mlir::PassManager &createTargetPassManager_(Target *target);
107108

108109
/// Compiles the input module for a single target.
109-
llvm::Error compileMLIRTarget_(Target &target, mlir::ModuleOp targetModuleOp);
110+
llvm::Error compileMLIRTarget_(Target &target, mlir::ModuleOp targetModuleOp,
111+
mlir::TimingScope &timing);
110112
/// Compiles the input payload for a single target.
111113
llvm::Error compilePayloadTarget_(Target &target,
112114
mlir::ModuleOp targetModuleOp,
113115
qssc::payload::Payload &payload,
116+
mlir::TimingScope &timing,
114117
bool doCompileMLIR);
115118

116119
PMBuilder pmBuilder;

include/HAL/TargetSystem.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,12 @@ class Target {
5151
};
5252

5353
public:
54-
virtual const std::string &getName() const { return name; }
54+
virtual llvm::StringRef getName() const { return name; }
5555
virtual llvm::StringRef getDescription() const { return ""; }
56+
/// @brief Get the Target resource directory sub-path for this target
57+
/// which will be used for resolving external static resources at runtime
58+
/// that are configured through the build system.
59+
virtual llvm::StringRef getResourcePath() const { return getName(); }
5660
Target *getParent() { return parent; }
5761
const Target *getParent() const { return parent; }
5862

@@ -129,7 +133,17 @@ class Target {
129133

130134
virtual ~Target() = default;
131135

136+
/// @brief Enable timing from this point for the target and its methods
137+
/// @param timingScope the root timer to nest timers from.
138+
void enableTiming(mlir::TimingScope &timingScope);
139+
/// @brief Disable(stop) ongoing timers
140+
void disableTiming();
141+
132142
protected:
143+
/// @brief Get a nested timer instance from the root timer
144+
/// @param name The name of the timing span
145+
mlir::TimingScope getTimer(llvm::StringRef name);
146+
133147
std::string name;
134148

135149
// parent is already owned by unique_ptr
@@ -139,6 +153,9 @@ class Target {
139153

140154
/// @brief Children targets storage.
141155
std::vector<std::unique_ptr<Target>> children_;
156+
157+
private:
158+
mlir::TimingScope rootTimer;
142159
};
143160

144161
class TargetSystem : public Target {

lib/API/api.cpp

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,11 @@ void showPayloads_() {
146146
/// @param config The configuration defining the context to build.
147147
/// @return The constructed TargetSystem.
148148
llvm::Expected<qssc::hal::TargetSystem &>
149-
buildTarget_(MLIRContext *context, const qssc::config::QSSConfig &config) {
149+
buildTarget_(MLIRContext *context, const qssc::config::QSSConfig &config,
150+
mlir::TimingScope &timing) {
151+
152+
mlir::TimingScope const buildTargetTiming = timing.nest("build-target");
153+
150154
const auto &targetName = config.getTargetName();
151155
const auto &targetConfigPath = config.getTargetConfigPath();
152156

@@ -193,13 +197,18 @@ llvm::Error generateQEM_(
193197
const QSSConfig &config,
194198
qssc::hal::compile::TargetCompilationManager *targetCompilationManager,
195199
std::unique_ptr<qssc::payload::Payload> payload, mlir::ModuleOp moduleOp,
196-
llvm::raw_ostream *ostream) {
200+
llvm::raw_ostream *ostream, mlir::TimingScope &timing) {
197201

202+
mlir::TimingScope buildQEMTiming = timing.nest("build-qem");
203+
targetCompilationManager->enableTiming(buildQEMTiming);
198204
if (auto err = targetCompilationManager->compilePayload(
199205
moduleOp, *payload,
200206
/* doCompileMLIR=*/!config.shouldBypassPayloadTargetCompilation()))
201207
return err;
208+
targetCompilationManager->disableTiming();
202209

210+
mlir::TimingScope const writePayloadTiming =
211+
buildQEMTiming.nest("write-payload");
203212
if (config.shouldEmitPlaintextPayload())
204213
payload->writePlain(*ostream);
205214
else
@@ -223,7 +232,6 @@ llvm::Error buildPassManager_(mlir::PassManager &pm, bool verifyPasses) {
223232
return llvm::createStringError(
224233
llvm::inconvertibleErrorCode(),
225234
"Unable to apply pass manager command line options");
226-
mlir::applyDefaultTimingPassManagerCLOptions(pm);
227235

228236
// Configure verifier
229237
pm.enableVerifier(verifyPasses);
@@ -232,9 +240,13 @@ llvm::Error buildPassManager_(mlir::PassManager &pm, bool verifyPasses) {
232240
}
233241

234242
llvm::Error buildPassManager(const QSSConfig &config, mlir::PassManager &pm,
235-
ErrorHandler errorHandler, bool verifyPasses) {
243+
ErrorHandler errorHandler, bool verifyPasses,
244+
mlir::TimingScope &timing) {
236245
if (auto err = buildPassManager_(pm, verifyPasses))
237246
return err;
247+
248+
pm.enableTiming(timing);
249+
238250
// Build the provided pipeline.
239251
if (failed(config.setupPassPipeline(pm)))
240252
return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -254,20 +266,26 @@ llvm::Error emitMLIR_(
254266
llvm::raw_ostream *ostream, mlir::MLIRContext &context,
255267
mlir::ModuleOp moduleOp, const QSSConfig &config,
256268
qssc::hal::compile::ThreadedCompilationManager &targetCompilationManager,
257-
ErrorHandler errorHandler) {
269+
ErrorHandler errorHandler, mlir::TimingScope &timing) {
270+
271+
mlir::TimingScope emitMlirTiming = timing.nest("emit-mlir");
272+
258273
if (config.shouldCompileTargetIR()) {
259274
// Check if we can run the target compilation scheduler.
260275
if (config.shouldAddTargetPasses()) {
276+
targetCompilationManager.enableTiming(emitMlirTiming);
261277
if (auto err = targetCompilationManager.compileMLIR(moduleOp))
262278
return llvm::joinErrors(
263279
llvm::createStringError(llvm::inconvertibleErrorCode(),
264280
"Failure while preparing target passes"),
265281
std::move(err));
282+
targetCompilationManager.disableTiming();
266283
}
267284
}
268285

269286
// Print the output.
270287
dumpMLIR_(ostream, moduleOp);
288+
271289
return llvm::Error::success();
272290
}
273291

@@ -280,7 +298,8 @@ llvm::Error emitMLIR_(
280298
llvm::Error emitQEM_(
281299
const QSSConfig &config, llvm::raw_ostream *ostream,
282300
std::unique_ptr<qssc::payload::Payload> payload, mlir::ModuleOp moduleOp,
283-
qssc::hal::compile::ThreadedCompilationManager &targetCompilationManager) {
301+
qssc::hal::compile::ThreadedCompilationManager &targetCompilationManager,
302+
mlir::TimingScope &timing) {
284303
if (config.shouldIncludeSource()) {
285304
if (config.isDirectInput()) {
286305
if (config.getInputType() == InputType::QASM)
@@ -308,7 +327,7 @@ llvm::Error emitQEM_(
308327
}
309328

310329
if (auto err = generateQEM_(config, &targetCompilationManager,
311-
std::move(payload), moduleOp, ostream))
330+
std::move(payload), moduleOp, ostream, timing))
312331
return err;
313332

314333
return llvm::Error::success();
@@ -400,11 +419,13 @@ llvm::Error compile_(int argc, char const **argv, std::string *outputString,
400419
// Instantiate after parsing command line options.
401420
MLIRContext context{};
402421

422+
mlir::TimingScope buildConfigTiming = timing.nest("build-config");
403423
auto configResult = qssc::config::buildToolConfig();
404424
if (auto err = configResult.takeError())
405425
return err;
406426
qssc::config::QSSConfig const config = configResult.get();
407427
qssc::config::setContextConfig(&context, config);
428+
buildConfigTiming.stop();
408429

409430
// Populate the context
410431
context.appendDialectRegistry(registry);
@@ -432,7 +453,7 @@ llvm::Error compile_(int argc, char const **argv, std::string *outputString,
432453
}
433454

434455
// Build the target for compilation
435-
auto targetResult = buildTarget_(&context, config);
456+
auto targetResult = buildTarget_(&context, config, timing);
436457
if (auto err = targetResult.takeError())
437458
return err;
438459
auto &target = targetResult.get();
@@ -508,6 +529,9 @@ llvm::Error compile_(int argc, char const **argv, std::string *outputString,
508529
mlir::ModuleOp moduleOp;
509530

510531
if (config.getInputType() == InputType::QASM) {
532+
533+
mlir::TimingScope loadQASM3Timing = timing.nest("load-qasm3");
534+
511535
if (config.getEmitAction() >= EmitAction::MLIR) {
512536
moduleOp = mlir::ModuleOp::create(FileLineColLoc::get(
513537
&context,
@@ -519,7 +543,8 @@ llvm::Error compile_(int argc, char const **argv, std::string *outputString,
519543
config.getInputSource().str(), !config.isDirectInput(),
520544
config.getEmitAction() == EmitAction::AST,
521545
config.getEmitAction() == EmitAction::ASTPretty,
522-
config.getEmitAction() >= EmitAction::MLIR, moduleOp, diagnosticCb))
546+
config.getEmitAction() >= EmitAction::MLIR, moduleOp, diagnosticCb,
547+
loadQASM3Timing))
523548
return frontendError;
524549

525550
if (config.getEmitAction() < EmitAction::MLIR)
@@ -528,6 +553,8 @@ llvm::Error compile_(int argc, char const **argv, std::string *outputString,
528553

529554
if (config.getInputType() == InputType::MLIR) {
530555

556+
mlir::TimingScope mlirParserTiming = timing.nest("parse-mlir");
557+
531558
// Tell sourceMgr about this buffer, which is what the parser will pick up.
532559
auto sourceMgr = std::make_shared<llvm::SourceMgr>();
533560
sourceMgr->AddNewSourceBuffer(std::move(file), llvm::SMLoc());
@@ -552,11 +579,10 @@ llvm::Error compile_(int argc, char const **argv, std::string *outputString,
552579
reproOptions.attachResourceParser(parseConfig);
553580

554581
// Parse the input file and reset the context threading state.
555-
mlir::TimingScope parserTiming = timing.nest("Parser");
556582
mlir::OwningOpRef<Operation *> op = mlir::parseSourceFileForTool(
557583
sourceMgr, parseConfig, !config.shouldUseExplicitModule());
558584

559-
parserTiming.stop();
585+
mlirParserTiming.stop();
560586

561587
if (!op)
562588
return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -606,25 +632,30 @@ llvm::Error compile_(int argc, char const **argv, std::string *outputString,
606632
"Unable to apply target compilation options.");
607633

608634
// Run additional passes specified on the command line
635+
636+
mlir::TimingScope commandLinePassesTiming =
637+
timing.nest("command-line-passes");
609638
mlir::PassManager pm(&context);
610-
if (auto err = buildPassManager(config, pm, errorHandler, verifyPasses))
639+
if (auto err = buildPassManager(config, pm, errorHandler, verifyPasses,
640+
commandLinePassesTiming))
611641
return err;
612642

613643
if (pm.size() && failed(pm.run(moduleOp)))
614644
return llvm::createStringError(llvm::inconvertibleErrorCode(),
615645
"Problems running the compiler pipeline!");
646+
commandLinePassesTiming.stop();
616647

617648
// Prepare outputs
618649
if (config.getEmitAction() == EmitAction::MLIR) {
619650
if (auto err = emitMLIR_(ostream, context, moduleOp, config,
620-
targetCompilationManager, errorHandler))
651+
targetCompilationManager, errorHandler, timing))
621652
return err;
622653
}
623654

624655
if (config.getEmitAction() == EmitAction::QEM ||
625656
config.getEmitAction() == EmitAction::QEQEM) {
626657
if (auto err = emitQEM_(config, ostream, std::move(payload), moduleOp,
627-
targetCompilationManager))
658+
targetCompilationManager, timing))
628659
return err;
629660
}
630661

0 commit comments

Comments
 (0)