summaryrefslogtreecommitdiff
path: root/demo
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2023-10-05 17:18:56 -0600
committerAlejandro Soto <alejandro@34project.org>2023-10-05 17:18:56 -0600
commitcf32fe6cf81040e04036f0fcf72f814ab891bb8a (patch)
treea1e1c50ab905ce6b7b85dcffc98c09995d72e693 /demo
parentd406720cecd7328f595255e65b6fd6b6814cefe4 (diff)
demo: implement perf command
Diffstat (limited to 'demo')
-rw-r--r--demo/demo.h4
-rw-r--r--demo/main.c30
-rw-r--r--demo/perf.c60
-rw-r--r--demo/util.c10
4 files changed, 98 insertions, 6 deletions
diff --git a/demo/demo.h b/demo/demo.h
index f98d599..c889e1a 100644
--- a/demo/demo.h
+++ b/demo/demo.h
@@ -35,6 +35,7 @@ int strcmp(const char *s1, const char *s2);
char *strtok_input(char **tokens);
int expect_end(char **tokens);
+void unexpected_eof();
int parse_hex(char **tokens, unsigned *val);
int parse_ptr(char **tokens, void **ptr);
@@ -45,4 +46,7 @@ int parse_cpu_mask(char **tokens, unsigned *mask);
void cache_debug(unsigned cpu, void *ptr);
+void perf_show(unsigned cpu);
+void perf_clear(unsigned cpu);
+
#endif
diff --git a/demo/main.c b/demo/main.c
index 988ef55..89347ad 100644
--- a/demo/main.c
+++ b/demo/main.c
@@ -6,6 +6,11 @@ struct cpu *__cpus[] = { &cpu0, &cpu1, &cpu2, &cpu3 };
static volatile unsigned boot_done;
+static void unknown_command(const char *cmd)
+{
+ print("unknown command '%s'", cmd);
+}
+
static void cmd_run(char **tokens)
{
unsigned mask;
@@ -55,6 +60,27 @@ static void cmd_cache(char **tokens)
cache_debug(cpu, ptr);
}
+static void cmd_perf(char **tokens)
+{
+ unsigned cpu;
+ const char *cmd;
+
+ if (parse_cpu(tokens, &cpu) < 0)
+ return;
+ else if (!(cmd = strtok_input(tokens))) {
+ unexpected_eof();
+ return;
+ } else if (expect_end(tokens) < 0)
+ return;
+
+ if (!strcmp(cmd, "clear"))
+ perf_clear(cpu);
+ else if (!strcmp(cmd, "show"))
+ perf_show(cpu);
+ else
+ unknown_command(cmd);
+}
+
static void bsp_main(void)
{
boot_done = 0;
@@ -83,8 +109,10 @@ static void bsp_main(void)
cmd_write(&tokens);
else if (!strcmp(cmd, "cache"))
cmd_cache(&tokens);
+ else if (!strcmp(cmd, "perf"))
+ cmd_perf(&tokens);
else
- print("unknown command '%s'", cmd);
+ unknown_command(cmd);
}
}
diff --git a/demo/perf.c b/demo/perf.c
new file mode 100644
index 0000000..28a20c8
--- /dev/null
+++ b/demo/perf.c
@@ -0,0 +1,60 @@
+#include "demo.h"
+
+#define PERF_BASE(n) (0x30150000 | (0x40 * (n)))
+#define PERF_CLEAR(n) (*(volatile unsigned *)PERF_BASE(n))
+#define PERF_MEM_READS(n) (*(const volatile unsigned *)PERF_BASE(n))
+#define PERF_MEM_WRITES(n) (*(const volatile unsigned *)(PERF_BASE(n) + 4))
+#define PERF_MEM_READ_CYCLES(n) (*(const volatile unsigned *)(PERF_BASE(n) + 8))
+#define PERF_MEM_WRITE_CYCLES(n) (*(const volatile unsigned *)(PERF_BASE(n) + 12))
+#define PERF_RING_READS(n) (*(const volatile unsigned *)(PERF_BASE(n) + 16))
+#define PERF_RING_INVALS(n) (*(const volatile unsigned *)(PERF_BASE(n) + 20))
+#define PERF_RING_READ_INVALS(n) (*(const volatile unsigned *)(PERF_BASE(n) + 24))
+#define PERF_RING_REPLIES(n) (*(const volatile unsigned *)(PERF_BASE(n) + 28))
+#define PERF_RING_FORWARDS(n) (*(const volatile unsigned *)(PERF_BASE(n) + 32))
+#define PERF_RING_CYCLES(n) (*(const volatile unsigned *)(PERF_BASE(n) + 36))
+#define PERF_IO_READS(n) (*(const volatile unsigned *)(PERF_BASE(n) + 40))
+#define PERF_IO_WRITES(n) (*(const volatile unsigned *)(PERF_BASE(n) + 44))
+
+#define PERF_MIN_MASK 0x0000ffff
+#define PERF_MAX_MASK 0xffff0000
+#define PERF_MAX_SHIFT 16
+
+void perf_show(unsigned cpu)
+{
+ print("dumping performance counters for cpu%u", cpu);
+
+ unsigned mem_reads = PERF_MEM_READS(cpu);
+ unsigned mem_writes = PERF_MEM_WRITES(cpu);
+ unsigned read_cycles = PERF_MEM_READ_CYCLES(cpu);
+ unsigned write_cycles = PERF_MEM_WRITE_CYCLES(cpu);
+ unsigned ring_reads = PERF_RING_READS(cpu);
+ unsigned ring_invals = PERF_RING_INVALS(cpu);
+ unsigned ring_read_invals = PERF_RING_READ_INVALS(cpu);
+ unsigned ring_replies = PERF_RING_REPLIES(cpu);
+ unsigned ring_forwards = PERF_RING_FORWARDS(cpu);
+ unsigned ring_cycles = PERF_RING_CYCLES(cpu);
+ unsigned io_reads = PERF_IO_READS(cpu);
+ unsigned io_writes = PERF_IO_WRITES(cpu);
+
+ unsigned min_ring_cycles = ring_cycles & PERF_MIN_MASK;
+ unsigned max_ring_cycles = (ring_cycles & PERF_MAX_MASK) >> PERF_MAX_SHIFT;
+ unsigned min_read_cycles = read_cycles & PERF_MIN_MASK;
+ unsigned max_read_cycles = (read_cycles & PERF_MAX_MASK) >> PERF_MAX_SHIFT;
+ unsigned min_write_cycles = write_cycles & PERF_MIN_MASK;
+ unsigned max_write_cycles = (write_cycles & PERF_MAX_MASK) >> PERF_MAX_SHIFT;
+ unsigned ring_sends = ring_reads + ring_invals + ring_read_invals;
+
+ print("requests: sends=%u forwards=%u replies=%u", ring_sends, ring_forwards, ring_replies);
+ print("requests sent: read=%u inval=%u read_inval=%u", ring_reads, ring_invals, ring_read_invals);
+ print("memory: misses=%u writebacks=%u", mem_reads, mem_writes);
+ print("uncached i/o: reads=%u writes=%u", io_reads, io_writes);
+ print("ring cycles: min=%u max=%u", min_ring_cycles, max_ring_cycles);
+ print("mem read cycles: min=%u max=%u", min_read_cycles, max_read_cycles);
+ print("mem write cycles: min=%u max=%u", min_write_cycles, max_write_cycles);
+}
+
+void perf_clear(unsigned cpu)
+{
+ PERF_CLEAR(cpu) = 0;
+ print("cleared performance counters for cpu%u", cpu);
+}
diff --git a/demo/util.c b/demo/util.c
index d08ec20..d728fac 100644
--- a/demo/util.c
+++ b/demo/util.c
@@ -7,11 +7,6 @@ static void bad_input(void)
print("bad input");
}
-static void unexpected_eof(void)
-{
- print("unexpected end-of-input");
-}
-
static int parse_cpu_token(const char *token, unsigned *cpu)
{
if (token[0] != 'c' || token[1] != 'p' || token[2] != 'u'
@@ -24,6 +19,11 @@ static int parse_cpu_token(const char *token, unsigned *cpu)
return 0;
}
+void unexpected_eof(void)
+{
+ print("unexpected end-of-input");
+}
+
int strcmp(const char *s1, const char *s2)
{
while (*s1 && *s1 == *s2)