diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /erts/emulator/hipe/hipe_perfctr.c | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'erts/emulator/hipe/hipe_perfctr.c')
-rw-r--r-- | erts/emulator/hipe/hipe_perfctr.c | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/erts/emulator/hipe/hipe_perfctr.c b/erts/emulator/hipe/hipe_perfctr.c new file mode 100644 index 0000000000..69bb648854 --- /dev/null +++ b/erts/emulator/hipe/hipe_perfctr.c @@ -0,0 +1,229 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-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$ + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "sys.h" +#include "error.h" +#include "global.h" +#include "bif.h" +#include "big.h" +#include "erl_binary.h" +#include "hipe_perfctr.h" +#include "libperfctr.h" + +static struct vperfctr *vperfctr; +static unsigned int have_rdtsc; +static double tsc_to_ms; +static unsigned int tsc_on; /* control calls must set tsc_on if have_rdtsc is true */ +static unsigned int nractrs; +static unsigned int users; +#define USER_BIFS (1<<0) +#define USER_HRVTIME (1<<1) + +static int hipe_perfctr_open(unsigned int user) +{ + struct perfctr_info info; + + if (!vperfctr) { + vperfctr = vperfctr_open(); + if (!vperfctr) + return -1; + if (vperfctr_info(vperfctr, &info) >= 0) { + tsc_to_ms = (double)(info.tsc_to_cpu_mult ? : 1) / (double)info.cpu_khz; + have_rdtsc = (info.cpu_features & PERFCTR_FEATURE_RDTSC) ? 1 : 0; + } + tsc_on = 0; + nractrs = 0; + } + users |= user; + return 0; +} + +static void hipe_perfctr_reset(void) +{ + struct vperfctr_control control; + + memset(&control, 0, sizeof control); + if (have_rdtsc) + control.cpu_control.tsc_on = 1; + nractrs = 0; + if (vperfctr_control(vperfctr, &control) >= 0) + tsc_on = 1; +} + +static void hipe_perfctr_close(unsigned int user) +{ + if (!vperfctr) + return; + users &= ~user; + switch (users) { + case 0: + vperfctr_unlink(vperfctr); + vperfctr_close(vperfctr); + vperfctr = NULL; + tsc_on = 0; + nractrs = 0; + break; + case USER_HRVTIME: + hipe_perfctr_reset(); + } +} + +/* + * Interface for HiPE's hrvtime code. + */ + +int hipe_perfctr_hrvtime_open(void) +{ + if (hipe_perfctr_open(USER_HRVTIME) < 0) + return -1; + if (have_rdtsc) { + if (!tsc_on) + hipe_perfctr_reset(); /* note: updates tsc_on */ + if (tsc_on) + return 0; + } + hipe_perfctr_hrvtime_close(); + return -1; +} + +void hipe_perfctr_hrvtime_close(void) +{ + hipe_perfctr_close(USER_HRVTIME); +} + +double hipe_perfctr_hrvtime_get(void) +{ + return (double)vperfctr_read_tsc(vperfctr) * tsc_to_ms; +} + +/* + * BIF interface for user-programmable performance counters. + */ + +BIF_RETTYPE hipe_bifs_vperfctr_open_0(BIF_ALIST_0) +{ + if (hipe_perfctr_open(USER_BIFS) < 0) + BIF_RET(am_false); /* arity 0 BIFs can't fail :-( */ + BIF_RET(am_true); +} + +BIF_RETTYPE hipe_bifs_vperfctr_close_0(BIF_ALIST_0) +{ + hipe_perfctr_close(USER_BIFS); + BIF_RET(NIL); +} + +static Eterm ull_to_integer(unsigned long long x, Process *p) +{ + unsigned long long tmpx; + unsigned int ds, i; + size_t sz; + Eterm *hp; + ErtsDigit *xp; + + if (x <= (unsigned long long)MAX_SMALL) + return make_small(x); + + /* Calculate number of digits. */ + ds = 0; + tmpx = x; + do { + ++ds; + tmpx = (tmpx >> (D_EXP / 2)) >> (D_EXP / 2); + } while (tmpx != 0); + + sz = BIG_NEED_SIZE(ds); /* number of words including arity */ + hp = HAlloc(p, sz); + *hp = make_pos_bignum_header(sz-1); + + xp = (ErtsDigit*)(hp+1); + i = 0; + do { + xp[i++] = (ErtsDigit)x; + x = (x >> (D_EXP / 2)) >> (D_EXP / 2); + } while (i < ds); + while (i & (BIG_DIGITS_PER_WORD-1)) + xp[i++] = 0; + + return make_big(hp); +} + +BIF_RETTYPE hipe_bifs_vperfctr_info_0(BIF_ALIST_0) +{ + struct perfctr_info info; + + if (!vperfctr || vperfctr_info(vperfctr, &info) < 0) + BIF_RET(am_false); /* arity 0 BIFs can't fail :-( */ + BIF_RET(new_binary(BIF_P, (void*)&info, sizeof info)); +} + +BIF_RETTYPE hipe_bifs_vperfctr_read_tsc_0(BIF_ALIST_0) +{ + unsigned long long val; + + if (!vperfctr || !tsc_on) + BIF_RET(am_false); /* arity 0 BIFs can't fail :-( */ + val = vperfctr_read_tsc(vperfctr); + BIF_RET(ull_to_integer(val, BIF_P)); +} + +BIF_RETTYPE hipe_bifs_vperfctr_read_pmc_1(BIF_ALIST_1) +{ + Uint pmc; + unsigned long long val; + + if (!vperfctr || + is_not_small(BIF_ARG_1) || + (pmc = unsigned_val(BIF_ARG_1), pmc >= nractrs)) + BIF_RET(am_false); /* for consistency with the arity 0 BIFs */ + val = vperfctr_read_pmc(vperfctr, pmc); + BIF_RET(ull_to_integer(val, BIF_P)); +} + +BIF_RETTYPE hipe_bifs_vperfctr_control_1(BIF_ALIST_1) +{ + void *bytes; + struct vperfctr_control control; + Uint bitoffs; + Uint bitsize; + + if (!vperfctr) + BIF_ERROR(BIF_P, BADARG); + if (is_not_binary(BIF_ARG_1)) + BIF_ERROR(BIF_P, BADARG); + if (binary_size(BIF_ARG_1) != sizeof control) + BIF_ERROR(BIF_P, BADARG); + ERTS_GET_BINARY_BYTES(BIF_ARG_1, bytes, bitoffs, bitsize); + ASSERT(bitoffs == 0); + ASSERT(bitsize == 0); + memcpy(&control, bytes, sizeof control); + if (have_rdtsc) + control.cpu_control.tsc_on = 1; + if (vperfctr_control(vperfctr, &control) < 0) { + hipe_perfctr_reset(); + BIF_ERROR(BIF_P, BADARG); + } + tsc_on = control.cpu_control.tsc_on; + nractrs = control.cpu_control.nractrs; + BIF_RET(NIL); +} |