blob: 9eb8f5fc91172199f9b0b98f47de0dbf2050f9ae [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/* Copyright (C) 2006-2007 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10** GNU General Public License for more details.
11*/
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <limits.h>
17#include <inttypes.h>
18#include <sys/stat.h>
19#include <sys/types.h>
20#include <errno.h>
21#include <sys/time.h>
22#include <time.h>
23#include "cpu.h"
24#include "exec-all.h"
25#include "trace.h"
26#include "varint.h"
David 'Digit' Turner4e024bb2010-09-22 14:19:28 +020027#include "android/utils/path.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080028
29TraceBB trace_bb;
30TraceInsn trace_insn;
31TraceStatic trace_static;
32TraceAddr trace_load;
33TraceAddr trace_store;
34TraceExc trace_exc;
35TracePid trace_pid;
36TraceMethod trace_method;
37static TraceHeader header;
38
39const char *trace_filename;
40int tracing;
41int trace_cache_miss;
42int trace_all_addr;
43
44// The simulation time in cpu clock cycles
45uint64_t sim_time = 1;
46
47// The current process id
48int current_pid;
49
50// The start and end (wall-clock) time in microseconds
51uint64_t start_time, end_time;
52uint64_t elapsed_usecs;
53
54// For debugging output
55FILE *ftrace_debug;
56
57// The maximum number of bytes consumed by an InsnRec after compression.
58// This is very conservative but needed to ensure no buffer overflows.
59#define kMaxInsnCompressed 14
60
61// The maximum number of bytes consumed by an BBRec after compression.
62// This is very conservative but needed to ensure no buffer overflows.
63#define kMaxBBCompressed 32
64
65// The maximum number of bytes consumed by an AddrRec after compression.
66// This is very conservative but needed to ensure no buffer overflows.
67#define kMaxAddrCompressed 14
68
69// The maximum number of bytes consumed by a MethodRec after compression.
70// This is very conservative but needed to ensure no buffer overflows.
71#define kMaxMethodCompressed 18
72
73// The maximum number of bytes consumed by an exception record after
74// compression.
75#define kMaxExcCompressed 38
76
77// The maximum number of bytes consumed by a pid record for
78// kPidSwitch, or kPidExit after compression.
79#define kMaxPidCompressed 15
80
81// The maximum number of bytes consumed by a pid record for kPidFork,
82// or kPidClone after compression.
83#define kMaxPid2Compressed 20
84
85// The maximum number of bytes consumed by a pid record for kPidExecArgs
86// after compression, not counting the bytes for the args.
87#define kMaxExecArgsCompressed 15
88
89// The maximum number of bytes consumed by a pid record for kPidName
90// after compression, not counting the bytes for the name.
91#define kMaxNameCompressed 20
92
93// The maximum number of bytes consumed by a pid record for kPidMmap
94// after compression, not counting the bytes for the pathname.
95#define kMaxMmapCompressed 33
96
97// The maximum number of bytes consumed by a pid record for kPidMunmap,
98// after compression.
99#define kMaxMunmapCompressed 28
100
101// The maximum number of bytes consumed by a pid record for kPidSymbol
102// after compression, not counting the bytes for the symbol name.
103#define kMaxSymbolCompressed 24
104
105// The maximum number of bytes consumed by a pid record for kPidKthreadName
106// after compression, not counting the bytes for the name.
107#define kMaxKthreadNameCompressed 25
108
109void trace_cleanup();
110
111// Return current time in microseconds as a 64-bit integer.
112uint64 Now() {
113 struct timeval tv;
114
115 gettimeofday(&tv, NULL);
116 uint64 val = tv.tv_sec;
117 val = val * 1000000ull + tv.tv_usec;
118 return val;
119}
120
121static void create_trace_dir(const char *dirname)
122{
123 int err;
124
125 err = path_mkdir(dirname, 0755);
126 if (err != 0 && errno != EEXIST) {
127 printf("err: %d\n", err);
128 perror(dirname);
129 exit(1);
130 }
131}
132
133static char *create_trace_path(const char *filename, const char *ext)
134{
135 char *fname;
136 const char *base_start, *base_end;
137 int ii, len, base_len, dir_len, path_len, qtrace_len;
138
139 // Handle error cases
140 if (filename == NULL || *filename == 0 || strcmp(filename, "/") == 0)
141 return NULL;
142
143 // Ignore a trailing slash, if any
144 len = strlen(filename);
145 if (filename[len - 1] == '/')
146 len -= 1;
147
148 // Find the basename. We don't use basename(3) because there are
149 // different behaviors for GNU and Posix in the case where the
150 // last character is a slash.
151 base_start = base_end = &filename[len];
152 for (ii = 0; ii < len; ++ii) {
153 base_start -= 1;
154 if (*base_start == '/') {
155 base_start += 1;
156 break;
157 }
158 }
159 base_len = base_end - base_start;
160 dir_len = len - base_len;
161 qtrace_len = strlen("/qtrace");
162
163 // Create space for the pathname: "/dir/basename/qtrace.ext"
164 // The "ext" string already contains the dot, so just add a byte
165 // for the terminating zero.
166 path_len = dir_len + base_len + qtrace_len + strlen(ext) + 1;
167 fname = malloc(path_len);
168 if (dir_len > 0)
169 strncpy(fname, filename, dir_len);
170 fname[dir_len] = 0;
171 strncat(fname, base_start, base_len);
172 strcat(fname, "/qtrace");
173 strcat(fname, ext);
174 return fname;
175}
176
177void convert_secs_to_date_time(time_t secs, uint32_t *pdate, uint32_t *ptime)
178{
179 struct tm *tm = localtime(&secs);
180 uint32_t year = tm->tm_year + 1900;
181 uint32_t thousands = year / 1000;
182 year -= thousands * 1000;
183 uint32_t hundreds = year / 100;
184 year -= hundreds * 100;
185 uint32_t tens = year / 10;
186 year -= tens * 10;
187 uint32_t ones = year;
188 year = (thousands << 12) | (hundreds << 8) | (tens << 4) | ones;
189
190 uint32_t mon = tm->tm_mon + 1;
191 tens = mon / 10;
192 ones = (mon - tens * 10);
193 mon = (tens << 4) | ones;
194
195 uint32_t day = tm->tm_mday;
196 tens = day / 10;
197 ones = (day - tens * 10);
198 day = (tens << 4) | ones;
199
200 *pdate = (year << 16) | (mon << 8) | day;
201
202 uint32_t hour = tm->tm_hour;
203 tens = hour / 10;
204 ones = (hour - tens * 10);
205 hour = (tens << 4) | ones;
206
207 uint32_t min = tm->tm_min;
208 tens = min / 10;
209 ones = (min - tens * 10);
210 min = (tens << 4) | ones;
211
212 uint32_t sec = tm->tm_sec;
213 tens = sec / 10;
214 ones = (sec - tens * 10);
215 sec = (tens << 4) | ones;
216
217 *ptime = (hour << 16) | (min << 8) | sec;
218}
219
220void write_trace_header(TraceHeader *header)
221{
222 TraceHeader swappedHeader;
223
224 memcpy(&swappedHeader, header, sizeof(TraceHeader));
225
226 convert32(swappedHeader.version);
227 convert32(swappedHeader.start_sec);
228 convert32(swappedHeader.start_usec);
229 convert32(swappedHeader.pdate);
230 convert32(swappedHeader.ptime);
231 convert32(swappedHeader.num_used_pids);
232 convert32(swappedHeader.first_unused_pid);
233 convert64(swappedHeader.num_static_bb);
234 convert64(swappedHeader.num_static_insn);
235 convert64(swappedHeader.num_dynamic_bb);
236 convert64(swappedHeader.num_dynamic_insn);
237 convert64(swappedHeader.elapsed_usecs);
238
239 fwrite(&swappedHeader, sizeof(TraceHeader), 1, trace_static.fstream);
240}
241
242void create_trace_bb(const char *filename)
243{
244 char *fname = create_trace_path(filename, ".bb");
245 trace_bb.filename = fname;
246
247 FILE *fstream = fopen(fname, "wb");
248 if (fstream == NULL) {
249 perror(fname);
250 exit(1);
251 }
252 trace_bb.fstream = fstream;
253 trace_bb.next = &trace_bb.buffer[0];
254 trace_bb.flush_time = 0;
255 trace_bb.compressed_ptr = trace_bb.compressed;
256 trace_bb.high_water_ptr = &trace_bb.compressed[kCompressedSize] - kMaxBBCompressed;
257 trace_bb.prev_bb_num = 0;
258 trace_bb.prev_bb_time = 0;
259 trace_bb.num_insns = 0;
260 trace_bb.recnum = 0;
261}
262
263void create_trace_insn(const char *filename)
264{
265 // Create the instruction time trace file
266 char *fname = create_trace_path(filename, ".insn");
267 trace_insn.filename = fname;
268
269 FILE *fstream = fopen(fname, "wb");
270 if (fstream == NULL) {
271 perror(fname);
272 exit(1);
273 }
274 trace_insn.fstream = fstream;
275 trace_insn.current = &trace_insn.dummy;
276 trace_insn.dummy.time_diff = 0;
277 trace_insn.dummy.repeat = 0;
278 trace_insn.prev_time = 0;
279 trace_insn.compressed_ptr = trace_insn.compressed;
280 trace_insn.high_water_ptr = &trace_insn.compressed[kCompressedSize] - kMaxInsnCompressed;
281}
282
283void create_trace_static(const char *filename)
284{
285 // Create the static basic block trace file
286 char *fname = create_trace_path(filename, ".static");
287 trace_static.filename = fname;
288
289 FILE *fstream = fopen(fname, "wb");
290 if (fstream == NULL) {
291 perror(fname);
292 exit(1);
293 }
294 trace_static.fstream = fstream;
295 trace_static.next_insn = 0;
296 trace_static.bb_num = 1;
297 trace_static.bb_addr = 0;
298
299 // Write an empty header to reserve space for it in the file.
300 // The header will be filled in later when post-processing the
301 // trace file.
302 memset(&header, 0, sizeof(TraceHeader));
303
304 // Write out the version number so that tools can detect if the trace
305 // file format is the same as what they expect.
306 header.version = TRACE_VERSION;
307
308 // Record the start time in the header now.
309 struct timeval tv;
310 struct timezone tz;
311 gettimeofday(&tv, &tz);
312 header.start_sec = tv.tv_sec;
313 header.start_usec = tv.tv_usec;
314 convert_secs_to_date_time(header.start_sec, &header.pdate, &header.ptime);
315 write_trace_header(&header);
316
317 // Write out the record for the unused basic block number 0.
318 uint64_t zero = 0;
319 fwrite(&zero, sizeof(uint64_t), 1, trace_static.fstream); // bb_num
320 fwrite(&zero, sizeof(uint32_t), 1, trace_static.fstream); // bb_addr
321 fwrite(&zero, sizeof(uint32_t), 1, trace_static.fstream); // num_insns
322}
323
324void create_trace_addr(const char *filename)
325{
326 // The "qtrace.load" and "qtrace.store" files are optional
327 trace_load.fstream = NULL;
328 trace_store.fstream = NULL;
329 if (trace_all_addr || trace_cache_miss) {
330 // Create the "qtrace.load" file
331 char *fname = create_trace_path(filename, ".load");
332 trace_load.filename = fname;
333
334 FILE *fstream = fopen(fname, "wb");
335 if (fstream == NULL) {
336 perror(fname);
337 exit(1);
338 }
339 trace_load.fstream = fstream;
340 trace_load.next = &trace_load.buffer[0];
341 trace_load.compressed_ptr = trace_load.compressed;
342 trace_load.high_water_ptr = &trace_load.compressed[kCompressedSize] - kMaxAddrCompressed;
343 trace_load.prev_addr = 0;
344 trace_load.prev_time = 0;
345
346 // Create the "qtrace.store" file
347 fname = create_trace_path(filename, ".store");
348 trace_store.filename = fname;
349
350 fstream = fopen(fname, "wb");
351 if (fstream == NULL) {
352 perror(fname);
353 exit(1);
354 }
355 trace_store.fstream = fstream;
356 trace_store.next = &trace_store.buffer[0];
357 trace_store.compressed_ptr = trace_store.compressed;
358 trace_store.high_water_ptr = &trace_store.compressed[kCompressedSize] - kMaxAddrCompressed;
359 trace_store.prev_addr = 0;
360 trace_store.prev_time = 0;
361 }
362}
363
364void create_trace_exc(const char *filename)
365{
366 // Create the exception trace file
367 char *fname = create_trace_path(filename, ".exc");
368 trace_exc.filename = fname;
369
370 FILE *fstream = fopen(fname, "wb");
371 if (fstream == NULL) {
372 perror(fname);
373 exit(1);
374 }
375 trace_exc.fstream = fstream;
376 trace_exc.compressed_ptr = trace_exc.compressed;
377 trace_exc.high_water_ptr = &trace_exc.compressed[kCompressedSize] - kMaxExcCompressed;
378 trace_exc.prev_time = 0;
379 trace_exc.prev_bb_recnum = 0;
380}
381
382void create_trace_pid(const char *filename)
383{
384 // Create the pid trace file
385 char *fname = create_trace_path(filename, ".pid");
386 trace_pid.filename = fname;
387
388 FILE *fstream = fopen(fname, "wb");
389 if (fstream == NULL) {
390 perror(fname);
391 exit(1);
392 }
393 trace_pid.fstream = fstream;
394 trace_pid.compressed_ptr = trace_pid.compressed;
395 trace_pid.prev_time = 0;
396}
397
398void create_trace_method(const char *filename)
399{
400 // Create the method trace file
401 char *fname = create_trace_path(filename, ".method");
402 trace_method.filename = fname;
403
404 FILE *fstream = fopen(fname, "wb");
405 if (fstream == NULL) {
406 perror(fname);
407 exit(1);
408 }
409 trace_method.fstream = fstream;
410 trace_method.compressed_ptr = trace_method.compressed;
411 trace_method.prev_time = 0;
412 trace_method.prev_addr = 0;
413 trace_method.prev_pid = 0;
414}
415
416void trace_init(const char *filename)
417{
418 // Create the trace files
419 create_trace_dir(filename);
420 create_trace_bb(filename);
421 create_trace_insn(filename);
422 create_trace_static(filename);
423 create_trace_addr(filename);
424 create_trace_exc(filename);
425 create_trace_pid(filename);
426 create_trace_method(filename);
427
428#if 0
429 char *fname = create_trace_path(filename, ".debug");
430 ftrace_debug = fopen(fname, "wb");
431 if (ftrace_debug == NULL) {
432 perror(fname);
433 exit(1);
434 }
435#else
436 ftrace_debug = NULL;
437#endif
438 atexit(trace_cleanup);
439
440 // If tracing is on, then start timing the simulator
441 if (tracing)
442 start_time = Now();
443}
444
445/* the following array is used to deal with def-use register interlocks, which we
446 * can compute statically (ignoring conditions), very fortunately.
447 *
448 * the idea is that interlock_base contains the number of cycles "executed" from
449 * the start of a basic block. It is set to 0 in trace_bb_start, and incremented
450 * in each call to get_insn_ticks_arm.
451 *
452 * interlocks[N] correspond to the value of interlock_base after which a register N
453 * can be used by another operation, it is set each time an instruction writes to
454 * the register in get_insn_ticks()
455 */
456
457static int interlocks[16];
458static int interlock_base;
459
460static void
461_interlock_def(int reg, int delay)
462{
463 if (reg >= 0)
464 interlocks[reg] = interlock_base + delay;
465}
466
467static int
468_interlock_use(int reg)
469{
470 int delay = 0;
471
472 if (reg >= 0)
473 {
474 delay = interlocks[reg] - interlock_base;
475 if (delay < 0)
476 delay = 0;
477 }
478 return delay;
479}
480
481void trace_bb_start(uint32_t bb_addr)
482{
483 int nn;
484
485 trace_static.bb_addr = bb_addr;
486 trace_static.is_thumb = 0;
487
488 interlock_base = 0;
489 for (nn = 0; nn < 16; nn++)
490 interlocks[nn] = 0;
491}
492
493void trace_add_insn(uint32_t insn, int is_thumb)
494{
495 trace_static.insns[trace_static.next_insn++] = insn;
496 // This relies on the fact that a basic block does not contain a mix
497 // of ARM and Thumb instructions. If that is not true, then many
498 // software tools that read the trace will have to change.
499 trace_static.is_thumb = is_thumb;
500}
501
502void trace_bb_end()
503{
504 int ii, num_insns;
505 uint32_t insn;
506
507 uint64_t bb_num = hostToLE64(trace_static.bb_num);
508 // If these are Thumb instructions, then encode that fact by setting
509 // the low bit of the basic-block address to 1.
510 uint32_t bb_addr = trace_static.bb_addr | trace_static.is_thumb;
511 bb_addr = hostToLE32(bb_addr);
512 num_insns = hostToLE32(trace_static.next_insn);
513 fwrite(&bb_num, sizeof(bb_num), 1, trace_static.fstream);
514 fwrite(&bb_addr, sizeof(bb_addr), 1, trace_static.fstream);
515 fwrite(&num_insns, sizeof(num_insns), 1, trace_static.fstream);
516 for (ii = 0; ii < trace_static.next_insn; ++ii) {
517 insn = hostToLE32(trace_static.insns[ii]);
518 fwrite(&insn, sizeof(insn), 1, trace_static.fstream);
519 }
520
521 trace_static.bb_num += 1;
522 trace_static.next_insn = 0;
523}
524
525void trace_cleanup()
526{
527 if (tracing) {
528 end_time = Now();
529 elapsed_usecs += end_time - start_time;
530 }
531 header.elapsed_usecs = elapsed_usecs;
532 double elapsed_secs = elapsed_usecs / 1000000.0;
533 double cycles_per_sec = 0;
534 if (elapsed_secs != 0)
535 cycles_per_sec = sim_time / elapsed_secs;
536 char *suffix = "";
537 if (cycles_per_sec >= 1000000) {
538 cycles_per_sec /= 1000000.0;
539 suffix = "M";
540 } else if (cycles_per_sec > 1000) {
541 cycles_per_sec /= 1000.0;
542 suffix = "K";
543 }
544 printf("Elapsed seconds: %.2f, simulated cycles/sec: %.1f%s\n",
545 elapsed_secs, cycles_per_sec, suffix);
546 if (trace_bb.fstream) {
547 BBRec *ptr;
548 BBRec *next = trace_bb.next;
549 char *comp_ptr = trace_bb.compressed_ptr;
550 int64_t prev_bb_num = trace_bb.prev_bb_num;
551 uint64_t prev_bb_time = trace_bb.prev_bb_time;
552 for (ptr = trace_bb.buffer; ptr != next; ++ptr) {
553 if (comp_ptr >= trace_bb.high_water_ptr) {
554 uint32_t size = comp_ptr - trace_bb.compressed;
555 fwrite(trace_bb.compressed, sizeof(char), size,
556 trace_bb.fstream);
557 comp_ptr = trace_bb.compressed;
558 }
559 int64_t bb_diff = ptr->bb_num - prev_bb_num;
560 prev_bb_num = ptr->bb_num;
561 uint64_t time_diff = ptr->start_time - prev_bb_time;
562 prev_bb_time = ptr->start_time;
563 comp_ptr = varint_encode_signed(bb_diff, comp_ptr);
564 comp_ptr = varint_encode(time_diff, comp_ptr);
565 comp_ptr = varint_encode(ptr->repeat, comp_ptr);
566 if (ptr->repeat)
567 comp_ptr = varint_encode(ptr->time_diff, comp_ptr);
568 }
569
570 // Add an extra record at the end containing the ending simulation
571 // time and a basic block number of 0.
572 uint64_t time_diff = sim_time - prev_bb_time;
573 if (time_diff > 0) {
574 int64_t bb_diff = -prev_bb_num;
575 comp_ptr = varint_encode_signed(bb_diff, comp_ptr);
576 comp_ptr = varint_encode(time_diff, comp_ptr);
577 comp_ptr = varint_encode(0, comp_ptr);
578 }
579
580 uint32_t size = comp_ptr - trace_bb.compressed;
581 if (size)
582 fwrite(trace_bb.compressed, sizeof(char), size, trace_bb.fstream);
583
584 // Terminate the file with three zeros so that we can detect
585 // the end of file quickly.
586 uint32_t zeros = 0;
587 fwrite(&zeros, 3, 1, trace_bb.fstream);
588 fclose(trace_bb.fstream);
589 }
590
591 if (trace_insn.fstream) {
592 InsnRec *ptr;
593 InsnRec *current = trace_insn.current + 1;
594 char *comp_ptr = trace_insn.compressed_ptr;
595 for (ptr = trace_insn.buffer; ptr != current; ++ptr) {
596 if (comp_ptr >= trace_insn.high_water_ptr) {
597 uint32_t size = comp_ptr - trace_insn.compressed;
598 uint32_t rval = fwrite(trace_insn.compressed, sizeof(char),
599 size, trace_insn.fstream);
600 if (rval != size) {
601 fprintf(stderr, "fwrite() failed\n");
602 perror(trace_insn.filename);
603 exit(1);
604 }
605 comp_ptr = trace_insn.compressed;
606 }
607 comp_ptr = varint_encode(ptr->time_diff, comp_ptr);
608 comp_ptr = varint_encode(ptr->repeat, comp_ptr);
609 }
610
611 uint32_t size = comp_ptr - trace_insn.compressed;
612 if (size) {
613 uint32_t rval = fwrite(trace_insn.compressed, sizeof(char), size,
614 trace_insn.fstream);
615 if (rval != size) {
616 fprintf(stderr, "fwrite() failed\n");
617 perror(trace_insn.filename);
618 exit(1);
619 }
620 }
621 fclose(trace_insn.fstream);
622 }
623
624 if (trace_static.fstream) {
625 fseek(trace_static.fstream, 0, SEEK_SET);
626 write_trace_header(&header);
627 fclose(trace_static.fstream);
628 }
629
630 if (trace_load.fstream) {
631 AddrRec *ptr;
632 char *comp_ptr = trace_load.compressed_ptr;
633 AddrRec *next = trace_load.next;
634 uint32_t prev_addr = trace_load.prev_addr;
635 uint64_t prev_time = trace_load.prev_time;
636 for (ptr = trace_load.buffer; ptr != next; ++ptr) {
637 if (comp_ptr >= trace_load.high_water_ptr) {
638 uint32_t size = comp_ptr - trace_load.compressed;
639 fwrite(trace_load.compressed, sizeof(char), size,
640 trace_load.fstream);
641 comp_ptr = trace_load.compressed;
642 }
643
644 int addr_diff = ptr->addr - prev_addr;
645 uint64_t time_diff = ptr->time - prev_time;
646 prev_addr = ptr->addr;
647 prev_time = ptr->time;
648
649 comp_ptr = varint_encode_signed(addr_diff, comp_ptr);
650 comp_ptr = varint_encode(time_diff, comp_ptr);
651 }
652
653 uint32_t size = comp_ptr - trace_load.compressed;
654 if (size) {
655 fwrite(trace_load.compressed, sizeof(char), size,
656 trace_load.fstream);
657 }
658
659 // Terminate the file with two zeros so that we can detect
660 // the end of file quickly.
661 uint32_t zeros = 0;
662 fwrite(&zeros, 2, 1, trace_load.fstream);
663 fclose(trace_load.fstream);
664 }
665
666 if (trace_store.fstream) {
667 AddrRec *ptr;
668 char *comp_ptr = trace_store.compressed_ptr;
669 AddrRec *next = trace_store.next;
670 uint32_t prev_addr = trace_store.prev_addr;
671 uint64_t prev_time = trace_store.prev_time;
672 for (ptr = trace_store.buffer; ptr != next; ++ptr) {
673 if (comp_ptr >= trace_store.high_water_ptr) {
674 uint32_t size = comp_ptr - trace_store.compressed;
675 fwrite(trace_store.compressed, sizeof(char), size,
676 trace_store.fstream);
677 comp_ptr = trace_store.compressed;
678 }
679
680 int addr_diff = ptr->addr - prev_addr;
681 uint64_t time_diff = ptr->time - prev_time;
682 prev_addr = ptr->addr;
683 prev_time = ptr->time;
684
685 comp_ptr = varint_encode_signed(addr_diff, comp_ptr);
686 comp_ptr = varint_encode(time_diff, comp_ptr);
687 }
688
689 uint32_t size = comp_ptr - trace_store.compressed;
690 if (size) {
691 fwrite(trace_store.compressed, sizeof(char), size,
692 trace_store.fstream);
693 }
694
695 // Terminate the file with two zeros so that we can detect
696 // the end of file quickly.
697 uint32_t zeros = 0;
698 fwrite(&zeros, 2, 1, trace_store.fstream);
699 fclose(trace_store.fstream);
700 }
701
702 if (trace_exc.fstream) {
703 uint32_t size = trace_exc.compressed_ptr - trace_exc.compressed;
704 if (size) {
705 fwrite(trace_exc.compressed, sizeof(char), size,
706 trace_exc.fstream);
707 }
708
709 // Terminate the file with 7 zeros so that we can detect
710 // the end of file quickly.
711 uint64_t zeros = 0;
712 fwrite(&zeros, 7, 1, trace_exc.fstream);
713 fclose(trace_exc.fstream);
714 }
715 if (trace_pid.fstream) {
716 uint32_t size = trace_pid.compressed_ptr - trace_pid.compressed;
717 if (size) {
718 fwrite(trace_pid.compressed, sizeof(char), size,
719 trace_pid.fstream);
720 }
721
722 // Terminate the file with 2 zeros so that we can detect
723 // the end of file quickly.
724 uint64_t zeros = 0;
725 fwrite(&zeros, 2, 1, trace_pid.fstream);
726 fclose(trace_pid.fstream);
727 }
728 if (trace_method.fstream) {
729 uint32_t size = trace_method.compressed_ptr - trace_method.compressed;
730 if (size) {
731 fwrite(trace_method.compressed, sizeof(char), size,
732 trace_method.fstream);
733 }
734
735 // Terminate the file with 2 zeros so that we can detect
736 // the end of file quickly.
737 uint64_t zeros = 0;
738 fwrite(&zeros, 2, 1, trace_method.fstream);
739 fclose(trace_method.fstream);
740 }
741 if (ftrace_debug)
742 fclose(ftrace_debug);
743}
744
745// Define the number of clock ticks for some instructions. Add one to these
746// (in some cases) if there is an interlock. We currently do not check for
747// interlocks.
748#define TICKS_OTHER 1
749#define TICKS_SMULxy 1
750#define TICKS_SMLAWy 1
751#define TICKS_SMLALxy 2
752#define TICKS_MUL 2
753#define TICKS_MLA 2
754#define TICKS_MULS 4 // no interlock penalty
755#define TICKS_MLAS 4 // no interlock penalty
756#define TICKS_UMULL 3
757#define TICKS_UMLAL 3
758#define TICKS_SMULL 3
759#define TICKS_SMLAL 3
760#define TICKS_UMULLS 5 // no interlock penalty
761#define TICKS_UMLALS 5 // no interlock penalty
762#define TICKS_SMULLS 5 // no interlock penalty
763#define TICKS_SMLALS 5 // no interlock penalty
764
765// Compute the number of cycles that this instruction will take,
766// not including any I-cache or D-cache misses. This function
767// is called for each instruction in a basic block when that
768// block is being translated.
769int get_insn_ticks_arm(uint32_t insn)
770{
771#if 1
772 int result = 1; /* by default, use 1 cycle */
773
774 /* See Chapter 12 of the ARM920T Reference Manual for details about clock cycles */
775
776 /* first check for invalid condition codes */
777 if ((insn >> 28) == 0xf)
778 {
779 if ((insn >> 25) == 0x7d) { /* BLX */
780 result = 3;
781 goto Exit;
782 }
783 /* XXX: if we get there, we're either in an UNDEFINED instruction */
784 /* or in co-processor related ones. For now, only return 1 cycle */
785 goto Exit;
786 }
787
788 /* other cases */
789 switch ((insn >> 25) & 7)
790 {
791 case 0:
792 if ((insn & 0x00000090) == 0x00000090) /* Multiplies, extra load/store, Table 3-2 */
793 {
794 /* XXX: TODO: Add support for multiplier operand content penalties in the translator */
795
796 if ((insn & 0x0fc000f0) == 0x00000090) /* 3-2: Multiply (accumulate) */
797 {
798 int Rm = (insn & 15);
799 int Rs = (insn >> 8) & 15;
800 int Rn = (insn >> 12) & 15;
801
802 if ((insn & 0x00200000) != 0) { /* MLA */
803 result += _interlock_use(Rn);
804 } else { /* MLU */
805 if (Rn != 0) /* UNDEFINED */
806 goto Exit;
807 }
808 /* cycles=2+m, assume m=1, this should be adjusted at interpretation time */
809 result += 2 + _interlock_use(Rm) + _interlock_use(Rs);
810 }
811 else if ((insn & 0x0f8000f0) == 0x00800090) /* 3-2: Multiply (accumulate) long */
812 {
813 int Rm = (insn & 15);
814 int Rs = (insn >> 8) & 15;
815 int RdLo = (insn >> 12) & 15;
816 int RdHi = (insn >> 16) & 15;
817
818 if ((insn & 0x00200000) != 0) { /* SMLAL & UMLAL */
819 result += _interlock_use(RdLo) + _interlock_use(RdHi);
820 }
821 /* else SMLL and UMLL */
822
823 /* cucles=3+m, assume m=1, this should be adjusted at interpretation time */
824 result += 3 + _interlock_use(Rm) + _interlock_use(Rs);
825 }
826 else if ((insn & 0x0fd00ff0) == 0x01000090) /* 3-2: Swap/swap byte */
827 {
828 int Rm = (insn & 15);
829 int Rd = (insn >> 8) & 15;
830
831 result = 2 + _interlock_use(Rm);
832 _interlock_def(Rd, result+1);
833 }
834 else if ((insn & 0x0e400ff0) == 0x00000090) /* 3-2: load/store halfword, reg offset */
835 {
836 int Rm = (insn & 15);
837 int Rd = (insn >> 12) & 15;
838 int Rn = (insn >> 16) & 15;
839
840 result += _interlock_use(Rn) + _interlock_use(Rm);
841 if ((insn & 0x00100000) != 0) /* it's a load, there's a 2-cycle interlock */
842 _interlock_def(Rd, result+2);
843 }
844 else if ((insn & 0x0e400ff0) == 0x00400090) /* 3-2: load/store halfword, imm offset */
845 {
846 int Rd = (insn >> 12) & 15;
847 int Rn = (insn >> 16) & 15;
848
849 result += _interlock_use(Rn);
850 if ((insn & 0x00100000) != 0) /* it's a load, there's a 2-cycle interlock */
851 _interlock_def(Rd, result+2);
852 }
853 else if ((insn & 0x0e500fd0) == 0x000000d0) /* 3-2: load/store two words, reg offset */
854 {
855 /* XXX: TODO: Enhanced DSP instructions */
856 }
857 else if ((insn & 0x0e500fd0) == 0x001000d0) /* 3-2: load/store half/byte, reg offset */
858 {
859 int Rm = (insn & 15);
860 int Rd = (insn >> 12) & 15;
861 int Rn = (insn >> 16) & 15;
862
863 result += _interlock_use(Rn) + _interlock_use(Rm);
864 if ((insn & 0x00100000) != 0) /* load, 2-cycle interlock */
865 _interlock_def(Rd, result+2);
866 }
867 else if ((insn & 0x0e5000d0) == 0x004000d0) /* 3-2: load/store two words, imm offset */
868 {
869 /* XXX: TODO: Enhanced DSP instructions */
870 }
871 else if ((insn & 0x0e5000d0) == 0x005000d0) /* 3-2: load/store half/byte, imm offset */
872 {
873 int Rd = (insn >> 12) & 15;
874 int Rn = (insn >> 16) & 15;
875
876 result += _interlock_use(Rn);
877 if ((insn & 0x00100000) != 0) /* load, 2-cycle interlock */
878 _interlock_def(Rd, result+2);
879 }
880 else
881 {
882 /* UNDEFINED */
883 }
884 }
885 else if ((insn & 0x0f900000) == 0x01000000) /* Misc. instructions, table 3-3 */
886 {
887 switch ((insn >> 4) & 15)
888 {
889 case 0:
890 if ((insn & 0x0fb0fff0) == 0x0120f000) /* move register to status register */
891 {
892 int Rm = (insn & 15);
893 result += _interlock_use(Rm);
894 }
895 break;
896
897 case 1:
898 if ( ((insn & 0x0ffffff0) == 0x01200010) || /* branch/exchange */
899 ((insn & 0x0fff0ff0) == 0x01600010) ) /* count leading zeroes */
900 {
901 int Rm = (insn & 15);
902 result += _interlock_use(Rm);
903 }
904 break;
905
906 case 3:
907 if ((insn & 0x0ffffff0) == 0x01200030) /* link/exchange */
908 {
909 int Rm = (insn & 15);
910 result += _interlock_use(Rm);
911 }
912 break;
913
914 default:
915 /* TODO: Enhanced DSP instructions */
916 ;
917 }
918 }
919 else /* Data processing */
920 {
921 int Rm = (insn & 15);
922 int Rn = (insn >> 16) & 15;
923
924 result += _interlock_use(Rn) + _interlock_use(Rm);
925 if ((insn & 0x10)) { /* register-controlled shift => 1 cycle penalty */
926 int Rs = (insn >> 8) & 15;
927 result += 1 + _interlock_use(Rs);
928 }
929 }
930 break;
931
932 case 1:
933 if ((insn & 0x01900000) == 0x01900000)
934 {
935 /* either UNDEFINED or move immediate to CPSR */
936 }
937 else /* Data processing immediate */
938 {
939 int Rn = (insn >> 12) & 15;
940 result += _interlock_use(Rn);
941 }
942 break;
943
944 case 2: /* load/store immediate */
945 {
946 int Rn = (insn >> 16) & 15;
947
948 result += _interlock_use(Rn);
949 if (insn & 0x00100000) { /* LDR */
950 int Rd = (insn >> 12) & 15;
951
952 if (Rd == 15) /* loading PC */
953 result = 5;
954 else
955 _interlock_def(Rd,result+1);
956 }
957 }
958 break;
959
960 case 3:
961 if ((insn & 0x10) == 0) /* load/store register offset */
962 {
963 int Rm = (insn & 15);
964 int Rn = (insn >> 16) & 15;
965
966 result += _interlock_use(Rm) + _interlock_use(Rn);
967
968 if (insn & 0x00100000) { /* LDR */
969 int Rd = (insn >> 12) & 15;
970 if (Rd == 15)
971 result = 5;
972 else
973 _interlock_def(Rd,result+1);
974 }
975 }
976 /* else UNDEFINED */
977 break;
978
979 case 4: /* load/store multiple */
980 {
981 int Rn = (insn >> 16) & 15;
982 uint32_t mask = (insn & 0xffff);
983 int count;
984
985 for (count = 0; mask; count++)
986 mask &= (mask-1);
987
988 result += _interlock_use(Rn);
989
990 if (insn & 0x00100000) /* LDM */
991 {
992 int nn;
993
994 if (insn & 0x8000) { /* loading PC */
995 result = count+4;
996 } else { /* not loading PC */
997 result = (count < 2) ? 2 : count;
998 }
999 /* create defs, all registers locked until the end of the load */
1000 for (nn = 0; nn < 15; nn++)
1001 if ((insn & (1U << nn)) != 0)
1002 _interlock_def(nn,result);
1003 }
1004 else /* STM */
1005 result = (count < 2) ? 2 : count;
1006 }
1007 break;
1008
1009 case 5: /* branch and branch+link */
1010 break;
1011
1012 case 6: /* coprocessor load/store */
1013 {
1014 int Rn = (insn >> 16) & 15;
1015
1016 if (insn & 0x00100000)
1017 result += _interlock_use(Rn);
1018
1019 /* XXX: other things to do ? */
1020 }
1021 break;
1022
1023 default: /* i.e. 7 */
1024 /* XXX: TODO: co-processor related things */
1025 ;
1026 }
1027Exit:
1028 interlock_base += result;
1029 return result;
1030#else /* old code - this seems to be completely buggy ?? */
1031 if ((insn & 0x0ff0f090) == 0x01600080) {
1032 return TICKS_SMULxy;
1033 } else if ((insn & 0x0ff00090) == 0x01200080) {
1034 return TICKS_SMLAWy;
1035 } else if ((insn & 0x0ff00090) == 0x01400080) {
1036 return TICKS_SMLALxy;
1037 } else if ((insn & 0x0f0000f0) == 0x00000090) {
1038 // multiply
1039 uint8_t bit23 = (insn >> 23) & 0x1;
1040 uint8_t bit22_U = (insn >> 22) & 0x1;
1041 uint8_t bit21_A = (insn >> 21) & 0x1;
1042 uint8_t bit20_S = (insn >> 20) & 0x1;
1043
1044 if (bit23 == 0) {
1045 // 32-bit multiply
1046 if (bit22_U != 0) {
1047 // This is an unexpected bit pattern.
1048 return TICKS_OTHER;
1049 }
1050 if (bit21_A == 0) {
1051 if (bit20_S)
1052 return TICKS_MULS;
1053 return TICKS_MUL;
1054 }
1055 if (bit20_S)
1056 return TICKS_MLAS;
1057 return TICKS_MLA;
1058 }
1059 // 64-bit multiply
1060 if (bit22_U == 0) {
1061 // Unsigned multiply long
1062 if (bit21_A == 0) {
1063 if (bit20_S)
1064 return TICKS_UMULLS;
1065 return TICKS_UMULL;
1066 }
1067 if (bit20_S)
1068 return TICKS_UMLALS;
1069 return TICKS_UMLAL;
1070 }
1071 // Signed multiply long
1072 if (bit21_A == 0) {
1073 if (bit20_S)
1074 return TICKS_SMULLS;
1075 return TICKS_SMULL;
1076 }
1077 if (bit20_S)
1078 return TICKS_SMLALS;
1079 return TICKS_SMLAL;
1080 }
1081 return TICKS_OTHER;
1082#endif
1083}
1084
1085int get_insn_ticks_thumb(uint32_t insn)
1086{
1087#if 1
1088 int result = 1;
1089
1090 switch ((insn >> 11) & 31)
1091 {
1092 case 0:
1093 case 1:
1094 case 2: /* Shift by immediate */
1095 {
1096 int Rm = (insn >> 3) & 7;
1097 result += _interlock_use(Rm);
1098 }
1099 break;
1100
1101 case 3: /* Add/Substract */
1102 {
1103 int Rn = (insn >> 3) & 7;
1104 result += _interlock_use(Rn);
1105
1106 if ((insn & 0x0400) == 0) { /* register value */
1107 int Rm = (insn >> 6) & 7;
1108 result += _interlock_use(Rm);
1109 }
1110 }
1111 break;
1112
1113 case 4: /* move immediate */
1114 break;
1115
1116 case 5:
1117 case 6:
1118 case 7: /* add/substract/compare immediate */
1119 {
1120 int Rd = (insn >> 8) & 7;
1121 result += _interlock_use(Rd);
1122 }
1123 break;
1124
1125 case 8:
1126 {
1127 if ((insn & 0x0400) == 0) /* data processing register */
1128 {
1129 /* the registers can also be Rs and Rn in some cases */
1130 /* but they're always read anyway and located at the */
1131 /* same place, so we don't check the opcode */
1132 int Rm = (insn >> 3) & 7;
1133 int Rd = (insn >> 3) & 7;
1134
1135 result += _interlock_use(Rm) + _interlock_use(Rd);
1136 }
1137 else switch ((insn >> 8) & 3)
1138 {
1139 case 0:
1140 case 1:
1141 case 2: /* special data processing */
1142 {
1143 int Rn = (insn & 7) | ((insn >> 4) & 0x8);
1144 int Rm = ((insn >> 3) & 15);
1145
1146 result += _interlock_use(Rn) + _interlock_use(Rm);
1147 }
1148 break;
1149
1150 case 3:
1151 if ((insn & 0xff07) == 0x4700) /* branch/exchange */
1152 {
1153 int Rm = (insn >> 3) & 15;
1154
1155 result = 3 + _interlock_use(Rm);
1156 }
1157 /* else UNDEFINED */
1158 break;
1159 }
1160 }
1161 break;
1162
1163 case 9: /* load from literal pool */
1164 {
1165 int Rd = (insn >> 8) & 7;
1166 _interlock_def(Rd,result+1);
1167 }
1168 break;
1169
1170 case 10:
1171 case 11: /* load/store register offset */
1172 {
1173 int Rd = (insn & 7);
1174 int Rn = (insn >> 3) & 7;
1175 int Rm = (insn >> 6) & 7;
1176
1177 result += _interlock_use(Rn) + _interlock_use(Rm);
1178
1179 switch ((insn >> 9) & 7)
1180 {
1181 case 0: /* STR */
1182 case 1: /* STRH */
1183 case 2: /* STRB */
1184 result += _interlock_use(Rd);
1185 break;
1186
1187 case 3: /* LDRSB */
1188 case 5: /* LDRH */
1189 case 6: /* LDRB */
1190 case 7: /* LDRSH */
1191 _interlock_def(Rd,result+2);
1192 break;
1193
1194 case 4: /* LDR */
1195 _interlock_def(Rd,result+1);
1196 }
1197 }
1198 break;
1199
1200 case 12: /* store word immediate offset */
1201 case 14: /* store byte immediate offset */
1202 {
1203 int Rd = (insn & 7);
1204 int Rn = (insn >> 3) & 7;
1205
1206 result += _interlock_use(Rd) + _interlock_use(Rn);
1207 }
1208 break;
1209
1210 case 13: /* load word immediate offset */
1211 {
1212 int Rd = (insn & 7);
1213 int Rn = (insn >> 3) & 7;
1214
1215 result += _interlock_use(Rn);
1216 _interlock_def(Rd,result+1);
1217 }
1218 break;
1219
1220 case 15: /* load byte immediate offset */
1221 {
1222 int Rd = (insn & 7);
1223 int Rn = (insn >> 3) & 7;
1224
1225 result += _interlock_use(Rn);
1226 _interlock_def(Rd,result+2);
1227 }
1228 break;
1229
1230 case 16: /* store halfword immediate offset */
1231 {
1232 int Rd = (insn & 7);
1233 int Rn = (insn >> 3) & 7;
1234
1235 result += _interlock_use(Rn) + _interlock_use(Rd);
1236 }
1237 break;
1238
1239 case 17: /* load halfword immediate offset */
1240 {
1241 int Rd = (insn & 7);
1242 int Rn = (insn >> 3) & 7;
1243
1244 result += _interlock_use(Rn);
1245 _interlock_def(Rd,result+2);
1246 }
1247 break;
1248
1249 case 18: /* store to stack */
1250 {
1251 int Rd = (insn >> 8) & 3;
1252 result += _interlock_use(Rd);
1253 }
1254 break;
1255
1256 case 19: /* load from stack */
1257 {
1258 int Rd = (insn >> 8) & 3;
1259 _interlock_def(Rd,result+1);
1260 }
1261 break;
1262
1263 case 20: /* add to PC */
1264 case 21: /* add to SP */
1265 {
1266 int Rd = (insn >> 8) & 3;
1267 result += _interlock_use(Rd);
1268 }
1269 break;
1270
1271 case 22:
1272 case 23: /* misc. instructions, table 6-2 */
1273 {
1274 if ((insn & 0xff00) == 0xb000) /* adjust stack pointer */
1275 {
1276 result += _interlock_use(14);
1277 }
1278 else if ((insn & 0x0600) == 0x0400) /* push pop register list */
1279 {
1280 uint32_t mask = insn & 0x01ff;
1281 int count, nn;
1282
1283 for (count = 0; mask; count++)
1284 mask &= (mask-1);
1285
1286 result = (count < 2) ? 2 : count;
1287
1288 if (insn & 0x0800) /* pop register list */
1289 {
1290 for (nn = 0; nn < 9; nn++)
1291 if (insn & (1 << nn))
1292 _interlock_def(nn, result);
1293 }
1294 else /* push register list */
1295 {
1296 for (nn = 0; nn < 9; nn++)
1297 if (insn & (1 << nn))
1298 result += _interlock_use(nn);
1299 }
1300 }
1301 /* else software breakpoint */
1302 }
1303 break;
1304
1305 case 24: /* store multiple */
1306 {
1307 int Rd = (insn >> 8) & 7;
1308 uint32_t mask = insn & 255;
1309 int count, nn;
1310
1311 for (count = 0; mask; count++)
1312 mask &= (mask-1);
1313
1314 result = (count < 2) ? 2 : count;
1315 result += _interlock_use(Rd);
1316
1317 for (nn = 0; nn < 8; nn++)
1318 if (insn & (1 << nn))
1319 result += _interlock_use(nn);
1320 }
1321 break;
1322
1323 case 25: /* load multiple */
1324 {
1325 int Rd = (insn >> 8) & 7;
1326 uint32_t mask = insn & 255;
1327 int count, nn;
1328
1329 for (count = 0; mask; count++)
1330 mask &= (mask-1);
1331
1332 result = (count < 2) ? 2 : count;
1333 result += _interlock_use(Rd);
1334
1335 for (nn = 0; nn < 8; nn++)
1336 if (insn & (1 << nn))
1337 _interlock_def(nn, result);
1338 }
1339 break;
1340
1341 case 26:
1342 case 27: /* conditional branch / undefined / software interrupt */
1343 switch ((insn >> 8) & 15)
1344 {
1345 case 14: /* UNDEFINED */
1346 case 15: /* SWI */
1347 break;
1348
1349 default: /* conditional branch */
1350 result = 3;
1351 }
1352 break;
1353
1354 case 28: /* unconditional branch */
1355 result = 3;
1356 break;
1357
1358 case 29: /* BLX suffix or undefined */
1359 if ((insn & 1) == 0)
1360 result = 3;
1361 break;
1362
1363 case 30: /* BLX/BLX prefix */
1364 break;
1365
1366 case 31: /* BL suffix */
1367 result = 3;
1368 break;
1369 }
1370 interlock_base += result;
1371 return result;
1372#else /* old code */
1373 if ((insn & 0xfc00) == 0x4340) /* MUL */
1374 return TICKS_SMULxy;
1375
1376 return TICKS_OTHER;
1377#endif
1378}
1379
1380// Adds an exception trace record.
1381void trace_exception(uint32 target_pc)
1382{
1383 if (trace_exc.fstream == NULL)
1384 return;
1385
1386 // Sometimes we get an unexpected exception as the first record. If the
1387 // basic block number is zero, then we know it is bogus.
1388 if (trace_bb.current_bb_num == 0)
1389 return;
1390
1391 uint32_t current_pc = trace_bb.current_bb_addr + 4 * (trace_bb.num_insns - 1);
1392#if 0
1393 if (ftrace_debug) {
1394 fprintf(ftrace_debug, "t%llu exc pc: 0x%x bb_addr: 0x%x num_insns: %d current_pc: 0x%x bb_num %llu bb_start_time %llu\n",
1395 sim_time, target_pc, trace_bb.current_bb_addr,
1396 trace_bb.num_insns, current_pc, trace_bb.current_bb_num,
1397 trace_bb.current_bb_start_time);
1398 }
1399#endif
1400 char *comp_ptr = trace_exc.compressed_ptr;
1401 if (comp_ptr >= trace_exc.high_water_ptr) {
1402 uint32_t size = comp_ptr - trace_exc.compressed;
1403 fwrite(trace_exc.compressed, sizeof(char), size, trace_exc.fstream);
1404 comp_ptr = trace_exc.compressed;
1405 }
1406 uint64_t time_diff = sim_time - trace_exc.prev_time;
1407 trace_exc.prev_time = sim_time;
1408 uint64_t bb_recnum_diff = trace_bb.recnum - trace_exc.prev_bb_recnum;
1409 trace_exc.prev_bb_recnum = trace_bb.recnum;
1410 comp_ptr = varint_encode(time_diff, comp_ptr);
1411 comp_ptr = varint_encode(current_pc, comp_ptr);
1412 comp_ptr = varint_encode(bb_recnum_diff, comp_ptr);
1413 comp_ptr = varint_encode(target_pc, comp_ptr);
1414 comp_ptr = varint_encode(trace_bb.current_bb_num, comp_ptr);
1415 comp_ptr = varint_encode(trace_bb.current_bb_start_time, comp_ptr);
1416 comp_ptr = varint_encode(trace_bb.num_insns, comp_ptr);
1417 trace_exc.compressed_ptr = comp_ptr;
1418}
1419
1420void trace_pid_1arg(int pid, int rec_type)
1421{
1422 if (trace_pid.fstream == NULL)
1423 return;
1424 char *comp_ptr = trace_pid.compressed_ptr;
1425 char *max_end_ptr = comp_ptr + kMaxPidCompressed;
1426 if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
1427 uint32_t size = comp_ptr - trace_pid.compressed;
1428 fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
1429 comp_ptr = trace_pid.compressed;
1430 }
1431 uint64_t time_diff = sim_time - trace_pid.prev_time;
1432 trace_pid.prev_time = sim_time;
1433 comp_ptr = varint_encode(time_diff, comp_ptr);
1434 comp_ptr = varint_encode(rec_type, comp_ptr);
1435 comp_ptr = varint_encode(pid, comp_ptr);
1436 trace_pid.compressed_ptr = comp_ptr;
1437}
1438
1439void trace_pid_2arg(int tgid, int pid, int rec_type)
1440{
1441 if (trace_pid.fstream == NULL)
1442 return;
1443 char *comp_ptr = trace_pid.compressed_ptr;
1444 char *max_end_ptr = comp_ptr + kMaxPid2Compressed;
1445 if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
1446 uint32_t size = comp_ptr - trace_pid.compressed;
1447 fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
1448 comp_ptr = trace_pid.compressed;
1449 }
1450 uint64_t time_diff = sim_time - trace_pid.prev_time;
1451 trace_pid.prev_time = sim_time;
1452 comp_ptr = varint_encode(time_diff, comp_ptr);
1453 comp_ptr = varint_encode(rec_type, comp_ptr);
1454 comp_ptr = varint_encode(tgid, comp_ptr);
1455 comp_ptr = varint_encode(pid, comp_ptr);
1456 trace_pid.compressed_ptr = comp_ptr;
1457}
1458
1459void trace_switch(int pid)
1460{
1461#if 0
1462 if (ftrace_debug && trace_pid.fstream)
1463 fprintf(ftrace_debug, "t%lld switch %d\n", sim_time, pid);
1464#endif
1465 trace_pid_1arg(pid, kPidSwitch);
1466 current_pid = pid;
1467}
1468
1469void trace_fork(int tgid, int pid)
1470{
1471#if 0
1472 if (ftrace_debug && trace_pid.fstream)
1473 fprintf(ftrace_debug, "t%lld fork %d\n", sim_time, pid);
1474#endif
1475 trace_pid_2arg(tgid, pid, kPidFork);
1476}
1477
1478void trace_clone(int tgid, int pid)
1479{
1480#if 0
1481 if (ftrace_debug && trace_pid.fstream)
1482 fprintf(ftrace_debug, "t%lld clone %d\n", sim_time, pid);
1483#endif
1484 trace_pid_2arg(tgid, pid, kPidClone);
1485}
1486
1487void trace_exit(int exitcode)
1488{
1489#if 0
1490 if (ftrace_debug && trace_pid.fstream)
1491 fprintf(ftrace_debug, "t%lld exit %d\n", sim_time, exitcode);
1492#endif
1493 trace_pid_1arg(exitcode, kPidExit);
1494}
1495
1496void trace_name(char *name)
1497{
1498#if 0
1499 if (ftrace_debug && trace_pid.fstream) {
1500 fprintf(ftrace_debug, "t%lld pid %d name %s\n",
1501 sim_time, current_pid, name);
1502 }
1503#endif
1504 if (trace_pid.fstream == NULL)
1505 return;
1506 int len = strlen(name);
1507 char *comp_ptr = trace_pid.compressed_ptr;
1508 char *max_end_ptr = comp_ptr + len + kMaxNameCompressed;
1509 if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
1510 uint32_t size = comp_ptr - trace_pid.compressed;
1511 fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
1512 comp_ptr = trace_pid.compressed;
1513 }
1514 uint64_t time_diff = sim_time - trace_pid.prev_time;
1515 trace_pid.prev_time = sim_time;
1516 comp_ptr = varint_encode(time_diff, comp_ptr);
1517 int rec_type = kPidName;
1518 comp_ptr = varint_encode(rec_type, comp_ptr);
1519 comp_ptr = varint_encode(current_pid, comp_ptr);
1520 comp_ptr = varint_encode(len, comp_ptr);
1521 strncpy(comp_ptr, name, len);
1522 comp_ptr += len;
1523 trace_pid.compressed_ptr = comp_ptr;
1524}
1525
1526void trace_execve(const char *argv, int len)
1527{
1528 int ii;
1529
1530 if (trace_pid.fstream == NULL)
1531 return;
1532 // Count the number of args
1533 int alen = 0;
1534 int sum_len = 0;
1535 int argc = 0;
1536 const char *ptr = argv;
1537 while (sum_len < len) {
1538 argc += 1;
1539 alen = strlen(ptr);
1540 ptr += alen + 1;
1541 sum_len += alen + 1;
1542 }
1543
1544#if 0
1545 if (ftrace_debug) {
1546 fprintf(ftrace_debug, "t%lld argc: %d\n", sim_time, argc);
1547 alen = 0;
1548 ptr = argv;
1549 for (ii = 0; ii < argc; ++ii) {
1550 fprintf(ftrace_debug, " argv[%d]: %s\n", ii, ptr);
1551 alen = strlen(ptr);
1552 ptr += alen + 1;
1553 }
1554 }
1555#endif
1556
1557 char *comp_ptr = trace_pid.compressed_ptr;
1558 char *max_end_ptr = comp_ptr + len + 5 * argc + kMaxExecArgsCompressed;
1559 if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
1560 uint32_t size = comp_ptr - trace_pid.compressed;
1561 fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
1562 comp_ptr = trace_pid.compressed;
1563 }
1564 uint64_t time_diff = sim_time - trace_pid.prev_time;
1565 trace_pid.prev_time = sim_time;
1566 comp_ptr = varint_encode(time_diff, comp_ptr);
1567 int rec_type = kPidExec;
1568 comp_ptr = varint_encode(rec_type, comp_ptr);
1569 comp_ptr = varint_encode(argc, comp_ptr);
1570
1571 ptr = argv;
1572 for (ii = 0; ii < argc; ++ii) {
1573 alen = strlen(ptr);
1574 comp_ptr = varint_encode(alen, comp_ptr);
1575 strncpy(comp_ptr, ptr, alen);
1576 comp_ptr += alen;
1577 ptr += alen + 1;
1578 }
1579 trace_pid.compressed_ptr = comp_ptr;
1580}
1581
1582void trace_mmap(unsigned long vstart, unsigned long vend,
1583 unsigned long offset, const char *path)
1584{
1585 if (trace_pid.fstream == NULL)
1586 return;
1587#if 0
1588 if (ftrace_debug)
1589 fprintf(ftrace_debug, "t%lld mmap %08lx - %08lx, offset %08lx '%s'\n",
1590 sim_time, vstart, vend, offset, path);
1591#endif
1592 int len = strlen(path);
1593 char *comp_ptr = trace_pid.compressed_ptr;
1594 char *max_end_ptr = comp_ptr + len + kMaxMmapCompressed;
1595 if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
1596 uint32_t size = comp_ptr - trace_pid.compressed;
1597 fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
1598 comp_ptr = trace_pid.compressed;
1599 }
1600 uint64_t time_diff = sim_time - trace_pid.prev_time;
1601 trace_pid.prev_time = sim_time;
1602 comp_ptr = varint_encode(time_diff, comp_ptr);
1603 int rec_type = kPidMmap;
1604 comp_ptr = varint_encode(rec_type, comp_ptr);
1605 comp_ptr = varint_encode(vstart, comp_ptr);
1606 comp_ptr = varint_encode(vend, comp_ptr);
1607 comp_ptr = varint_encode(offset, comp_ptr);
1608 comp_ptr = varint_encode(len, comp_ptr);
1609 strncpy(comp_ptr, path, len);
1610 trace_pid.compressed_ptr = comp_ptr + len;
1611}
1612
1613void trace_munmap(unsigned long vstart, unsigned long vend)
1614{
1615 if (trace_pid.fstream == NULL)
1616 return;
1617#if 0
1618 if (ftrace_debug)
1619 fprintf(ftrace_debug, "t%lld munmap %08lx - %08lx\n",
1620 sim_time, vstart, vend);
1621#endif
1622 char *comp_ptr = trace_pid.compressed_ptr;
1623 char *max_end_ptr = comp_ptr + kMaxMunmapCompressed;
1624 if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
1625 uint32_t size = comp_ptr - trace_pid.compressed;
1626 fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
1627 comp_ptr = trace_pid.compressed;
1628 }
1629 uint64_t time_diff = sim_time - trace_pid.prev_time;
1630 trace_pid.prev_time = sim_time;
1631 comp_ptr = varint_encode(time_diff, comp_ptr);
1632 int rec_type = kPidMunmap;
1633 comp_ptr = varint_encode(rec_type, comp_ptr);
1634 comp_ptr = varint_encode(vstart, comp_ptr);
1635 comp_ptr = varint_encode(vend, comp_ptr);
1636 trace_pid.compressed_ptr = comp_ptr;
1637}
1638
1639void trace_dynamic_symbol_add(unsigned long vaddr, const char *name)
1640{
1641 if (trace_pid.fstream == NULL)
1642 return;
1643#if 0
1644 if (ftrace_debug)
1645 fprintf(ftrace_debug, "t%lld sym %08lx '%s'\n", sim_time, vaddr, name);
1646#endif
1647 int len = strlen(name);
1648 char *comp_ptr = trace_pid.compressed_ptr;
1649 char *max_end_ptr = comp_ptr + len + kMaxSymbolCompressed;
1650 if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
1651 uint32_t size = comp_ptr - trace_pid.compressed;
1652 fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
1653 comp_ptr = trace_pid.compressed;
1654 }
1655 uint64_t time_diff = sim_time - trace_pid.prev_time;
1656 trace_pid.prev_time = sim_time;
1657 comp_ptr = varint_encode(time_diff, comp_ptr);
1658 int rec_type = kPidSymbolAdd;
1659 comp_ptr = varint_encode(rec_type, comp_ptr);
1660 comp_ptr = varint_encode(vaddr, comp_ptr);
1661 comp_ptr = varint_encode(len, comp_ptr);
1662 strncpy(comp_ptr, name, len);
1663 trace_pid.compressed_ptr = comp_ptr + len;
1664}
1665
1666void trace_dynamic_symbol_remove(unsigned long vaddr)
1667{
1668 if (trace_pid.fstream == NULL)
1669 return;
1670#if 0
1671 if (ftrace_debug)
1672 fprintf(ftrace_debug, "t%lld remove %08lx\n", sim_time, vaddr);
1673#endif
1674 char *comp_ptr = trace_pid.compressed_ptr;
1675 char *max_end_ptr = comp_ptr + kMaxSymbolCompressed;
1676 if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
1677 uint32_t size = comp_ptr - trace_pid.compressed;
1678 fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
1679 comp_ptr = trace_pid.compressed;
1680 }
1681 uint64_t time_diff = sim_time - trace_pid.prev_time;
1682 trace_pid.prev_time = sim_time;
1683 comp_ptr = varint_encode(time_diff, comp_ptr);
1684 int rec_type = kPidSymbolRemove;
1685 comp_ptr = varint_encode(rec_type, comp_ptr);
1686 comp_ptr = varint_encode(vaddr, comp_ptr);
1687 trace_pid.compressed_ptr = comp_ptr;
1688}
1689
1690void trace_init_name(int tgid, int pid, const char *name)
1691{
1692 if (trace_pid.fstream == NULL)
1693 return;
1694#if 0
1695 if (ftrace_debug)
1696 fprintf(ftrace_debug, "t%lld kthread %d %s\n", sim_time, pid, name);
1697#endif
1698 int len = strlen(name);
1699 char *comp_ptr = trace_pid.compressed_ptr;
1700 char *max_end_ptr = comp_ptr + len + kMaxKthreadNameCompressed;
1701 if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
1702 uint32_t size = comp_ptr - trace_pid.compressed;
1703 fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
1704 comp_ptr = trace_pid.compressed;
1705 }
1706 uint64_t time_diff = sim_time - trace_pid.prev_time;
1707 trace_pid.prev_time = sim_time;
1708 comp_ptr = varint_encode(time_diff, comp_ptr);
1709 int rec_type = kPidKthreadName;
1710 comp_ptr = varint_encode(rec_type, comp_ptr);
1711 comp_ptr = varint_encode(tgid, comp_ptr);
1712 comp_ptr = varint_encode(pid, comp_ptr);
1713 comp_ptr = varint_encode(len, comp_ptr);
1714 strncpy(comp_ptr, name, len);
1715 trace_pid.compressed_ptr = comp_ptr + len;
1716}
1717
1718void trace_init_exec(unsigned long start, unsigned long end,
1719 unsigned long offset, const char *exe)
1720{
1721}
1722
1723// This function is called by the generated code to record the basic
1724// block number.
1725void trace_bb_helper(uint64_t bb_num, TranslationBlock *tb)
1726{
1727 BBRec *bb_rec = tb->bb_rec;
1728 uint64_t prev_time = tb->prev_time;
1729 trace_bb.current_bb_addr = tb->pc;
1730 trace_bb.current_bb_num = bb_num;
1731 trace_bb.current_bb_start_time = sim_time;
1732 trace_bb.num_insns = 0;
1733 trace_bb.recnum += 1;
1734
1735#if 0
1736 if (ftrace_debug)
1737 fprintf(ftrace_debug, "t%lld %lld\n", sim_time, bb_num);
1738#endif
1739 if (bb_rec && bb_rec->bb_num == bb_num && prev_time > trace_bb.flush_time) {
1740 uint64_t time_diff = sim_time - prev_time;
1741 if (bb_rec->repeat == 0) {
1742 bb_rec->repeat = 1;
1743 bb_rec->time_diff = time_diff;
1744 tb->prev_time = sim_time;
1745 return;
1746 } else if (time_diff == bb_rec->time_diff) {
1747 bb_rec->repeat += 1;
1748 tb->prev_time = sim_time;
1749 return;
1750 }
1751 }
1752
1753 BBRec *next = trace_bb.next;
1754 if (next == &trace_bb.buffer[kMaxNumBasicBlocks]) {
1755 BBRec *ptr;
1756 char *comp_ptr = trace_bb.compressed_ptr;
1757 int64_t prev_bb_num = trace_bb.prev_bb_num;
1758 uint64_t prev_bb_time = trace_bb.prev_bb_time;
1759 for (ptr = trace_bb.buffer; ptr != next; ++ptr) {
1760 if (comp_ptr >= trace_bb.high_water_ptr) {
1761 uint32_t size = comp_ptr - trace_bb.compressed;
1762 fwrite(trace_bb.compressed, sizeof(char), size, trace_bb.fstream);
1763 comp_ptr = trace_bb.compressed;
1764 }
1765 int64_t bb_diff = ptr->bb_num - prev_bb_num;
1766 prev_bb_num = ptr->bb_num;
1767 uint64_t time_diff = ptr->start_time - prev_bb_time;
1768 prev_bb_time = ptr->start_time;
1769 comp_ptr = varint_encode_signed(bb_diff, comp_ptr);
1770 comp_ptr = varint_encode(time_diff, comp_ptr);
1771 comp_ptr = varint_encode(ptr->repeat, comp_ptr);
1772 if (ptr->repeat)
1773 comp_ptr = varint_encode(ptr->time_diff, comp_ptr);
1774 }
1775 trace_bb.compressed_ptr = comp_ptr;
1776 trace_bb.prev_bb_num = prev_bb_num;
1777 trace_bb.prev_bb_time = prev_bb_time;
1778
1779 next = trace_bb.buffer;
1780 trace_bb.flush_time = sim_time;
1781 }
1782 tb->bb_rec = next;
1783 next->bb_num = bb_num;
1784 next->start_time = sim_time;
1785 next->time_diff = 0;
1786 next->repeat = 0;
1787 tb->prev_time = sim_time;
1788 next += 1;
1789 trace_bb.next = next;
1790}
1791
1792// This function is called by the generated code to record the simulation
1793// time at the start of each instruction.
1794void trace_insn_helper()
1795{
1796 InsnRec *current = trace_insn.current;
1797 uint64_t time_diff = sim_time - trace_insn.prev_time;
1798 trace_insn.prev_time = sim_time;
1799
1800 // Keep track of the number of traced instructions so far in this
1801 // basic block in case we get an exception in the middle of the bb.
1802 trace_bb.num_insns += 1;
1803
1804#if 0
1805 if (ftrace_debug) {
1806 uint32_t current_pc = trace_bb.current_bb_addr + 4 * (trace_bb.num_insns - 1);
1807 fprintf(ftrace_debug, "%llu %x\n", sim_time, current_pc);
1808 }
1809#endif
1810 if (time_diff == current->time_diff) {
1811 current->repeat += 1;
1812 if (current->repeat != 0)
1813 return;
1814
1815 // The repeat count wrapped around, so back up one and create
1816 // a new record.
1817 current->repeat -= 1;
1818 }
1819 current += 1;
1820
1821 if (current == &trace_insn.buffer[kInsnBufferSize]) {
1822 InsnRec *ptr;
1823 char *comp_ptr = trace_insn.compressed_ptr;
1824 for (ptr = trace_insn.buffer; ptr != current; ++ptr) {
1825 if (comp_ptr >= trace_insn.high_water_ptr) {
1826 uint32_t size = comp_ptr - trace_insn.compressed;
1827 uint32_t rval = fwrite(trace_insn.compressed, sizeof(char),
1828 size, trace_insn.fstream);
1829 if (rval != size) {
1830 fprintf(stderr, "fwrite() failed\n");
1831 perror(trace_insn.filename);
1832 exit(1);
1833 }
1834 comp_ptr = trace_insn.compressed;
1835 }
1836 comp_ptr = varint_encode(ptr->time_diff, comp_ptr);
1837 comp_ptr = varint_encode(ptr->repeat, comp_ptr);
1838 }
1839 trace_insn.compressed_ptr = comp_ptr;
1840 current = trace_insn.buffer;
1841 }
1842 current->time_diff = time_diff;
1843 current->repeat = 0;
1844 trace_insn.current = current;
1845}
1846
1847// Adds an interpreted method trace record. Each trace record is a time
1848// stamped entry or exit to a method in a language executed by a "virtual
1849// machine". This allows profiling tools to show the method names instead
1850// of the core virtual machine interpreter.
1851void trace_interpreted_method(uint32_t addr, int call_type)
1852{
1853 if (trace_method.fstream == NULL)
1854 return;
1855#if 0
1856 fprintf(stderr, "trace_method time: %llu p%d 0x%x %d\n",
1857 sim_time, current_pid, addr, call_type);
1858#endif
1859 char *comp_ptr = trace_method.compressed_ptr;
1860 char *max_end_ptr = comp_ptr + kMaxMethodCompressed;
1861 if (max_end_ptr >= &trace_method.compressed[kCompressedSize]) {
1862 uint32_t size = comp_ptr - trace_method.compressed;
1863 fwrite(trace_method.compressed, sizeof(char), size, trace_method.fstream);
1864 comp_ptr = trace_method.compressed;
1865 }
1866 uint64_t time_diff = sim_time - trace_method.prev_time;
1867 trace_method.prev_time = sim_time;
1868
1869 int32_t addr_diff = addr - trace_method.prev_addr;
1870 trace_method.prev_addr = addr;
1871
1872 int32_t pid_diff = current_pid - trace_method.prev_pid;
1873 trace_method.prev_pid = current_pid;
1874
1875 comp_ptr = varint_encode(time_diff, comp_ptr);
1876 comp_ptr = varint_encode_signed(addr_diff, comp_ptr);
1877 comp_ptr = varint_encode_signed(pid_diff, comp_ptr);
1878 comp_ptr = varint_encode(call_type, comp_ptr);
1879 trace_method.compressed_ptr = comp_ptr;
1880}