24 #include <stdatomic.h>
28 #define STATS_BUFFER_ENTRIES (1024)
29 #define STD_DEV_POWER_2_EXP 5
30 #define STATS_MAX_STRLEN 32U
74 sizeof(
struct stats_glob) == 32 + 8 * (STATS_GLOBAL_COUNT),
75 "structs aren't naturally packed, parsing may be difficult");
79 [STATS_ROLLBACK] =
"rollbacks",
81 [STATS_MSG_SILENT] =
"silent messages",
82 [STATS_MSG_PROCESSED] =
"processed messages"
88 static FILE *stats_node_tmp;
89 static FILE **stats_tmps;
92 static __thread
timer_uint last_ts[STATS_COUNT];
94 static void file_write_chunk(FILE *f,
const void *data,
size_t data_size)
96 if (
unlikely(fwrite(data, data_size, 1, f) != 1))
100 static void *file_memory_load(FILE *f, int64_t *f_size_p)
102 fseek(f, 0, SEEK_END);
103 long f_size = ftell(f);
104 fseek(f, 0, SEEK_SET);
106 if (fread(ret, f_size, 1, f) != 1) {
121 static FILE *
file_open(
const char *open_type,
const char *fmt, ...)
123 va_list args, args_cp;
125 va_copy(args_cp, args);
127 size_t l = vsnprintf(NULL, 0, fmt, args_cp) + 1;
131 vsnprintf(f_name, l, fmt, args);
134 FILE *ret = fopen(f_name, open_type);
166 if (mem_stat_setup() < 0)
170 setvbuf(stats_node_tmp, NULL, _IOFBF,
171 STATS_BUFFER_ENTRIES *
sizeof(
struct stats_node));
182 setvbuf(stats_tmps[
rid], NULL, _IOFBF,
183 STATS_BUFFER_ENTRIES *
sizeof(stats_cur));
188 static void stats_files_receive(FILE *o)
190 for (
nid_t j = 1; j < n_nodes; ++j) {
193 file_write_chunk(o, sg_p, buf_size);
197 for (uint64_t i = 0; i < iters; ++i) {
199 int64_t f_size = buf_size;
200 file_write_chunk(o, &f_size,
sizeof(f_size));
201 file_write_chunk(o, buf, buf_size);
207 static void stats_files_send(
void)
209 stats_glob_cur.
max_rss = mem_stat_rss_max_get();
214 void *f_buf = file_memory_load(stats_node_tmp, &f_size);
215 f_size = min(INT_MAX, f_size);
220 f_buf = file_memory_load(stats_tmps[i], &f_size);
221 f_size = min(INT_MAX, f_size);
229 static void stats_file_final_write(FILE *o)
231 uint16_t endian_check = 61455U;
232 file_write_chunk(o, &endian_check,
sizeof(endian_check));
234 int64_t n = STATS_COUNT;
235 file_write_chunk(o, &n,
sizeof(n));
236 for (
int i = 0; i < STATS_COUNT; ++i) {
237 size_t l = min(strlen(
s_names[i]), STATS_MAX_STRLEN);
238 file_write_chunk(o,
s_names[i], l);
239 unsigned char nul = 0;
240 for (; l < STATS_MAX_STRLEN; ++l)
241 file_write_chunk(o, &nul, 1);
245 file_write_chunk(o, &n,
sizeof(n));
247 stats_glob_cur.
max_rss = mem_stat_rss_max_get();
249 file_write_chunk(o, &stats_glob_cur,
sizeof(stats_glob_cur));
252 void *buf = file_memory_load(stats_node_tmp, &buf_size);
253 file_write_chunk(o, &buf_size,
sizeof(buf_size));
254 file_write_chunk(o, buf, buf_size);
258 buf = file_memory_load(stats_tmps[i], &buf_size);
259 file_write_chunk(o, &buf_size,
sizeof(buf_size));
260 file_write_chunk(o, buf, buf_size);
284 log_log(
LOG_WARN,
"Unavailable stats file: stats will be dumped on stdout");
288 stats_file_final_write(o);
291 stats_files_receive(o);
299 void stats_time_start(
enum stats_time this_stat)
304 void stats_time_take(
enum stats_time this_stat)
307 const uint64_t t =
timer_value(last_ts[this_stat]);
310 const int64_t num = (t * s_mes->
count - s_mes->
sum_t);
311 s_mes->
var_t += ((num * num) << (2 * STD_DEV_POWER_2_EXP)) /
323 file_write_chunk(stats_tmps[
rid], &stats_cur,
sizeof(stats_cur));
324 memset(&stats_cur, 0,
sizeof(stats_cur));
330 {.
gvt =
gvt, .rss = mem_stat_rss_current_get()};
331 file_write_chunk(stats_node_tmp, &stats_node_cur,
sizeof(stats_node_cur));
332 memset(&stats_node_cur, 0,
sizeof(stats_node_cur));
334 printf(
"\rVirtual time: %lf",
gvt);
338 void stats_dump(
void)