add timing logic
This commit is contained in:
parent
a66ea40850
commit
e9f3e9a236
|
@ -3,6 +3,11 @@
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include "rvprof_internal.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
|
// global flag for cycle counter availability
|
||||||
static volatile int g_cycle_counter_available = 0;
|
static volatile int g_cycle_counter_available = 0;
|
||||||
static volatile jmp_buf g_cycle_test_jmpbuf;
|
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){
|
static void sigkill_handler(int sig){
|
||||||
g_cycle_counter_available = 0;
|
g_cycle_counter_available = 0;
|
||||||
longjmp(g_cycle_test_jmpbuf, 1);
|
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