scc  2024.06
SystemC components library
perf_estimator.cpp
1 /*******************************************************************************
2  * Copyright 2018 MINRES Technologies GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *******************************************************************************/
16 
17 #include "perf_estimator.h"
18 #include "report.h"
19 
20 #if defined(_WIN32)
21 #include <Windows.h>
22 #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__MACH__) && defined(__APPLE__))
23 #include <ctime>
24 #include <sys/resource.h>
25 #include <sys/times.h>
26 #include <unistd.h>
27 #else
28 #error "Cannot compile file because of an unknown method to retrieve OS time."
29 #endif
30 #if !defined(WIN32) and !defined(__APPLE__)
31 #include <malloc.h>
32 #endif
33 
34 namespace scc {
35 using namespace sc_core;
36 
37 SC_HAS_PROCESS(perf_estimator);
38 
39 perf_estimator::perf_estimator(const sc_module_name& nm, sc_time beat_delay_)
40 : sc_module(nm)
41 , beat_delay(beat_delay_) {
42  soc.set();
43  if(beat_delay.value()) {
44  SC_METHOD(beat);
45  }
46 }
47 
48 perf_estimator::~perf_estimator() {
49  time_stamp eod;
50  eod.set();
51  SCCINFO("perf_estimator") << "constr & elab time: " << (eoe.proc_clock_stamp - soc.proc_clock_stamp) << "s";
52  SCCINFO("perf_estimator") << "simulation time: " << (eos.proc_clock_stamp - sos.proc_clock_stamp) << "s";
53  if(cycle_period.value()) {
54  uint64_t cycles = sc_time_stamp().value() / cycle_period.value();
55  SCCINFO("perf_estimator") << "simulation speed: "
56  << (sc_time_stamp().value() ? cycles / (eos.proc_clock_stamp - soc.proc_clock_stamp) : 0.0)
57  << " cycles/s";
58  }
59  SCCINFO("perf_estimator") << "max resident memory: " << max_memory << "kB";
60 }
61 
62 void perf_estimator::end_of_elaboration() { eoe.set(); }
63 
64 void perf_estimator::start_of_simulation() {
65  sos.set();
66  get_memory();
67 }
68 
69 void perf_estimator::end_of_simulation() {
70  eos.set();
71  sc_time now = sc_time_stamp();
72  unsigned long long elapsed_wall = (eos.wall_clock_stamp - sos.wall_clock_stamp).total_microseconds();
73  auto elapsed_proc = (unsigned long long)((eos.proc_clock_stamp - sos.proc_clock_stamp) * 1000000);
74  auto elapsed_sim = (unsigned long long)(now.to_seconds() * 1000000.);
75  if(elapsed_sim > 0) {
76  double wall_perf = elapsed_wall / elapsed_sim;
77  double proc_perf = elapsed_proc / elapsed_sim;
78  SCCINFO("perf_estimator") << "Wall clock (process clock) based simulation real time factor is " << wall_perf << "(" << proc_perf
79  << ")";
80  }
81  get_memory();
82 }
83 
84 void perf_estimator::beat() {
85  if(sc_time_stamp().value())
86  SCCINFO("perf_estimator") << "Heart beat, rss mem: " << get_memory() << "kB";
87  next_trigger(beat_delay);
88 #if !defined(WIN32) and !defined(__APPLE__)
89  malloc_trim(0);
90 #endif
91 }
92 } /* namespace scc */
93 
94 auto scc::perf_estimator::time_stamp::get_cpu_time() -> double {
95 #if defined(_WIN32)
96  FILETIME create_time;
97  FILETIME exit_time;
98  FILETIME kernel_time;
99  FILETIME user_time;
100  if(GetProcessTimes(GetCurrentProcess(), &create_time, &exit_time, &kernel_time, &user_time) != -1) {
101  SYSTEMTIME system_time;
102  if(FileTimeToSystemTime(&user_time, &system_time) != -1)
103  return (double)system_time.wHour * 3600.0 + (double)system_time.wMinute * 60.0 + (double)system_time.wSecond +
104  (double)system_time.wMilliseconds / 1000.;
105  }
106 #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__MACH__) && defined(__APPLE__))
107 #if _POSIX_TIMERS > 0
108  {
109  clockid_t id;
110  struct timespec stamp {};
111 #if _POSIX_CPUTIME > 0
112  if(clock_getcpuclockid(0, &id) == -1)
113 #endif
114 #if defined(CLOCK_PROCESS_CPUTIME_ID)
115  id = CLOCK_PROCESS_CPUTIME_ID;
116 #elif defined(CLOCK_VIRTUAL)
117  id = CLOCK_VIRTUAL;
118 #else
119  id = (clockid_t)-1;
120 #endif
121  if(id != (clockid_t)-1 && clock_gettime(id, &stamp) != -1)
122  return (double)stamp.tv_sec + (double)stamp.tv_nsec / 1000000000.0;
123  }
124 #endif
125 #if defined(RUSAGE_SELF)
126  {
127  struct rusage usage {};
128  if(getrusage(RUSAGE_SELF, &usage) != -1)
129  return (double)usage.ru_utime.tv_sec + (double)usage.ru_utime.tv_usec / 1000000.0;
130  }
131 #endif
132 #if defined(_SC_CLK_TICK)
133  {
134  const double ticks = (double)sysconf(_SC_CLK_TCK);
135  struct tms s;
136  if(times(&s) != (clock_t)-1)
137  return (double)s.tms_utime / ticks;
138  }
139 #endif
140 #if defined(CLOCKS_PER_SEC)
141  {
142  clock_t c = clock();
143  if(c != (clock_t)-1)
144  return (double)c / (double)CLOCKS_PER_SEC;
145  }
146 #endif
147 #endif
148  return 1.0;
149 }
150 
151 long scc::perf_estimator::get_memory() {
152 #if defined(RUSAGE_SELF)
153  {
154  struct rusage usage {};
155  if(getrusage(RUSAGE_SELF, &usage) != -1) {
156  max_memory = std::max(max_memory, usage.ru_maxrss);
157  return usage.ru_maxrss;
158  }
159  }
160 #endif
161  return 0L;
162 }
perf_estimator()
default constructor creating an unnamed perf_estimator
SCC TLM utilities.