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;