1 #ifndef NETGEN_CORE_PAJE_TRACE_HPP
2 #define NETGEN_CORE_PAJE_TRACE_HPP
3 
4 #include <limits>
5 #include <vector>
6 
7 #include "logging.hpp"       // for logger
8 #include "ngcore_api.hpp"    // for NGCORE_API
9 #include "utils.hpp"
10 
11 namespace ngcore
12 {
13 
14   extern NGCORE_API class PajeTrace *trace;
15   class PajeTrace
16     {
17     public:
18       using TClock = std::chrono::system_clock;
19 
20     protected:
21       std::shared_ptr<Logger> logger = GetLogger("PajeTrace");
22     private:
23       NGCORE_API static size_t max_tracefile_size;
24       NGCORE_API static bool trace_thread_counter;
25       NGCORE_API static bool trace_threads;
26       NGCORE_API static bool mem_tracing_enabled;
27 
28       bool tracing_enabled;
29       TTimePoint start_time;
30       int nthreads;
31       size_t n_memory_events_at_start;
32 
33     public:
34       NGCORE_API void WriteTimingChart();
35 #ifdef NETGEN_TRACE_MEMORY
36       NGCORE_API void WriteMemoryChart( std::string fname );
37 #endif // NETGEN_TRACE_MEMORY
38 
39       // Approximate number of events to trace. Tracing will
40       // be stopped if any thread reaches this number of events
41       unsigned int max_num_events_per_thread;
42 
SetTraceMemory(bool trace_memory)43       static void SetTraceMemory( bool trace_memory )
44         {
45           mem_tracing_enabled = trace_memory;
46         }
47 
SetTraceThreads(bool atrace_threads)48       static void SetTraceThreads( bool atrace_threads )
49         {
50           trace_threads = atrace_threads;
51         }
52 
SetTraceThreadCounter(bool trace_threads)53       static void SetTraceThreadCounter( bool trace_threads )
54         {
55           trace_thread_counter = trace_threads;
56         }
57 
SetMaxTracefileSize(size_t max_size)58       static void SetMaxTracefileSize( size_t max_size )
59         {
60           max_tracefile_size = max_size;
61         }
62 
63       std::string tracefile_name;
64 
65       struct Job
66         {
67           int job_id;
68           const std::type_info *type;
69           TTimePoint start_time;
70           TTimePoint stop_time;
71         };
72 
73       struct Task
74         {
75           int thread_id;
76 
77           int id;
78           int id_type;
79 
80           int additional_value;
81 
82           TTimePoint time;
83           bool is_start;
84 
85           static constexpr int ID_NONE = -1;
86           static constexpr int ID_JOB = 1;
87           static constexpr int ID_TIMER = 2;
88         };
89 
90       struct TimerEvent
91         {
92           int timer_id;
93           TTimePoint time;
94           bool is_start;
95           int thread_id;
96 
operator <ngcore::PajeTrace::TimerEvent97           bool operator < (const TimerEvent & other) const { return time < other.time; }
98         };
99 
100       struct ThreadLink
101         {
102           int thread_id;
103           int key;
104           TTimePoint time;
105           bool is_start;
operator <ngcore::PajeTrace::ThreadLink106           bool operator < (const ThreadLink & other) const { return time < other.time; }
107         };
108 
109       struct MemoryEvent
110         {
111           TTimePoint time;
112           size_t size;
113           int id;
114           bool is_alloc;
115 
operator <ngcore::PajeTrace::MemoryEvent116           bool operator < (const MemoryEvent & other) const { return time < other.time; }
117         };
118 
119       std::vector<std::vector<Task> > tasks;
120       std::vector<Job> jobs;
121       std::vector<TimerEvent> timer_events;
122       std::vector<std::vector<ThreadLink> > links;
123       NGCORE_API static std::vector<MemoryEvent> memory_events;
124 
125     public:
126       NGCORE_API void StopTracing();
127 
128       PajeTrace() = delete;
129       PajeTrace(const PajeTrace &) = delete;
130       PajeTrace(PajeTrace &&) = delete;
131       NGCORE_API PajeTrace(int anthreads, std::string aname = "");
132       NGCORE_API ~PajeTrace();
133 
134       void operator=(const PajeTrace &) = delete;
135       void operator=(PajeTrace &&) = delete;
136 
StartTimer(int timer_id)137       void StartTimer(int timer_id)
138         {
139           if(!tracing_enabled) return;
140           if(unlikely(timer_events.size() == max_num_events_per_thread))
141             StopTracing();
142           timer_events.push_back(TimerEvent{timer_id, GetTimeCounter(), true});
143         }
144 
StopTimer(int timer_id)145       void StopTimer(int timer_id)
146         {
147           if(!tracing_enabled) return;
148           if(unlikely(timer_events.size() == max_num_events_per_thread))
149             StopTracing();
150           timer_events.push_back(TimerEvent{timer_id, GetTimeCounter(), false});
151         }
152 
AllocMemory(int id,size_t size)153       void AllocMemory(int id, size_t size)
154         {
155           if(!mem_tracing_enabled) return;
156           memory_events.push_back(MemoryEvent{GetTimeCounter(), size, id, true});
157         }
158 
FreeMemory(int id,size_t size)159       void FreeMemory(int id, size_t size)
160         {
161           if(!mem_tracing_enabled) return;
162           memory_events.push_back(MemoryEvent{GetTimeCounter(), size, id, false});
163         }
164 
ChangeMemory(int id,long long size)165       void ChangeMemory(int id, long long size)
166         {
167           if(size>0)
168             AllocMemory(id, size);
169           if(size<0)
170             FreeMemory(id, -size);
171         }
172 
173 
StartTask(int thread_id,int id,int id_type=Task::ID_NONE,int additional_value=-1)174       NETGEN_INLINE int StartTask(int thread_id, int id, int id_type = Task::ID_NONE, int additional_value = -1)
175         {
176           if(!tracing_enabled) return -1;
177           if(!trace_threads && !trace_thread_counter) return -1;
178 	  if(unlikely(tasks[thread_id].size() == max_num_events_per_thread))
179             StopTracing();
180           int task_num = tasks[thread_id].size();
181           tasks[thread_id].push_back( Task{thread_id, id, id_type, additional_value, GetTimeCounter(), true} );
182           return task_num;
183         }
184 
StopTask(int thread_id,int id,int id_type=Task::ID_NONE)185       void StopTask(int thread_id, int id, int id_type = Task::ID_NONE)
186         {
187           if(!trace_threads && !trace_thread_counter) return;
188           tasks[thread_id].push_back( Task{thread_id, id, id_type, 0, GetTimeCounter(), false} );
189         }
190 
StartJob(int job_id,const std::type_info & type)191       void StartJob(int job_id, const std::type_info & type)
192         {
193           if(!tracing_enabled) return;
194           if(jobs.size() == max_num_events_per_thread)
195             StopTracing();
196           jobs.push_back( Job{job_id, &type, GetTimeCounter()} );
197         }
198 
StopJob()199       void StopJob()
200         {
201           if(tracing_enabled)
202             jobs.back().stop_time = GetTimeCounter();
203         }
204 
StartLink(int thread_id,int key)205       void StartLink(int thread_id, int key)
206         {
207           if(!tracing_enabled) return;
208           if(links[thread_id].size() == max_num_events_per_thread)
209             StopTracing();
210           links[thread_id].push_back( ThreadLink{thread_id, key, GetTimeCounter(), true} );
211         }
212 
StopLink(int thread_id,int key)213       void StopLink(int thread_id, int key)
214         {
215           if(!tracing_enabled) return;
216           if(links[thread_id].size() == max_num_events_per_thread)
217             StopTracing();
218           links[thread_id].push_back( ThreadLink{thread_id, key, GetTimeCounter(), false} );
219         }
220 
221       void Write( const std::string & filename );
222 
223       void SendData(); // MPI parallel data reduction
224 
225     };
226 } // namespace ngcore
227 
228 #endif // NETGEN_CORE_PAJE_TRACE_HPP
229