62 #include <sys/types.h> 81 #define GVT_BUFF_ROWS 50 119 struct stat_t global_stats = {.gvt_round_time_min =
INFTY};
136 #define safe_asprintf(ret_addr, format, ...) ({ \ 137 char *__pstr = NULL; \ 138 int __ret = snprintf(0, 0, format, ##__VA_ARGS__); \ 140 rootsim_error(true, "Error in snprintf()!"); \ 141 __pstr = rsalloc(__ret + 1); \ 142 __ret = snprintf(__pstr, __ret + 1, format, ##__VA_ARGS__); \ 144 rootsim_error(true, "Error in snprintf()!"); \ 145 *(ret_addr) = __pstr; \ 162 if (!(dir = opendir(path))) {
166 while ( (dirt = readdir(dir))) {
167 if ((strcmp(dirt->d_name,
".") == 0) || (strcmp(dirt->d_name,
"..") == 0))
172 if (stat(buf, &st) == -1) {
173 rootsim_error(
false,
"stat() file \"%s\" failed, %s\n", buf, strerror(errno));
174 }
else if (S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)) {
175 if (unlink(buf) == -1)
176 rootsim_error(
false,
"unlink() file \"%s\" failed, %s\n", buf, strerror(errno));
178 else if (S_ISDIR(st.st_mode)) {
186 if (rmdir(path) == -1)
187 rootsim_error(
false,
"rmdir() directory \"%s\" failed, %s\n", path, strerror(errno));
204 strncpy(opath, path,
sizeof(opath));
207 if(opath[len - 1] ==
'/')
208 opath[len - 1] =
'\0';
211 for(p = opath + 1; *p; p++) {
214 if(access(opath, F_OK))
215 if (mkdir(opath, S_IRWXU))
216 if (errno != EEXIST) {
217 rootsim_error(
true,
"Could not create output directory", opath);
224 if(access(opath, F_OK)) {
225 if (mkdir(opath, S_IRWXU)) {
226 if (errno != EEXIST) {
227 if (errno != EEXIST) {
228 rootsim_error(
true,
"Could not create output directory", opath);
235 static void print_config_to_file(FILE *f)
238 "****************************\n" 239 "* ROOT-Sim Configuration *\n" 240 "****************************\n" 242 "Cores: %ld available, %d used\n" 243 "Number of Logical Processes: %u\n" 244 "Output Statistics Directory: %s\n" 247 "MPI multithread support: %s\n" 249 "GVT Time Period: %.2f seconds\n" 250 "Checkpointing Type: %s\n" 251 "Checkpointing Period: %d\n" 252 "Snapshot Reconstruction Type: %s\n" 253 "Halt Simulation After: %d\n" 254 "LPs Distribution Mode across Kernels: %s\n" 255 "Check Termination Mode: %s\n" 277 void print_config(
void) {
279 print_config_to_file(stdout);
300 static __thread
char size_str[32];
307 }
else if (size <= 1024 * 1024) {
310 }
else if (size <= 1024 * 1024 * 1024) {
312 divisor = 1024 * 1024;
315 divisor = 1024 * 1024 * 1024;
318 snprintf(size_str, 32, fmt, size / divisor);
323 #define HEADER_STR "------------------------------------------------------------" 324 static void print_header(FILE *f,
const char *title)
326 char buf[
sizeof(HEADER_STR)] = HEADER_STR;
327 unsigned title_len = strlen(title);
328 assert(title_len <
sizeof(HEADER_STR));
329 memcpy(buf + ((
sizeof(HEADER_STR) - title_len) / 2), title, title_len);
330 fprintf(f, HEADER_STR
"\n%s\n" HEADER_STR
"\n\n", buf);
334 static void print_timer_stats(FILE *f, timer *start_timer, timer *stop_timer,
double total_time)
336 char timer_string[TIMER_BUFFER_LEN];
338 fprintf(f,
"SIMULATION STARTED AT ..... : %s \n", timer_string);
340 fprintf(f,
"SIMULATION FINISHED AT .... : %s \n", timer_string);
341 fprintf(f,
"TOTAL SIMULATION TIME ..... : %.03f seconds \n\n", total_time);
345 static void print_common_stats(FILE *f,
struct stat_t *stats_p,
bool want_thread_stats,
bool want_local_stats)
347 double rollback_frequency = (stats_p->tot_rollbacks / stats_p->tot_events);
348 double rollback_length = (stats_p->tot_rollbacks > 0 ? (stats_p->tot_events - stats_p->committed_events) / stats_p->tot_rollbacks : 0);
349 double efficiency = (1 - rollback_frequency * rollback_length) * 100;
351 fprintf(f,
"TOTAL KERNELS ............. : %d \n",
n_ker);
352 if(want_local_stats) {
353 fprintf(f,
"KERNEL ID ................. : %d \n",
kid);
354 fprintf(f,
"LPs HOSTED BY KERNEL....... : %d \n",
n_prc);
355 fprintf(f,
"TOTAL_THREADS ............. : %d \n",
n_cores);
357 fprintf(f,
"TOTAL_THREADS ............. : %d \n",
n_cores *
n_ker);
358 fprintf(f,
"TOTAL LPs.................. : %d \n",
n_prc_tot);
360 if(want_thread_stats) {
361 fprintf(f,
"THREAD ID ................. : %d \n",
local_tid);
365 fprintf(f,
"TOTAL EXECUTED EVENTS ..... : %.0f \n", stats_p->tot_events);
366 fprintf(f,
"TOTAL COMMITTED EVENTS..... : %.0f \n", stats_p->committed_events);
367 fprintf(f,
"TOTAL REPROCESSED EVENTS... : %.0f \n", stats_p->reprocessed_events);
368 fprintf(f,
"TOTAL ROLLBACKS EXECUTED... : %.0f \n", stats_p->tot_rollbacks);
369 fprintf(f,
"TOTAL ANTIMESSAGES......... : %.0f \n", stats_p->tot_antimessages);
370 fprintf(f,
"ROLLBACK FREQUENCY......... : %.2f %%\n", rollback_frequency * 100);
371 fprintf(f,
"ROLLBACK LENGTH............ : %.2f events\n", rollback_length);
372 fprintf(f,
"EFFICIENCY................. : %.2f %%\n", efficiency);
373 fprintf(f,
"AVERAGE EVENT COST......... : %.2f us\n", stats_p->event_time / stats_p->tot_events);
374 fprintf(f,
"AVERAGE EVENT COST (EMA)... : %.2f us\n", stats_p->exponential_event_time);
375 fprintf(f,
"AVERAGE CHECKPOINT COST.... : %.2f us\n", stats_p->ckpt_time / stats_p->tot_ckpts);
376 fprintf(f,
"AVERAGE RECOVERY COST...... : %.2f us\n", (stats_p->tot_recoveries > 0 ? stats_p->recovery_time / stats_p->tot_recoveries : 0));
377 fprintf(f,
"AVERAGE LOG SIZE........... : %s\n",
format_size(stats_p->ckpt_mem / stats_p->tot_ckpts));
379 fprintf(f,
"IDLE CYCLES................ : %.0f\n", stats_p->idle_cycles);
380 if(!want_thread_stats){
381 fprintf(f,
"LAST COMMITTED GVT ........ : %f\n",
get_last_gvt());
383 fprintf(f,
"NUMBER OF GVT REDUCTIONS... : %.0f\n", stats_p->gvt_computations);
384 if(!want_thread_stats &&
n_ker > 1){
385 fprintf(f,
"MIN GVT ROUND TIME......... : %.2f us\n", stats_p->gvt_round_time_min);
386 fprintf(f,
"MAX GVT ROUND TIME......... : %.2f us\n", stats_p->gvt_round_time_max);
387 fprintf(f,
"AVERAGE GVT ROUND TIME..... : %.2f us\n", stats_p->gvt_round_time / stats_p->gvt_computations);
389 fprintf(f,
"SIMULATION TIME SPEED...... : %.2f units per GVT\n",stats_p->simtime_advancement);
390 fprintf(f,
"AVERAGE MEMORY USAGE....... : %s\n",
format_size(stats_p->memory_usage / stats_p->gvt_computations));
391 if(!want_thread_stats)
392 fprintf(f,
"PEAK MEMORY USAGE.......... : %s\n",
format_size(stats_p->max_resident_set));
396 static void print_termination_status(FILE *f,
int exit_code)
400 fprintf(f,
"\n--------- SIMULATION CORRECTLY COMPLETED ----------\n");
404 fprintf(f,
"\n--------- SIMULATION ABNORMALLY TERMINATED ----------\n");
408 void print_gvt_stats_file(
void)
414 fwrite(gvt_buf.rows,
sizeof(
struct _gvt_buffer_row_t), gvt_buf.pos, f_blob);
416 fprintf(f_final,
"#%15.15s %15.15s ",
"\"WCT\"",
"\"GVT VALUE\"");
417 fprintf(f_final,
"%15.15s %15.15s\n",
"\"EVENTS\"",
"\"CUMUL EVENTS\"");
422 elems = fread(gvt_buf.rows,
sizeof(
struct _gvt_buffer_row_t), GVT_BUFF_ROWS, f_blob);
423 for(i = 0; i < elems; ++i) {
425 fprintf(f_final,
" %15lf %15lf ", gvt_buf.rows[i].exec_time, gvt_buf.rows[i].gvt);
426 fprintf(f_final,
"%15u %15u\n", gvt_buf.rows[i].committed, gvt_buf.rows[i].cumulated);
428 }
while(!feof(f_blob));
444 register unsigned int i;
447 timer simulation_finished;
453 timer_start(simulation_finished);
456 print_header(f,
"SERIAL STATISTICS");
458 fprintf(f,
"TOTAL LPs.................. : %d \n",
n_prc_tot);
459 fprintf(f,
"TOTAL EXECUTED EVENTS ..... : %.0f \n", system_wide_stats.tot_events);
460 fprintf(f,
"AVERAGE EVENT COST......... : %.3f us\n", total_time / system_wide_stats.tot_events * 1000 * 1000);
461 fprintf(f,
"AVERAGE EVENT COST (EMA)... : %.2f us\n", system_wide_stats.exponential_event_time);
463 fprintf(f,
"LAST COMMITTED GVT ........ : %f\n", system_wide_stats.gvt_time);
464 fprintf(f,
"SIMULATION TIME SPEED...... : %.2f units per GVT\n",system_wide_stats.simtime_advancement);
465 fprintf(f,
"AVERAGE MEMORY USAGE....... : %s\n",
format_size(system_wide_stats.memory_usage / system_wide_stats.gvt_computations));
467 print_termination_status(f, exit_code);
470 print_termination_status(stdout, exit_code);
476 timer_start(simulation_finished);
481 print_gvt_stats_file();
487 fprintf(f,
"#%15.15s %15.15s %15.15s %15.15s",
"\"GID\"",
"\"LID\"",
"\"TOTAL EVENTS\"",
"\"COMM EVENTS\"");
488 fprintf(f,
" %15.15s %15.15s %15.15s %15.15s",
"\"REPROC EVENTS\"",
"\"ROLLBACKS\"",
"\"ANTIMSG\"",
"\"AVG EVT COST\"");
489 fprintf(f,
" %15.15s %15.15s %15.15s\n",
"\"AVG CKPT COST\"",
"\"AVG REC COST\"",
"\"IDLE CYCLES\"");
491 foreach_bound_lp(lp) {
492 unsigned int lp_id = lp->lid.to_int;
494 fprintf(f,
" %15u ", lp->gid.to_int);
495 fprintf(f,
"%15u ", lp_id);
496 fprintf(f,
"%15.0lf ", lp_stats[lp_id].tot_events);
497 fprintf(f,
"%15.0lf ", lp_stats[lp_id].committed_events);
498 fprintf(f,
"%15.0lf ", lp_stats[lp_id].reprocessed_events);
499 fprintf(f,
"%15.0lf ", lp_stats[lp_id].tot_rollbacks);
500 fprintf(f,
"%15.0lf ", lp_stats[lp_id].tot_antimessages);
501 fprintf(f,
"%15lf ", lp_stats[lp_id].event_time / lp_stats[lp_id].tot_events);
502 fprintf(f,
"%15.0lf ", lp_stats[lp_id].ckpt_time / lp_stats[lp_id].tot_ckpts);
503 fprintf(f,
"%15.0lf ", (lp_stats[lp_id].tot_rollbacks > 0 ? lp_stats[lp_id].recovery_time / lp_stats[lp_id].tot_recoveries : 0));
504 fprintf(f,
"%15.0lf ", lp_stats[lp_id].idle_cycles);
512 foreach_bound_lp(lp) {
513 thread_stats[
local_tid].vec += lp_stats[lp->lid.to_int].vec;
519 print_header(f,
"THREAD STATISTICS");
520 print_common_stats(f, &thread_stats[
local_tid],
true,
true);
521 print_termination_status(f, exit_code);
529 system_wide_stats.vec += thread_stats[i].vec;
531 system_wide_stats.exponential_event_time /=
n_cores;
532 system_wide_stats.max_resident_set =
getPeakRSS();
534 system_wide_stats.gvt_computations /=
n_cores;
538 print_config_to_file(f);
540 print_header(f,
"NODE STATISTICS");
542 print_common_stats(f, &system_wide_stats,
false,
true);
543 print_termination_status(f, exit_code);
549 global_stats.exponential_event_time /=
n_ker;
551 global_stats.gvt_computations /=
n_ker;
552 global_stats.simtime_advancement /=
n_ker;
555 print_config_to_file(f);
557 print_header(f,
"GLOBAL STATISTICS");
559 print_common_stats(f, &global_stats,
false,
false);
560 print_termination_status(f, exit_code);
565 print_termination_status(stdout, exit_code);
573 inline void statistics_on_gvt(
double gvt)
576 unsigned int committed = 0;
577 static __thread
unsigned int cumulated = 0;
578 double exec_time, simtime_advancement, keep_exponential_event_time;
585 foreach_bound_lp(lp) {
586 committed += lp_stats_gvt[lp->lid.to_int].committed_events;
588 cumulated += committed;
591 gvt_buf.rows[gvt_buf.pos++] = (
struct _gvt_buffer_row_t){exec_time, gvt, committed, cumulated};
593 if(gvt_buf.pos >= GVT_BUFF_ROWS){
601 thread_stats[
local_tid].gvt_computations += 1.0;
603 simtime_advancement = gvt - thread_stats[
local_tid].gvt_time;
606 thread_stats[
local_tid].simtime_advancement =
607 0.1 * simtime_advancement +
608 0.9 * thread_stats[
local_tid].simtime_advancement;
610 thread_stats[
local_tid].simtime_advancement = simtime_advancement;
614 foreach_bound_lp(lp) {
615 lid = lp->lid.to_int;
617 lp_stats[lid].vec += lp_stats_gvt[lid].vec;
619 lp_stats[lid].exponential_event_time = lp_stats_gvt[lid].exponential_event_time;
621 keep_exponential_event_time = lp_stats_gvt[lid].exponential_event_time;
622 bzero(&lp_stats_gvt[lid],
sizeof(
struct stat_t));
623 lp_stats_gvt[lid].exponential_event_time = keep_exponential_event_time;
628 inline void statistics_on_gvt_serial(
double gvt)
630 system_wide_stats.gvt_computations += 1.0;
633 double simtime_advancement = gvt - system_wide_stats.gvt_time;
636 system_wide_stats.simtime_advancement =
637 0.1 * simtime_advancement +
638 0.9 * system_wide_stats.simtime_advancement;
640 system_wide_stats.simtime_advancement = simtime_advancement;
643 system_wide_stats.gvt_time = gvt;
647 #define assign_new_file(destination, format, ...) \ 649 safe_asprintf(&name_buf, "%s/" format, rootsim_config.output_dir, ##__VA_ARGS__);\ 650 if (((destination) = fopen(name_buf, "w+")) == NULL)\ 651 rootsim_error(true, "Cannot open %s\n", name_buf);\ 663 char *name_buf = NULL;
670 assign_new_file(
unique_files[STAT_FILE_U_GLOBAL],
"sequential_stats");
682 assign_new_file(
unique_files[STAT_FILE_U_NODE], STAT_FILE_NAME_NODE
"_%u",
kid);
684 assign_new_file(
unique_files[STAT_FILE_U_GLOBAL], STAT_FILE_NAME_GLOBAL);
688 assign_new_file(
unique_files[STAT_FILE_U_NODE], STAT_FILE_NAME_NODE);
694 thread_files[STAT_FILE_T_LP] = rsalloc(
sizeof(FILE *) * n_cores);
696 assign_new_file(
thread_files[STAT_FILE_T_LP][i],
"thread_%u_%u/%s",
kid, i, STAT_FILE_NAME_LP);
701 thread_files[STAT_FILE_T_GVT] = rsalloc(
sizeof(FILE *) * n_cores);
704 assign_new_file(
thread_files[STAT_FILE_T_GVT][i],
"thread_%u_%u/%s",
kid, i, STAT_FILE_NAME_GVT);
710 thread_files[STAT_FILE_T_THREAD] = rsalloc(
sizeof(FILE *) * n_cores);
712 assign_new_file(
thread_files[STAT_FILE_T_THREAD][i],
"thread_%u_%u/%s",
kid, i, STAT_FILE_NAME_THREAD);
722 lp_stats_gvt = rsalloc(
n_prc *
sizeof(
struct stat_t));
723 bzero(lp_stats_gvt,
n_prc *
sizeof(
struct stat_t));
724 thread_stats = rsalloc(n_cores *
sizeof(
struct stat_t));
725 bzero(thread_stats, n_cores *
sizeof(
struct stat_t));
728 #undef assign_new_file 738 register unsigned int i, j;
740 for(i = 0; i < NUM_STAT_FILE_U; i++) {
745 for(i = 0; i < NUM_STAT_FILE_T; i++) {
754 rsfree(thread_stats);
756 rsfree(lp_stats_gvt);
760 void statistics_post_data_serial(
enum stat_msg_t type,
double data)
764 system_wide_stats.tot_events += 1.0;
767 case STAT_EVENT_TIME:
768 system_wide_stats.event_time += data;
769 system_wide_stats.exponential_event_time = 0.1 * data + 0.9 * system_wide_stats.exponential_event_time;
773 rootsim_error(
true,
"Wrong LP statistics post type: %d. Aborting...\n", type);
778 void statistics_post_data(
struct lp_struct *lp,
enum stat_msg_t type,
double data)
784 unsigned int lid = lp ? lp->
lid.
to_int : UINT_MAX;
788 case STAT_ANTIMESSAGE:
789 lp_stats_gvt[lid].tot_antimessages += 1.0;
793 lp_stats_gvt[lid].tot_events += 1.0;
796 case STAT_EVENT_TIME:
797 lp_stats_gvt[lid].event_time += data;
798 lp_stats_gvt[lid].exponential_event_time = 0.1 * data + 0.9 * lp_stats_gvt[lid].exponential_event_time;
802 lp_stats_gvt[lid].committed_events += data;
806 lp_stats_gvt[lid].tot_rollbacks += 1.0;
810 lp_stats_gvt[lid].tot_ckpts += 1.0;
814 lp_stats_gvt[lid].ckpt_mem += data;
818 lp_stats_gvt[lid].ckpt_time += data;
822 lp_stats_gvt[lid].tot_recoveries++;
825 case STAT_RECOVERY_TIME:
826 lp_stats_gvt[lid].recovery_time += data;
829 case STAT_IDLE_CYCLES:
834 lp_stats_gvt[lid].reprocessed_events += data;
837 case STAT_GVT_ROUND_TIME:
838 system_wide_stats.gvt_round_time_min = fmin(data, system_wide_stats.gvt_round_time_min);
839 system_wide_stats.gvt_round_time_max = fmax(data, system_wide_stats.gvt_round_time_max);
840 system_wide_stats.gvt_round_time += data;
844 rootsim_error(
true,
"Wrong LP statistics post type: %d. Aborting...\n", type);
849 double statistics_get_lp_data(
struct lp_struct *lp,
unsigned int type)
853 case STAT_GET_EVENT_TIME_LP:
854 return lp_stats[lp->
lid.
to_int].exponential_event_time;
857 rootsim_error(
true,
"Wrong statistics get type: %d. Aborting...\n", type);
static struct stat_t * thread_stats
Keeps statistics on a per-thread basis.
static struct stat_t * lp_stats_gvt
Keeps statistics on a per-LP basis in a GVT phase.
void statistics_fini(void)
void statistics_start(void)
Message queueing subsystem.
seed_type set_seed
The master seed to be used in this run.
static void _rmdir(const char *path)
static struct stat_t system_wide_stats
Keeps global statistics.
int check_termination_mode
Check termination strategy: standard or incremental.
static char * format_size(double size)
char * output_dir
Destination Directory of output files.
Core ROOT-Sim functionalities.
#define safe_asprintf(ret_addr, format,...)
void statistics_init(void)
unsigned int n_cores
Total number of cores required for simulation.
int ckpt_period
Number of events to execute before taking a snapshot in PSS (ignored otherwise)
void _mkdir(const char *path)
simtime_t get_last_gvt(void)
#define timer_tostring(timer_name, string)
string must be a char array of at least TIMER_BUFFER_LEN bytes to keep the whole string ...
int checkpointing
Type of checkpointing scheme (e.g., PSS, CSS, ...)
unsigned int to_int
The LID numerical value.
static FILE ** thread_blob_files
Pointers to the files used as binary buffer for the GVT statistics.
The ROOT-Sim scheduler main module header.
size_t getCurrentRSS(void)
Generic thread management facilities.
static timer simulation_timer
This is a timer that start during the initialization of statistics subsystem and can be used to know ...
bool mpi_support_multithread
Flag telling whether the MPI runtime supports multithreading.
static struct stat_t * lp_stats
Keeps statistics on a per-LP basis.
void mpi_reduce_statistics(struct stat_t *global, struct stat_t *local)
Invoke statistics reduction.
#define INFTY
Infinite timestamp: this is the highest timestamp in a simulation run.
#define D_DIFFER_ZERO(a)
Difference from zero condition for doubles.
int scheduler
Which scheduler to be used.
simulation_configuration rootsim_config
This global variable holds the configuration for the current simulation.
Memory Manager main header.
Memory usage module header.
static FILE ** thread_files[NUM_STAT_FILE_T]
Pointers to per-thread files.
static FILE * unique_files[NUM_STAT_FILE_U]
Pointers to unique files.
bool thread_barrier(barrier_t *b)
int simulation_time
Wall-clock-time based termination predicate.
barrier_t all_thread_barrier
Barrier for all worker threads.
#define get_cores()
Macro to get the core count on the hosting machine.
#define master_thread()
This macro expands to true if the current KLT is the master thread for the local kernel.
unsigned int n_prc
Number of logical processes hosted by the current kernel instance.
#define master_kernel()
This macro expands to true if the local kernel is the master kernel.
const char *const param_to_text[][5]
enum stats_levels stats
Produce performance statistic file (default STATS_ALL)
LID_t lid
Local ID of the LP.
int lps_distribution
Policy for the LP to Kernel mapping.
__thread unsigned int n_prc_per_thread
This is used to keep track of how many LPs were bound to the current KLT.
void statistics_stop(int exit_code)
#define MAX_PATHLEN
Longest length of a path.
__thread unsigned int local_tid
int snapshot
Type of snapshot (e.g., full, incremental, autonomic, ...)
static __thread struct _gvt_buffer gvt_buf
This structure is used to buffer statistics gathered on GVT computation.
unsigned int n_prc_tot
Total number of logical processes running in the simulation.
int gvt_time_period
Wall-Clock time to wait before executiong GVT operations.
bool serial
If the simulation must be run serially.
unsigned int n_ker
Total number of simulation kernel instances running.
unsigned int kid
Identifier of the local kernel.