scc 2025.09
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
34namespace scc {
35using namespace sc_core;
36
37#if SYSTEMC_VERSION < 20250221
38SC_HAS_PROCESS(perf_estimator);
39#endif
40perf_estimator::perf_estimator(const sc_module_name& nm, sc_time beat_delay_)
41: sc_module(nm)
42, beat_delay(beat_delay_) {
43 soc.set();
44 if(beat_delay.value()) {
45 SC_METHOD(beat);
46 }
47}
48
50 time_stamp eod;
51 eod.set();
52 SCCINFO("perf_estimator") << "constr & elab time: " << (eoe.proc_clock_stamp - soc.proc_clock_stamp) << "s";
53 SCCINFO("perf_estimator") << "simulation time: " << (eos.proc_clock_stamp - sos.proc_clock_stamp) << "s";
54 if(cycle_period.value()) {
55 uint64_t cycles = sc_time_stamp().value() / cycle_period.value();
56 SCCINFO("perf_estimator") << "simulation speed: "
57 << (sc_time_stamp().value() ? cycles / (eos.proc_clock_stamp - soc.proc_clock_stamp) : 0.0)
58 << " cycles/s";
59 }
60 SCCINFO("perf_estimator") << "max resident memory: " << max_memory << "kB";
61}
62
64
65void perf_estimator::start_of_simulation() {
66 sos.set();
67 get_memory();
68}
69
70void perf_estimator::end_of_simulation() {
71 eos.set();
72 sc_time now = sc_time_stamp();
73 unsigned long long elapsed_wall = (eos.wall_clock_stamp - sos.wall_clock_stamp).total_microseconds();
74 auto elapsed_proc = (unsigned long long)((eos.proc_clock_stamp - sos.proc_clock_stamp) * 1000000);
75 auto elapsed_sim = (unsigned long long)(now.to_seconds() * 1000000.);
76 if(elapsed_sim > 0) {
77 double wall_perf = elapsed_wall / elapsed_sim;
78 double proc_perf = elapsed_proc / elapsed_sim;
79 SCCINFO("perf_estimator") << "Wall clock (process clock) based simulation real time factor is " << wall_perf << "(" << proc_perf
80 << ")";
81 }
82 get_memory();
83}
84
85void perf_estimator::beat() {
86 if(sc_time_stamp().value())
87 SCCINFO("perf_estimator") << "Heart beat, rss mem: " << get_memory() << "kB";
88 next_trigger(beat_delay);
89#if !defined(WIN32) and !defined(__APPLE__)
90 malloc_trim(0);
91#endif
92}
93} /* namespace scc */
94
95auto scc::perf_estimator::time_stamp::get_cpu_time() -> double {
96#if defined(_WIN32)
97 FILETIME create_time;
98 FILETIME exit_time;
99 FILETIME kernel_time;
100 FILETIME user_time;
101 if(GetProcessTimes(GetCurrentProcess(), &create_time, &exit_time, &kernel_time, &user_time) != -1) {
102 SYSTEMTIME system_time;
103 if(FileTimeToSystemTime(&user_time, &system_time) != -1)
104 return (double)system_time.wHour * 3600.0 + (double)system_time.wMinute * 60.0 + (double)system_time.wSecond +
105 (double)system_time.wMilliseconds / 1000.;
106 }
107#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__MACH__) && defined(__APPLE__))
108#if _POSIX_TIMERS > 0
109 {
110 clockid_t id;
111 struct timespec stamp {};
112#if _POSIX_CPUTIME > 0
113 if(clock_getcpuclockid(0, &id) == -1)
114#endif
115#if defined(CLOCK_PROCESS_CPUTIME_ID)
116 id = CLOCK_PROCESS_CPUTIME_ID;
117#elif defined(CLOCK_VIRTUAL)
118 id = CLOCK_VIRTUAL;
119#else
120 id = (clockid_t)-1;
121#endif
122 if(id != (clockid_t)-1 && clock_gettime(id, &stamp) != -1)
123 return (double)stamp.tv_sec + (double)stamp.tv_nsec / 1000000000.0;
124 }
125#endif
126#if defined(RUSAGE_SELF)
127 {
128 struct rusage usage {};
129 if(getrusage(RUSAGE_SELF, &usage) != -1)
130 return (double)usage.ru_utime.tv_sec + (double)usage.ru_utime.tv_usec / 1000000.0;
131 }
132#endif
133#if defined(_SC_CLK_TICK)
134 {
135 const double ticks = (double)sysconf(_SC_CLK_TCK);
136 struct tms s;
137 if(times(&s) != (clock_t)-1)
138 return (double)s.tms_utime / ticks;
139 }
140#endif
141#if defined(CLOCKS_PER_SEC)
142 {
143 clock_t c = clock();
144 if(c != (clock_t)-1)
145 return (double)c / (double)CLOCKS_PER_SEC;
146 }
147#endif
148#endif
149 return 1.0;
150}
151
152long scc::perf_estimator::get_memory() {
153#if defined(RUSAGE_SELF)
154 {
155 struct rusage usage {};
156 if(getrusage(RUSAGE_SELF, &usage) != -1) {
157 max_memory = std::max(max_memory, usage.ru_maxrss);
158 return usage.ru_maxrss;
159 }
160 }
161#endif
162 return 0L;
163}
a performance estimator
perf_estimator()
default constructor creating an unnamed perf_estimator
void end_of_elaboration() override
SystemC callbacks.
virtual ~perf_estimator()
destructor
time_stamp soc
the recorded time stamps
SCC TLM utilities.