diff options
Diffstat (limited to 'erts/emulator/hipe/hipe_bif1.c')
-rw-r--r-- | erts/emulator/hipe/hipe_bif1.c | 937 |
1 files changed, 937 insertions, 0 deletions
diff --git a/erts/emulator/hipe/hipe_bif1.c b/erts/emulator/hipe/hipe_bif1.c new file mode 100644 index 0000000000..5188950e17 --- /dev/null +++ b/erts/emulator/hipe/hipe_bif1.c @@ -0,0 +1,937 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-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% + */ +/* $Id$ + * hipe_bif1.c + * + * Performance analysis support. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "sys.h" +#include "global.h" +#include "bif.h" +#include "big.h" +#include "error.h" +#include "beam_load.h" +#include "hipe_bif0.h" +#include "hipe_bif1.h" + +#define BeamOpCode(Op) ((Uint)BeamOp(Op)) + +BIF_RETTYPE hipe_bifs_call_count_on_1(BIF_ALIST_1) +{ + Eterm *pc; + struct hipe_call_count *hcc; + + pc = hipe_bifs_find_pc_from_mfa(BIF_ARG_1); + if (!pc) + BIF_ERROR(BIF_P, BADARG); + ASSERT(pc[-5] == BeamOpCode(op_i_func_info_IaaI)); + if (pc[0] == BeamOpCode(op_hipe_trap_call)) + BIF_ERROR(BIF_P, BADARG); + if (pc[0] == BeamOpCode(op_hipe_call_count)) + BIF_RET(NIL); + hcc = erts_alloc(ERTS_ALC_T_HIPE, sizeof(*hcc)); + hcc->count = 0; + hcc->opcode = pc[0]; + pc[-4] = (Eterm)hcc; + pc[0] = BeamOpCode(op_hipe_call_count); + BIF_RET(am_true); +} + +BIF_RETTYPE hipe_bifs_call_count_off_1(BIF_ALIST_1) +{ + Eterm *pc; + struct hipe_call_count *hcc; + unsigned count; + + pc = hipe_bifs_find_pc_from_mfa(BIF_ARG_1); + if (!pc) + BIF_ERROR(BIF_P, BADARG); + ASSERT(pc[-5] == BeamOpCode(op_i_func_info_IaaI)); + if (pc[0] != BeamOpCode(op_hipe_call_count)) + BIF_RET(am_false); + hcc = (struct hipe_call_count*)pc[-4]; + count = hcc->count; + pc[0] = hcc->opcode; + pc[-4] = (Eterm)NULL; + erts_free(ERTS_ALC_T_HIPE, hcc); + BIF_RET(make_small(count)); +} + +BIF_RETTYPE hipe_bifs_call_count_get_1(BIF_ALIST_1) +{ + Eterm *pc; + struct hipe_call_count *hcc; + + pc = hipe_bifs_find_pc_from_mfa(BIF_ARG_1); + if (!pc) + BIF_ERROR(BIF_P, BADARG); + ASSERT(pc[-5] == BeamOpCode(op_i_func_info_IaaI)); + if (pc[0] != BeamOpCode(op_hipe_call_count)) + BIF_RET(am_false); + hcc = (struct hipe_call_count*)pc[-4]; + BIF_RET(make_small(hcc->count)); +} + +BIF_RETTYPE hipe_bifs_call_count_clear_1(BIF_ALIST_1) +{ + Eterm *pc; + struct hipe_call_count *hcc; + unsigned count; + + pc = hipe_bifs_find_pc_from_mfa(BIF_ARG_1); + if (!pc) + BIF_ERROR(BIF_P, BADARG); + ASSERT(pc[-5] == BeamOpCode(op_i_func_info_IaaI)); + if (pc[0] != BeamOpCode(op_hipe_call_count)) + BIF_RET(am_false); + hcc = (struct hipe_call_count*)pc[-4]; + count = hcc->count; + hcc->count = 0; + BIF_RET(make_small(count)); +} + +unsigned int hipe_trap_count; + +BIF_RETTYPE hipe_bifs_trap_count_get_0(BIF_ALIST_0) +{ + BIF_RET(make_small(hipe_trap_count)); +} + +BIF_RETTYPE hipe_bifs_trap_count_clear_0(BIF_ALIST_0) +{ + unsigned int count = hipe_trap_count; + hipe_trap_count = 0; + BIF_RET(make_small(count)); +} + +/***************************************************************************** + * BIFs for benchmarking. These only do useful things if + * __BENCHMARK__ is defined in beam/benchmark.h. For documentation + * about how to add new counters or maintain the existing counters, + * see benchmark.h. + * + * If benchmarking is not enabled all BIFs will return false. If the + * required benchmark feature is not enabled, the counter will remain + * zero. + * + * process_info/0 -> { Number of live processes, + * Processes spawned in total } + * + * Live processes are increased when a new process is created, and + * decreased when a process dies. Processes spawned is increased + * when a process is created. + * + * + * process_info_clear/0 -> true + * + * Will reset the processes spawned-counters to zero. If this is + * done at some improper time, live processes may become a negative + * value. This is not a problem in itself, just as long as you know + * about it. + * + * + * message_info/0 -> { Messages sent, + * Messages copied, + * Ego messages (sender = receiver), + * Words sent, + * Words copied, + * Words preallocated } + * + * Counting the words sent in a shared heap system will affect + * runtime performance since it means that we have to calculate the + * size of the mesage. With private heaps, this is done anyway and + * will not affect performance. + * + * + * message_info_clear/0 -> true + * + * Reset the message counters to zero. + * + * + * message_sizes/0 -> true + * + * Displays a text-mode bar diagram with message sizes. There are no + * guaranties that this is printed in a way the Erlang system is + * supposed to print things. + * + * + * gc_info/0 -> { Minor collections, + * Major collections, + * Used heap, + * Allocated heap, + * Max used heap, + * Max allocated heap } + * + * Information about private heap garbage collections. Number of + * minor and major collections, how much heap is used and allocated + * and how much heap has been in use and allocated at most since the + * counters were reset. + * + * + * shared_gc_info/0 -> { Minor collections of the shared heap, + * Major collections of the shared heap, + * Used shared heap, + * Allocated shared heap, + * Max used shared heap, + * Max allocated shared heap } + * + * The same as above, but for the shared heap / message area. Note, + * that in a shared heap system the max used heap and max allocated + * heap are mostly the same, since the heap allways is filled before + * a garbage collection, and most garbage collections do not enlarge + * the heap. The private heap numbers are much more interesting. + * + * + * incremental_gc_info/0 -> { Complete minor GC cycles, + * Complete major GC cycles, + * Minor GC stages, + * Major GC stages } + * + * + * gc_info_clear/0 -> true + * + * Reset counters for both private and shared garbage collection. + * + * + * BM Timers + * --------- + * + * All timers returns tuples of the kind: { Minutes, Seconds, Milliseconds } + * except for the max times in garbage collection where times are normally + * small. The tuple is therefor: { Seconds, Milliseconds, Microseconds } + * + * system_timer/0 -> Mutator time + * + * This timer is not a real-time clock, it only runs when a process + * is scheduled to run. You can not find out the accual time a + * program has taken to run using this timer. + * + * + * system_timer_clear/0 -> true + * + * Reset system timer to zero. + * + * + * send_timer/0 -> { Send time, + * Copy time, + * Size time } + * + * Time spent in sending messages. The copy time and size time are + * only active if the copying is needed in send. Copying of data + * into ETS-tables etc is not timed with this timer. + * + * + * send_timer_clear/0 -> true + * + * Reset send timers to zero. + * + * + * gc_timer/0 -> { Time in minor collection, + * Time in major collection, + * Max time in minor collection (�s), + * Max time in major collection (�s) } + * + * Total time spent in garbage collection of the private heaps. The + * max times are for one separate collection. + * + * + * shared_gc_timer/0 -> { Time in minor collection, + * Time in major collection, + * Max time in minor collection (�s), + * Max time in major collection (�s) } + * + * Total time spent in garbage collection of the shared heap / + * message area. The max times are for one separate collection. + * + * + * gc_timer_clear/0 -> true + * + * Reset private and shared garbage collection timers to zero. Note, + * that the max-times are also reset. + * + * + * misc_timer/0 -> { Misc 0, Misc 1, Misc 2 } + * + * Timers for debug purposes. In a normal system, these timers are + * never used. Add these timers at places where you want to time + * something not covered here. Use BM_SWAP_TIMER(from,to) to start + * one of the misc timers. + * + * ... code timed by the system timer ... + * BM_SWAP_TIMER(system,misc1); + * ... code we want to time ... + * BM_SWAP_TIMER(misc1,system); + * ... back on system time ... + * + * + * misc_timer_clear/0 -> true + * + * Reset misc timers to zero. + */ + +BIF_RETTYPE hipe_bifs_process_info_0(BIF_ALIST_0) +{ +#ifdef __BENCHMARK__ +#ifndef BM_COUNTERS + Uint processes_busy = 0; + Uint processes_spawned = 0; +#endif + Eterm *hp; + + hp = HAlloc(BIF_P, 3); + BIF_RET(TUPLE2(hp, + make_small(processes_busy), + make_small(processes_spawned))); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_process_info_clear_0(BIF_ALIST_0) +{ +#ifdef __BENCHMARK__ +#ifdef BM_COUNTERS + processes_spawned = 0; +#endif + BIF_RET(am_true); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_message_info_0(BIF_ALIST_0) +{ +#ifdef __BENCHMARK__ + Eterm *hp; +#ifndef BM_COUNTERS + unsigned long messages_sent = 0; + unsigned long messages_copied = 0; + unsigned long messages_ego = 0; +#endif +#ifndef BM_MESSAGE_SIZES + unsigned long words_sent = 0; + unsigned long words_copied = 0; + unsigned long words_prealloc = 0; +#endif + + hp = HAlloc(BIF_P, 7); + BIF_RET(TUPLE6(hp, + make_small(messages_sent), + make_small(messages_copied), + make_small(messages_ego), + make_small(words_sent), + make_small(words_copied), + make_small(words_prealloc))); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_message_info_clear_0(BIF_ALIST_0) +{ +#ifdef __BENCHMARK__ +#ifdef BM_COUNTERS + messages_sent = 0; + messages_copied = 0; + messages_ego = 0; +#endif +#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 + BIF_RET(am_true); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_message_sizes_0(BIF_ALIST_0) +{ +#ifdef BM_MESSAGE_SIZES + int i, j, max = 0; + int tmp[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + + for (i = 0; i < 65; i++) { + tmp[0] += message_sizes[i]; + if (tmp[0] > max) + max = tmp[0]; + } + for (i = 65; i < 999; i++) { + tmp[i / 100 + 1] += message_sizes[i]; + if (tmp[i / 100 + 1] > max) + max = tmp[i / 100 + 1]; + } + tmp[11] = message_sizes[999]; + if (tmp[11] > max) + max = tmp[11]; + for (i = -1; i < 11; i++) { + int num = (tmp[i + 1] * 50) / max; + if (i == -1) + printf("\n\r 0 - 64: (%6d) |", tmp[0]); + else if (i == 0) + printf("\n\r 65 - 99: (%6d) |", tmp[1]); + else if (i == 10) + printf("\n\r >= 1000: (%6d) |", tmp[11]); + else + printf("\n\r%3d - %3d: (%6d) |", i * 100, i * 100 + 99, + tmp[i + 1]); + + for (j = 0; j < num; j++) + printf("."); + } + printf("\n\r"); + + BIF_RET(am_true); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_gc_info_0(BIF_ALIST_0) +{ +#ifdef __BENCHMARK__ +#ifndef BM_COUNTERS + Uint minor_gc = 0; + Uint major_gc = 0; +#endif +#ifndef BM_HEAP_SIZES + Uint max_used_heap = 0; + Uint max_allocated_heap = 0; +#endif + Eterm *hp; + Uint used_heap = (BIF_P->htop - BIF_P->heap) + + (OLD_HTOP(BIF_P) - OLD_HEAP(BIF_P)) + + MBUF_SIZE(BIF_P); + + Uint alloc_heap = (BIF_P->hend - BIF_P->heap) + + (OLD_HEND(BIF_P) - OLD_HEAP(BIF_P)) + + MBUF_SIZE(BIF_P); + + hp = HAlloc(BIF_P, 7); + BIF_RET(TUPLE6(hp, + make_small((Uint)minor_gc), + make_small((Uint)major_gc), + make_small((Uint)used_heap), + make_small((Uint)alloc_heap), + make_small(max_used_heap), + make_small(max_allocated_heap))); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_shared_gc_info_0(BIF_ALIST_0) +{ +#ifdef __BENCHMARK__ +#if !(defined(BM_COUNTERS) && defined(HYBRID)) + Uint minor_global_gc = 0; + Uint major_global_gc = 0; +#endif +#ifndef BM_HEAP_SIZES + Uint max_used_global_heap = 0; + Uint max_allocated_global_heap = 0; +#endif + Eterm *hp; + +#if defined(HYBRID) + Uint tmp_used_heap = (Uint)((BIF_P->htop - BIF_P->heap) + + (OLD_HTOP(BIF_P) - OLD_HEAP(BIF_P)) + + MBUF_SIZE(BIF_P)); + Uint tmp_allocated_heap = (Uint)((BIF_P->hend - BIF_P->heap) + + (OLD_HEND(BIF_P) - OLD_HEAP(BIF_P)) + + MBUF_SIZE(BIF_P)); +#else + Uint tmp_used_heap = 0; + Uint tmp_allocated_heap = 0; +#endif + hp = HAlloc(BIF_P, 7); + BIF_RET(TUPLE6(hp, + make_small((uint)minor_global_gc), + make_small((uint)major_global_gc), + make_small(tmp_used_heap), + make_small(tmp_allocated_heap), + make_small(max_used_global_heap), + make_small(max_allocated_global_heap))); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_incremental_gc_info_0(BIF_ALIST_0) +{ +#ifdef __BENCHMARK__ +#if !(defined(BM_COUNTERS) && defined(INCREMENTAL)) + Uint minor_gc_cycles = 0; + Uint major_gc_cycles = 0; + Uint minor_gc_stages = 0; + Uint major_gc_stages = 0; +#endif + Eterm *hp; + + hp = HAlloc(BIF_P, 5); + BIF_RET(TUPLE4(hp, + make_small(minor_gc_cycles), + make_small(major_gc_cycles), + make_small(minor_gc_stages), + make_small(major_gc_stages))); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_gc_info_clear_0(BIF_ALIST_0) +{ +#ifdef __BENCHMARK__ + +#ifdef BM_COUNTERS + minor_gc = 0; + major_gc = 0; +#ifdef HYBRID + minor_global_gc = 0; + major_global_gc = 0; + gc_in_copy = 0; +#ifdef INCREMENTAL + minor_gc_cycles = 0; + major_gc_cycles = 0; + minor_gc_stages = 0; + major_gc_stages = 0; +#endif +#endif +#endif + +#ifdef BM_HEAP_SIZES + max_used_heap = 0; + max_allocated_heap = 0; + max_used_global_heap = 0; + max_allocated_global_heap = 0; +#endif + + BIF_RET(am_true); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_pause_times_0(BIF_ALIST_0) +{ +#ifdef BM_TIMERS + int i; + int total_time = 0, n = 0; + int left = 0, right = 0, mid = 0; + + printf("Pause times in minor collection:\r\n"); + for (i = 0; i < MAX_PAUSE_TIME; i++) { + if (pause_times[i] > 0) { + printf("%d: %ld\r\n", i, pause_times[i]); + 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]; + } + } + } + + printf("Number of collections: %d\r\n", n); + printf("Total collection time: %d\r\n", total_time); + if (n > 0) + printf("Mean pause time: %d\r\n", total_time / n); + + printf("Geometrical mean: %d\r\n", mid); + + total_time = 0; n = 0; + left = 0; right = 0; mid = 0; + printf("Pause times in major collection:\r\n"); + for (i = 0; i < MAX_PAUSE_TIME; i++) { + if (pause_times_old[i] > 0) { + printf("%d: %ld\r\n", i, pause_times_old[i]); + total_time += pause_times_old[i] * i; + n += pause_times_old[i]; + } + } + + printf("Number of collections: %d\r\n", n); + printf("Total collection time: %d\r\n", total_time); + if (n > 0) + printf("Mean pause time: %d\r\n", total_time / n); + + BIF_RET(am_true); +#else + BIF_RET(am_false); +#endif +} + +/* XXX: these macros have free variables */ +#ifdef BM_TIMERS +#if USE_PERFCTR +#define MAKE_TIME(_timer_) { \ + BM_TIMER_T tmp = _timer_##_time; \ + milli = (uint)(tmp - ((int)(tmp / 1000)) * 1000); \ + tmp /= 1000; \ + sec = (uint)(tmp - ((int)(tmp / 60)) * 60); \ + min = (uint)tmp / 60; } + +#define MAKE_MICRO_TIME(_timer_) { \ + BM_TIMER_T tmp = _timer_##_time * 1000; \ + micro = (uint)(tmp - ((int)(tmp / 1000)) * 1000); \ + tmp /= 1000; \ + milli = (uint)(tmp - ((int)(tmp / 1000)) * 1000); \ + sec = (uint)tmp / 1000; } + +#else +#define MAKE_TIME(_timer_) { \ + BM_TIMER_T tmp = _timer_##_time / 1000000; \ + milli = tmp % 1000; \ + tmp /= 1000; \ + sec = tmp % 60; \ + min = tmp / 60; } + +#define MAKE_MICRO_TIME(_timer_) { \ + BM_TIMER_T tmp = _timer_##_time / 1000; \ + micro = tmp % 1000; \ + tmp /= 1000; \ + milli = tmp % 1000; \ + sec = tmp / 1000; } + +#endif +#else +#define MAKE_TIME(_timer_) +#define MAKE_MICRO_TIME(_timer_) +#endif + +BIF_RETTYPE hipe_bifs_system_timer_0(BIF_ALIST_0) +{ +#ifdef __BENCHMARK__ + uint min = 0; + uint sec = 0; + uint milli = 0; + Eterm *hp; + + hp = HAlloc(BIF_P, 4); + MAKE_TIME(system); + BIF_RET(TUPLE3(hp, + make_small(min), + make_small(sec), + make_small(milli))); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_system_timer_clear_0(BIF_ALIST_0) +{ +#ifdef BM_TIMERS + system_time = 0; + BIF_RET(am_true); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_send_timer_0(BIF_ALIST_0) +{ +#ifdef __BENCHMARK__ + uint min = 0; + uint sec = 0; + uint milli = 0; + Eterm *hp; + Eterm sendtime, copytime, sizetime; + + hp = HAlloc(BIF_P, 4 * 4); + + MAKE_TIME(send); + sendtime = TUPLE3(hp, + make_small(min), + make_small(sec), + make_small(milli)); + hp += 4; + + MAKE_TIME(copy); + copytime = TUPLE3(hp, + make_small(min), + make_small(sec), + make_small(milli)); + hp += 4; + + MAKE_TIME(size); + sizetime = TUPLE3(hp, + make_small(min), + make_small(sec), + make_small(milli)); + hp += 4; + BIF_RET(TUPLE3(hp, sendtime, copytime, sizetime)); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_send_timer_clear_0(BIF_ALIST_0) +{ +#ifdef BM_TIMERS + send_time = 0; + copy_time = 0; + size_time = 0; + BIF_RET(am_true); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_gc_timer_0(BIF_ALIST_0) +{ +#ifdef __BENCHMARK__ + Eterm *hp; + uint min = 0; + uint sec = 0; + uint milli = 0; + uint micro = 0; + Eterm minor, major, max_min, max_maj; + + hp = HAlloc(BIF_P, 4 * 4 + 5); + + MAKE_TIME(minor_gc); + minor = TUPLE3(hp, + make_small(min), + make_small(sec), + make_small(milli)); + hp += 4; + + MAKE_TIME(major_gc); + major = TUPLE3(hp, + make_small(min), + make_small(sec), + make_small(milli)); + hp += 4; + + MAKE_MICRO_TIME(max_minor); + max_min = TUPLE3(hp, + make_small(sec), + make_small(milli), + make_small(micro)); + hp += 4; + + MAKE_MICRO_TIME(max_major); + max_maj = TUPLE3(hp, + make_small(sec), + make_small(milli), + make_small(micro)); + hp += 4; + + BIF_RET(TUPLE4(hp, minor, major, max_min, max_maj)); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_shared_gc_timer_0(BIF_ALIST_0) +{ +#ifdef __BENCHMARK__ + Eterm *hp; + uint min = 0; + uint sec = 0; + uint milli = 0; + uint micro = 0; + Eterm minor, major, max_min, max_maj; + + hp = HAlloc(BIF_P, 4 * 4 + 5); + + MAKE_TIME(minor_global_gc); + minor = TUPLE3(hp, + make_small(min), + make_small(sec), + make_small(milli)); + hp += 4; + + MAKE_TIME(major_global_gc); + major = TUPLE3(hp, + make_small(min), + make_small(sec), + make_small(milli)); + hp += 4; + + MAKE_MICRO_TIME(max_global_minor); + max_min = TUPLE3(hp, + make_small(sec), + make_small(milli), + make_small(micro)); + hp += 4; + + MAKE_MICRO_TIME(max_global_major); + max_maj = TUPLE3(hp, + make_small(sec), + make_small(milli), + make_small(micro)); + hp += 4; + + BIF_RET(TUPLE4(hp, minor, major, max_min, max_maj)); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_gc_timer_clear_0(BIF_ALIST_0) +{ +#ifdef BM_TIMERS + minor_gc_time = 0; + major_gc_time = 0; + max_minor_time = 0; + max_major_time = 0; + minor_global_gc_time = 0; + major_global_gc_time = 0; + max_global_minor_time = 0; + max_global_major_time = 0; + BIF_RET(am_true); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_misc_timer_0(BIF_ALIST_0) +{ +#ifdef __BENCHMARK__ + uint min = 0; + uint sec = 0; + uint milli = 0; + Eterm *hp; + Eterm misctime1, misctime2, misctime3; + + hp = HAlloc(BIF_P, 4 * 4); + + MAKE_TIME(misc0); + misctime1 = TUPLE3(hp, + make_small(min), + make_small(sec), + make_small(milli)); + hp += 4; + + MAKE_TIME(misc1); + misctime2 = TUPLE3(hp, + make_small(min), + make_small(sec), + make_small(milli)); + hp += 4; + + MAKE_TIME(misc2); + misctime3 = TUPLE3(hp, + make_small(min), + make_small(sec), + make_small(milli)); + hp += 4; + BIF_RET(TUPLE3(hp, misctime1, misctime2, misctime3)); +#else + BIF_RET(am_false); +#endif +} + +BIF_RETTYPE hipe_bifs_misc_timer_clear_0(BIF_ALIST_0) +{ +#ifdef BM_TIMERS + misc0_time = 0; + misc1_time = 0; + misc2_time = 0; + BIF_RET(am_true); +#else + BIF_RET(am_false); +#endif +} + +#undef MAKE_TIME +#undef MAKE_MICRO_TIME + +/* + * HiPE hrvtime(). + * These implementations are currently available: + * + On Linux with the perfctr extension we can use the process' + * virtualised time-stamp counter. To enable this mode you must + * pass `--with-perfctr=/path/to/perfctr' when configuring. + * + The fallback, which is the same as {X,_} = runtime(statistics). + */ + +#if USE_PERFCTR + +#include "hipe_perfctr.h" +static int hrvtime_is_open; +#define hrvtime_is_started() hrvtime_is_open + +static void start_hrvtime(void) +{ + if (hipe_perfctr_hrvtime_open() >= 0) + hrvtime_is_open = 1; +} + +#define get_hrvtime() hipe_perfctr_hrvtime_get() +#define stop_hrvtime() hipe_perfctr_hrvtime_close() + +#else + +/* + * Fallback, if nothing better exists. + * This is the same as {X,_} = statistics(runtime), which uses + * times(2) on Unix systems. + */ + +#define hrvtime_is_started() 1 +#define start_hrvtime() do{}while(0) +#define stop_hrvtime() do{}while(0) + +static double get_hrvtime(void) +{ + unsigned long ms_user; + elapsed_time_both(&ms_user, NULL, NULL, NULL); + return (double)ms_user; +} + +#endif /* hrvtime support */ + +BIF_RETTYPE hipe_bifs_get_hrvtime_0(BIF_ALIST_0) +{ + Eterm *hp; + Eterm res; + FloatDef f; + + if (!hrvtime_is_started()) { + start_hrvtime(); + if (!hrvtime_is_started()) + BIF_RET(NIL); /* arity 0 BIFs may not fail */ + } + f.fd = get_hrvtime(); + hp = HAlloc(BIF_P, FLOAT_SIZE_OBJECT); + res = make_float(hp); + PUT_DOUBLE(f, hp); + BIF_RET(res); +} + +BIF_RETTYPE hipe_bifs_stop_hrvtime_0(BIF_ALIST_0) +{ + stop_hrvtime(); + BIF_RET(am_true); +} |