From d0901aa7933ac31b0bf7648a31ec5c13de864457 Mon Sep 17 00:00:00 2001 From: Yong He Date: Tue, 11 Jul 2023 09:29:27 -0700 Subject: Add perf benchmark utility. (#2977) * Add perf benchmark utility. * Update documentation. * Fix. * Fix doc. --------- Co-authored-by: Yong He --- source/core/slang-performance-profiler.cpp | 52 ++++++++++++++++++++++++++++ source/core/slang-performance-profiler.h | 42 ++++++++++++++++++++++ source/slang/slang-compiler.h | 4 +++ source/slang/slang-diagnostic-defs.h | 2 +- source/slang/slang-emit.cpp | 2 ++ source/slang/slang-ir-autodiff.cpp | 2 ++ source/slang/slang-ir-inline.cpp | 5 +++ source/slang/slang-ir-legalize-types.cpp | 5 +++ source/slang/slang-ir-link.cpp | 3 ++ source/slang/slang-ir-loop-unroll.cpp | 3 ++ source/slang/slang-ir-lower-generics.cpp | 4 ++- source/slang/slang-ir-specialize.cpp | 2 ++ source/slang/slang-ir-ssa-simplification.cpp | 2 ++ source/slang/slang-options.cpp | 7 ++++ source/slang/slang.cpp | 14 ++++++-- 15 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 source/core/slang-performance-profiler.cpp create mode 100644 source/core/slang-performance-profiler.h (limited to 'source') diff --git a/source/core/slang-performance-profiler.cpp b/source/core/slang-performance-profiler.cpp new file mode 100644 index 000000000..f5f74f99d --- /dev/null +++ b/source/core/slang-performance-profiler.cpp @@ -0,0 +1,52 @@ +#include "slang-performance-profiler.h" +#include "slang-dictionary.h" + +namespace Slang +{ + struct FuncProfileInfo + { + int invocationCount = 0; + std::chrono::nanoseconds duration = std::chrono::nanoseconds::zero(); + }; + class PerformanceProfilerImpl : public PerformanceProfiler + { + public: + OrderedDictionary data; + + virtual FuncProfileContext enterFunction(const char* funcName) override + { + auto entry = data.tryGetValue(funcName); + if (!entry) + { + data.add(funcName, FuncProfileInfo()); + entry = data.tryGetValue(funcName); + } + entry->invocationCount++; + FuncProfileContext ctx; + ctx.funcName = funcName; + ctx.startTime = std::chrono::high_resolution_clock::now(); + return ctx; + } + virtual void exitFunction(FuncProfileContext ctx) override + { + auto endTime = std::chrono::high_resolution_clock::now(); + auto duration = endTime - ctx.startTime; + auto entry = data.tryGetValue(ctx.funcName); + entry->duration += duration; + } + virtual void getResult(StringBuilder& out) override + { + for (auto func : data) + { + out << func.key << ": \t"; + out << func.value.invocationCount << "\t" << func.value.duration.count()/1000000 << "\n"; + } + } + }; + + PerformanceProfiler* Slang::PerformanceProfiler::getProfiler() + { + static PerformanceProfilerImpl profiler = PerformanceProfilerImpl(); + return &profiler; + } +} diff --git a/source/core/slang-performance-profiler.h b/source/core/slang-performance-profiler.h new file mode 100644 index 000000000..323940ade --- /dev/null +++ b/source/core/slang-performance-profiler.h @@ -0,0 +1,42 @@ +#ifndef SLANG_CORE_PERFORMANCE_PROFILER_H +#define SLANG_CORE_PERFORMANCE_PROFILER_H + +#include "slang-string.h" +#include + +namespace Slang +{ + +struct FuncProfileContext +{ + const char* funcName = nullptr; + std::chrono::time_point startTime; +}; + +class PerformanceProfiler +{ +public: + virtual FuncProfileContext enterFunction(const char* funcName) = 0; + virtual void exitFunction(FuncProfileContext context) = 0; + virtual void getResult(StringBuilder& out) = 0; +public: + static PerformanceProfiler* getProfiler(); +}; + +struct PerformanceProfilerFuncRAIIContext +{ + FuncProfileContext context; + PerformanceProfilerFuncRAIIContext(const char* funcName) + { + context = PerformanceProfiler::getProfiler()->enterFunction(funcName); + } + ~PerformanceProfilerFuncRAIIContext() + { + PerformanceProfiler::getProfiler()->exitFunction(context); + } +}; + +#define SLANG_PROFILE PerformanceProfilerFuncRAIIContext _profileContext(__func__) +} + +#endif diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index 7082eccd7..e6385c76d 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -2646,6 +2646,7 @@ namespace Slang virtual SLANG_NO_THROW void SLANG_MCALL setDiagnosticFlags(SlangDiagnosticFlags flags) SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL setDebugInfoFormat(SlangDebugInfoFormat format) SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL setReportDownstreamTime(bool value) SLANG_OVERRIDE; + virtual SLANG_NO_THROW void SLANG_MCALL setReportPerfBenchmark(bool value) SLANG_OVERRIDE; void setHLSLToVulkanLayoutOptions(int targetIndex, HLSLToVulkanLayoutOptions* vulkanLayoutOptions); EndToEndCompileRequest( @@ -2691,6 +2692,9 @@ namespace Slang bool m_isCommandLineCompile = false; bool m_reportDownstreamCompileTime = false; + + // If set, will print out compiler performance benchmark results. + bool m_reportPerfBenchmark = false; String m_diagnosticOutput; diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 92f79eac5..1832a3b46 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -143,7 +143,7 @@ DIAGNOSTIC( 99, Error, unknownDebugOption, "unknown debug option, known optio DIAGNOSTIC( 100, Error, failedToLoadDownstreamCompiler, "failed to load downstream compiler '$0'") DIAGNOSTIC( 101, Error, downstreamCompilerDoesntSupportWholeProgramCompilation, "downstream compiler '$0' doesn't support whole program compilation") DIAGNOSTIC( 102, Note, downstreamCompileTime, "downstream compile time: $0s") - +DIAGNOSTIC( 103, Note, performanceBenchmarkResult, "compiler performance benchmark:\n$0") DIAGNOSTIC(99999, Note, noteFailedToLoadDynamicLibrary, "failed to load dynamic library '$0'") // diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 41230d169..d71cc5507 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -89,6 +89,7 @@ #include "../compiler-core/slang-artifact-associated-impl.h" #include "../core/slang-castable.h" +#include "../core/slang-performance-profiler.h" #include @@ -199,6 +200,7 @@ Result linkAndOptimizeIR( LinkingAndOptimizationOptions const& options, LinkedIR& outLinkedIR) { + SLANG_PROFILE; auto session = codeGenContext->getSession(); auto sink = codeGenContext->getSink(); auto target = codeGenContext->getTargetFormat(); diff --git a/source/slang/slang-ir-autodiff.cpp b/source/slang/slang-ir-autodiff.cpp index 6d56736ad..2231e0ce7 100644 --- a/source/slang/slang-ir-autodiff.cpp +++ b/source/slang/slang-ir-autodiff.cpp @@ -6,6 +6,7 @@ #include "slang-ir-single-return.h" #include "slang-ir-ssa-simplification.h" #include "slang-ir-validate.h" +#include "../core/slang-performance-profiler.h" namespace Slang { @@ -1726,6 +1727,7 @@ bool processAutodiffCalls( DiagnosticSink* sink, IRAutodiffPassOptions const&) { + SLANG_PROFILE; bool modified = false; // Create shared context for all auto-diff related passes diff --git a/source/slang/slang-ir-inline.cpp b/source/slang/slang-ir-inline.cpp index f825a9461..db4bb50a8 100644 --- a/source/slang/slang-ir-inline.cpp +++ b/source/slang/slang-ir-inline.cpp @@ -3,6 +3,7 @@ #include "slang-ir-ssa-simplification.h" +#include "../core/slang-performance-profiler.h" // This file provides general facilities for inlining function calls. // @@ -671,6 +672,8 @@ struct MandatoryEarlyInliningPass : InliningPassBase void performMandatoryEarlyInlining(IRModule* module) { + SLANG_PROFILE; + MandatoryEarlyInliningPass pass(module); pass.considerAllCallSites(); } @@ -785,6 +788,8 @@ struct ForceInliningPass : InliningPassBase void performForceInlining(IRModule* module) { + SLANG_PROFILE; + ForceInliningPass pass(module); pass.considerAllCallSites(); } diff --git a/source/slang/slang-ir-legalize-types.cpp b/source/slang/slang-ir-legalize-types.cpp index 162498bf0..a88d43db3 100644 --- a/source/slang/slang-ir-legalize-types.cpp +++ b/source/slang/slang-ir-legalize-types.cpp @@ -11,6 +11,7 @@ // that the concrete type of everything is known. #include "../compiler-core/slang-name.h" +#include "../core/slang-performance-profiler.h" #include "slang-ir.h" #include "slang-ir-clone.h" @@ -3843,6 +3844,8 @@ void legalizeResourceTypes( IRModule* module, DiagnosticSink* sink) { + SLANG_PROFILE; + SLANG_UNUSED(sink); IRResourceTypeLegalizationContext context(module); @@ -3853,6 +3856,8 @@ void legalizeExistentialTypeLayout( IRModule* module, DiagnosticSink* sink) { + SLANG_PROFILE; + SLANG_UNUSED(module); SLANG_UNUSED(sink); diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp index f57919e44..081fd7486 100644 --- a/source/slang/slang-ir-link.cpp +++ b/source/slang/slang-ir-link.cpp @@ -9,6 +9,7 @@ #include "slang-ir-autodiff.h" #include "slang-module-library.h" +#include "../core/slang-performance-profiler.h" #include "../compiler-core/slang-artifact.h" namespace Slang @@ -1428,6 +1429,8 @@ static bool _isPublicOrHLSLExported(IRInst* inst) LinkedIR linkIR( CodeGenContext* codeGenContext) { + SLANG_PROFILE; + auto linkage = codeGenContext->getLinkage(); auto program = codeGenContext->getProgram(); auto session = codeGenContext->getSession(); diff --git a/source/slang/slang-ir-loop-unroll.cpp b/source/slang/slang-ir-loop-unroll.cpp index 05e829827..36a2abbfc 100644 --- a/source/slang/slang-ir-loop-unroll.cpp +++ b/source/slang/slang-ir-loop-unroll.cpp @@ -7,6 +7,7 @@ #include "slang-ir-util.h" #include "slang-ir-simplify-cfg.h" #include "slang-ir-dce.h" +#include "../core/slang-performance-profiler.h" namespace Slang { @@ -508,6 +509,8 @@ bool unrollLoopsInFunc( bool unrollLoopsInModule(IRModule* module, DiagnosticSink* sink) { + SLANG_PROFILE; + for (auto inst : module->getGlobalInsts()) { if (auto genFunc = as(inst)) diff --git a/source/slang/slang-ir-lower-generics.cpp b/source/slang/slang-ir-lower-generics.cpp index fc810e54e..6a5abbf8c 100644 --- a/source/slang/slang-ir-lower-generics.cpp +++ b/source/slang/slang-ir-lower-generics.cpp @@ -15,7 +15,7 @@ #include "slang-ir-witness-table-wrapper.h" #include "slang-ir-ssa-simplification.h" #include "slang-ir-util.h" - +#include "../core/slang-performance-profiler.h" namespace Slang { @@ -181,6 +181,8 @@ namespace Slang IRModule* module, DiagnosticSink* sink) { + SLANG_PROFILE; + SharedGenericsLoweringContext sharedContext; sharedContext.targetReq = targetReq; sharedContext.module = module; diff --git a/source/slang/slang-ir-specialize.cpp b/source/slang/slang-ir-specialize.cpp index 80dcec82b..48b083b7d 100644 --- a/source/slang/slang-ir-specialize.cpp +++ b/source/slang/slang-ir-specialize.cpp @@ -7,6 +7,7 @@ #include "slang-ir-ssa-simplification.h" #include "slang-ir-lower-witness-lookup.h" #include "slang-ir-dce.h" +#include "../core/slang-performance-profiler.h" namespace Slang { @@ -2340,6 +2341,7 @@ bool specializeModule( IRModule* module, DiagnosticSink* sink) { + SLANG_PROFILE; SpecializationContext context; context.module = module; context.sink = sink; diff --git a/source/slang/slang-ir-ssa-simplification.cpp b/source/slang/slang-ir-ssa-simplification.cpp index 66b4ceccb..43c9f8d2e 100644 --- a/source/slang/slang-ir-ssa-simplification.cpp +++ b/source/slang/slang-ir-ssa-simplification.cpp @@ -11,6 +11,7 @@ #include "slang-ir-remove-unused-generic-param.h" #include "slang-ir-redundancy-removal.h" #include "slang-ir-propagate-func-properties.h" +#include "../core/slang-performance-profiler.h" namespace Slang { @@ -18,6 +19,7 @@ namespace Slang // until no more changes are possible. void simplifyIR(IRModule* module, DiagnosticSink* sink) { + SLANG_PROFILE; bool changed = true; const int kMaxIterations = 8; const int kMaxFuncIterations = 16; diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp index 09c46b7ef..ad061a4e5 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -72,6 +72,7 @@ enum class OptionKind InputFilesRemain, EmitIr, ReportDownstreamTime, + ReportPerfBenchmark, SourceEmbedStyle, SourceEmbedName, @@ -427,6 +428,7 @@ void initCommandOptions(CommandOptions& options) { OptionKind::DumpWarningDiagnostics, "-dump-warning-diagnostics", nullptr, "Dump to output list of warning diagnostic numeric and name ids." }, { OptionKind::InputFilesRemain, "--", nullptr, "Treat the rest of the command line as input files."}, { OptionKind::ReportDownstreamTime, "-report-downstream-time", nullptr, "Reports the time spent in the downstream compiler." }, + { OptionKind::ReportPerfBenchmark, "-report-perf-benchmark", nullptr, "Reports compiler performance benchmark results." }, { OptionKind::SourceEmbedStyle, "-source-embed-style", "-source-embed-style ", "If source embedding is enabled, defines the style used. When enabled (with any style other than `none`), " "will write compile results into embeddable source for the target language. " @@ -1867,6 +1869,11 @@ SlangResult OptionsParser::_parse( m_compileRequest->setReportDownstreamTime(true); break; } + case OptionKind::ReportPerfBenchmark: + { + m_compileRequest->setReportPerfBenchmark(true); + break; + } case OptionKind::ModuleName: { CommandLineArg moduleName; diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index daa9cda3b..ffeabb0bd 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -7,7 +7,7 @@ #include "../core/slang-type-text-util.h" #include "../core/slang-type-convert-util.h" #include "../core/slang-castable.h" - +#include "../core/slang-performance-profiler.h" // Artifact #include "../compiler-core/slang-artifact-impl.h" #include "../compiler-core/slang-artifact-desc-util.h" @@ -4813,6 +4813,11 @@ void EndToEndCompileRequest::setReportDownstreamTime(bool value) m_reportDownstreamCompileTime = value; } +void EndToEndCompileRequest::setReportPerfBenchmark(bool value) +{ + m_reportPerfBenchmark = value; +} + void EndToEndCompileRequest::setDiagnosticCallback(SlangDiagnosticCallback callback, void const* userData) { ComPtr writer(new CallbackWriter(callback, userData, WriterFlag::IsConsole)); @@ -5181,7 +5186,12 @@ SlangResult EndToEndCompileRequest::EndToEndCompileRequest::compile() double downstreamTime = downstreamEndTime - downstreamStartTime; String downstreamTimeStr = String(downstreamTime, "%.2f"); getSink()->diagnose(SourceLoc(), Diagnostics::downstreamCompileTime, downstreamTimeStr); - + } + if (m_reportPerfBenchmark) + { + StringBuilder perfResult; + PerformanceProfiler::getProfiler()->getResult(perfResult); + getSink()->diagnose(SourceLoc(), Diagnostics::performanceBenchmarkResult, perfResult.produceString()); } // Repro dump handling -- cgit v1.2.3