From c08defe81076d25aef9a688835485f458becbb2d Mon Sep 17 00:00:00 2001 From: Lucian Radu Teodorescu Date: Sun, 3 Mar 2019 18:44:45 +0200 Subject: [PATCH] Add tracy profiling to the SparrowCompiler Add tracy repository as external Add Profiling options for Sparrow. If enabled, one can capture profiling data while running the compiler. Add scopes for most important operations (including Nest_setContext, Nest_computeType and Nest_semanticCheck). Make the compiler used optimized version of the parser. --- .gitmodules | 4 + CMakeLists.txt | 10 +- Macros.cmake | 4 +- externals/tracy | 1 + src/LLVMBackend/CtModule.cpp | 29 ++++- src/LLVMBackend/Generator.cpp | 44 ++++++-- src/LLVMBackend/Tr/PrepareTranslate.cpp | 3 + src/Nest/Api/NodeKindRegistrar.h | 9 ++ src/Nest/CMakeLists.txt | 8 ++ src/Nest/Utils/Profiling.h | 104 ++++++++++++++++++ src/Nest/Utils/ProfilingFwd.h | 13 +++ src/Nest/src/Api/Compiler.cpp | 29 ++++- src/Nest/src/Api/Node.c | 34 ++++++ src/Nest/src/Api/NodeKindRegistrar.c | 61 +++++++++- src/Nest/src/Utils/Profiling.cpp | 19 ++++ src/Nest/src/Utils/cppif/NodeHandle.cpp | 2 + src/SparrowCompiler/SparrowCompiler.cpp | 2 + src/SparrowFrontend/CMakeLists.txt | 2 +- .../Services/Concepts/ConceptsServiceImpl.cpp | 4 + .../Services/Convert/ConvertServiceImpl.cpp | 2 + .../Services/Overload/OverloadServiceImpl.cpp | 8 ++ src/SparrowFrontend/SparrowSourceCode.cpp | 10 +- 22 files changed, 378 insertions(+), 24 deletions(-) create mode 160000 externals/tracy create mode 100644 src/Nest/Utils/Profiling.h create mode 100644 src/Nest/Utils/ProfilingFwd.h create mode 100644 src/Nest/src/Utils/Profiling.cpp diff --git a/.gitmodules b/.gitmodules index 1cbcfa0e..cfb66e50 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,7 @@ path = externals/rapidcheck url = https://github.com/emil-e/rapidcheck.git branch = master +[submodule "externals/tracy"] + path = externals/tracy + url = https://lucteo@bitbucket.org/wolfpld/tracy.git + branch = master diff --git a/CMakeLists.txt b/CMakeLists.txt index a3c67b7d..8415948a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,8 @@ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/src/SparrowCompiler/VersionInfo.h.in # User passed compilation options option(BOOTSTRAP_SPARROW "Use system-wide SparrowCompiler to compile Sparrow files needed for the compiler" OFF) message(STATUS "BOOTSTRAP_SPARROW: ${BOOTSTRAP_SPARROW}") +option(SPARROW_PROFILING "Enable Tracy integration into Sparrow compiler" OFF) +message(STATUS "SPARROW_PROFILING: ${SPARROW_PROFILING}") # Where to output the results of the compilation set(OutDir ${CMAKE_CURRENT_SOURCE_DIR}/build/bin) @@ -91,12 +93,18 @@ if(MSVC) add_definitions( -D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE ) else() add_definitions( -D__STDC_LIMIT_MACROS=1 ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" ) # set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address" ) add_definitions( -Wall ) # All warnings... add_definitions( -Wno-deprecated ) # ... and except deprecated functions endif() +if(SPARROW_PROFILING) + add_definitions( -DSPARROW_PROFILING=1 ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17" ) +else() + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" ) +endif() + # Add our macros include(Macros.cmake) diff --git a/Macros.cmake b/Macros.cmake index adce9380..2f20527e 100644 --- a/Macros.cmake +++ b/Macros.cmake @@ -8,6 +8,8 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) find_program(SPARROW_EXECUTABLE_EXT NAMES SparrowCompiler DOC "path to the SparrowCompiler executable (external)") # Try to find an external llc executable find_program(LLC_EXECUTABLE_EXT NAMES spr-llc "${LLVM_TOOLS_BINARY_DIR}/llc" DOC "path to the llc executable (external)") +# Try to find an external opt executable +find_program(OPT_EXECUTABLE_EXT NAMES spr-opt "${LLVM_TOOLS_BINARY_DIR}/opt" DOC "path to the opt executable (external)") MACRO(GROUP_NAME_FROM_PATH filePath resultVar) IF(MSVC OR APPLE) @@ -104,7 +106,7 @@ macro(LLVMASM_TARGET Name Input Output) endif() add_custom_command(OUTPUT ${LLVMASM_TARGET_outputs} - COMMAND ${LLC_EXECUTABLE_EXT} --filetype=obj ${LLVMASM_EXECUTABLE_opts} -o ${Output} ${Input} + COMMAND ${OPT_EXECUTABLE_EXT} -O2 ${Input} | ${LLC_EXECUTABLE_EXT} --filetype=obj ${LLVMASM_EXECUTABLE_opts} -o ${Output} VERBATIM DEPENDS ${Input} ${LLVMASM_TARGET_ARG_DEPENDS} COMMENT "[LLVM][${Name}] Building object ${Output}" diff --git a/externals/tracy b/externals/tracy new file mode 160000 index 00000000..c0d0d0d4 --- /dev/null +++ b/externals/tracy @@ -0,0 +1 @@ +Subproject commit c0d0d0d42ba7e29654bf6ae481d7b7841ac75a19 diff --git a/src/LLVMBackend/CtModule.cpp b/src/LLVMBackend/CtModule.cpp index 1f14bbd6..39db87db 100644 --- a/src/LLVMBackend/CtModule.cpp +++ b/src/LLVMBackend/CtModule.cpp @@ -15,6 +15,7 @@ #include "Nest/Api/Compiler.h" #include "Nest/Utils/CompilerSettings.hpp" #include "Nest/Utils/Diagnostic.hpp" +#include "Nest/Utils/Profiling.h" #include "Nest/Utils/CompilerStats.hpp" #include "Nest/Utils/cppif/StringRef.hpp" @@ -140,6 +141,7 @@ void CtModule::recreateModule() { } void CtModule::syncModule() { + PROFILING_ZONE(); if (!llvmModule_->empty() || !llvmModule_->global_empty()) { // Uncomment this for debugging // llvmModule_->dump(); @@ -179,6 +181,8 @@ void CtModule::ctProcessBackendCode(Node* node) { } Node* CtModule::ctEvaluateExpression(Node* node) { + PROFILING_ZONE_TEXT(Nest_toStringEx(node)); + ASSERT(llvmModule_); // Gather statistics if requested @@ -284,10 +288,17 @@ Node* CtModule::ctEvaluateExpression(Node* node) { // - transform this into a function pointer that receives the output as a parameter // - call the function, to fill up the data buffer using FunType = void (*)(const char*); - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) - auto fptr = (FunType)llvmExecutionEngine_->getFunctionAddress(funName); + FunType fptr; + { + PROFILING_ZONE_NAMED("CT getFunctionAddress"); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) + fptr = (FunType)llvmExecutionEngine_->getFunctionAddress(funName); + } ASSERT(fptr); - fptr(dataBuffer.begin); + { + PROFILING_ZONE_NAMED("CT exec"); + fptr(dataBuffer.begin); + } // Create a CtValue containing the data resulted from expression evaluation Type t = node->type; @@ -301,9 +312,17 @@ Node* CtModule::ctEvaluateExpression(Node* node) { // - call the function using FunType = void (*)(); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) - auto fptr = (FunType)llvmExecutionEngine_->getFunctionAddress(funName); + FunType fptr; + { + PROFILING_ZONE_NAMED("CT getFunctionAddress"); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) + fptr = (FunType)llvmExecutionEngine_->getFunctionAddress(funName); + } ASSERT(fptr); - fptr(); + { + PROFILING_ZONE_NAMED("CT exec"); + fptr(); + } // Create a Nop operation for return res = Feather_mkNop(node->location); diff --git a/src/LLVMBackend/Generator.cpp b/src/LLVMBackend/Generator.cpp index a3e9e102..8eb7ec27 100644 --- a/src/LLVMBackend/Generator.cpp +++ b/src/LLVMBackend/Generator.cpp @@ -6,6 +6,7 @@ #include "Nest/Api/Compiler.h" #include "Nest/Utils/CompilerSettings.hpp" #include "Nest/Utils/CompilerStats.hpp" +#include "Nest/Utils/Profiling.h" #include @@ -49,6 +50,13 @@ string replaceExtension( /// Run the command with the given arguments /// The command should be the first in the list of arguments void runCmd(const vector& args) { +#if SPARROW_PROFILING + std::ostringstream ossProfiling; + for (const string& arg : args) + ossProfiling << arg << " "; + PROFILING_ZONE_TEXT(ossProfiling.str().c_str()); +#endif + ASSERT(args.size() > 0); const auto& s = *Nest_compilerSettings(); @@ -84,6 +92,8 @@ void runCmd(const vector& args) { /// Write the given LLVM module, as a bitcode to disk void writeBitcodeFile(const Module& module, const string& outputFilename) { + PROFILING_ZONE(); + error_code errorInfo; unique_ptr outFile( new TOOL_OUPUT_FILE_CLS(outputFilename.c_str(), errorInfo, sys::fs::OpenFlags::F_None)); @@ -98,6 +108,8 @@ void writeBitcodeFile(const Module& module, const string& outputFilename) { /// Write the given LLVM module, as an assembly file to disk void writeAssemblyFile(const Module& module, const string& outputFilename) { + PROFILING_ZONE(); + error_code errorInfo; unique_ptr outFile( new TOOL_OUPUT_FILE_CLS(outputFilename.c_str(), errorInfo, sys::fs::OpenFlags::F_None)); @@ -185,6 +197,8 @@ void generateNativeObjGCC( } // namespace void LLVMB::generateRtAssembly(const llvm::Module& module) { + PROFILING_ZONE(); + const auto& s = *Nest_compilerSettings(); string filename = replaceExtension(s.output_, s.output_, ".ll"); @@ -192,6 +206,8 @@ void LLVMB::generateRtAssembly(const llvm::Module& module) { } void LLVMB::generateCtAssembly(const llvm::Module& module) { + PROFILING_ZONE(); + const auto& s = *Nest_compilerSettings(); // Safety check @@ -229,22 +245,30 @@ void LLVMB::link(const vector& inputs, const string& outFilename) // the sourcecodes into one big module, and perform those operations here // Link all the input modules to a single module - // we desotry all the modules in this process + // we destroy all the modules in this process if (inputs.empty()) REP_INTERNAL(NOLOC, "At least one bitcode needs to be passed to the linker"); llvm::Module* compositeModule = inputs[0]; - llvm::Linker liner(*compositeModule); - for (size_t i = 1; i < inputs.size(); ++i) { - unique_ptr mod(inputs[i]); - if (liner.linkInModule(move(mod), llvm::Linker::OverrideFromSrc)) - REP_INTERNAL(NOLOC, "Link error"); + { + PROFILING_ZONE_NAMED("linking modules") + + llvm::Linker linker(*compositeModule); + for (size_t i = 1; i < inputs.size(); ++i) { + unique_ptr mod(inputs[i]); + if (linker.linkInModule(move(mod), llvm::Linker::OverrideFromSrc)) + REP_INTERNAL(NOLOC, "Link error"); + } } // Verify the module - string err; - raw_string_ostream errStream(err); - if (verifyModule(*compositeModule, &errStream)) - REP_INTERNAL(NOLOC, "LLVM Verification failed for generated program: %1%") % err; + { + PROFILING_ZONE_NAMED("verifying composite module") + + string err; + raw_string_ostream errStream(err); + if (verifyModule(*compositeModule, &errStream)) + REP_INTERNAL(NOLOC, "LLVM Verification failed for generated program: %1%") % err; + } bool shouldOptimize = !s.optimizerArgs_.empty() || s.optimizationLevel_ != "0"; diff --git a/src/LLVMBackend/Tr/PrepareTranslate.cpp b/src/LLVMBackend/Tr/PrepareTranslate.cpp index 217de219..1b57dd8b 100644 --- a/src/LLVMBackend/Tr/PrepareTranslate.cpp +++ b/src/LLVMBackend/Tr/PrepareTranslate.cpp @@ -8,6 +8,7 @@ #include #include #include +#include "Nest/Utils/Profiling.h" #include using namespace LLVMB; @@ -28,6 +29,8 @@ bool isDecl(Node* node) { } // namespace void Tr::prepareTranslate(Node* node, GlobalContext& ctx) { + // PROFILING_ZONE(); + if (!node) return; diff --git a/src/Nest/Api/NodeKindRegistrar.h b/src/Nest/Api/NodeKindRegistrar.h index 4ff7c968..f1df1aa6 100644 --- a/src/Nest/Api/NodeKindRegistrar.h +++ b/src/Nest/Api/NodeKindRegistrar.h @@ -1,6 +1,7 @@ #pragma once #include "TypeRef.h" +#include "Nest/Utils/ProfilingFwd.h" #ifdef __cplusplus extern "C" { @@ -33,6 +34,14 @@ FToString Nest_getToStringFun(int nodeKind); //! Resets the registered node kinds void Nest_resetRegisteredNodeKinds(); +#if SPARROW_PROFILING + +const Nest_Profiling_LocType* Nest_Profiling_getSetContextLoc(int nodeKind); +const Nest_Profiling_LocType* Nest_Profiling_getComputeTypeLoc(int nodeKind); +const Nest_Profiling_LocType* Nest_Profiling_getSemanticCheckLoc(int nodeKind); + +#endif + #ifdef __cplusplus } #endif diff --git a/src/Nest/CMakeLists.txt b/src/Nest/CMakeLists.txt index b4be9b36..3b978093 100644 --- a/src/Nest/CMakeLists.txt +++ b/src/Nest/CMakeLists.txt @@ -69,7 +69,15 @@ SET(sourceFiles "src/Utils/cppif/StringRef.cpp" "src/Utils/cppif/Type.cpp" "src/Utils/cppif/TypeWithStorage.cpp" + ) +if(SPARROW_PROFILING) + SET(sourceFiles + ${sourceFiles} + "src/Utils/Profiling.cpp" + ) + add_definitions( -DSPARROW_PROFILING=1 ) +endif() # Project settings INCLUDE_DIRECTORIES( "." ) diff --git a/src/Nest/Utils/Profiling.h b/src/Nest/Utils/Profiling.h new file mode 100644 index 00000000..3a3ae9dc --- /dev/null +++ b/src/Nest/Utils/Profiling.h @@ -0,0 +1,104 @@ +#pragma once + +#include "ProfilingFwd.h" + +#if SPARROW_PROFILING + +#define TRACY_ENABLE 1 + +#ifdef __cplusplus + +//////////////////////////////////////////////////////////////////////////////// +// C++ profiling definitions + +#include "../../../externals/tracy/Tracy.hpp" + +#include "Nest/Api/StringRef.h" + +#define PROFILING_ZONE() ZoneScoped +#define PROFILING_ZONE_NAMED(staticName) ZoneScopedN(staticName) +#define PROFILING_ZONE_TEXT(text) \ + ZoneScoped; \ + _Nest_Profiling_zoneSetText(___tracy_scoped_zone, text) +#define PROFILING_ZONE_NAMED_TEXT(staticName, text) \ + ZoneScopedN(staticName); \ + _Nest_Profiling_zoneSetText(___tracy_scoped_zone, text) +#define PROFILING_ZONE_SETTEEXT(text) _Nest_Profiling_zoneSetText(___tracy_scoped_zone, text) + +#define PROFILING_PLOT(name, val) tracy::Profiler::PlotData(name, val) + +#define PROFILING_MESSAGE_STATIC(staticText) tracy::Profiler::Message(staticText) +#define PROFILING_MESSAGE(text) _Nest_Profiling_message(text) + +inline void _Nest_Profiling_zoneSetText(tracy::ScopedZone& zone, const char* text) { + zone.Text(text, strlen(text)); +} +inline void _Nest_Profiling_zoneSetText(tracy::ScopedZone& zone, Nest_StringRef text) { + zone.Text(text.begin, text.end - text.begin); +} + +inline void _Nest_Profiling_message(const char* text) { + tracy::Profiler::Message(text, strlen(text)); +} +inline void _Nest_Profiling_message(Nest_StringRef text) { + tracy::Profiler::Message(text.begin, text.end - text.begin); +} + +#else // __cplusplus + +//////////////////////////////////////////////////////////////////////////////// +// C-only profiling definitions + +#include "../../../externals/tracy/TracyC.h" + +typedef TracyCZoneCtx Nest_Profiling_ZoneCtx; + +#define PROFILING_C_ZONE_BEGIN(ctx) \ + static const struct Nest_Profiling_LocType TracyConcat(__tracy_source_location, __LINE__) = { \ + NULL, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0}; \ + Nest_Profiling_ZoneCtx ctx = \ + ___tracy_emit_zone_begin(&TracyConcat(__tracy_source_location, __LINE__), 1); + +#define PROFILING_C_ZONE_BEGIN_LOC(ctx, locPtr) \ + Nest_Profiling_ZoneCtx ctx = ___tracy_emit_zone_begin(locPtr, 1) + +#define PROFILING_C_ZONE_END(ctx) ___tracy_emit_zone_end(ctx) +#define PROFILING_C_ZONE_SETTEEXT(ctx, text) ___tracy_emit_zone_text(ctx, text, strlen(text)) + +#endif // __cplusplus + +//////////////////////////////////////////////////////////////////////////////// +// Both C and C++ profiling definitions + +#ifdef __cplusplus +extern "C" { +#endif + +//! Creates a location type for profiling +const Nest_Profiling_LocType* Nest_Profiling_createLoc( + const char* name, const char* function, const char* file, unsigned line, unsigned color); + +#ifdef __cplusplus +} +#endif + +#else // SPARROW_PROFILING + +//////////////////////////////////////////////////////////////////////////////// +// Profiling not enabled + +#define PROFILING_ZONE() /*nothing*/ +#define PROFILING_ZONE_NAMED(staticName) /*nothing*/ +#define PROFILING_ZONE_TEXT(text) /*nothing*/ +#define PROFILING_ZONE_NAMED_TEXT(staticName, text) /*nothing*/ +#define PROFILING_ZONE_SETTEEXT(text) /*nothing*/ +#define PROFILING_PLOT(name, val) /*nothing*/ +#define PROFILING_MESSAGE_STATIC(staticText) /*nothing*/ +#define PROFILING_MESSAGE(text) /*nothing*/ + +#define PROFILING_C_ZONE_BEGIN(ctx) /*nothing*/ +#define PROFILING_C_ZONE_BEGIN_LOC(ctx, locPtr) /*nothing*/ +#define PROFILING_C_ZONE_END(ctx) /*nothing*/ +#define PROFILING_C_ZONE_SETTEEXT(ctx, text) /*nothing*/ + +#endif \ No newline at end of file diff --git a/src/Nest/Utils/ProfilingFwd.h b/src/Nest/Utils/ProfilingFwd.h new file mode 100644 index 00000000..b0993135 --- /dev/null +++ b/src/Nest/Utils/ProfilingFwd.h @@ -0,0 +1,13 @@ +#pragma once + +#ifndef SPARROW_PROFILING +#define SPARROW_PROFILING 0 +#endif + +#if SPARROW_PROFILING + +//! Profiling type to store the source location data (from the compiler). +//! Includes zone name, function name, filename, line number and color +typedef struct ___tracy_source_location_data Nest_Profiling_LocType; + +#endif \ No newline at end of file diff --git a/src/Nest/src/Api/Compiler.cpp b/src/Nest/src/Api/Compiler.cpp index cf349d5b..dde73de6 100644 --- a/src/Nest/src/Api/Compiler.cpp +++ b/src/Nest/src/Api/Compiler.cpp @@ -3,6 +3,7 @@ #include "Nest/Utils/CompilerSettings.hpp" #include "Nest/Utils/Alloc.h" #include "Nest/Utils/Diagnostic.hpp" +#include "Nest/Utils/Profiling.h" #include "Nest/Utils/cppif/StringRef.hpp" #include "Nest/Utils/cppif/Fwd.hpp" #include "Nest/Utils/cppif/NodeUtils.hpp" @@ -135,7 +136,10 @@ pair _handleImportFile(const ImportInfo& import) { // Do the parsing // REP_INFO(NOLOC, "Parsing: %1%") % import.filename_.string(); - Nest_parseSourceCode(sourceCode, newContext); + { + PROFILING_ZONE_NAMED("Parsing"); + Nest_parseSourceCode(sourceCode, newContext); + } // Notify the listeners that a new source code was parsed _executeCUCallbacks(_sourceCodeParsedCallbacks, sourceCode); @@ -194,6 +198,8 @@ Nest_SourceCode* _handleImport(const ImportInfo& import) { } void Nest_compilerInit() { + PROFILING_ZONE(); + // TODO (files): Check why this breaks AssertTest.spr // try { // _curPath = boost::filesystem::current_path(); @@ -204,6 +210,8 @@ void Nest_compilerInit() { } void Nest_compilerDestroy() { + PROFILING_ZONE(); + _settings = Nest_CompilerSettings{}; _rootContext = nullptr; ; @@ -243,6 +251,8 @@ void Nest_createBackend(const char* mainFilename) { } Nest_SourceCode* Nest_compileFile(Nest_StringRef filename) { + PROFILING_ZONE_TEXT(filename); + if (Nest::StringRef(filename).empty() || filename.begin[0] == '\r' || filename.begin[0] == '\n') return nullptr; @@ -310,6 +320,7 @@ Nest_SourceCode* Nest_compileFile(Nest_StringRef filename) { Nest_SourceCode* Nest_addSourceCodeByFilename( const Nest_SourceCode* orig, Nest_StringRef filename) { + PROFILING_ZONE_TEXT(filename); return _handleImport(ImportInfo(orig, filename)); } @@ -335,12 +346,16 @@ void Nest_semanticCheckQueuedNodes() { } void Nest_ctProcess(Nest_Node* node) { + PROFILING_ZONE(); + node = Nest_semanticCheck(node); if (node) _backend->ctProcess(_backend, node); } Nest_Node* Nest_ctEval(Nest_Node* node) { + PROFILING_ZONE(); + node = Nest_semanticCheck(node); if (!node) return nullptr; @@ -351,8 +366,16 @@ Nest_Node* Nest_ctEval(Nest_Node* node) { return Nest_semanticCheck(res); } -unsigned Nest_sizeOf(Nest_TypeRef type) { return _backend->sizeOf(_backend, type); } -unsigned Nest_alignmentOf(Nest_TypeRef type) { return _backend->alignmentOf(_backend, type); } +unsigned Nest_sizeOf(Nest_TypeRef type) { + PROFILING_ZONE(); + + return _backend->sizeOf(_backend, type); +} +unsigned Nest_alignmentOf(Nest_TypeRef type) { + PROFILING_ZONE(); + + return _backend->alignmentOf(_backend, type); +} void Nest_registerSourceCodeCreatedCallback(FSourceCodeCallback callback) { _sourceCodeCreatedCallbacks.push_back(callback); diff --git a/src/Nest/src/Api/Node.c b/src/Nest/src/Api/Node.c index 77cd4d55..902ab552 100644 --- a/src/Nest/src/Api/Node.c +++ b/src/Nest/src/Api/Node.c @@ -1,12 +1,15 @@ #include "Nest/Api/Node.h" #include "Nest/Api/NodeKindRegistrar.h" +#include "Nest/Api/SourceCode.h" #include "Nest/Utils/NodeUtils.h" #include "Nest/Utils/Alloc.h" #include "Nest/Utils/Assert.h" #include "Nest/Utils/Diagnostic.h" +#include "Nest/Utils/Profiling.h" #include #include +#include unsigned _myMinU(unsigned a, unsigned b) { return a < b ? a : b; } unsigned _myMaxU(unsigned a, unsigned b) { return b < a ? a : b; } @@ -106,6 +109,9 @@ Nest_Node* Nest_cloneNode(Nest_Node* node) { void Nest_setContext(Nest_Node* node, Nest_CompilationContext* context) { if (context == node->context) return; + + PROFILING_C_ZONE_BEGIN_LOC(ctx, Nest_Profiling_getSetContextLoc(node->nodeKind)); + ASSERT(context); node->context = context; @@ -117,6 +123,7 @@ void Nest_setContext(Nest_Node* node, Nest_CompilationContext* context) { Nest_getSetContextForChildrenFun(node->nodeKind)(node); _applyModifiers(node, modTypeAfterSetContext); + PROFILING_C_ZONE_END(ctx); } Nest_TypeRef Nest_computeType(Nest_Node* node) { @@ -129,6 +136,8 @@ Nest_TypeRef Nest_computeType(Nest_Node* node) { Nest_reportFmt(node->location, diagInternalError, "No context associated with node %s", Nest_toString(node)); + PROFILING_C_ZONE_BEGIN_LOC(ctx, Nest_Profiling_getComputeTypeLoc(node->nodeKind)); + node->computeTypeStarted = 1; _applyModifiers(node, modTypeBeforeComputeType); @@ -137,11 +146,14 @@ Nest_TypeRef Nest_computeType(Nest_Node* node) { node->type = Nest_getComputeTypeFun(node->nodeKind)(node); if (!node->type) { node->nodeError = 1; + PROFILING_C_ZONE_END(ctx); return 0; } _applyModifiers(node, modTypeAfterComputeType); + PROFILING_C_ZONE_END(ctx); + return node->type; } @@ -163,16 +175,20 @@ Nest_Node* Nest_semanticCheck(Nest_Node* node) { } node->semanticCheckStarted = 1; + PROFILING_C_ZONE_BEGIN_LOC(ctx, Nest_Profiling_getSemanticCheckLoc(node->nodeKind)); + _applyModifiers(node, modTypeBeforeSemanticCheck); // Actually do the semantic check Nest_Node* res = Nest_getSemanticCheckFun(node->nodeKind)(node); if (!res) { node->nodeError = 1; + PROFILING_C_ZONE_END(ctx); return 0; } if (!_setExplanation(node, res)) { node->nodeError = 1; + PROFILING_C_ZONE_END(ctx); return 0; } if (!node->type) @@ -182,6 +198,24 @@ Nest_Node* Nest_semanticCheck(Nest_Node* node) { _applyModifiers(node, modTypeAfterSemanticCheck); +#ifdef SPARROW_PROFILING + const char* nodeDesc = Nest_toStringEx(node); + if (nodeDesc) { + char zoneDesc[256]; + int len = 0; + if (node->location.sourceCode) + len = snprintf(zoneDesc, 256, "%s:%d:%d\n%s", node->location.sourceCode->url, + (int)node->location.start.line, (int)node->location.start.col, nodeDesc); + else + len = snprintf(zoneDesc, 256, "?:%d:%d\n%s", (int)node->location.start.line, + (int)node->location.start.col, nodeDesc); + if (len > 0) { + PROFILING_C_ZONE_SETTEEXT(ctx, zoneDesc); + } + } +#endif + PROFILING_C_ZONE_END(ctx); + return node->explanation; } diff --git a/src/Nest/src/Api/NodeKindRegistrar.c b/src/Nest/src/Api/NodeKindRegistrar.c index 6d8f5f85..860be8c9 100644 --- a/src/Nest/src/Api/NodeKindRegistrar.c +++ b/src/Nest/src/Api/NodeKindRegistrar.c @@ -1,6 +1,10 @@ #include "Nest/Api/NodeKindRegistrar.h" #include "Nest/Api/Node.h" #include "Nest/Utils/Assert.h" +#include "Nest/Utils/Profiling.h" + +#include +#include struct _NodeKindDescription { const char* name; @@ -8,8 +12,25 @@ struct _NodeKindDescription { FComputeType funComputeType; FSetContextForChildren funSetContextForChildren; FToString funToString; + +#if SPARROW_PROFILING + const Nest_Profiling_LocType* setContextLoc; + const Nest_Profiling_LocType* computeTypeLoc; + const Nest_Profiling_LocType* semanticCheckLoc; +#endif }; +#if SPARROW_PROFILING +const char* strconcat(const char* s1, const char* s2) { + size_t len = strlen(s1) + strlen(s2) + 1; + char* res = (char*)malloc(len); + res[0] = 0; + strcat(res, s1); + strcat(res, s2); + return res; +} +#endif + /// The registered node kinds struct _NodeKindDescription _allNodeKinds[1000]; unsigned int _numNodeKinds = 0; @@ -24,9 +45,33 @@ int Nest_registerNodeKind(const char* name, FSemanticCheck funSemanticCheck, funSetContextForChildren = Nest_defaultFunSetContextForChildren; if (!funToString) funToString = Nest_defaultFunToString; + +#if SPARROW_PROFILING + const Nest_Profiling_LocType* setContextLoc = + Nest_Profiling_createLoc(strconcat("setCtx ", name), "Nest_setContext", "Node.c", + 1, 0x4f94cd); // SteelBlue3 + const Nest_Profiling_LocType* computeTypeLoc = + Nest_Profiling_createLoc(strconcat("compType ", name), "Nest_computeType", "Node.c", + 1, 0x36648b); // SteelBlue4 + const Nest_Profiling_LocType* semanticCheckLoc = + Nest_Profiling_createLoc(strconcat("semCheck ", name), "Nest_semanticCheck", "Node.c", + 1, 0x27408b); // RoyalBlue4 +#endif + struct _NodeKindDescription nk = { - name, funSemanticCheck, funComputeType, funSetContextForChildren, funToString}; + name, + funSemanticCheck, + funComputeType, + funSetContextForChildren, + funToString, +#if SPARROW_PROFILING + setContextLoc, + computeTypeLoc, + semanticCheckLoc, +#endif + }; _allNodeKinds[nodeKindId] = nk; + return nodeKindId; } @@ -53,3 +98,17 @@ FToString Nest_getToStringFun(int nodeKind) { } void Nest_resetRegisteredNodeKinds() { _numNodeKinds = 0; } + +#if SPARROW_PROFILING + +const Nest_Profiling_LocType* Nest_Profiling_getSetContextLoc(int nodeKind) { + return _allNodeKinds[nodeKind].setContextLoc; +} +const Nest_Profiling_LocType* Nest_Profiling_getComputeTypeLoc(int nodeKind) { + return _allNodeKinds[nodeKind].computeTypeLoc; +} +const Nest_Profiling_LocType* Nest_Profiling_getSemanticCheckLoc(int nodeKind) { + return _allNodeKinds[nodeKind].semanticCheckLoc; +} + +#endif diff --git a/src/Nest/src/Utils/Profiling.cpp b/src/Nest/src/Utils/Profiling.cpp new file mode 100644 index 00000000..1887c223 --- /dev/null +++ b/src/Nest/src/Utils/Profiling.cpp @@ -0,0 +1,19 @@ +#include "Nest/Utils/Profiling.h" + +#if SPARROW_PROFILING + +// Include TracyClient.cpp after defining TRACY_ENABLE +#include "../../../externals/tracy/TracyClient.cpp" + +extern "C" const Nest_Profiling_LocType* Nest_Profiling_createLoc( + const char* name, const char* function, const char* file, unsigned line, unsigned color) { + Nest_Profiling_LocType* loc = (Nest_Profiling_LocType*)malloc(sizeof(Nest_Profiling_LocType)); + loc->name = name; + loc->function = function; + loc->file = file; + loc->line = line; + loc->color = color; + return loc; +} + +#endif \ No newline at end of file diff --git a/src/Nest/src/Utils/cppif/NodeHandle.cpp b/src/Nest/src/Utils/cppif/NodeHandle.cpp index 09c312a4..04806f4d 100644 --- a/src/Nest/src/Utils/cppif/NodeHandle.cpp +++ b/src/Nest/src/Utils/cppif/NodeHandle.cpp @@ -39,6 +39,8 @@ void NodeHandle::clearCompilationState() { Nest_clearCompilationState(handle); } const char* NodeHandle::toString() const { return Nest_getToStringFun(handle->nodeKind)(handle); } const char* NodeHandle::toStringEx() const { + if (!handle) + return ""; ostringstream ss; ss << toString(); if (handle->type) diff --git a/src/SparrowCompiler/SparrowCompiler.cpp b/src/SparrowCompiler/SparrowCompiler.cpp index 9ac965bc..91db4f5d 100644 --- a/src/SparrowCompiler/SparrowCompiler.cpp +++ b/src/SparrowCompiler/SparrowCompiler.cpp @@ -9,6 +9,7 @@ #include "Nest/Utils/CompilerStats.hpp" #include "Nest/Utils/Diagnostic.hpp" #include "Nest/Utils/PrintTimer.hpp" +#include "Nest/Utils/Profiling.h" #include "Nest/Utils/cppif/StringRef.hpp" #include "Nest/Api/Backend.h" #include "Nest/Api/CompilationContext.h" @@ -172,6 +173,7 @@ void doCompilation(const vector& modules) { // If we have no errors, start linking if (Nest_getErrorsNum() == 0 && !s.syntaxOnly_) { + PROFILING_ZONE_NAMED("Linking") try { Nest::Common::PrintTimer timer(s.verbose_, "", "[%d ms]\n"); if (s.verbose_) diff --git a/src/SparrowFrontend/CMakeLists.txt b/src/SparrowFrontend/CMakeLists.txt index 10f6be3b..f54517e5 100644 --- a/src/SparrowFrontend/CMakeLists.txt +++ b/src/SparrowFrontend/CMakeLists.txt @@ -55,7 +55,7 @@ if(BOOTSTRAP_SPARROW) SPARROW_TARGET(SparrowParser ${CMAKE_CURRENT_SOURCE_DIR}/Grammar/parserIf.spr ${CMAKE_CURRENT_BINARY_DIR}/parserIf.o - COMPILE_FLAGS "-dump-assembly -fno-colors -fno-main -c" + COMPILE_FLAGS "-dump-assembly -fno-colors -fno-main -c -O2" DEPENDS Grammar/parser.spr Grammar/parserDefs.spr Grammar/ext.spr diff --git a/src/SparrowFrontend/Services/Concepts/ConceptsServiceImpl.cpp b/src/SparrowFrontend/Services/Concepts/ConceptsServiceImpl.cpp index a62f779f..390f0ba6 100644 --- a/src/SparrowFrontend/Services/Concepts/ConceptsServiceImpl.cpp +++ b/src/SparrowFrontend/Services/Concepts/ConceptsServiceImpl.cpp @@ -3,9 +3,13 @@ #include "SparrowFrontend/Helpers/Generics.h" #include "SparrowFrontend/Helpers/SprTypeTraits.h" +#include "Nest/Utils/Profiling.h" + namespace SprFrontend { bool ConceptsServiceImpl::conceptIsFulfilled(ConceptDecl concept, Type type) { + PROFILING_ZONE(); + ASSERT(concept); auto instSet = concept.instantiationsSet(); diff --git a/src/SparrowFrontend/Services/Convert/ConvertServiceImpl.cpp b/src/SparrowFrontend/Services/Convert/ConvertServiceImpl.cpp index 98b9d61f..34a3dc9a 100644 --- a/src/SparrowFrontend/Services/Convert/ConvertServiceImpl.cpp +++ b/src/SparrowFrontend/Services/Convert/ConvertServiceImpl.cpp @@ -14,6 +14,7 @@ #include "Feather/Utils/cppif/FeatherTypes.hpp" #include "Nest/Utils/Tuple.hpp" +#include "Nest/Utils/Profiling.h" #include @@ -407,6 +408,7 @@ bool ConvertServiceImpl::adjustReferences(ConversionResult& res, TypeWithStorage const ConversionResult& ConvertServiceImpl::cachedCheckConversion( CompilationContext* context, int flags, Type srcType, Type destType) { + PROFILING_ZONE(); // Try to find the conversion in the map -- first, try without a source code KeyType key(srcType, destType, flags, nullptr); diff --git a/src/SparrowFrontend/Services/Overload/OverloadServiceImpl.cpp b/src/SparrowFrontend/Services/Overload/OverloadServiceImpl.cpp index 21f5fa8b..65fde3a5 100644 --- a/src/SparrowFrontend/Services/Overload/OverloadServiceImpl.cpp +++ b/src/SparrowFrontend/Services/Overload/OverloadServiceImpl.cpp @@ -13,6 +13,8 @@ #include "Feather/Utils/FeatherUtils.hpp" #include "Feather/Utils/cppif/FeatherNodes.hpp" +#include "Nest/Utils/Profiling.h" + using namespace SprFrontend; using namespace Nest; @@ -172,6 +174,8 @@ void selectMostSpecializedErrReport( Node* OverloadServiceImpl::selectOverload(CompilationContext* context, const Location& loc, EvalMode evalMode, Nest_NodeRange decls, Nest_NodeRange args, OverloadReporting errReporting, StringRef funName) { + PROFILING_ZONE_TEXT(funName); + auto numDecls = Nest_nodeRangeSize(decls); Node* firstDecl = numDecls > 0 ? at(decls, 0) : nullptr; @@ -284,6 +288,8 @@ Node* OverloadServiceImpl::selectOverload(CompilationContext* context, const Loc bool OverloadServiceImpl::selectConversionCtor( CompilationContext* context, Node* destClass, EvalMode destMode, Type argType) { + PROFILING_ZONE(); + ASSERT(argType); // Get all the candidates @@ -305,6 +311,8 @@ bool OverloadServiceImpl::selectConversionCtor( } Node* OverloadServiceImpl::selectCtToRtCtor(Node* ctArg) { + PROFILING_ZONE(); + const Location& loc = ctArg->location; ASSERT(ctArg->type); if (ctArg->type->mode != modeCt || !ctArg->type->hasStorage) diff --git a/src/SparrowFrontend/SparrowSourceCode.cpp b/src/SparrowFrontend/SparrowSourceCode.cpp index e7a46ce2..fc70a199 100644 --- a/src/SparrowFrontend/SparrowSourceCode.cpp +++ b/src/SparrowFrontend/SparrowSourceCode.cpp @@ -5,6 +5,7 @@ #include "Nest/Utils/Alloc.h" #include "Nest/Utils/Diagnostic.hpp" +#include "Nest/Utils/Profiling.h" #include "Nest/Api/SourceCode.h" #include "Nest/Api/SourceCodeKindRegistrar.h" @@ -16,8 +17,11 @@ namespace { void parseSourceCode(Nest_SourceCode* sourceCode, CompilationContext* ctx) { Location loc = Nest_mkLocation1(sourceCode, 1, 1); - Parser parser(loc); - sourceCode->mainNode = parser.parseModule(); + { + PROFILING_ZONE_NAMED("parseModule"); + Parser parser(loc); + sourceCode->mainNode = parser.parseModule(); + } if (sourceCode->mainNode) Nest_setContext(sourceCode->mainNode, ctx); @@ -54,6 +58,8 @@ void SprFe_registerSparrowSourceCode() { } Node* SprFe_parseSparrowExpression(Location loc, const char* code) { + PROFILING_ZONE(); + // Only use the start part of the location loc.end = loc.start;