From 0499f1d8a7f70b965d8129e04ecbe8132b455ede Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Tue, 7 Mar 2006 22:12:09 +0000 Subject: [PATCH] Use the Alpha PCC as a cpu ticker for process runtime accounting. This is slightly more tricky than on x86 as although the PCC is 64-bits, it is not a simple 64-bit counter like the TSC. Instead, the upper 32-bits have PAL-defined behavior and the lower 32-bits run as a free-running 32-bit counter. To handle this, we detect overflows by maintaining a small amount of per-cpu state and use this to simulate the upper 32-bits of the counter providing a full 64-bit counter to the consumers of cpu_ticks(). --- sys/alpha/alpha/clock.c | 26 ++++++++++++++++++++++++++ sys/alpha/include/pcpu.h | 4 +++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/sys/alpha/alpha/clock.c b/sys/alpha/alpha/clock.c index e71cc2946dee..6d24a314e666 100644 --- a/sys/alpha/alpha/clock.c +++ b/sys/alpha/alpha/clock.c @@ -137,6 +137,7 @@ static u_char timer2_state; static void calibrate_clocks(u_int32_t firmware_freq, u_int32_t *pcc, u_int32_t *timer); static void set_timer_freq(u_int freq, int intr_freq); +static uint64_t read_cycle_count(void); void clockattach(device_t dev) @@ -152,6 +153,7 @@ clockattach(device_t dev) calibrate_clocks(cycles_per_sec, &pcc, &freq); cycles_per_sec = pcc; + set_cputicker(read_cycle_count, cycles_per_sec, 0); /* * XXX: TurboLaser doesn't have an i8254 counter. @@ -555,6 +557,30 @@ alpha_get_timecount(struct timecounter* tc) return alpha_rpcc(); } +/* + * The RPCC register actually consists of two halves. The lower half + * is a raw 32-bit counter that wraps. The upper half is defined in + * the Digital UNIX PAL as being a raw per-process cycle count mod 2^32 + * that is updated on each call to swpctx. In order to produce a 64-bit + * counter, we just use the lower half and simulate the upper 32-bits. + * The architecture guarantees that there will always be at least one + * clock interrupt in between overlaps in the lower half, so as long as + * we call this function every clock interrupt we should not miss any + * overlaps. + */ +uint64_t +read_cycle_count(void) +{ + unsigned pcc_cnt; + + /* Assert a critical section? */ + pcc_cnt = alpha_rpcc() & 0xffffffff; + if (pcc_cnt < PCPU_GET(last_pcc_cnt)) + PCPU_SET(pcc_base, PCPU_GET(pcc_base) + 1); + PCPU_SET(last_pcc_cnt, pcc_cnt); + return (pcc_cnt | ((uint64_t)PCPU_GET(pcc_base) << 32)); +} + int acquire_timer2(int mode) { diff --git a/sys/alpha/include/pcpu.h b/sys/alpha/include/pcpu.h index 660839abe81e..eb043620c92c 100644 --- a/sys/alpha/include/pcpu.h +++ b/sys/alpha/include/pcpu.h @@ -38,7 +38,9 @@ u_int64_t pc_idlepcbphys; /* pa of pc_idlepcb */ \ u_int64_t pc_pending_ipis; /* pending IPI's */ \ u_int32_t pc_next_asn; /* next ASN to alloc */ \ - u_int32_t pc_current_asngen /* ASN rollover check */ + u_int32_t pc_current_asngen; /* ASN rollover check */ \ + u_int32_t pc_last_pcc_cnt; /* Previous PCC_CNT value */ \ + u_int32_t pc_pcc_base /* Hi word of cycle count. */ struct pcpu;