add timing logic
This commit is contained in:
parent
a66ea40850
commit
e9f3e9a236
|
@ -3,6 +3,11 @@
|
|||
#include <setjmp.h>
|
||||
#include "rvprof_internal.h"
|
||||
|
||||
/*
|
||||
The inline assembly calls in this file are the only places where the code is really RISCV-specific.
|
||||
Maybe replace with a library call in the future
|
||||
*/
|
||||
|
||||
// global flag for cycle counter availability
|
||||
static volatile int g_cycle_counter_available = 0;
|
||||
static volatile jmp_buf g_cycle_test_jmpbuf;
|
||||
|
@ -11,4 +16,85 @@ static volatile jmp_buf g_cycle_test_jmpbuf;
|
|||
static void sigkill_handler(int sig){
|
||||
g_cycle_counter_available = 0;
|
||||
longjmp(g_cycle_test_jmpbuf, 1);
|
||||
}
|
||||
|
||||
static inline uint64_t read_cycles(void){
|
||||
if (!g_cycle_counter_available) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t cycles;
|
||||
|
||||
|
||||
__asm__ volatile("csrr %0, cycle" : "=r"(cycles));
|
||||
return cycles;
|
||||
}
|
||||
|
||||
// nanosecond timing for all actual measurements
|
||||
static inline uint64_t read_time_ns(void){
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (uint64_t)ts.tv_sec * 1000000000ULL + (uint64_t)ts.tv_nsec;
|
||||
}
|
||||
|
||||
int rvprof_timing_test_cycle_counter(void){
|
||||
// set up signal handler for illegal instruction
|
||||
struct sigaction old_action, new_action;
|
||||
new_action.sa_handler = sigill_handler;
|
||||
sigemptyset(&new_action.sa_mask);
|
||||
new_action.sa_flags = 0;
|
||||
|
||||
if (sigaction(SIGILL, &new_action, &old_action) != 0){
|
||||
// can't set up signal handler, assume cycle counter not available
|
||||
g_cycle_counter_available = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// test cycle counter access
|
||||
if (setjmp(g_cycle_test_jmpbuf) == 0) {
|
||||
uint64_t cycles1, cycles2;
|
||||
|
||||
__asm__ volatile("csrr %0, cycle" : "=r"(cycles1));
|
||||
|
||||
// small delay
|
||||
for (volatile int i = 0; i < 1000; i++);
|
||||
|
||||
__asm__ volatile("csrr %0, cycle" : "=r"(cycles2));
|
||||
|
||||
if (cycles2 > cycles1){
|
||||
g_cycle_counter_available = 1;
|
||||
} else {
|
||||
g_cycle_counter_available = 0;
|
||||
}
|
||||
}else{
|
||||
// illegal instruction occurred
|
||||
g_cycle_counter_available = 0;
|
||||
}
|
||||
|
||||
// restore original signal handler
|
||||
sigaction(SIGILL, &old_action, NULL);
|
||||
|
||||
return g_cycle_counter_available;
|
||||
}
|
||||
|
||||
rvprof_error_t rvprof_timing_init(void){
|
||||
// always use nanosecond timer for actual timing
|
||||
g_rvprof.use_cycles = 0;
|
||||
|
||||
// test if cycle counter is available for informational display
|
||||
g_rvprof.cycles_available = rvprof_timing_test_cycle_counter();
|
||||
|
||||
return RVPROF_SUCCESS;
|
||||
}
|
||||
|
||||
uint64_t rvprof_timing_get_current(void) {
|
||||
return read_time_ns();
|
||||
}
|
||||
|
||||
uint64_t rvprof_timing_get_cycles(void) {
|
||||
return read_cycles(); // Returns 0 if not available
|
||||
}
|
||||
|
||||
double rvprof_timing_to_seconds(uint64_t nanoseconds) {
|
||||
return (double)nanoseconds / 1000000000.0;
|
||||
}
|
Loading…
Reference in New Issue