From 678b4497c2bc230de4e00e43e89fc6d2b0055c53 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Wed, 2 Jan 2019 18:38:03 +0100 Subject: [PATCH] Paje tracing --- libsrc/core/CMakeLists.txt | 4 +- libsrc/core/archive.cpp | 10 - libsrc/core/archive.hpp | 4 +- libsrc/core/logging.hpp | 53 ++- libsrc/core/ngcore_api.hpp | 24 +- libsrc/core/paje_trace.cpp | 659 +++++++++++++++++++++++++++++++++++++ libsrc/core/paje_trace.hpp | 215 ++++++++++++ libsrc/core/utils.cpp | 20 ++ libsrc/core/utils.hpp | 23 ++ 9 files changed, 973 insertions(+), 39 deletions(-) create mode 100644 libsrc/core/paje_trace.cpp create mode 100644 libsrc/core/paje_trace.hpp create mode 100644 libsrc/core/utils.cpp create mode 100644 libsrc/core/utils.hpp diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt index b75e7582..3e10f58d 100644 --- a/libsrc/core/CMakeLists.txt +++ b/libsrc/core/CMakeLists.txt @@ -1,5 +1,5 @@ -add_library(ngcore SHARED archive.cpp logging.cpp) +add_library(ngcore SHARED archive.cpp logging.cpp paje_trace.cpp utils.cpp) target_compile_definitions(ngcore PRIVATE NGCORE_EXPORTS) if(NOT WIN32) @@ -32,7 +32,7 @@ if(USE_PYTHON) endif(USE_PYTHON) install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp logging.hpp - exception.hpp symboltable.hpp + exception.hpp symboltable.hpp paje_trace.hpp utils.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel) if(ENABLE_CPP_CORE_GUIDELINES_CHECK) diff --git a/libsrc/core/archive.cpp b/libsrc/core/archive.cpp index 64789904..9d7f2cd5 100644 --- a/libsrc/core/archive.cpp +++ b/libsrc/core/archive.cpp @@ -19,16 +19,6 @@ namespace ngcore void SetLibraryVersion(const std::string& library, const VersionInfo& version) { library_versions[library] = version; } -#ifdef WIN32 - // windows does demangling in typeid(T).name() - std::string Demangle(const char* typeinfo) { return typeinfo; } -#else - std::string Demangle(const char* typeinfo) { int status; return abi::__cxa_demangle(typeinfo, - nullptr, - nullptr, - &status); } -#endif - // clang-tidy should ignore this static object static std::unique_ptr> type_register; // NOLINT const detail::ClassArchiveInfo& Archive :: GetArchiveRegister(const std::string& classname) diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp index 11d4ae71..04915cbc 100644 --- a/libsrc/core/archive.hpp +++ b/libsrc/core/archive.hpp @@ -15,8 +15,9 @@ #include "exception.hpp" // for UnreachableCodeException, Exception #include "logging.hpp" // for logger -#include "ngcore_api.hpp" // for NGCORE_API, unlikely +#include "ngcore_api.hpp" // for NGCORE_API #include "type_traits.hpp" // for all_of_tmpl +#include "utils.hpp" // for Demangle, unlikely #include "version.hpp" // for VersionInfo #ifdef NETGEN_PYTHON @@ -28,7 +29,6 @@ namespace ngcore // Libraries using this archive can store their version here to implement backwards compatibility NGCORE_API const VersionInfo& GetLibraryVersion(const std::string& library); NGCORE_API void SetLibraryVersion(const std::string& library, const VersionInfo& version); - NGCORE_API std::string Demangle(const char* typeinfo); class NGCORE_API Archive; diff --git a/libsrc/core/logging.hpp b/libsrc/core/logging.hpp index 8952a5f6..e0e3efd6 100644 --- a/libsrc/core/logging.hpp +++ b/libsrc/core/logging.hpp @@ -26,23 +26,6 @@ namespace spdlog { // Dummys if Netgen is compiled with USE_SPDLOG=OFF. - class logger - { - public: - template - void trace(const T& /*unused*/) {} - template - void debug(const T& /*unused*/) {} - template - void info(const T& text) { std::cout << text << std::endl; } - template - void warn(const T& text) { std::cout << text << std::endl; } - template - void error(const T& text) { std::cout << text << std::endl; } - template - void critical(const T& text) { std::cout << text << std::endl; } - }; - namespace level { enum level_enum @@ -57,6 +40,42 @@ namespace spdlog }; } // namespace level + class logger + { + public: + template + void log_helper( T t) { std::clog << t; } + + template + void log_helper( T t, Args ... args) + { + std::clog << t; + log_helper(args...); + std::clog << ", "; + } + + template + void log( level::level_enum level, const char* fmt, Args ... args) + { + std::clog << level << ": " << fmt << "\t Arguments: "; + log_helper(args...); + std::clog << "\n"; + } + + template + void trace( const char* fmt, Args ... args) { log(level::level_enum::trace, fmt, args...); } + template + void debug( const char* fmt, Args ... args) { log(level::level_enum::debug, fmt, args...); } + template + void info( const char* fmt, Args ... args) { log(level::level_enum::info, fmt, args...); } + template + void warn( const char* fmt, Args ... args) { log(level::level_enum::warn, fmt, args...); } + template + void error( const char* fmt, Args ... args) { log(level::level_enum::err, fmt, args...); } + template + void critical( const char* fmt, Args ... args) { log(level::level_enum::critical, fmt, args...); } + }; + namespace sinks { class sink {}; diff --git a/libsrc/core/ngcore_api.hpp b/libsrc/core/ngcore_api.hpp index 5c65cf3a..a84a1381 100644 --- a/libsrc/core/ngcore_api.hpp +++ b/libsrc/core/ngcore_api.hpp @@ -15,15 +15,23 @@ #define NGCORE_API NGCORE_API_IMPORT #endif -namespace ngcore -{ -#if defined(__GNUC__) - inline bool likely (bool x) { return bool(__builtin_expect(long(x), 1L)); } - inline bool unlikely (bool x) { return bool(__builtin_expect(long(x), 0L)); } +#ifdef __INTEL_COMPILER + #ifdef WIN32 + #define NETGEN_INLINE __forceinline inline + #define NETGEN_LAMBDA_INLINE + #else + #define NETGEN_INLINE __forceinline inline + #define NETGEN_LAMBDA_INLINE __attribute__ ((__always_inline__)) + #endif #else - inline bool likely (bool x) { return x; } - inline bool unlikely (bool x) { return x; } + #ifdef __GNUC__ + #define NETGEN_INLINE __attribute__ ((__always_inline__)) inline + #define NETGEN_LAMBDA_INLINE __attribute__ ((__always_inline__)) + #define NETGEN_VLA + #else + #define NETGEN_INLINE inline + #define NETGEN_LAMBDA_INLINE + #endif #endif -} // namespace ngcore #endif // NETGEN_CORE_NGCORE_API_HPP diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp new file mode 100644 index 00000000..2742d25e --- /dev/null +++ b/libsrc/core/paje_trace.cpp @@ -0,0 +1,659 @@ +#include +#include +#include +#include +#include +#include + +#include "archive.hpp" // for Demangle +#include "paje_trace.hpp" + +static constexpr int MAX_TRACE_LINE_SIZE = 50; +extern const char *header; + +namespace ngcore +{ + // Produce no traces by default + size_t PajeTrace::max_tracefile_size = 11110000; + + // If true, produce variable counting active threads + // increases trace by a factor of two + bool PajeTrace::trace_thread_counter = true; + bool PajeTrace::trace_threads = true; + + PajeTrace :: PajeTrace(int anthreads, std::string aname) + { + start_time = GetTime(); + + nthreads = anthreads; + tracefile_name = aname; + + int bytes_per_event=33; + max_num_events_per_thread = std::min( (size_t)std::numeric_limits::max, max_tracefile_size/bytes_per_event/(2*nthreads+1)*10/7); + if(max_num_events_per_thread>0) + { + logger->info( "Tracefile size = {}MB", max_tracefile_size/1024/1024); + logger->info( "Tracing {} events per thread", max_num_events_per_thread , " events per thread"); + } + + tasks.resize(nthreads); + int reserve_size = std::min(1000000U, max_num_events_per_thread); + for(auto & t : tasks) + t.reserve(reserve_size); + + links.resize(nthreads); + for(auto & l : links) + l.reserve(reserve_size); + + jobs.reserve(reserve_size); + timer_events.reserve(reserve_size); + + tracing_enabled = true; + } + + PajeTrace :: ~PajeTrace() + { + if(tracefile_name.size()>0) + Write(tracefile_name); + } + + + void PajeTrace::StopTracing() + { + if(tracing_enabled && max_num_events_per_thread>0) + { + logger->warn("Maximum number of traces reached, tracing is stopped now."); + } + tracing_enabled = false; + } + + using std::string; + class PajeFile + { + public: + typedef PajeTrace::TTimePoint TTimePoint; + static void Hue2RGB ( double x, double &r, double &g, double &b ) + { + double d = 1.0/6.0; + if(x logger = GetLogger("PajeTrace"); + + + double ConvertTime(TTimePoint t) { + // return time in milliseconds as double + // return std::chrono::duration(t-start_time).count()*1000.0; + // return std::chrono::duration(t-start_time).count() / 2.7e3; + return (t-start_time) / 2.7e6; + } + + enum PType + { + SET_VARIABLE=1, + ADD_VARIABLE, + SUB_VARIABLE, + PUSH_STATE, + POP_STATE, + START_LINK, + STOP_LINK + }; + + struct PajeEvent + { + PajeEvent( int aevent_type, double atime, int atype, int acontainer, double avar_value ) + : time(atime), var_value(avar_value), event_type(aevent_type), type(atype), container(acontainer) + { } + + PajeEvent( int aevent_type, double atime, int atype, int acontainer, int avalue = 0, int aid = 0, bool avalue_is_alias = true ) + : time(atime), event_type(aevent_type), type(atype), container(acontainer), value(avalue), id(aid), value_is_alias(avalue_is_alias) + { } + + PajeEvent( int aevent_type, double atime, int atype, int acontainer, int avalue, int astart_container, int akey ) + : time(atime), event_type(aevent_type), type(atype), container(acontainer), value(avalue), start_container(astart_container), id(akey) + { } + + double time; + double var_value = 0.0; + int event_type; + int type; + int container; + int value = 0; + int start_container = 0; + int id = 0; + bool value_is_alias = true; + + bool operator < (const PajeEvent & other) const { + // Same times can occur for very small tasks -> take "starting" events first (eg. PajePushState before PajePopState) + if(time == other.time) + return event_type < other.event_type; + else + return (time < other.time); + } + + int write(char *buf) + { + const int &key = id; + const int &end_container = start_container; + switch(event_type) + { + case PajeSetVariable: + return sprintf( buf, "%d\t%.15g\ta%d\ta%d\t%.15g\n", PajeSetVariable, time, type, container, var_value ); + case PajeAddVariable: + return sprintf( buf, "%d\t%.15g\ta%d\ta%d\t%.15g\n", PajeAddVariable, time, type, container, var_value ); + case PajeSubVariable: + return sprintf( buf, "%d\t%.15g\ta%d\ta%d\t%.15g\n", PajeSubVariable, time, type, container, var_value ); + case PajePushState: + if(value_is_alias) + return sprintf( buf, "%d\t%.15g\ta%d\ta%d\ta%d\t%d\n", PajePushState, time, type, container, value, id); + else + return sprintf( buf, "%d\t%.15g\ta%d\ta%d\t%d\t%d\n", PajePushState, time, type, container, value, id); + case PajePopState: + return sprintf( buf, "%d\t%.15g\ta%d\ta%d\n", PajePopState, time, type, container ); + case PajeStartLink: + return sprintf( buf, "%d\t%.15g\ta%d\ta%d\t%d\ta%d\t%d\n", PajeStartLink, time, type, container, value, start_container, key ); + case PajeEndLink: + return sprintf( buf, "%d\t%.15g\ta%d\ta%d\t%d\ta%d\t%d\n", PajeEndLink, time, type, container, value, end_container, key ); + } + return 0; + } + }; + + std::vector events; + + public: + PajeFile( string filename, TTimePoint astart_time ) + { + start_time = astart_time; + ctrace_stream = fopen (filename.c_str(),"w"); + fprintf(ctrace_stream, "%s", header ); + alias_counter = 0; + } + int DefineContainerType ( int parent_type, string name ) + { + int alias = ++alias_counter; + if(parent_type!=0) + fprintf( ctrace_stream, "%d\ta%d\ta%d\t\"%s\"\n", PajeDefineContainerType, alias, parent_type, name.c_str() ); + else + fprintf( ctrace_stream, "%d\ta%d\t%d\t\"%s\"\n", PajeDefineContainerType, alias, parent_type, name.c_str() ); + return alias; + } + + int DefineVariableType ( int container_type, string name ) + { + int alias = ++alias_counter; + fprintf( ctrace_stream, "%d\ta%d\ta%d\t\"%s\"\t\"1.0 1.0 1.0\"\n", PajeDefineVariableType, alias, container_type, name.c_str() ); + return alias; + } + + int DefineStateType ( int type, string name ) + { + int alias = ++alias_counter; + fprintf( ctrace_stream, "%d\ta%d\ta%d\t\"%s\"\n", PajeDefineStateType, alias, type, name.c_str() ); + return alias; + } + + // int DefineEventType () + // { + // Write("event not implemented"); + // } + + int DefineLinkType (int parent_container_type, int start_container_type, int stop_container_type, string name) + { + int alias = ++alias_counter; + fprintf( ctrace_stream, "%d\ta%d\ta%d\ta%d\ta%d\t\"%s\"\n", PajeDefineLinkType, alias, parent_container_type, start_container_type, stop_container_type, name.c_str() ); + return alias; + } + + int DefineEntityValue (int type, string name, double hue = -1) + { + if(hue==-1) + { + std::hash shash; + size_t h = shash(name); + h ^= h>>32; + h = (uint32_t)h; + hue = h*1.0/std::numeric_limits::max(); + } + + int alias = ++alias_counter; + double r,g,b; + Hue2RGB( hue, r, g, b ); + fprintf( ctrace_stream, "%d\ta%d\ta%d\t\"%s\"\t\"%.15g %.15g %.15g\"\n", PajeDefineEntityValue, alias, type, name.c_str(), r,g,b ); + return alias; + } + + int CreateContainer ( int type, int parent, string name ) + { + int alias = ++alias_counter; + if(parent!=0) + fprintf( ctrace_stream, "%d\t0\ta%d\ta%d\ta%d\t\"%s\"\n", PajeCreateContainer, alias, type, parent, name.c_str() ); + else + fprintf( ctrace_stream, "%d\t0\ta%d\ta%d\t%d\t\"%s\"\n", PajeCreateContainer, alias, type, parent, name.c_str() ); + return alias; + } + void DestroyContainer () + {} + + void SetVariable (TTimePoint time, int type, int container, double value ) + { + events.push_back( PajeEvent( PajeSetVariable, ConvertTime(time), type, container, value ) ); + } + + void AddVariable (TTimePoint time, int type, int container, double value ) + { + events.push_back( PajeEvent( PajeAddVariable, ConvertTime(time), type, container, value ) ); + } + + void SubVariable (TTimePoint time, int type, int container, double value ) + { + events.push_back( PajeEvent( PajeSubVariable, ConvertTime(time), type, container, value ) ); + } + + void SetState () + {} + + void PushState ( TTimePoint time, int type, int container, int value, int id = 0, bool value_is_alias = true ) + { + events.push_back( PajeEvent( PajePushState, ConvertTime(time), type, container, value, id) ); + } + + void PopState ( TTimePoint time, int type, int container ) + { + events.push_back( PajeEvent( PajePopState, ConvertTime(time), type, container ) ); + } + + void ResetState () + {} + + void StartLink ( TTimePoint time, int type, int container, int value, int start_container, int key ) + { + events.push_back( PajeEvent( PajeStartLink, ConvertTime(time), type, container, value, start_container, key ) ); + } + + void EndLink ( TTimePoint time, int type, int container, int value, int end_container, int key ) + { + events.push_back( PajeEvent( PajeEndLink, ConvertTime(time), type, container, value, end_container, key ) ); + } + + void NewEvent () + {} + + void WriteEvents() + { + logger->info("Sorting traces..."); + std::sort (events.begin(), events.end()); + + char buf[2*MAX_TRACE_LINE_SIZE]; + logger->info("Writing traces... "); + for (int i = 0; i < events.size(); i++) + { + events[i].write( buf ); + fprintf( ctrace_stream, "%s", buf ); + } + logger->info("Done"); + } + + private: + enum + { + PajeDefineContainerType = 0, + PajeDefineVariableType = 1, + PajeDefineStateType = 2, + PajeDefineEventType = 3, + PajeDefineLinkType = 4, + PajeDefineEntityValue = 5, + PajeCreateContainer = 6, + PajeDestroyContainer = 7, + PajeSetVariable = 8, + PajeAddVariable = 9, + PajeSubVariable = 10, + PajeSetState = 11, + PajePushState = 12, + PajePopState = 13, + PajeResetState = 14, + PajeStartLink = 15, + PajeEndLink = 16, + PajeNewEvent = 17 + }; + + }; + + NGCORE_API PajeTrace *trace; + + void PajeTrace::Write( string filename ) + { + int n_events = jobs.size() + timer_events.size(); + for(auto & vtasks : tasks) + n_events += vtasks.size(); + + logger->info("{} events traced", n_events); + + if(n_events==0) + { + logger->info("No data traced, skip writing trace file"); + return; + } + + if(!tracing_enabled) + { + logger->warning("Tracing stopped during computation due to tracefile size limit of {} megabytes.", max_tracefile_size/1024/1024); + } + + PajeFile paje(filename, start_time); + + const int container_type_task_manager = paje.DefineContainerType( 0, "Task Manager" ); + const int container_type_node = paje.DefineContainerType( container_type_task_manager, "Node"); + const int container_type_thread = paje.DefineContainerType( container_type_task_manager, "Thread"); + const int container_type_timer = container_type_thread; //paje.DefineContainerType( container_type_task_manager, "Timers"); + const int container_type_jobs = paje.DefineContainerType( container_type_task_manager, "Jobs"); + + const int state_type_job = paje.DefineStateType( container_type_jobs, "Job" ); + const int state_type_task = paje.DefineStateType( container_type_thread, "Task" ); + const int state_type_timer = paje.DefineStateType( container_type_timer, "Timer state" ); + + const int variable_type_active_threads = paje.DefineVariableType( container_type_jobs, "Active threads" ); + + const int container_task_manager = paje.CreateContainer( container_type_task_manager, 0, "The task manager" ); + const int container_jobs = paje.CreateContainer( container_type_jobs, container_task_manager, "Jobs" ); + paje.SetVariable( start_time, variable_type_active_threads, container_jobs, 0.0 ); + + const int num_nodes = 1; //task_manager ? task_manager->GetNumNodes() : 1; + std::vector container_nodes; + + for(int i=0; i thread_aliases; + if(trace_threads) + for (int i=0; i job_map; + std::map job_task_map; + + for(Job & j : jobs) + if(job_map.find(j.type) == job_map.end()) + { + string name = Demangle(j.type->name()); + job_map[j.type] = paje.DefineEntityValue( state_type_job, name, -1 ); + job_task_map[j.type] = paje.DefineEntityValue( state_type_task, name, -1 ); + } + + for(Job & j : jobs) + { + paje.PushState( j.start_time, state_type_job, container_jobs, job_map[j.type] ); + paje.PopState( j.stop_time, state_type_job, container_jobs ); + } + + std::set timer_ids; + std::map timer_aliases; + + for(auto & event : timer_events) + timer_ids.insert(event.timer_id); + + + for(auto & vtasks : tasks) + for (Task & t : vtasks) + if(t.id_type==Task::ID_TIMER) + timer_ids.insert(t.id); + + for(auto id : timer_ids) + timer_aliases[id] = paje.DefineEntityValue( state_type_timer, "a timer" /* TODO: NgProfiler::GetName(id).c_str()*/, -1 ); + + int timerdepth = 0; + int maxdepth = 0; + for(auto & event : timer_events) + { + if(event.is_start) + { + timerdepth++; + maxdepth = timerdepth>maxdepth ? timerdepth : maxdepth; + } + else + timerdepth--; + } + + std::vector timer_container_aliases; + timer_container_aliases.resize(maxdepth); + for(int i=0; i links_merged; + links_merged.reserve(nlinks); + std::vector pos(nthreads); + + int nlinks_merged = 0; + while(nlinks_merged < nlinks) + { + int minpos = -1; + TTimePoint mintime; + for (int t = 0; t started_links; + + int link_type = paje.DefineLinkType(container_type_node, container_type_thread, container_type_thread, "links"); + + // match links + for ( auto & l : links_merged ) + { + if(l.is_start) + { + started_links.push_back(l); + } + else + { + unsigned int i = 0; + while(i +#include +#include // for __rdtsc() CPU time step counter + +#include "ngcore_api.hpp" // for NGCORE_API +#include "logging.hpp" // for logger + +namespace ngcore +{ + + extern NGCORE_API class PajeTrace *trace; + class PajeTrace + { + public: + typedef std::chrono::system_clock TClock; + // typedef TClock::time_point TTimePoint; + typedef size_t TTimePoint; + + protected: + std::shared_ptr logger = GetLogger("PajeTrace"); + private: + friend class TraceDisabler; + + NGCORE_API static size_t max_tracefile_size; + static bool trace_thread_counter; + static bool trace_threads; + + bool tracing_enabled; + TTimePoint start_time; + int nthreads; + + public: + + // Approximate number of events to trace. Tracing will + // be stopped if any thread reaches this number of events + unsigned int max_num_events_per_thread; + + static void SetTraceThreads( bool atrace_threads ) + { + trace_threads = atrace_threads; + } + + static void SetTraceThreadCounter( bool trace_threads ) + { + trace_thread_counter = trace_threads; + } + + static void SetMaxTracefileSize( size_t max_size ) + { + max_tracefile_size = max_size; + } + + std::string tracefile_name; + + struct Job + { + int job_id; + const std::type_info *type; + TTimePoint start_time; + TTimePoint stop_time; + }; + + struct Task + { + int thread_id; + + int id; + int id_type; + + int additional_value; + + TTimePoint start_time; + TTimePoint stop_time; + + static constexpr int ID_NONE = -1; + static constexpr int ID_JOB = 1; + static constexpr int ID_TIMER = 2; + }; + + struct TimerEvent + { + int timer_id; + TTimePoint time; + bool is_start; + int thread_id; + + bool operator < (const TimerEvent & other) const { return time < other.time; } + }; + + struct ThreadLink + { + int thread_id; + int key; + TTimePoint time; + bool is_start; + bool operator < (const ThreadLink & other) const { return time < other.time; } + }; + + std::vector > tasks; + std::vector jobs; + std::vector timer_events; + std::vector > links; + + TTimePoint GetTime() + { + // return TClock::now(); + return TTimePoint(__rdtsc()); + } + + public: + NGCORE_API void StopTracing(); + + PajeTrace(int anthreads, std::string aname = ""); + ~PajeTrace(); + + void StartTimer(int timer_id) + { + if(!tracing_enabled) return; + if(unlikely(timer_events.size() == max_num_events_per_thread)) + StopTracing(); + timer_events.push_back(TimerEvent{timer_id, GetTime(), true}); + } + + void StopTimer(int timer_id) + { + if(!tracing_enabled) return; + if(unlikely(timer_events.size() == max_num_events_per_thread)) + StopTracing(); + timer_events.push_back(TimerEvent{timer_id, GetTime(), false}); + } + + NETGEN_INLINE int StartTask(int thread_id, int id, int id_type = Task::ID_NONE, int additional_value = -1) + { + if(!tracing_enabled) return -1; + if(!trace_threads && !trace_thread_counter) return -1; + if(unlikely(tasks[thread_id].size() == max_num_events_per_thread)) + StopTracing(); + int task_num = tasks[thread_id].size(); + tasks[thread_id].push_back( Task{thread_id, id, id_type, additional_value, GetTime()} ); + return task_num; + } + + void StopTask(int thread_id, int task_num) + { + if(!trace_threads && !trace_thread_counter) return; + if(task_num>=0) + tasks[thread_id][task_num].stop_time = GetTime(); + } + + void SetTask(int thread_id, int task_num, int additional_value) { + if(!trace_threads && !trace_thread_counter) return; + if(task_num>=0) + tasks[thread_id][task_num].additional_value = additional_value; + } + + void StartJob(int job_id, const std::type_info & type) + { + if(!tracing_enabled) return; + if(jobs.size() == max_num_events_per_thread) + StopTracing(); + jobs.push_back( Job{job_id, &type, GetTime()} ); + } + + void StopJob() + { + if(tracing_enabled) + jobs.back().stop_time = GetTime(); + } + + void StartLink(int thread_id, int key) + { + if(!tracing_enabled) return; + if(links[thread_id].size() == max_num_events_per_thread) + StopTracing(); + links[thread_id].push_back( ThreadLink{thread_id, key, GetTime(), true} ); + } + + void StopLink(int thread_id, int key) + { + if(!tracing_enabled) return; + if(links[thread_id].size() == max_num_events_per_thread) + StopTracing(); + links[thread_id].push_back( ThreadLink{thread_id, key, GetTime(), false} ); + } + + void Write( std::string filename ); + + }; + + class TraceDisabler + { + bool trace_thread_counter; + bool trace_threads; + + public: + TraceDisabler() + { + trace_thread_counter = PajeTrace::trace_thread_counter; + PajeTrace::trace_thread_counter = false; + trace_threads = PajeTrace::trace_threads; + PajeTrace::trace_threads = false; + } + + ~TraceDisabler() + { + PajeTrace::trace_thread_counter = trace_thread_counter; + PajeTrace::trace_threads = trace_threads; + } + }; +} + +#endif // NETGEN_CORE_PAJE_TRACE_HPP diff --git a/libsrc/core/utils.cpp b/libsrc/core/utils.cpp new file mode 100644 index 00000000..5fbb11a4 --- /dev/null +++ b/libsrc/core/utils.cpp @@ -0,0 +1,20 @@ +#include "utils.hpp" + +#ifndef WIN32 +#include +#endif + +namespace ngcore +{ +#ifdef WIN32 + // windows does demangling in typeid(T).name() + NGCORE_API std::string Demangle(const char* typeinfo) { return typeinfo; } +#else + NGCORE_API std::string Demangle(const char* typeinfo) { int status; return abi::__cxa_demangle(typeinfo, + nullptr, + nullptr, + &status); } +} // namespace ngcore + +#endif + diff --git a/libsrc/core/utils.hpp b/libsrc/core/utils.hpp new file mode 100644 index 00000000..f80d55d8 --- /dev/null +++ b/libsrc/core/utils.hpp @@ -0,0 +1,23 @@ +#ifndef NETGEN_CORE_UTILS_HPP +#define NETGEN_CORE_UTILS_HPP + +#include +#include + +#include "ngcore_api.hpp" // for NGCORE_API + +namespace ngcore +{ + NGCORE_API std::string Demangle(const char* typeinfo); + +#if defined(__GNUC__) + inline bool likely (bool x) { return bool(__builtin_expect(long(x), 1L)); } + inline bool unlikely (bool x) { return bool(__builtin_expect(long(x), 0L)); } +#else + inline bool likely (bool x) { return x; } + inline bool unlikely (bool x) { return x; } +#endif + +} // namespace ngcore + +#endif // NETGEN_CORE_UTILS_HPP