pulp-runtime/kernel/bench.c
2019-12-15 14:12:22 +01:00

243 lines
6.3 KiB
C

/*
* Copyright (C) 2018 ETH Zurich and University of Bologna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include "bench/bench.h"
#include "hal/pulp.h"
#include "archi/pulp.h"
// Flag for disabling the printf output
uint32_t enable_printf = 1;
void bench_disable_printf(void) {
enable_printf = 0;
}
void bench_timer_start(void) {
if (get_core_id()==0)
start_timer();
#ifdef PROFILE
perf_start();
#endif
}
void bench_timer_stop(void) {
if (get_core_id()==0)
stop_timer();
#ifdef PROFILE
perf_stop();
#endif
}
void bench_timer_reset(void) {
if (get_core_id()==0) {
stop_timer();
reset_timer();
}
#ifdef PROFILE
perf_reset();
#endif
}
void print_result(testcase_t *test, testresult_t *result)
{
printf("== test: %s -> ", test->name);
if (result->errors == 0)
printf("success, ");
else
printf("fail, ");
printf("nr. of errors: %d", result->errors);
if(result->time == 0)
printf("\n");
else
printf(", execution time: %d\n", result->time);
#ifdef PROFILE
perf_print_all();
#endif
}
void print_summary(unsigned int errors)
{
#ifdef RTL_SDK
volatile int* ptr = (int*)(0x10001000+get_core_id()*4*2);
ptr[1] = errors;
#endif
#ifdef RTL_SDK
if (errors == 0) {
ptr[0] = 0xABBAABBA;
else {
ptr[0] = 0xDEADBEEF;
}
#endif
if(enable_printf) {
printf("==== SUMMARY: ");
if (errors == 0) {
printf("SUCCESS\n");
} else {
printf("FAIL\n");
}
}
}
void run_benchmark(testcase_t *test, testresult_t *result)
{
result->errors = 0;
bench_timer_reset();
test->test(result, bench_timer_start, bench_timer_stop);
result->time = get_time();
}
int run_suite(testcase_t *tests)
{
// figure out how many tests should be run
int num = 0;
while(tests[num].name != 0) num++;
unsigned int errors = 0;
int i;
// perform the tests
for (i = 0; i < num; i++) {
testresult_t result;
run_benchmark(&tests[i], &result);
if(enable_printf) print_result(&tests[i], &result);
errors += result.errors;
}
print_summary(errors);
return errors;
}
void check_uint32(testresult_t* result, const char* fail_msg, uint32_t actual, uint32_t expected)
{
if(actual != expected) {
result->errors += 1;
if(enable_printf) printf("%s: Actual %X, expected %X\n", fail_msg, (unsigned int) actual, (unsigned int)expected);
}
}
void perf_print_all(void) {
#ifdef __riscv__
printf("Perf CYCLES: %d\n", cpu_perf_get(0));
printf("Perf INSTR: %d\n", cpu_perf_get(1));
printf("Perf CINSTR: %d\n", cpu_perf_get(10));
printf("Perf LD_STALL: %d\n", cpu_perf_get(2));
printf("Perf JR_STALL: %d\n", cpu_perf_get(3));
printf("Perf IMISS: %d\n", cpu_perf_get(4));
printf("Perf LD: %d\n", cpu_perf_get(5));
printf("Perf ST: %d\n", cpu_perf_get(6));
printf("Perf JUMP: %d\n", cpu_perf_get(7));
printf("Perf BRANCH: %d\n", cpu_perf_get(8));
printf("Perf BTAKEN: %d\n", cpu_perf_get(9));
printf("Perf LD EXT: %d\n", cpu_perf_get(11));
printf("Perf ST EXT: %d\n", cpu_perf_get(12));
printf("Perf LD EXT CYC: %d\n", cpu_perf_get(13));
printf("Perf ST EXT CYC: %d\n", cpu_perf_get(14));
printf("Perf TCDM CONT: %d\n", cpu_perf_get(15));
printf("Perf CSR HAZARD: %d\n", cpu_perf_get(16));
#ifdef HARD_FLOAT
if (!rt_is_fc()) {
printf("Perf APU_TY_CONF: %d\n", cpu_perf_get(17));
printf("Perf APU_CONT: %d\n", cpu_perf_get(18));
printf("Perf APU_DEP: %d\n", cpu_perf_get(19));
printf("Perf APU_WB: %d\n", cpu_perf_get(20));
}
#endif
#else
#ifdef CSR_PCER_ALL_EVENTS_MASK
printf("Perf CYCLES: %d\n", cpu_perf_get(SPR_PCER_CYCLES));
printf("Perf INSTR: %d\n", cpu_perf_get(SPR_PCER_INSTR));
printf("Perf LD_STALL: %d\n", cpu_perf_get(SPR_PCER_LD_STALL));
printf("Perf JMP_STALL: %d\n", cpu_perf_get(SPR_PCER_JMP_STALL));
printf("Perf IMISS: %d\n", cpu_perf_get(SPR_PCER_IMISS));
printf("Perf WBRANCH: %d\n", cpu_perf_get(SPR_PCER_WBRANCH));
printf("Perf WBRANCH_CYC: %d\n", cpu_perf_get(SPR_PCER_WBRANCH_CYC));
printf("Perf LD: %d\n", cpu_perf_get(SPR_PCER_LD));
printf("Perf ST: %d\n", cpu_perf_get(SPR_PCER_ST));
printf("Perf JUMP: %d\n", cpu_perf_get(SPR_PCER_JUMP));
printf("Perf BRANCH: %d\n", cpu_perf_get(SPR_PCER_BRANCH));
printf("Perf DELAY NOP: %d\n", cpu_perf_get(SPR_PCER_DELAY_NOP));
printf("Perf LD EXT: %d\n", cpu_perf_get(SPR_PCER_LD_EXT));
printf("Perf ST EXT: %d\n", cpu_perf_get(SPR_PCER_ST_EXT));
printf("Perf LD EXT CYC: %d\n", cpu_perf_get(SPR_PCER_LD_EXT_CYC));
printf("Perf ST EXT CYC: %d\n", cpu_perf_get(SPR_PCER_ST_EXT_CYC));
printf("Perf TCDM CONT: %d\n", cpu_perf_get(SPR_PCER_TCDM_CONT));
#endif
#endif
// new ICACHE handles this differently
// // icache
// int i;
// for(i = 0; i < 4; i++) {
// printf("I$ bank %d: Read hits %d\n", i, read_hit_icache_reg(i));
// printf("I$ bank %d: Trans %d\n", i, read_trans_icache_reg(i));
// }
}
// use weak attribute here, so we can overwrite this function to provide custom
// exception handlers, e.g. for tests
//__attribute__((interrupt))
__attribute__((weak))
void illegal_insn_handler_c(void)
{
#ifndef __ariane__
unsigned int exception_address, insn;
#ifdef __riscv__
asm("csrr %0, 0x341" : "=r" (exception_address) : );
#else
exception_address = hal_spr_read(SPR_EPCR_BASE);
#endif
insn = *((unsigned int*)(exception_address));
printf("Illegal instruction encountered at address 0x%08X: %X\n", exception_address, insn);
exit(1);
#endif
}
int bench_cluster_exec(int cid, int (*entry)())
{
if (rt_cluster_id() != (unsigned int)cid)
{
cluster_start(cid, entry);
return cluster_wait(cid);
}
return 0;
}
extern int main(int argc, const char * const argv[]);
int bench_cluster_forward(int cid)
{
return bench_cluster_exec(cid, main);
}