| OLD | NEW |
| 1 /* Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 /* Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 * Use of this source code is governed by a BSD-style license that can be | 2 * Use of this source code is governed by a BSD-style license that can be |
| 3 * found in the LICENSE file. | 3 * found in the LICENSE file. |
| 4 */ | 4 */ |
| 5 | 5 |
| 6 | 6 |
| 7 /* XRay -- a simple profiler for Native Client */ | 7 /* XRay -- a simple profiler for Native Client */ |
| 8 | 8 |
| 9 #include <alloca.h> | 9 #include <alloca.h> |
| 10 #include <assert.h> | 10 #include <assert.h> |
| 11 #include <errno.h> | 11 #include <errno.h> |
| 12 #include <stdarg.h> | 12 #include <stdarg.h> |
| 13 #include <stdint.h> | 13 #include <stdint.h> |
| 14 #include <stdio.h> | 14 #include <stdio.h> |
| 15 #include <stdlib.h> | 15 #include <stdlib.h> |
| 16 #include <string.h> | 16 #include <string.h> |
| 17 #include <unistd.h> | 17 #include <unistd.h> |
| 18 #include "xray/xray_priv.h" | 18 #include "xray/xray_priv.h" |
| 19 | 19 |
| 20 #if defined(XRAY) | 20 #if defined(XRAY) |
| 21 | 21 |
| 22 #define FORCE_INLINE __attribute__((always_inline)) |
| 23 |
| 24 #if defined(__amd64__) |
| 25 FORCE_INLINE uint64_t RDTSC64() { |
| 26 uint64_t a, d; |
| 27 __asm__ __volatile__("rdtsc" : "=a" (a), "=d" (d)); |
| 28 return ((uint64_t)a) | (((uint64_t)d) << 32); |
| 29 } |
| 30 #define RDTSC(_x) _x = RDTSC64() |
| 31 #else |
| 22 #define RDTSC(_x) __asm__ __volatile__ ("rdtsc" : "=A" (_x)); | 32 #define RDTSC(_x) __asm__ __volatile__ ("rdtsc" : "=A" (_x)); |
| 23 #define FORCE_INLINE __attribute__((always_inline)) | 33 #endif |
| 34 |
| 24 | 35 |
| 25 /* Use a TLS variable for cheap thread uid. */ | 36 /* Use a TLS variable for cheap thread uid. */ |
| 26 volatile __thread int g_xray_thread_id; | 37 volatile __thread int g_xray_thread_id; |
| 27 | 38 |
| 28 | 39 |
| 29 struct XRayTraceStackEntry { | 40 struct XRayTraceStackEntry { |
| 30 uint32_t depth_addr; | 41 uint32_t depth_addr; |
| 31 uint64_t tsc; | 42 uint64_t tsc; |
| 32 uint32_t dest; | 43 uint32_t dest; |
| 33 uint32_t annotation_index; | 44 uint32_t annotation_index; |
| (...skipping 550 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 584 int XRayTraceBufferNextEntry(int index) { | 595 int XRayTraceBufferNextEntry(int index) { |
| 585 if (XRayTraceBufferIsAnnotation(index)) | 596 if (XRayTraceBufferIsAnnotation(index)) |
| 586 index = XRayTraceBufferSkipAnnotation(index); | 597 index = XRayTraceBufferSkipAnnotation(index); |
| 587 else | 598 else |
| 588 index = XRayTraceBufferIncrementIndex(index); | 599 index = XRayTraceBufferIncrementIndex(index); |
| 589 return index; | 600 return index; |
| 590 } | 601 } |
| 591 | 602 |
| 592 | 603 |
| 593 /* Dumps the trace report for a given frame. */ | 604 /* Dumps the trace report for a given frame. */ |
| 594 void XRayTraceReport(FILE* f, int frame, char* label, float cutoff) { | 605 void XRayTraceReport(FILE* f, int frame, char* label, |
| 606 float percent_cutoff, int ticks_cutoff) { |
| 595 int index; | 607 int index; |
| 596 int start; | 608 int start; |
| 597 int end; | 609 int end; |
| 598 float total; | 610 float total; |
| 599 int bad_depth = 0; | |
| 600 char space[257]; | 611 char space[257]; |
| 601 memset(space, ' ', 256); | 612 memset(space, ' ', 256); |
| 602 space[256] = 0; | 613 space[256] = 0; |
| 603 if (NULL == f) { | 614 if (NULL == f) { |
| 604 f = stdout; | 615 f = stdout; |
| 605 } | 616 } |
| 606 fprintf(f, | 617 fprintf(f, |
| 607 "======================================================================\n"); | 618 "======================================================================\n"); |
| 608 if (NULL != label) | 619 if (NULL != label) |
| 609 fprintf(f, "label %s\n", label); | 620 fprintf(f, "label %s\n", label); |
| 610 fprintf(f, "\n"); | 621 fprintf(f, "\n"); |
| 611 fprintf(f, | 622 fprintf(f, |
| 612 " Address Ticks Percent Function <optional annotation>\n"); | 623 " Address Ticks Percent Function <optional annotation>\n"); |
| 613 fprintf(f, | 624 fprintf(f, |
| 614 "----------------------------------------------------------------------\n"); | 625 "----------------------------------------------------------------------\n"); |
| 615 start = g_xray.frame.entry[frame].start; | 626 start = g_xray.frame.entry[frame].start; |
| 616 end = g_xray.frame.entry[frame].end; | 627 end = g_xray.frame.entry[frame].end; |
| 617 total = (float)g_xray.frame.entry[frame].total_ticks; | 628 total = (float)g_xray.frame.entry[frame].total_ticks; |
| 618 index = start; | 629 index = start; |
| 619 while (index != end) { | 630 while (index != end) { |
| 620 if (!XRayTraceBufferIsAnnotation(index)) { | 631 if (!XRayTraceBufferIsAnnotation(index)) { |
| 621 const char* symbol_name; | 632 const char* symbol_name; |
| 622 char annotation[1024]; | 633 char annotation[1024]; |
| 623 struct XRayTraceBufferEntry* e = &g_xray.buffer[index]; | 634 struct XRayTraceBufferEntry* e = &g_xray.buffer[index]; |
| 624 uint32_t depth = XRAY_EXTRACT_DEPTH(e->depth_addr); | 635 uint32_t depth = XRAY_EXTRACT_DEPTH(e->depth_addr); |
| 625 uint32_t addr = XRAY_EXTRACT_ADDR(e->depth_addr); | 636 uint32_t addr = XRAY_EXTRACT_ADDR(e->depth_addr); |
| 626 uint32_t ticks = (e->ticks); | 637 uint32_t ticks = (e->ticks); |
| 627 uint32_t annotation_index = (e->annotation_index); | 638 uint32_t annotation_index = (e->annotation_index); |
| 628 float percent = 100.0f * (float)ticks / total; | 639 float percent = 100.0f * (float)ticks / total; |
| 629 if (percent >= cutoff) { | 640 if (percent >= percent_cutoff && ticks >= ticks_cutoff) { |
| 630 if (depth > 250) bad_depth++; | |
| 631 struct XRaySymbol* symbol; | 641 struct XRaySymbol* symbol; |
| 632 symbol = XRaySymbolTableLookup(g_xray.symbols, addr); | 642 symbol = XRaySymbolTableLookup(g_xray.symbols, addr); |
| 633 symbol_name = XRaySymbolGetName(symbol); | 643 symbol_name = XRaySymbolGetName(symbol); |
| 634 if (0 != annotation_index) { | 644 if (0 != annotation_index) { |
| 635 XRayTraceBufferCopyToString(annotation_index, annotation); | 645 XRayTraceBufferCopyToString(annotation_index, annotation); |
| 636 } else { | 646 } else { |
| 637 strcpy(annotation, ""); | 647 strcpy(annotation, ""); |
| 638 } | 648 } |
| 639 fprintf(f, "0x%08X %10ld %5.1f %s%s %s\n", | 649 fprintf(f, "0x%08X %10ld %5.1f %s%s %s\n", |
| 640 (unsigned int)addr, (int64_t)ticks, percent, | 650 (unsigned int)addr, (int64_t)ticks, percent, |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 717 index, | 727 index, |
| 718 (int64_t)total_ticks, | 728 (int64_t)total_ticks, |
| 719 capture_size, | 729 capture_size, |
| 720 annotation_count, | 730 annotation_count, |
| 721 label); | 731 label); |
| 722 } | 732 } |
| 723 } | 733 } |
| 724 | 734 |
| 725 | 735 |
| 726 /* Dump a frame report followed by trace report(s) for each frame. */ | 736 /* Dump a frame report followed by trace report(s) for each frame. */ |
| 727 void XRayReport(FILE* f, float cutoff) { | 737 void XRayReport(FILE* f, float percent_cutoff, int ticks_cutoff) { |
| 728 int head; | 738 int head; |
| 729 int index; | 739 int index; |
| 730 int counter = 0; | 740 int counter = 0; |
| 731 fprintf(f, "Number of symbols: %d\n", XRaySymbolCount(g_xray.symbols)); | 741 if (g_xray.symbols) |
| 742 fprintf(f, "Number of symbols: %d\n", XRaySymbolCount(g_xray.symbols)); |
| 732 XRayFrameReport(f); | 743 XRayFrameReport(f); |
| 733 fprintf(f, "\n"); | 744 fprintf(f, "\n"); |
| 734 head = g_xray.frame.head; | 745 head = g_xray.frame.head; |
| 735 index = g_xray.frame.tail; | 746 index = g_xray.frame.tail; |
| 736 while (index != head) { | 747 while (index != head) { |
| 737 char label[XRAY_MAX_LABEL]; | 748 char label[XRAY_MAX_LABEL]; |
| 738 fprintf(f, "\n"); | 749 fprintf(f, "\n"); |
| 739 XRayFrameMakeLabel(counter, label); | 750 XRayFrameMakeLabel(counter, label); |
| 740 XRayTraceReport(f, index, label, cutoff); | 751 XRayTraceReport(f, index, label, percent_cutoff, ticks_cutoff); |
| 741 index = XRayFrameNext(index); | 752 index = XRayFrameNext(index); |
| 753 |
| 742 ++counter; | 754 ++counter; |
| 743 } | 755 } |
| 744 fprintf(f, | 756 fprintf(f, |
| 745 "======================================================================\n"); | 757 "======================================================================\n"); |
| 746 #if defined(XRAY_OUTPUT_HASH_COLLISIONS) | 758 #if defined(XRAY_OUTPUT_HASH_COLLISIONS) |
| 747 XRayHashTableHisto(f); | 759 XRayHashTableHisto(f); |
| 748 #endif | 760 #endif |
| 761 fflush(f); |
| 749 } | 762 } |
| 750 | 763 |
| 751 | 764 |
| 752 /* Write a profile report to text file. */ | 765 /* Write a profile report to text file. */ |
| 753 void XRaySaveReport(const char* filename, float cutoff) { | 766 void XRaySaveReport(const char* filename, |
| 767 float percent_cutoff, |
| 768 int ticks_cutoff) { |
| 754 FILE* f; | 769 FILE* f; |
| 755 f = fopen(filename, "wt"); | 770 f = fopen(filename, "wt"); |
| 756 if (NULL != f) { | 771 if (NULL != f) { |
| 757 XRayReport(f, cutoff); | 772 XRayReport(f, percent_cutoff, ticks_cutoff); |
| 758 fclose(f); | 773 fclose(f); |
| 759 } | 774 } |
| 760 } | 775 } |
| 761 | 776 |
| 762 | 777 |
| 763 /* Initialize XRay */ | 778 /* Initialize XRay */ |
| 764 void XRayInit(int stack_depth, int buffer_size, int frame_count, | 779 void XRayInit(int stack_depth, int buffer_size, int frame_count, |
| 765 const char* mapfilename) { | 780 const char* mapfilename) { |
| 766 int adj_frame_count = frame_count + 1; | 781 int adj_frame_count = frame_count + 1; |
| 767 assert(false == g_xray.initialized); | 782 assert(false == g_xray.initialized); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 781 g_xray.disabled = 0; | 796 g_xray.disabled = 0; |
| 782 g_xray.annotation_filter = 0xFFFFFFFF; | 797 g_xray.annotation_filter = 0xFFFFFFFF; |
| 783 g_xray.guard0 = XRAY_GUARD_VALUE; | 798 g_xray.guard0 = XRAY_GUARD_VALUE; |
| 784 g_xray.guard1 = XRAY_GUARD_VALUE; | 799 g_xray.guard1 = XRAY_GUARD_VALUE; |
| 785 g_xray.guard2 = XRAY_GUARD_VALUE; | 800 g_xray.guard2 = XRAY_GUARD_VALUE; |
| 786 g_xray.initialized = true; | 801 g_xray.initialized = true; |
| 787 XRaySetMaxStackDepth(stack_depth); | 802 XRaySetMaxStackDepth(stack_depth); |
| 788 XRayReset(); | 803 XRayReset(); |
| 789 | 804 |
| 790 /* Mapfile is optional; we don't need it for captures, only for reports. */ | 805 /* Mapfile is optional; we don't need it for captures, only for reports. */ |
| 791 if (NULL != mapfilename) { | 806 g_xray.symbols = XRaySymbolTableCreate(XRAY_DEFAULT_SYMBOL_TABLE_SIZE); |
| 792 g_xray.symbols = XRaySymbolTableCreate(XRAY_DEFAULT_SYMBOL_TABLE_SIZE); | 807 if (NULL != mapfilename) |
| 793 XRaySymbolTableParseMapfile(g_xray.symbols, mapfilename); | 808 XRaySymbolTableParseMapfile(g_xray.symbols, mapfilename); |
| 794 } | |
| 795 } | 809 } |
| 796 | 810 |
| 797 | 811 |
| 798 /* Shut down and free memory used by XRay. */ | 812 /* Shut down and free memory used by XRay. */ |
| 799 void XRayShutdown() { | 813 void XRayShutdown() { |
| 800 assert(true == g_xray.initialized); | 814 assert(true == g_xray.initialized); |
| 801 assert(NULL == g_xray.recording); | 815 assert(NULL == g_xray.recording); |
| 802 XRayCheckGuards(); | 816 XRayCheckGuards(); |
| 803 if (NULL != g_xray.symbols) { | 817 if (NULL != g_xray.symbols) { |
| 804 XRaySymbolTableFree(g_xray.symbols); | 818 XRaySymbolTableFree(g_xray.symbols); |
| 805 } | 819 } |
| 806 XRayFree(g_xray.frame.entry); | 820 XRayFree(g_xray.frame.entry); |
| 807 XRayFree(g_xray.buffer); | 821 XRayFree(g_xray.buffer); |
| 808 g_xray.initialized = false; | 822 g_xray.initialized = false; |
| 809 } | 823 } |
| 810 | 824 |
| 811 #endif /* XRAY */ | 825 #endif /* XRAY */ |
| 812 | 826 |
| OLD | NEW |