cavatools: initialize repository
[cavatools.git] / traceinfo / traceinfo.c
1 /*
2 Copyright (c) 2020 Peter Hsu. All Rights Reserved. See LICENCE file for details.
3 */
4
5 #include <stdint.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <assert.h>
9 #include <string.h>
10 #include <time.h>
11
12 #include "caveat.h"
13 #include "opcodes.h"
14 #include "insn.h"
15 #include "shmfifo.h"
16
17 long report_frequency;
18 time_t start_tick;
19 long insn_count =0;
20 long mem_refs =0;
21 long segments =0;
22
23 struct fifo_t* trace_buffer;
24 int hart;
25 uint64_t mem_queue[tr_memq_len];
26
27
28 static inline void status_report()
29 {
30 double elapse = (clock() - start_tick) / CLOCKS_PER_SEC;
31 fprintf(stderr, "\r%3.1fB insns %3.1fB mems (%ld segments) in %3.1f seconds for %3.1f MIPS",
32 insn_count/1e9, mem_refs/1e9, segments, elapse, insn_count/1e6/elapse);
33 }
34
35
36 void stat_mem_trace(long pc)
37 {
38 long next_report =report_frequency;
39 int withregs =0;
40 for (uint64_t tr=fifo_get(trace_buffer); tr!=tr_eof; tr=fifo_get(trace_buffer)) {
41 if (is_mem(tr)) {
42 mem_refs++;
43 continue;
44 }
45 if (is_bbk(tr))
46 continue;
47 if (is_frame(tr)) {
48 hart = tr_delta(tr);
49 pc = tr_pc(tr);
50 fprintf(stderr, "Frame(pc=%d, mem=%d, reg=%d), hart#=%d, pc=0x%lx\n", (tr&tr_has_pc)!=0, (tr&tr_has_mem)!=0, (tr&tr_has_reg)!=0, hart, pc);
51 dieif(tr & tr_has_reg, "trace with register updates must be viewed with program binary");
52 ++segments;
53 continue;
54 }
55 if (tr_code(tr) == tr_icount) {
56 insn_count = tr_value(tr);
57 if (insn_count >= next_report) {
58 status_report();
59 next_report += report_frequency;
60 }
61 continue;
62 }
63 /* ignore other trace record types */
64 }
65 }
66
67
68 void stat_pc_trace(long pc)
69 {
70 long next_report =report_frequency;
71 int withregs =0;
72 for (uint64_t tr=fifo_get(trace_buffer); tr!=tr_eof; tr=fifo_get(trace_buffer)) {
73 if (is_mem(tr)) {
74 mem_refs++;
75 continue;
76 }
77 if (is_bbk(tr)) {
78 if (withregs) {
79 long epc = pc + tr_delta(tr);
80 while (pc < epc) {
81 const struct insn_t* p = insn(pc);
82 if (p->op_rd != NOREG) {
83 long val = fifo_get(trace_buffer);
84 }
85 pc += shortOp(p->op_code) ? 2 : 4;
86 }
87 }
88 else
89 pc += tr_delta(tr);
90 if (is_goto(tr))
91 pc = tr_pc(tr);
92 continue;
93 }
94 if (is_frame(tr)) {
95 hart = tr_delta(tr);
96 pc = tr_pc(tr);
97 withregs = (tr & tr_has_reg) != 0;
98 fprintf(stderr, "Frame(pc=%d, mem=%d, reg=%d), hart#=%d, pc=0x%lx\n", (tr&tr_has_pc)!=0, (tr&tr_has_mem)!=0, withregs, hart, pc);
99 ++segments;
100 continue;
101 }
102 if (tr_code(tr) == tr_icount) {
103 insn_count = tr_value(tr);
104 if (insn_count >= next_report) {
105 status_report();
106 next_report += report_frequency;
107 }
108 continue;
109 }
110 /* ignore other trace record types */
111 }
112 }
113
114 void print_listing(long pc)
115 {
116 uint64_t* memq = mem_queue; /* help compiler allocate in register */
117 long tail =0;
118 int withregs =0;
119 for (uint64_t tr=fifo_get(trace_buffer); tr!=tr_eof; tr=fifo_get(trace_buffer)) {
120 if (is_mem(tr)) {
121 memq[tail++] = tr_value(tr);
122 continue;
123 }
124 if (is_bbk(tr)) {
125 static char buf[1024];
126 char bing = is_goto(tr) ? '@' : '!';
127 long epc = pc + tr_delta(tr);
128 long head = 0;
129 while (pc < epc) {
130 const struct insn_t* p = insn(pc);
131 if (memOp(p->op_code))
132 printf("%c[%016lx]", bing, memq[head++]);
133 else if (insnAttr[p->op_code].unit == Unit_b && (pc+(shortOp(p->op_code)?2:4)) == epc)
134 printf("%c<%16lx>", bing, tr_pc(tr));
135 else
136 printf("%c %16s ", bing, "");
137 if (withregs) {
138 if (p->op_rd == NOREG && p->op_rd != 0)
139 printf("%22s", "");
140 else {
141 long val = fifo_get(trace_buffer);
142 printf("%4s=%016lx ", regName[p->op_rd], val);
143 }
144 }
145 print_pc(pc, stdout);
146 print_insn(pc, stdout);
147 ++insn_count;
148 pc += shortOp(p->op_code) ? 2 : 4;
149 bing = ' ';
150 }
151 if (is_goto(tr))
152 pc = tr_pc(tr);
153 tail = 0;
154 continue;
155 }
156 if (is_frame(tr)) {
157 hart = tr_delta(tr);
158 pc = tr_pc(tr);
159 withregs = (tr & tr_has_reg) != 0;
160 int withpc = (tr & tr_has_pc) != 0;
161 fprintf(stderr, "Frame(pc=%d, mem=%d, reg=%d, timing=%d), hart#=%d, pc=0x%lx\n", withpc, (tr&tr_has_mem)!=0, withregs, (tr&tr_has_timing)!=0, hart, pc);
162 if (!withpc) {
163 fprintf(stderr, "Cannot print listing of trace without pc!\n");
164 exit(-1);
165 }
166 continue;
167 }
168 /* ignore other trace record types */
169 }
170 }
171
172
173 long atohex(const char* p)
174 {
175 for (long n=0; ; p++) {
176 long digit;
177 if ('0' <= *p && *p <= '9')
178 digit = *p - '0';
179 else if ('a' <= *p && *p <= 'f')
180 digit = 10 + (*p - 'a');
181 else if ('A' <= *p && *p <= 'F')
182 digit = 10 + (*p - 'F');
183 else
184 return n;
185 n = 16*n + digit;
186 }
187 }
188
189 static const char* shm_path;
190 static long list;
191 static long report;
192
193 const struct options_t opt[] =
194 { { "--in=s", .s=&shm_path, .ds=0, .h="Trace file from any cavatools =name" },
195 { "--list", .b=&list, .bv=1, .h="Print assembly listing (only traces from caveat)" },
196 { "--report=i", .i=&report, .di=1000, .h="Progress report every =number million instructions" },
197 { 0 }
198 };
199 const char* usage = "traceinfo --in=trace [traceinfo-options] target-program";
200
201 int main(int argc, const char** argv)
202 {
203
204 int numopts = parse_options(argv+1);
205 if (!shm_path)
206 help_exit();
207 report_frequency = report * 1000000;
208 long entry =0;
209 if (argc > numopts+1) {
210 entry = load_elf_binary(argv[1+numopts], 0);
211 insnSpace_init();
212 }
213 trace_buffer = fifo_open(shm_path);
214 start_tick = clock();
215 if (list)
216 print_listing(entry);
217 else if (argc > numopts+1)
218 stat_pc_trace(entry);
219 else
220 stat_mem_trace(entry);
221 fifo_close(trace_buffer);
222 fprintf(stderr, "\n%ld Instructions, %ld memory references in trace\n", insn_count, mem_refs);
223 return 0;
224 }