/* * %CopyrightBegin% * * Copyright Ericsson AB 2002-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * %CopyrightEnd% */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "sys.h" #include "global.h" #include "benchmark.h" #ifdef BM_COUNTERS unsigned long long processes_busy; unsigned long long processes_spawned; unsigned long long messages_sent; unsigned long long messages_copied; unsigned long long messages_ego; unsigned long long minor_gc; unsigned long long major_gc; #endif /* BM_COUNTERS */ #ifdef BM_TIMERS #if (defined(__i386__) || defined(__x86_64__)) && USE_PERFCTR #include "libperfctr.h" struct vperfctr *system_clock; double cpu_khz; BM_NEW_TIMER(start); static double get_hrvtime(void) { unsigned long long ticks; double milli_seconds; ticks = vperfctr_read_tsc(system_clock); milli_seconds = (double)ticks / cpu_khz; return milli_seconds; } static void stop_hrvtime(void) { if(system_clock) { vperfctr_stop(system_clock); vperfctr_close(system_clock); system_clock = NULL; } } #else /* not perfctr, asuming Solaris */ #include <time.h> BM_TIMER_T system_clock; #endif unsigned long local_pause_times[MAX_PAUSE_TIME]; unsigned long pause_times[MAX_PAUSE_TIME]; unsigned long pause_times_old[MAX_PAUSE_TIME]; BM_TIMER_T mmu; BM_TIMER_T mmu_counter; BM_NEW_TIMER(timer); BM_NEW_TIMER(system); BM_NEW_TIMER(gc); BM_NEW_TIMER(minor_gc); BM_NEW_TIMER(major_gc); BM_NEW_TIMER(minor_global_gc); BM_NEW_TIMER(major_global_gc); BM_NEW_TIMER(send); BM_NEW_TIMER(copy); BM_NEW_TIMER(size); BM_NEW_TIMER(max_minor); BM_NEW_TIMER(max_major); BM_NEW_TIMER(max_global_minor); BM_NEW_TIMER(max_global_major); BM_NEW_TIMER(misc0); BM_NEW_TIMER(misc1); BM_NEW_TIMER(misc2); #endif /* BM_TIMERS */ #ifdef BM_HEAP_SIZES unsigned long long max_used_heap; unsigned long long max_allocated_heap; unsigned long long max_used_global_heap; unsigned long long max_allocated_global_heap; #endif /* BM_HEAP_SIZES */ #ifdef BM_MESSAGE_SIZES unsigned long long words_sent; unsigned long long words_copied; unsigned long long words_prealloc; unsigned long long message_sizes[1000]; #endif /* BM_MESSAGE_SIZES */ /***** * The following functions have to be defined, but they only have contents * if certain keywords are defined. */ void init_benchmarking() { #ifdef BM_TIMERS #if (defined(__i386__) || defined(__x86_64__)) && USE_PERFCTR /* pass `--with-perfctr=/path/to/perfctr' when configuring */ struct perfctr_info info; struct vperfctr_control control; int i; system_clock = vperfctr_open(); if (system_clock != NULL) { if (vperfctr_info(system_clock,&info) >= 0) { cpu_khz = (double)info.cpu_khz; if (info.cpu_features & PERFCTR_FEATURE_RDTSC) { memset(&control,0,sizeof control); control.cpu_control.tsc_on = 1; } } if (vperfctr_control(system_clock,&control) < 0) { vperfctr_close(system_clock); system_clock = NULL; } } for (i = 0; i < 1000; i++) { BM_START_TIMER(system); BM_STOP_TIMER(system); } timer_time = system_time / 1000; start_time = 0; #else int i; for (i = 0; i < 1000; i++) { BM_START_TIMER(system); BM_STOP_TIMER(system); } timer_time = system_time / 1000; #endif for (i = 0; i < MAX_PAUSE_TIME; i++) { local_pause_times[i] = 0; pause_times[i] = 0; pause_times_old[i] = 0; } mmu = 0; mmu_counter = 0; BM_MMU_INIT(); #endif /* BM_TIMERS */ #ifdef BM_COUNTERS processes_busy = 0; processes_spawned = 0; messages_sent = 0; messages_copied = 0; messages_ego = 0; minor_gc = 0; major_gc = 0; #endif /* BM_COUNTERS */ #ifdef BM_HEAP_SIZES max_used_heap = 0; max_allocated_heap = 0; max_used_global_heap = 0; max_allocated_global_heap = 0; #endif /* BM_HEAP_SIZES */ #ifdef BM_MESSAGE_SIZES words_sent = 0; words_copied = 0; words_prealloc = 0; { int i; for (i = 0; i < 1000; i++) message_sizes[i] = 0; } #endif /* BM_MESSAGE_SIZES */ } void save_statistics() { #ifdef BM_STATISTICS FILE *file = fopen(BM_STATISTICS_FILE,"a"); long i = 0; if (file) { erts_fprintf(file,"-------------------------------------------------------------------------\n"); erts_fprintf(file,"The counters are reset at system start and are sums over the entire node.\n"); erts_fprintf(file,"You may reset them manually using the BIFs in the module hipe_bifs.\n"); erts_fprintf(file,"All times are given in milliseconds.\n"); erts_fprintf(file,"-------------------------------------------------------------------------\n"); erts_fprintf(file,"Node: %T\n",erts_this_node->sysname); #ifdef BM_COUNTERS erts_fprintf(file,"Number of processes spawned: %lld\n",processes_spawned); erts_fprintf(file,"Number of local minor GCs: %lld\n",minor_gc); erts_fprintf(file,"Number of local major GCs: %lld\n",major_gc); erts_fprintf(file,"Number of messages sent: %lld\n",messages_sent); erts_fprintf(file,"Number of messages copied: %lld\n",messages_copied); erts_fprintf(file,"Number of messages sent to self: %lld\n",messages_ego); #endif /* BM_COUNTERS */ #ifdef BM_MESSAGE_SIZES erts_fprintf(file,"Number of words sent: %lld\n",words_sent); erts_fprintf(file,"Number of words copied: %lld\n",words_copied); erts_fprintf(file,"Number of words preallocated: %lld\n",words_prealloc); #endif /* BM_MESSAGE_SIZES */ #ifdef BM_HEAP_SIZES erts_fprintf(file,"Biggest local heap used (in words): %lld\n",max_used_heap); erts_fprintf(file,"Biggest local heap allocated (in words): %lld\n",max_allocated_heap); erts_fprintf(file,"Biggest global heap used (in words): %lld\n",max_used_global_heap); erts_fprintf(file,"Biggest global heap allocated (in words): %lld\n",max_allocated_global_heap); #endif /* BM_HEAP_SIZES */ #ifdef BM_TIMERS erts_fprintf(file,"--- The total active system time is the sum of all times below ---\n"); BM_TIME_PRINTER("Mutator time",system_time); BM_TIME_PRINTER("Time spent in send (excluding size & copy)",send_time); BM_TIME_PRINTER("Time spent in size",size_time); BM_TIME_PRINTER("Time spent in copy",copy_time); BM_TIME_PRINTER("Time spent in local minor GC",minor_gc_time); BM_TIME_PRINTER("Time spent in local major GC",major_gc_time); BM_TIME_PRINTER("Time spent in global minor GC",minor_global_gc_time); BM_TIME_PRINTER("Time spent in global major GC",major_global_gc_time); erts_fprintf(file,"---\n"); BM_TIME_PRINTER("Maximum time spent in one separate local minor GC",max_minor_time); BM_TIME_PRINTER("Maximum time spent in one separate local major GC",max_major_time); BM_TIME_PRINTER("Maximum time spent in one separate global minor GC",max_global_minor_time); BM_TIME_PRINTER("Maximum time spent in one separate global major GC",max_global_major_time); #endif /* BM_TIMERS */ #if 0 /* Save a log file for import into excel */ long long total_time, n; long left, right, mid; #ifdef BM_COUNTERS erts_fprintf(file,"Spawns\tLocalGC\tMAGC\tMessages\tMutator_t\tLocalGC_t\tMAGC_t\tLocMaxP\tLocMeanP\tLocGeoMP\tMAMaxP\tMAMeanP\tMAGeoMP\t\tCMAGC\tCMAGC_t\n"); erts_fprintf(file,"%lld\t%lld\t%lld\t%lld\t", processes_spawned, minor_garbage_cols + major_garbage_cols, minor_global_garbage_cols + major_global_garbage_cols, messages_sent); #endif /* BM_COUNTERS */ #ifdef BM_TIMERS erts_fprintf(file,"%lld\t%lld\t%lld\t", (long long)(system_time + send_time + size_time + copy_time), (long long)(minor_gc_time + major_gc_time), (long long)(minor_global_gc_time + major_global_gc_time)); total_time = 0; n = 0; left = 0; right = 0; mid = 0; for (i = 0; i < MAX_PAUSE_TIME; i++) { total_time += local_pause_times[i] * i; n += local_pause_times[i]; if (i > mid) right += local_pause_times[i]; while(right > left) { left += local_pause_times[mid++]; right -= local_pause_times[mid]; } } erts_fprintf(file,"%lld\t%lld\t%ld\t", (long long)((max_minor_time > max_major_time ? max_minor_time : max_major_time)*1000), total_time / n, mid); total_time = 0; n = 0; left = 0; right = 0; mid = 0; for (i = 0; i < MAX_PAUSE_TIME; i++) { if (pause_times[i] > 0) { total_time += pause_times[i] * i; n += pause_times[i]; if (i > mid) right += pause_times[i]; while(right > left) { left += pause_times[mid++]; right -= pause_times[mid]; } } } erts_fprintf(file,"%lld\t%lld\t%ld\t", (long long)((max_global_minor_time > max_global_major_time ? max_global_minor_time : max_global_major_time)*1000), (n > 0 ? total_time / n : 0), mid); erts_fprintf(file,"\t%lld\t%lld\n",n,total_time); erts_fprintf(file,"\nMinor:\n"); for (i = 0; i < MAX_PAUSE_TIME; i++) { if (i < 1000 || pause_times[i] > 0) { erts_fprintf(file,"%d\t%ld\n",i,pause_times[i]); } } fprintf(file,"Major:\n"); for (i = 0; i < MAX_PAUSE_TIME; i++) { if (pause_times_old[i] > 0) { fprintf(file,"%d\t%ld\n",i,pause_times_old[i]); } } #endif /* BM_TIMERS */ #ifdef BM_TIMERS total_time = 0; n = 0; left = 0; right = 0; mid = 0; fprintf(file,"\nLocal:\n"); for (i = 0; i < MAX_PAUSE_TIME; i++) { if (local_pause_times[i] > 0) { erts_fprintf(file,"%d\t%ld\n",i,local_pause_times[i]); total_time += local_pause_times[i] * i; n += local_pause_times[i]; if (i > mid) right += local_pause_times[i]; while(right > left) { left += local_pause_times[mid++]; right -= local_pause_times[mid]; } } } erts_fprintf(file,"Mid: %ld Mean: %ld\n",(long)mid, (long)(n > 0 ? total_time / n : 0)); #endif #endif /* 0 */ fclose(file); } else fprintf(stderr,"Sorry... Can not write to %s!\n\r",BM_STATISTICS_FILE); #endif /* BM_STATISTICS */ }