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 |