souffle  2.0.2-371-g6315b36
ProfileEvent.h
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2018, The Souffle Developers. All rights reserved.
4  * Licensed under the Universal Permissive License v 1.0 as shown at:
5  * - https://opensource.org/licenses/UPL
6  * - <souffle root>/licenses/SOUFFLE-UPL.txt
7  */
8 
9 /************************************************************************
10  *
11  * @file ProfileEvent.h
12  *
13  * Declares classes for profile events
14  *
15  ***********************************************************************/
16 
17 #pragma once
18 
22 #include <atomic>
23 #include <chrono>
24 #include <condition_variable>
25 #include <cstdint>
26 #include <ctime>
27 #include <iostream>
28 #include <mutex>
29 #include <sstream>
30 #include <string>
31 #include <thread>
32 #ifdef WIN32
33 #include <Psapi.h>
34 #else
35 #include <sys/resource.h>
36 #include <sys/time.h>
37 #endif // WIN32
38 
39 namespace souffle {
40 
41 /**
42  * Profile Event Singleton
43  */
44 class ProfileEventSingleton {
45  /** profile database */
46  profile::ProfileDatabase database;
47  std::string filename{""};
48 
49  ProfileEventSingleton() = default;
50 
51 public:
53  stopTimer();
55  }
56 
57  /** get instance */
59  static ProfileEventSingleton singleton;
60  return singleton;
61  }
62 
63  /** create config record */
64  void makeConfigRecord(const std::string& key, const std::string& value) {
65  profile::EventProcessorSingleton::instance().process(database, "@config", key.c_str(), value.c_str());
66  }
67 
68  /** create time event */
69  void makeTimeEvent(const std::string& txt) {
71  database, txt.c_str(), std::chrono::duration_cast<microseconds>(now().time_since_epoch()));
72  }
73 
74  /** create an event for recording start and end times */
75  void makeTimingEvent(const std::string& txt, time_point start, time_point end, size_t startMaxRSS,
76  size_t endMaxRSS, size_t size, size_t iteration) {
77  microseconds start_ms = std::chrono::duration_cast<microseconds>(start.time_since_epoch());
78  microseconds end_ms = std::chrono::duration_cast<microseconds>(end.time_since_epoch());
80  database, txt.c_str(), start_ms, end_ms, startMaxRSS, endMaxRSS, size, iteration);
81  }
82 
83  /** create quantity event */
84  void makeQuantityEvent(const std::string& txt, size_t number, int iteration) {
86  }
87 
88  /** create utilisation event */
89  void makeUtilisationEvent(const std::string& txt) {
90  /* current time */
91  microseconds time = std::chrono::duration_cast<microseconds>(now().time_since_epoch());
92 
93 #ifdef WIN32
94  HANDLE hProcess = GetCurrentProcess();
95  FILETIME systemFileTime, userFileTime;
96  GetProcessTimes(hProcess, nullptr, nullptr, &systemFileTime, &userFileTime);
97  /* system CPU time and user CPU time are both expected to be in
98  microseconds below, GetProcessTime gives us a value which is a
99  counter of 100 nanosecond units. */
100  /* system CPU time used */
101  uint64_t systemTime = systemFileTime.dwHighDateTime;
102  systemTime = (systemTime << 32) | systemFileTime.dwLowDateTime;
103  systemTime /= 1000;
104  /* user CPU time used */
105  uint64_t userTime = userFileTime.dwHighDateTime;
106  userTime = (userTime << 32) | userFileTime.dwLowDateTime;
107  userTime /= 1000;
108  PROCESS_MEMORY_COUNTERS processMemoryCounters;
109  GetProcessMemoryInfo(hProcess, &processMemoryCounters, sizeof(processMemoryCounters));
110  /* Maximum resident set size (kb) */
111  size_t maxRSS = processMemoryCounters.PeakWorkingSetSize / 1000;
112 #else
113  /* system CPU time used */
114  struct rusage ru {};
115  getrusage(RUSAGE_SELF, &ru);
116  /* system CPU time used */
117  uint64_t systemTime = ru.ru_stime.tv_sec * 1000000 + ru.ru_stime.tv_usec;
118  /* user CPU time used */
119  uint64_t userTime = ru.ru_utime.tv_sec * 1000000 + ru.ru_utime.tv_usec;
120  /* Maximum resident set size (kb) */
121  size_t maxRSS = ru.ru_maxrss;
122 #endif // WIN32
123 
125  database, txt.c_str(), time, systemTime, userTime, maxRSS);
126  }
127 
128  void setOutputFile(std::string outputFilename) {
129  filename = outputFilename;
130  }
131  /** Dump all events */
132  void dump() {
133  if (!filename.empty()) {
134  std::ofstream os(filename);
135  if (!os.is_open()) {
136  std::cerr << "Cannot open profile log file <" + filename + ">";
137  } else {
138  database.print(os);
139  }
140  }
141  }
142 
143  /** Start timer */
144  void startTimer() {
145  timer.start();
146  }
147 
148  /** Stop timer */
149  void stopTimer() {
150  timer.stop();
151  }
152 
153  void resetTimerInterval(uint32_t interval = 1) {
154  timer.resetTimerInterval(interval);
155  }
156  const profile::ProfileDatabase& getDB() const {
157  return database;
158  }
159 
160  void setDBFromFile(const std::string& databaseFilename) {
161  database = profile::ProfileDatabase(databaseFilename);
162  }
163 
164 private:
165  /** Profile Timer */
166  class ProfileTimer {
167  private:
168  /** time interval between per utilisation read */
169  uint32_t t;
170 
171  /** timer is running */
172  std::atomic<bool> running{false};
173 
174  /** thread timer runs on */
175  std::thread th;
176 
177  std::condition_variable conditionVariable;
178  std::mutex timerMutex;
179 
180  /** number of utilisation events */
181  std::atomic<uint32_t> runCount{0};
182 
183  /** run method for thread th */
184  void run() {
186  ++runCount;
187  if (runCount % 128 == 0) {
189  }
190  }
191 
192  uint32_t getInterval() {
193  return t;
194  }
195 
196  /** Increase value of time interval by factor of 2 */
197  void increaseInterval() {
198  // Don't increase time interval past 60 seconds
199  if (t < 60000) {
200  t = t * 2;
201  }
202  }
203 
204  public:
205  /*
206  * @param interval the size of the timing interval in milliseconds
207  */
208  ProfileTimer(uint32_t interval = 10) : t(interval) {}
209 
210  /** start timer on the thread th */
211  void start() {
212  if (running) {
213  return;
214  }
215  running = true;
216 
217  th = std::thread([this]() {
218  while (running) {
219  run();
220  std::unique_lock<std::mutex> lock(timerMutex);
221  conditionVariable.wait_for(lock, std::chrono::milliseconds(getInterval()));
222  }
223  });
224  }
225 
226  /** stop timer on the thread th */
227  void stop() {
228  running = false;
229  conditionVariable.notify_all();
230  if (th.joinable()) {
231  th.join();
232  }
233  }
234 
235  /** Reset timer interval.
236  *
237  * The timer interval increases as the program executes. Resetting the interval is useful to
238  * ensure that detailed usage information is gathered even in long running programs, if desired.
239  *
240  * @param interval the size of the timing interval in milliseconds
241  */
242  void resetTimerInterval(uint32_t interval = 10) {
243  t = interval;
244  runCount = 0;
245  conditionVariable.notify_all();
246  }
247  };
248 
249  ProfileTimer timer;
250 };
251 
252 } // namespace souffle
souffle::profile::EventProcessorSingleton::process
void process(ProfileDatabase &db, const char *txt,...)
process a profile event
Definition: EventProcessor.h:81
TCB_SPAN_NAMESPACE_NAME::detail::size
constexpr auto size(const C &c) -> decltype(c.size())
Definition: span.h:198
souffle::ProfileEventSingleton::filename
std::string filename
Definition: ProfileEvent.h:59
souffle::ProfileEventSingleton::~ProfileEventSingleton
~ProfileEventSingleton()
Definition: ProfileEvent.h:64
souffle::ProfileEventSingleton::ProfileTimer::t
uint32_t t
time interval between per utilisation read
Definition: ProfileEvent.h:181
souffle::ProfileEventSingleton::stopTimer
void stopTimer()
Stop timer.
Definition: ProfileEvent.h:161
souffle::ProfileEventSingleton::instance
static ProfileEventSingleton & instance()
get instance
Definition: ProfileEvent.h:70
souffle::ProfileEventSingleton::ProfileEventSingleton
ProfileEventSingleton()=default
MiscUtil.h
souffle::ProfileEventSingleton::ProfileTimer::start
void start()
start timer on the thread th
Definition: ProfileEvent.h:223
iteration
Iteration & iteration
Definition: Reader.h:129
souffle::ProfileEventSingleton::ProfileTimer::timerMutex
std::mutex timerMutex
Definition: ProfileEvent.h:190
souffle::now
time_point now()
Definition: MiscUtil.h:89
EventProcessor.h
souffle::ProfileEventSingleton::ProfileTimer::th
std::thread th
thread timer runs on
Definition: ProfileEvent.h:187
souffle::ProfileEventSingleton::timer
ProfileTimer timer
Definition: ProfileEvent.h:261
souffle::ProfileEventSingleton::ProfileTimer::getInterval
uint32_t getInterval()
Definition: ProfileEvent.h:204
souffle::ProfileEventSingleton::makeQuantityEvent
void makeQuantityEvent(const std::string &txt, size_t number, int iteration)
create quantity event
Definition: ProfileEvent.h:96
souffle::time_point
std::chrono::high_resolution_clock::time_point time_point
Definition: MiscUtil.h:85
souffle::ProfileEventSingleton::setOutputFile
void setOutputFile(std::string outputFilename)
Definition: ProfileEvent.h:140
souffle::ProfileEventSingleton::ProfileTimer::conditionVariable
std::condition_variable conditionVariable
Definition: ProfileEvent.h:189
souffle::ProfileEventSingleton::makeConfigRecord
void makeConfigRecord(const std::string &key, const std::string &value)
create config record
Definition: ProfileEvent.h:76
souffle::ProfileEventSingleton::ProfileTimer::increaseInterval
void increaseInterval()
Increase value of time interval by factor of 2.
Definition: ProfileEvent.h:209
souffle::ProfileEventSingleton::resetTimerInterval
void resetTimerInterval(uint32_t interval=1)
Definition: ProfileEvent.h:165
souffle::test::time
long time(const std::string &name, const Op &operation)
Definition: btree_multiset_test.cpp:411
souffle::ProfileEventSingleton::ProfileTimer
Profile Timer.
Definition: ProfileEvent.h:178
souffle::ProfileEventSingleton
Profile Event Singleton.
Definition: ProfileEvent.h:50
souffle::ProfileEventSingleton::makeUtilisationEvent
void makeUtilisationEvent(const std::string &txt)
create utilisation event
Definition: ProfileEvent.h:101
souffle::ProfileEventSingleton::makeTimeEvent
void makeTimeEvent(const std::string &txt)
create time event
Definition: ProfileEvent.h:81
souffle::ProfileEventSingleton::database
profile::ProfileDatabase database
profile database
Definition: ProfileEvent.h:58
souffle::ProfileEventSingleton::ProfileTimer::runCount
std::atomic< uint32_t > runCount
number of utilisation events
Definition: ProfileEvent.h:193
souffle::ProfileEventSingleton::setDBFromFile
void setDBFromFile(const std::string &databaseFilename)
Definition: ProfileEvent.h:172
souffle
Definition: AggregateOp.h:25
ProfileDatabase.h
souffle::ProfileEventSingleton::getDB
const profile::ProfileDatabase & getDB() const
Definition: ProfileEvent.h:168
souffle::ProfileEventSingleton::makeTimingEvent
void makeTimingEvent(const std::string &txt, time_point start, time_point end, size_t startMaxRSS, size_t endMaxRSS, size_t size, size_t iteration)
create an event for recording start and end times
Definition: ProfileEvent.h:87
souffle::ProfileEventSingleton::ProfileTimer::running
std::atomic< bool > running
timer is running
Definition: ProfileEvent.h:184
souffle::ProfileEventSingleton::ProfileTimer::stop
void stop()
stop timer on the thread th
Definition: ProfileEvent.h:239
souffle::profile::EventProcessorSingleton::instance
static EventProcessorSingleton & instance()
get instance
Definition: EventProcessor.h:70
souffle::ProfileEventSingleton::ProfileTimer::ProfileTimer
ProfileTimer(uint32_t interval=10)
Definition: ProfileEvent.h:220
souffle::ProfileEventSingleton::dump
void dump()
Dump all events.
Definition: ProfileEvent.h:144
souffle::ProfileEventSingleton::startTimer
void startTimer()
Start timer.
Definition: ProfileEvent.h:156
souffle::ProfileEventSingleton::ProfileTimer::run
void run()
run method for thread th
Definition: ProfileEvent.h:196
souffle::ProfileEventSingleton::ProfileTimer::resetTimerInterval
void resetTimerInterval(uint32_t interval=10)
Reset timer interval.
Definition: ProfileEvent.h:254