aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/benchmark.h
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/benchmark.h')
-rw-r--r--erts/emulator/beam/benchmark.h340
1 files changed, 340 insertions, 0 deletions
diff --git a/erts/emulator/beam/benchmark.h b/erts/emulator/beam/benchmark.h
new file mode 100644
index 0000000000..eedb06a1b6
--- /dev/null
+++ b/erts/emulator/beam/benchmark.h
@@ -0,0 +1,340 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2002-2009. 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%
+ */
+
+#ifndef __BENCHMARK_H__
+#define __BENCHMARK_H__
+
+/* The define __BENCHMARK__ is the master switch to turn on and off
+ * benchmarking. This will enable the benchmark-BIFs in hipe_bif1.c.
+ * Documentation for the BIFs is in hipe_bif1.c, and that is where you
+ * will find the information about how to accually get some data out
+ * from these timers and counters.
+ */
+/* #define __BENCHMARK__ */
+
+#ifdef __BENCHMARK__
+/*
+ * The defines below enables different parts of the benchmaring.
+ * Counters and timers that are disabled, always report zero in
+ * the BIFs.
+ */
+
+/* BM_TIMERS keeps track of the time spent in diferent parts of the
+ * system. It only measures accual active time, not time spent in idle
+ * mode. These timers requires hardware support. For Linux, use the
+ * package perfctr from user.it.uu.se/~mikpe/linux/perfctr. If this
+ * package is not specified when configuring the system
+ * (--with-perfctr=PATH), the Solaris hrtime_t will be used.
+ * To add new timers look below.
+ */
+#define BM_TIMERS
+
+/* BM_COUNTERS count all kinds of events that occurs in the system.
+ * Among other things it counts the number of messages, then number of
+ * garbage collections, the number of processes spawned etc.
+ * To add new counters look below.
+ */
+#define BM_COUNTERS
+
+/* BM_MESSAGE_SIZES keeps a log of the size of all messages sent in
+ * the system. This introduce an overhead in time for the shared heap
+ * system since all message sizes have to be calculated at send.
+ */
+/* #define BM_MESSAGE_SIZES */
+
+/* BM_HEAP_SIZES goes through all processes at garbage collection time
+ * to sum their allocated and used heap sizes. In anything else than a
+ * shared heap system, this will cost.
+ */
+/* #define BM_HEAP_SIZES */
+
+/* BM_STATISTICS saves an entry in the file BM_STATISTICS_FILE. This
+ * is done for each erlang node at exit time.
+ */
+/* #define BM_STATISTICS */
+
+#endif /* __BENCHMARK__ */
+
+
+#ifdef BM_STATISTICS
+# define BM_STATISTICS_FILE "/tmp/erlang_statistics.joppe.log"
+#endif /* BM_STATISTICS */
+
+
+/************ There are no more settings below this line *************/
+
+/*
+ * Maintenance and how to add new stuff is documented by the code
+ * below ;-)
+ */
+
+#ifdef BM_COUNTERS
+/*********************************************************************
+ * To add new counters:
+ *
+ * Add the variable here AND in benchmark.c. Use the macro
+ * BM_COUNT(var) in the code where you want to increase it.
+ *
+ */
+extern unsigned long long processes_busy;
+extern unsigned long long processes_spawned;
+extern unsigned long long messages_sent;
+extern unsigned long long messages_copied;
+extern unsigned long long messages_ego;
+extern unsigned long long minor_gc;
+extern unsigned long long major_gc;
+#ifdef HYBRID
+extern unsigned long long minor_global_gc;
+extern unsigned long long major_global_gc;
+extern unsigned long long gc_in_copy;
+#ifdef INCREMENTAL
+extern unsigned long long minor_gc_cycles;
+extern unsigned long long major_gc_cycles;
+extern unsigned long long minor_gc_stages;
+extern unsigned long long major_gc_stages;
+#endif
+#endif
+
+#define BM_COUNT(var) (var)++;
+
+#define BM_EGO_COUNT(send,rec) { \
+ if ((send) == (rec)) \
+ BM_COUNT(messages_ego); }
+
+#define BM_LAZY_COPY_START long long gcs = minor_global_gc + major_global_gc;
+#define BM_LAZY_COPY_STOP { gcs = (minor_global_gc + major_global_gc) - gcs; \
+ if (gcs > gc_in_copy) gc_in_copy = gcs; }
+
+#else /* !BM_COUNTERS */
+# define BM_COUNT(var)
+# define BM_EGO_COUNT(send,rec)
+# define BM_LAZY_COPY_START
+# define BM_LAZY_COPY_STOP
+#endif /* BM_COUNTERS */
+
+
+#ifdef BM_TIMERS
+/*********************************************************************
+ * To add new timers:
+ *
+ * Add the variable below using the form extern BM_TIMER_T blah_time.
+ * Also add them in benchmark.c using the macro NEW_TIMER(blah). Use
+ * the macro BM_SWAP_TIMER(from,blah) ... BM_SWAP_TIMER(blah,to) to
+ * start and stop the new timer. Note, that you have to know what
+ * timer is running at the place where you want to insert your new
+ * timer to be able to stop and start (from,to) it.
+ *
+ * You can use the macros BM_STOP_TIMER(blah) and BM_START_TIMER(blah)
+ * around code that should not be timed at all. As above, you have to
+ * know what timer to start and stop. The system timer is running at
+ * most places in the emulator. Only the garbage collector and the
+ * message sending has its own timers at the moment.
+ *
+ * The timer_time used when stopping timers is the time it takes to
+ * start and stop the timers, calculated in init_benchmarking(). If it
+ * is not there, the time it takes to do this will accually be
+ * substantial compared to some small times in the system we want to
+ * meassure (send time in shared heap for instance).
+ */
+
+#if (defined(__i386__) || defined(__x86_64__)) && USE_PERFCTR
+#include "libperfctr.h"
+
+#define BM_TIMER_T double
+
+extern struct vperfctr *system_clock;
+extern double cpu_khz;
+extern BM_TIMER_T start_time;
+
+#define BM_START_TIMER(t) start_time = \
+ (BM_TIMER_T)vperfctr_read_tsc(system_clock) / \
+ cpu_khz;
+
+#define BM_STOP_TIMER(t) do { \
+ BM_TIMER_T tmp = ((BM_TIMER_T)vperfctr_read_tsc(system_clock) / cpu_khz); \
+ tmp -= (start_time + timer_time); \
+ t##_time += (tmp > 0 ? tmp : 0); \
+} while(0)
+
+#define BM_TIME_PRINTER(str,time) do { \
+ int min,sec,milli,micro; \
+ BM_TIMER_T tmp = (time) * 1000; \
+ micro = (uint)(tmp - ((int)(tmp / 1000)) * 1000); \
+ tmp /= 1000; \
+ milli = (uint)(tmp - ((int)(tmp / 1000)) * 1000); \
+ tmp /= 1000; \
+ sec = (uint)(tmp - ((int)(tmp / 60)) * 60); \
+ min = (uint)tmp / 60; \
+ erts_fprintf(file,str": %d:%02d.%03d %03d\n",min,sec,milli,micro); \
+} while(0)
+
+#else /* !USE_PERFCTR (Assuming Solaris) */
+
+#define BM_TIMER_T hrtime_t
+#define BM_START_TIMER(t) system_clock = sys_gethrtime()
+#define BM_STOP_TIMER(t) do { \
+ BM_TIMER_T tmp = (sys_gethrtime() - system_clock) - timer_time; \
+ t##_time += (tmp > 0 ? tmp : 0); \
+} while(0)
+
+#define BM_TIME_PRINTER(str,time) do { \
+ int min,sec,milli,micro; \
+ BM_TIMER_T tmp; \
+ tmp = (time) / 1000; \
+ micro = tmp % 1000; \
+ tmp /= 1000; \
+ milli = tmp % 1000; \
+ tmp /= 1000; \
+ sec = tmp % 60; \
+ min = tmp / 60; \
+ erts_fprintf(file,str": %d:%02d.%03d %03d\n",min,sec,milli,micro); \
+} while(0)
+
+extern BM_TIMER_T system_clock;
+#endif /* USE_PERFCTR */
+
+extern BM_TIMER_T timer_time;
+extern BM_TIMER_T system_time;
+extern BM_TIMER_T gc_time;
+extern BM_TIMER_T minor_gc_time;
+extern BM_TIMER_T major_gc_time;
+extern BM_TIMER_T minor_global_gc_time;
+extern BM_TIMER_T major_global_gc_time;
+extern BM_TIMER_T send_time;
+extern BM_TIMER_T copy_time;
+extern BM_TIMER_T size_time;
+extern BM_TIMER_T max_minor_time;
+extern BM_TIMER_T max_major_time;
+extern BM_TIMER_T max_global_minor_time;
+extern BM_TIMER_T max_global_major_time;
+extern BM_TIMER_T misc0_time;
+extern BM_TIMER_T misc1_time;
+extern BM_TIMER_T misc2_time;
+
+#define MAX_PAUSE_TIME 500000
+extern unsigned long local_pause_times[MAX_PAUSE_TIME];
+extern unsigned long pause_times[MAX_PAUSE_TIME];
+extern unsigned long pause_times_old[MAX_PAUSE_TIME];
+
+#define MMU_INTERVAL 5 /* milli seconds */
+extern BM_TIMER_T mmu_counter;
+extern BM_TIMER_T mmu;
+
+#define BM_NEW_TIMER(t) BM_TIMER_T t##_time = 0;
+#define BM_RESET_TIMER(t) t##_time = 0;
+#define BM_SWAP_TIMER(t1,t2) do { BM_STOP_TIMER(t1); BM_START_TIMER(t2); } while(0)
+#define BM_MMU_INIT() do { \
+ BM_TIMER_T gc = gc_time; \
+ while (gc > 0) { \
+ if (gc > MMU_INTERVAL) { \
+ gc -= MMU_INTERVAL - mmu_counter; \
+ erts_printf("%d\n",(int)((mmu / MMU_INTERVAL) * 100)); \
+ mmu_counter = 0; mmu = 0; \
+ } else { \
+ mmu_counter += gc; \
+ if (mmu_counter >= MMU_INTERVAL) { \
+ mmu_counter -= MMU_INTERVAL; \
+ erts_printf("%d\n",(int)((mmu / MMU_INTERVAL) * 100)); \
+ mmu = 0; \
+ } \
+ gc = 0; \
+ } \
+ } \
+ BM_RESET_TIMER(system); \
+ BM_RESET_TIMER(send); \
+ BM_RESET_TIMER(copy); \
+ BM_RESET_TIMER(size); \
+} while(0)
+
+#define BM_MMU_READ() do { \
+ BM_TIMER_T mut = system_time + send_time + copy_time + size_time; \
+ while (mut > 0) { \
+ if (mut > MMU_INTERVAL) { \
+ BM_TIMER_T tmp = MMU_INTERVAL - mmu_counter; \
+ mmu += tmp; mut -= tmp; \
+ erts_printf("%d\n",(int)((mmu / MMU_INTERVAL) * 100)); \
+ mmu_counter = 0; mmu = 0; \
+ } else { \
+ mmu_counter += mut; mmu += mut; \
+ if (mmu_counter >= MMU_INTERVAL) { \
+ mmu_counter -= MMU_INTERVAL; \
+ mmu -= mmu_counter; \
+ erts_printf("%d\n",(int)((mmu / MMU_INTERVAL) * 100)); \
+ mmu = mmu_counter; \
+ } \
+ mut = 0; \
+ } \
+ } \
+} while(0)
+
+#else /* !BM_TIMERS */
+# define BM_NEW_TIMER(t)
+# define BM_START_TIMER(t)
+# define BM_STOP_TIMER(t)
+# define BM_RESET_TIMER(t)
+# define BM_SWAP_TIMER(t1,t2)
+# define BM_TIME_PRINTER(str,time)
+# define BM_MMU_INIT()
+# define BM_MMU_READ()
+#endif /* BM_TIMERS */
+
+#ifdef BM_HEAP_SIZES
+extern unsigned long long max_used_heap;
+extern unsigned long long max_allocated_heap;
+extern unsigned long long max_used_global_heap;
+extern unsigned long long max_allocated_global_heap;
+#endif /* BM_HEAP_SIZES */
+
+#ifdef BM_MESSAGE_SIZES
+extern unsigned long long words_sent;
+extern unsigned long long words_copied;
+extern unsigned long long words_prealloc;
+extern unsigned long long message_sizes[1000];
+
+#define BM_MESSAGE_COPIED(size) { \
+ words_copied += size; \
+ BM_COUNT(messages_copied); }
+
+#define BM_PREALLOC_DATA(size) { \
+ words_prealloc += size; }
+
+#define BM_MESSAGE(mess,send,rec) { \
+ Uint msize = size_object(mess); \
+ words_sent += msize; \
+ if (msize < 1000) \
+ message_sizes[msize]++; \
+ else \
+ message_sizes[999]++; \
+ BM_EGO_COUNT(send,rec); \
+ BM_COUNT(messages_sent); }
+
+#else /* !BM_MESSAGE_SIZES */
+
+#define BM_MESSAGE_COPIED(size) BM_COUNT(messages_copied);
+#define BM_PREALLOC_DATA(size)
+#define BM_MESSAGE(mess,send,rec) { \
+ BM_EGO_COUNT(send,rec); \
+ BM_COUNT(messages_sent); }
+
+#endif /* BM_MESSAGE_SIZES */
+
+void init_benchmarking(void);
+void save_statistics(void);
+
+#endif /* _BENCHMARK_H_ */