collect execution statistics

This commit is contained in:
Denis Drakhnia 2023-12-13 07:46:00 +02:00
parent 352518856d
commit 0e0d06070c
2 changed files with 91 additions and 20 deletions

View File

@ -5,9 +5,15 @@
#define CODE %r0
#define TAPE %r1
#define TAPE_SIZE %r2
#define PC %r3
#define CUR %r4
#define ACC %r5
#define STATS %r3
#define PC %r4
#define CUR %r5
#define ACC %r6
#define STATS_OPS %r7
#define STATS_CALLS %r8
#define STATS_BRANCHES %r9
#define STATS_BRANCHES_TAKEN %r10
#define STATS_CPU_CYCLES %r11
! Pipeline registers
#define NPC_F %b[0]
@ -49,24 +55,34 @@
.balign 8
run_program_e2k:
{
setwd wsz=12, nfx=1, dbl=1
setbn rsz=7, rbs=4, rcur=0
setwd wsz=16, nfx=1, dbl=1
setbn rsz=7, rbs=8, rcur=0
setbp psz=13
nop 4
addd,1 TAPE, 0, CUR
addd,2 0, 0, PC
ldb,3 TAPE, 0, ACC
disp PIPELINE, pipeline
}
{
nop 3
ldd,0 STATS, 0, STATS_OPS
ldd,2 STATS, 8, STATS_CALLS
ldd,3 STATS, 16, STATS_BRANCHES
ldd,5 STATS, 24, STATS_BRANCHES_TAKEN
}
{
rrd,0 %clkr, STATS_CPU_CYCLES
ct PIPELINE
}
call:
{
setwd wsz=8, nfx=1, dbl=1
setbn rsz=3, rbs=4, rcur=0
setwd wsz=12, nfx=1, dbl=1
setbn rsz=3, rbs=8, rcur=0
setbp psz=0
cmpedb,0 IMM_E, FUNC_PUTC, %pred31
cmpedb,1 IMM_E, FUNC_GETC, %pred30
addd,2 STATS_CALLS, 1, STATS_CALLS
#ifdef FUNC_DEBUG
cmpedb,3 IMM_E, FUNC_DEBUG, %pred29
#endif
@ -83,10 +99,10 @@ call:
#endif
{
addd,0 ACC, 0, %b[0] ? %pred31
call %ctpr1, wbs=4 ? %pred31
call %ctpr1, wbs=8 ? %pred31
}
{
call %ctpr2, wbs=4 ? %pred30
call %ctpr2, wbs=8 ? %pred30
}
#ifdef FUNC_DEBUG
{
@ -95,12 +111,12 @@ call:
addd,2 TAPE, 0, %b[2] ? %pred29
addd,3 CUR, 0, %b[3] ? %pred29
addd,4 ACC, 0, %b[4] ? %pred29
call %ctpr3, wbs=4 ? %pred29
call %ctpr3, wbs=8 ? %pred29
}
#endif
{
setwd wsz=12, nfx=1, dbl=1
setbn rsz=7, rbs=4, rcur=0
setwd wsz=16, nfx=1, dbl=1
setbn rsz=7, rbs=8, rcur=0
setbp psz=13
addd,0 %b[0], 0, ACC ? %pred30
}
@ -169,6 +185,8 @@ loop:
pass @p6, IS_NOT_TAKEN
}
{
addd,0 STATS_OPS, 1, STATS_OPS
! Decode
cmpandesb,1,sm INSN_D, OP_ADD, IS_NOT_ADD_D
cmpandesb,3,sm INSN_D, OP_EXE, IS_NOT_EXE_D
@ -187,11 +205,28 @@ loop:
! Execute (extra): restart pipeline
addd,0 NPC_E, 0, PC ? IS_NOT_TAKEN
addd,1 BRANCH_TARGET_E, 0, PC ? ~IS_NOT_TAKEN
addd,2 STATS_BRANCHES, 1, STATS_BRANCHES ? ~IS_NOT_BRANCH
addd,3 STATS_BRANCHES_TAKEN, 1, STATS_BRANCHES_TAKEN ? ~IS_NOT_TAKEN
ct PIPELINE ? ~IS_NOT_BRANCH
}
{
nop 5
! remove end op from counter
rrd,0 %clkr, %g16
subd,1 STATS_OPS, 1, STATS_OPS
return %ctpr3
}
{
subd,0 %g16, STATS_CPU_CYCLES, STATS_CPU_CYCLES
std,2 STATS_OPS, STATS, 0
std,5 STATS_CALLS, STATS, 8
}
{
std,2 STATS_BRANCHES, STATS, 16
std,5 STATS_BRANCHES_TAKEN, STATS, 24
}
{
nop 3
std,2 STATS_CPU_CYCLES, STATS, 32
}
ct %ctpr3

View File

@ -6,6 +6,7 @@
#include <string.h>
#include <stdbool.h>
#include <stdarg.h>
#include <inttypes.h>
#include <unistd.h>
#include <getopt.h>
#include <time.h>
@ -14,6 +15,14 @@
#define TAPE_SIZE 30000
#define MAX_NESTING 100
typedef struct Stats {
uint64_t ops;
uint64_t calls;
uint64_t branches;
uint64_t taken_branches;
uint64_t cpu_cycles;
} Stats;
typedef enum Mode {
MODE_ASM,
MODE_BC,
@ -25,6 +34,7 @@ typedef struct Options {
bool dump;
bool dump_only;
bool time;
bool stats;
char **files;
} Options;
@ -43,12 +53,13 @@ static bool parse_opts(int argc, char *argv[], Options *opts) {
for (;;) {
int option_index = 0;
static struct option long_options[] = {
{"mode", required_argument, 0, 'm'},
{"dump", no_argument, 0, 'd'},
{"dump-only", no_argument, 0, 'D'},
{"mode", required_argument, 0, 'm'},
{"stats", no_argument, 0, 's'},
{0, 0, 0, 0 }
};
int c = getopt_long(argc, argv, "dDm:t",
int c = getopt_long(argc, argv, "dDm:ts",
long_options, &option_index);
if (c == -1) {
break;
@ -66,6 +77,9 @@ static bool parse_opts(int argc, char *argv[], Options *opts) {
case 't':
opts->time = true;
break;
case 's':
opts->stats = true;
break;
case 'm':
if (strcmp(optarg, "asm") == 0) {
opts->mode = MODE_ASM;
@ -95,7 +109,8 @@ static bool parse_opts(int argc, char *argv[], Options *opts) {
}
#ifdef __e2k__
void run_program_e2k(const int32_t *code, uint8_t *tape, size_t tape_size);
void run_program_e2k(const int32_t *code, uint8_t *tape,
size_t tape_size, Stats *stats);
#endif
static inline int32_t make_insn(uint8_t op, int32_t n) {
@ -235,22 +250,29 @@ static void dump_program(const char *path, const int32_t *code) {
printf_err("\n");
}
static void run_program_bc(const int32_t *code, uint8_t *tape, size_t tape_size) {
static void run_program_bc(const int32_t *code, uint8_t *tape,
size_t tape_size, Stats *stats)
{
uint32_t pc = 0, i = 0;
uint8_t cur = tape[i];
for (; code[pc]; ++pc) {
int32_t n = insn_imm(code[pc]);
stats->ops += 1;
switch (code[pc] & OP_MASK) {
case OP_BEQZ:
stats->branches += 1;
if (cur == 0) {
pc += n / 4;
stats->taken_branches += 1;
}
break;
case OP_BNEZ:
stats->branches += 1;
if (cur != 0) {
pc += n / 4;
stats->taken_branches += 1;
}
break;
case OP_ADD:
@ -262,6 +284,7 @@ static void run_program_bc(const int32_t *code, uint8_t *tape, size_t tape_size)
cur = tape[i];
break;
case OP_CALL:
stats->calls += 1;
switch (n) {
case FUNC_GETC:
cur = getchar();
@ -323,6 +346,7 @@ int main(int argc, char *argv[], char *envp[]) {
}
if (!opts.dump_only) {
Stats stats = { 0 };
struct timespec start;
memset(tape, 0, TAPE_SIZE);
@ -336,12 +360,13 @@ int main(int argc, char *argv[], char *envp[]) {
case MODE_BC:
#if __e2k__
if (opts.mode == MODE_ASM) {
run_program_e2k(code, tape, TAPE_SIZE);
run_program_e2k(code, tape, TAPE_SIZE, &stats);
} else
#endif
{
run_program_bc(code, tape, TAPE_SIZE);
run_program_bc(code, tape, TAPE_SIZE, &stats);
}
break;
case MODE_NAIVE:
run_program_naive(program, tape, TAPE_SIZE);
@ -366,6 +391,17 @@ int main(int argc, char *argv[], char *envp[]) {
printf_err(" Time: %.2f%s\n", time, units);
}
if (opts.stats) {
printf_err(" Stats\n");
printf_err(" ops: %" PRIu64 "\n", stats.ops);
printf_err(" calls: %" PRIu64 "\n", stats.calls);
printf_err(" branches: %" PRIu64 " (taken %" PRIu64 ")\n",
stats.branches, stats.taken_branches);
if (stats.cpu_cycles) {
printf_err(" cpu cycles: %" PRIu64 "\n", stats.cpu_cycles);
}
}
}
if (opts.dump || opts.time) {