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