Home | History | Annotate | Download | only in xray
      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
      3  * found in the LICENSE file. */
      4 
      5 
      6 /* XRay -- a simple profiler for Native Client */
      7 
      8 #include <assert.h>
      9 #include <errno.h>
     10 #include <stdarg.h>
     11 #include <stdint.h>
     12 #include <stdio.h>
     13 #include <stdlib.h>
     14 #include <string.h>
     15 #include <sys/time.h>
     16 #include <unistd.h>
     17 #include "xray/xray_priv.h"
     18 
     19 #if defined(XRAY)
     20 
     21 #define FORCE_INLINE  __attribute__((always_inline))
     22 
     23 /* GTSC - Get Time Stamp Counter */
     24 #if defined(__amd64__) && !defined(XRAY_NO_RDTSC)
     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 GTSC(_x) _x = RDTSC64()
     31 #elif defined(__i386__) && !defined(XRAY_NO_RDTSC)
     32 #define GTSC(_x)      __asm__ __volatile__ ("rdtsc" : "=A" (_x));
     33 #else
     34 FORCE_INLINE uint64_t GTOD() {
     35   struct timeval tv;
     36   gettimeofday(&tv, NULL);
     37   return (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec;
     38 }
     39 #define GTSC(_x) _x = GTOD();
     40 #endif
     41 
     42 /* Use a TLS variable for cheap thread uid. */
     43 __thread struct XRayTraceCapture* g_xray_capture = NULL;
     44 __thread int g_xray_thread_id_placeholder = 0;
     45 
     46 
     47 struct XRayTraceStackEntry {
     48   uint32_t depth_addr;
     49   uint64_t tsc;
     50   uint32_t dest;
     51   uint32_t annotation_index;
     52 };
     53 
     54 
     55 struct XRayTraceFrameEntry {
     56   /* Indices into global tracebuffer */
     57   int start;
     58   int end;
     59   uint64_t start_tsc;
     60   uint64_t end_tsc;
     61   uint64_t total_ticks;
     62   int annotation_count;
     63   bool valid;
     64 
     65 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION
     66   struct XRayTimestampPair start_time;
     67   struct XRayTimestampPair end_time;
     68 #endif
     69 };
     70 
     71 
     72 struct XRayTraceFrame {
     73   struct XRayTraceFrameEntry* entry;
     74   int head;
     75   int tail;
     76   int count;
     77 };
     78 
     79 
     80 struct XRayTraceCapture {
     81   /* Common variables share cache line */
     82   bool recording;
     83   uint32_t stack_depth;
     84   uint32_t max_stack_depth;
     85   int buffer_index;
     86   int buffer_size;
     87   int disabled;
     88   int annotation_count;
     89   struct XRaySymbolTable* symbols;
     90   bool initialized;
     91   uint32_t annotation_filter;
     92   uint32_t guard0;
     93   struct XRayTraceStackEntry stack[XRAY_TRACE_STACK_SIZE] XRAY_ALIGN64;
     94   uint32_t guard1;
     95   uint32_t guard2;
     96   char annotation[XRAY_ANNOTATION_STACK_SIZE] XRAY_ALIGN64;
     97   uint32_t guard3;
     98   struct XRayTraceBufferEntry* buffer;
     99   struct XRayTraceFrame frame;
    100 
    101 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION
    102   int32_t thread_id;
    103 #endif
    104 } XRAY_ALIGN64;
    105 
    106 
    107 #ifdef __cplusplus
    108 extern "C" {
    109 #endif
    110 
    111 #if defined(__pnacl__)
    112 XRAY_NO_INSTRUMENT void __pnacl_profile_func_enter(const char* fname);
    113 XRAY_NO_INSTRUMENT void __pnacl_profile_func_exit(const char* fname);
    114 #else
    115 XRAY_NO_INSTRUMENT void __cyg_profile_func_enter(void* this_fn,
    116                                                  void* call_site);
    117 XRAY_NO_INSTRUMENT void __cyg_profile_func_exit(void* this_fn,
    118                                                 void* call_site);
    119 #endif
    120 
    121 XRAY_NO_INSTRUMENT void __xray_profile_append_annotation(
    122     struct XRayTraceCapture* capture,
    123     struct XRayTraceStackEntry* se,
    124     struct XRayTraceBufferEntry* be);
    125 
    126 #ifdef __cplusplus
    127 }
    128 #endif
    129 
    130 /* Asserts that the guard values haven't changed. */
    131 void XRayCheckGuards(struct XRayTraceCapture* capture) {
    132   assert(capture->guard0 == XRAY_GUARD_VALUE_0x12345678);
    133   assert(capture->guard1 == XRAY_GUARD_VALUE_0x12345678);
    134   assert(capture->guard2 == XRAY_GUARD_VALUE_0x87654321);
    135   assert(capture->guard3 == XRAY_GUARD_VALUE_0x12345678);
    136 }
    137 
    138 /* Decrements the trace index, wrapping around if needed. */
    139 XRAY_FORCE_INLINE int XRayTraceDecrementIndexInline(
    140     struct XRayTraceCapture* capture, int index) {
    141   --index;
    142   if (index < 0)
    143     index = capture->buffer_size - 1;
    144   return index;
    145 }
    146 
    147 /* Increments the trace index, wrapping around if needed. */
    148 XRAY_FORCE_INLINE int XRayTraceIncrementIndexInline(
    149     struct XRayTraceCapture* capture, int index) {
    150   ++index;
    151   if (index >= capture->buffer_size)
    152     index = 0;
    153   return index;
    154 }
    155 
    156 /* Returns true if the trace entry is an annotation string. */
    157 bool XRayTraceIsAnnotation(
    158     struct XRayTraceCapture* capture, int index) {
    159   struct XRayTraceBufferEntry* be = &capture->buffer[index];
    160   char* dst = (char*)be;
    161   return 0 == *dst;
    162 }
    163 
    164 int XRayTraceIncrementIndex(struct XRayTraceCapture* capture, int index) {
    165   return XRayTraceIncrementIndexInline(capture, index);
    166 }
    167 
    168 int XRayTraceDecrementIndex(struct XRayTraceCapture* capture, int index) {
    169   return XRayTraceDecrementIndexInline(capture, index);
    170 }
    171 
    172 /* The entry in the tracebuffer at index is an annotation string. */
    173 /* Calculate the next index value representing the next trace entry. */
    174 int XRayTraceSkipAnnotation(struct XRayTraceCapture* capture, int index) {
    175   /* Annotations are strings embedded in the trace buffer. */
    176   /* An annotation string can span multiple trace entries. */
    177   /* Skip over the string by looking for zero termination. */
    178   assert(capture);
    179   assert(XRayTraceIsAnnotation(capture, index));
    180   bool done = false;
    181   int start_index = 1;
    182   int i;
    183   while (!done) {
    184     char* str = (char*) &capture->buffer[index];
    185     const int num = sizeof(capture->buffer[index]);
    186     for (i = start_index; i < num; ++i) {
    187       if (0 == str[i]) {
    188         done = true;
    189         break;
    190       }
    191     }
    192     index = XRayTraceIncrementIndexInline(capture, index);
    193     start_index = 0;
    194   }
    195   return index;
    196 }
    197 
    198 
    199 struct XRayTraceBufferEntry* XRayTraceGetEntry(
    200     struct XRayTraceCapture* capture, int index) {
    201   return &capture->buffer[index];
    202 }
    203 
    204 /* Starting at index, return the index into the trace buffer */
    205 /* for the next trace entry.  Index can wrap (ringbuffer) */
    206 int XRayTraceNextEntry(struct XRayTraceCapture* capture, int index) {
    207   if (XRayTraceIsAnnotation(capture, index))
    208     index = XRayTraceSkipAnnotation(capture, index);
    209   else
    210     index = XRayTraceIncrementIndexInline(capture, index);
    211   return index;
    212 }
    213 
    214 int XRayFrameGetTraceStartIndex(struct XRayTraceCapture* capture, int frame) {
    215   assert(capture);
    216   assert(capture->initialized);
    217   assert(!capture->recording);
    218   return capture->frame.entry[frame].start;
    219 }
    220 
    221 int XRayFrameGetTraceEndIndex(struct XRayTraceCapture* capture, int frame) {
    222   assert(capture);
    223   assert(capture->initialized);
    224   assert(!capture->recording);
    225   return capture->frame.entry[frame].end;
    226 }
    227 
    228 /* Not very accurate, annotation strings will also be counted as "entries" */
    229 int XRayFrameGetTraceCount(
    230     struct XRayTraceCapture* capture, int frame) {
    231   assert(true == capture->initialized);
    232   assert(frame >= 0);
    233   assert(frame < capture->frame.count);
    234   assert(!capture->recording);
    235   int start = capture->frame.entry[frame].start;
    236   int end = capture->frame.entry[frame].end;
    237   int num;
    238   if (start < end)
    239     num = end - start;
    240   else
    241     num = capture->buffer_size - (start - end);
    242   return num;
    243 }
    244 
    245 /* Append a string to trace buffer. */
    246 void XRayTraceAppendString(struct XRayTraceCapture* capture, char* src) {
    247   int index = capture->buffer_index;
    248   bool done = false;
    249   int start_index = 1;
    250   int s = 0;
    251   int i;
    252   char* dst = (char*)&capture->buffer[index];
    253   const int num = sizeof(capture->buffer[index]);
    254   dst[0] = 0;
    255   while (!done) {
    256     for (i = start_index; i < num; ++i) {
    257       dst[i] = src[s];
    258       if (0 == src[s]) {
    259         dst[i] = 0;
    260         done = true;
    261         break;
    262       }
    263       ++s;
    264     }
    265     index = XRayTraceIncrementIndexInline(capture, index);
    266     dst = (char*)&capture->buffer[index];
    267     start_index = 0;
    268   }
    269   capture->buffer_index = index;
    270 }
    271 
    272 /* Copies annotation from trace buffer to output string. */
    273 int XRayTraceCopyToString(
    274     struct XRayTraceCapture* capture, int index, char* dst) {
    275   assert(XRayTraceIsAnnotation(capture, index));
    276   bool done = false;
    277   int i;
    278   int d = 0;
    279   int start_index = 1;
    280   while (!done) {
    281     char* src = (char*) &capture->buffer[index];
    282     const int num = sizeof(capture->buffer[index]);
    283     for (i = start_index; i < num; ++i) {
    284       dst[d] = src[i];
    285       if (0 == src[i]) {
    286         done = true;
    287         break;
    288       }
    289       ++d;
    290     }
    291     index = XRayTraceIncrementIndexInline(capture, index);
    292     start_index = 0;
    293   }
    294   return index;
    295 }
    296 
    297 
    298 /* Generic memory malloc for XRay */
    299 /* validates pointer returned by malloc */
    300 /* memsets memory block to zero */
    301 void* XRayMalloc(size_t t) {
    302   void* data;
    303   data = calloc(1, t);
    304   if (NULL == data) {
    305     printf("XRay: malloc(%d) failed, panic shutdown!\n", t);
    306     exit(-1);
    307   }
    308   return data;
    309 }
    310 
    311 
    312 /* Generic memory free for XRay */
    313 void XRayFree(void* data) {
    314   assert(NULL != data);
    315   free(data);
    316 }
    317 
    318 
    319 /* Main profile capture function that is called at the start */
    320 /* of every instrumented function.  This function is implicitly */
    321 /* called when code is compilied with the -finstrument-functions option */
    322 #if defined(__pnacl__)
    323 void __pnacl_profile_func_enter(const char* this_fn) {
    324 #else
    325 void __cyg_profile_func_enter(void* this_fn, void* call_site) {
    326 #endif
    327   struct XRayTraceCapture* capture = g_xray_capture;
    328   if (capture && capture->recording) {
    329     uint32_t depth = capture->stack_depth;
    330     if (depth < capture->max_stack_depth) {
    331       struct XRayTraceStackEntry* se = &capture->stack[depth];
    332       uint32_t addr = (uint32_t)this_fn;
    333       se->depth_addr = XRAY_PACK_DEPTH_ADDR(depth, addr);
    334       se->dest = capture->buffer_index;
    335       se->annotation_index = 0;
    336       GTSC(se->tsc);
    337       capture->buffer_index =
    338         XRayTraceIncrementIndexInline(capture, capture->buffer_index);
    339     }
    340     ++capture->stack_depth;
    341   }
    342 }
    343 
    344 
    345 /* Main profile capture function that is called at the exit of */
    346 /* every instrumented function.  This function is implicity called */
    347 /* when the code is compiled with the -finstrument-functions option */
    348 #if defined(__pnacl__)
    349 void __pnacl_profile_func_exit(const char* this_fn) {
    350 #else
    351 void __cyg_profile_func_exit(void* this_fn, void* call_site) {
    352 #endif
    353   struct XRayTraceCapture* capture = g_xray_capture;
    354   if (capture && capture->recording) {
    355     --capture->stack_depth;
    356     if (capture->stack_depth < capture->max_stack_depth) {
    357       uint32_t depth = capture->stack_depth;
    358       struct XRayTraceStackEntry* se = &capture->stack[depth];
    359       uint32_t buffer_index = se->dest;
    360       uint64_t tsc;
    361       struct XRayTraceBufferEntry* be = &capture->buffer[buffer_index];
    362       GTSC(tsc);
    363       be->depth_addr = se->depth_addr;
    364       be->start_tick = se->tsc;
    365       be->end_tick = tsc;
    366       be->annotation_index = 0;
    367       if (0 != se->annotation_index)
    368         __xray_profile_append_annotation(capture, se, be);
    369     }
    370   }
    371 }
    372 
    373 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION
    374 void XRayGetTSC(uint64_t* tsc) {
    375   GTSC(*tsc);
    376 }
    377 
    378 int32_t XRayGetSavedThreadID(struct XRayTraceCapture* capture) {
    379   return capture->thread_id;
    380 }
    381 
    382 struct XRayTimestampPair XRayFrameGetStartTimestampPair(
    383     struct XRayTraceCapture* capture, int frame) {
    384   return capture->frame.entry[frame].start_time;
    385 }
    386 
    387 struct XRayTimestampPair XRayFrameGetEndTimestampPair(
    388     struct XRayTraceCapture* capture, int frame) {
    389   return capture->frame.entry[frame].end_time;
    390 }
    391 #endif
    392 
    393 /* Special case appending annotation string to trace buffer */
    394 /* this function should only ever be called from __cyg_profile_func_exit() */
    395 void __xray_profile_append_annotation(struct XRayTraceCapture* capture,
    396                                       struct XRayTraceStackEntry* se,
    397                                       struct XRayTraceBufferEntry* be) {
    398   struct XRayTraceStackEntry* parent = se - 1;
    399   int start = parent->annotation_index;
    400   be->annotation_index = capture->buffer_index;
    401   char* str = &capture->annotation[start];
    402   XRayTraceAppendString(capture, str);
    403   *str = 0;
    404   ++capture->annotation_count;
    405 }
    406 
    407 
    408 
    409 /* Annotates the trace buffer. no filtering. */
    410 void __XRayAnnotate(const char* fmt, ...) {
    411   va_list args;
    412   struct XRayTraceCapture* capture = g_xray_capture;
    413   /* Only annotate functions recorded in the trace buffer. */
    414   if (capture && capture->initialized) {
    415     if (0 == capture->disabled) {
    416       if (capture->recording) {
    417         char buffer[1024];
    418         int r;
    419         va_start(args, fmt);
    420         r = vsnprintf(buffer, sizeof(buffer), fmt, args);
    421         va_end(args);
    422         {
    423           /* Get current string ptr */
    424           int depth = capture->stack_depth - 1;
    425           struct XRayTraceStackEntry* se = &capture->stack[depth];
    426           if (0 == se->annotation_index) {
    427             struct XRayTraceStackEntry* parent = se - 1;
    428             se->annotation_index = parent->annotation_index;
    429           }
    430           char* dst = &capture->annotation[se->annotation_index];
    431           strcpy(dst, buffer);
    432           int len = strlen(dst);
    433           se->annotation_index += len;
    434         }
    435       }
    436     }
    437   }
    438 }
    439 
    440 
    441 /* Annotates the trace buffer with user strings.  Can be filtered. */
    442 void __XRayAnnotateFiltered(const uint32_t filter, const char* fmt, ...) {
    443   va_list args;
    444   struct XRayTraceCapture* capture = g_xray_capture;
    445   if (capture && capture->initialized) {
    446     if (0 != (filter & capture->annotation_filter)) {
    447       if (0 == capture->disabled) {
    448         if (capture->recording) {
    449           char buffer[XRAY_TRACE_ANNOTATION_LENGTH];
    450           int r;
    451           va_start(args, fmt);
    452           r = vsnprintf(buffer, sizeof(buffer), fmt, args);
    453           va_end(args);
    454           {
    455             /* get current string ptr */
    456             int depth = capture->stack_depth - 1;
    457             struct XRayTraceStackEntry* se = &capture->stack[depth];
    458             if (0 == se->annotation_index) {
    459               struct XRayTraceStackEntry* parent = se - 1;
    460               se->annotation_index = parent->annotation_index;
    461             }
    462             char* dst = &capture->annotation[se->annotation_index];
    463             strcpy(dst, buffer);
    464             int len = strlen(dst);
    465             se->annotation_index += len;
    466           }
    467         }
    468       }
    469     }
    470   }
    471 }
    472 
    473 
    474 /* Allows user to specify annotation filter value, a 32 bit mask. */
    475 void XRaySetAnnotationFilter(struct XRayTraceCapture* capture,
    476                              uint32_t filter) {
    477   capture->annotation_filter = filter;
    478 }
    479 
    480 
    481 /* Reset xray profiler. */
    482 void XRayReset(struct XRayTraceCapture* capture) {
    483   assert(capture);
    484   assert(capture->initialized);
    485   assert(!capture->recording);
    486   capture->buffer_index = 0;
    487   capture->stack_depth = 0;
    488   capture->disabled = 0;
    489   capture->frame.head = 0;
    490   capture->frame.tail = 0;
    491   memset(capture->frame.entry, 0,
    492     sizeof(capture->frame.entry[0]) * capture->frame.count);
    493   memset(&capture->stack, 0,
    494     sizeof(capture->stack[0]) * XRAY_TRACE_STACK_SIZE);
    495   XRayCheckGuards(capture);
    496 }
    497 
    498 
    499 /* Change the maximum stack depth captures are made. */
    500 void XRaySetMaxStackDepth(struct XRayTraceCapture* capture, int stack_depth) {
    501   assert(capture);
    502   assert(capture->initialized);
    503   assert(!capture->recording);
    504   if (stack_depth < 1)
    505     stack_depth = 1;
    506   if (stack_depth >= XRAY_TRACE_STACK_SIZE)
    507     stack_depth = (XRAY_TRACE_STACK_SIZE - 1);
    508   capture->max_stack_depth = stack_depth;
    509 }
    510 
    511 
    512 int XRayFrameGetCount(struct XRayTraceCapture* capture) {
    513   return capture->frame.count;
    514 }
    515 
    516 int XRayFrameGetTail(struct XRayTraceCapture* capture) {
    517   return capture->frame.tail;
    518 }
    519 
    520 int XRayFrameGetHead(struct XRayTraceCapture* capture) {
    521   return capture->frame.head;
    522 }
    523 
    524 int XRayFrameGetPrev(struct XRayTraceCapture* capture, int i) {
    525   i = i - 1;
    526   if (i < 0)
    527     i = capture->frame.count - 1;
    528   return i;
    529 }
    530 
    531 int XRayFrameGetNext(struct XRayTraceCapture* capture, int i) {
    532   i = i + 1;
    533   if (i >= capture->frame.count)
    534     i = 0;
    535   return i;
    536 }
    537 
    538 bool XRayFrameIsValid(struct XRayTraceCapture* capture, int i) {
    539   return capture->frame.entry[i].valid;
    540 }
    541 
    542 int XRayFrameGetTotalTicks(struct XRayTraceCapture* capture, int i) {
    543   return capture->frame.entry[i].total_ticks;
    544 }
    545 
    546 int XRayFrameGetAnnotationCount(struct XRayTraceCapture* capture, int i) {
    547   return capture->frame.entry[i].annotation_count;
    548 }
    549 
    550 void XRayFrameMakeLabel(struct XRayTraceCapture* capture,
    551                         int counter,
    552                         char* label) {
    553   snprintf(label, XRAY_MAX_LABEL, "@@@frame%d@@@", counter);
    554 }
    555 
    556 
    557 /* Scans the ring buffer going backwards to find last valid complete frame. */
    558 /* Will mark whether frames are valid or invalid during the traversal. */
    559 int XRayFrameFindTail(struct XRayTraceCapture* capture) {
    560   int head = capture->frame.head;
    561   int index = XRayFrameGetPrev(capture, head);
    562   int total_capture = 0;
    563   int last_valid_frame = index;
    564   /* Check for no captures */
    565   if (capture->frame.head == capture->frame.tail)
    566     return capture->frame.head;
    567   /* Go back and invalidate all captures that have been stomped. */
    568   while (index != head) {
    569     bool valid = capture->frame.entry[index].valid;
    570     if (valid) {
    571       total_capture += XRayFrameGetTraceCount(capture, index) + 1;
    572       if (total_capture < capture->buffer_size) {
    573         last_valid_frame = index;
    574         capture->frame.entry[index].valid = true;
    575       } else {
    576         capture->frame.entry[index].valid = false;
    577       }
    578     }
    579     index = XRayFrameGetPrev(capture, index);
    580   }
    581   return last_valid_frame;
    582 }
    583 
    584 
    585 /* Starts a new frame and enables capturing, and must be paired with */
    586 /* XRayEndFrame()  Trace capturing only occurs on the thread which called */
    587 /* XRayBeginFrame() and each instance of capture can only trace one thread */
    588 /* at a time. */
    589 void XRayStartFrame(struct XRayTraceCapture* capture) {
    590   int i;
    591   assert(NULL == g_xray_capture);
    592   assert(capture->initialized);
    593   assert(!capture->recording);
    594   i = capture->frame.head;
    595   XRayCheckGuards(capture);
    596   /* Add a trace entry marker so we can detect wrap around stomping */
    597   struct XRayTraceBufferEntry* be = &capture->buffer[capture->buffer_index];
    598   be->depth_addr = XRAY_FRAME_MARKER;
    599   capture->buffer_index =
    600       XRayTraceIncrementIndex(capture, capture->buffer_index);
    601   /* Set start of the frame we're about to trace */
    602   capture->frame.entry[i].start = capture->buffer_index;
    603   capture->disabled = 0;
    604   capture->stack_depth = 1;
    605   /* The trace stack[0] is reserved */
    606   memset(&capture->stack[0], 0, sizeof(capture->stack[0]));
    607   /* Annotation index 0 is reserved to indicate no annotation */
    608   capture->stack[0].annotation_index = 1;
    609   capture->annotation[0] = 0;
    610   capture->annotation[1] = 0;
    611   capture->annotation_count = 0;
    612   capture->recording = true;
    613   GTSC(capture->frame.entry[i].start_tsc);
    614   g_xray_capture = capture;
    615 
    616 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION
    617   capture->frame.entry[i].start_time = XRayGenerateTimestampsNow();
    618 #endif
    619 
    620 }
    621 
    622 
    623 /* Ends a frame and disables capturing. Advances to the next frame. */
    624 /* Must be paired with XRayStartFrame(), and called from the same thread. */
    625 void XRayEndFrame(struct XRayTraceCapture* capture) {
    626   int i;
    627   assert(capture);
    628   assert(capture->initialized);
    629   assert(capture->recording);
    630   assert(g_xray_capture == capture);
    631   assert(0 == capture->disabled);
    632   assert(1 == capture->stack_depth);
    633   i = capture->frame.head;
    634   GTSC(capture->frame.entry[i].end_tsc);
    635   capture->frame.entry[i].total_ticks =
    636     capture->frame.entry[i].end_tsc - capture->frame.entry[i].start_tsc;
    637   capture->recording = NULL;
    638   capture->frame.entry[i].end = capture->buffer_index;
    639   capture->frame.entry[i].valid = true;
    640   capture->frame.entry[i].annotation_count = capture->annotation_count;
    641   capture->frame.head = XRayFrameGetNext(capture, capture->frame.head);
    642   /* If the table is filled, bump the tail. */
    643   if (capture->frame.head == capture->frame.tail)
    644     capture->frame.tail = XRayFrameGetNext(capture, capture->frame.tail);
    645   capture->frame.tail = XRayFrameFindTail(capture);
    646   /* Check that we didn't stomp over trace entry marker. */
    647   int marker = XRayTraceDecrementIndex(capture, capture->frame.entry[i].start);
    648   struct XRayTraceBufferEntry* be = &capture->buffer[marker];
    649   if (be->depth_addr != XRAY_FRAME_MARKER) {
    650     fprintf(stderr,
    651       "XRay: XRayStopFrame() detects insufficient trace buffer size!\n");
    652     XRayReset(capture);
    653   } else {
    654     /* Replace marker with an empty annotation string. */
    655     be->depth_addr = XRAY_NULL_ANNOTATION;
    656     XRayCheckGuards(capture);
    657   }
    658   g_xray_capture = NULL;
    659 
    660 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION
    661   capture->frame.entry[i].end_time = XRayGenerateTimestampsNow();
    662 #endif
    663 }
    664 
    665 
    666 /* Get the last frame captured.  Do not call while capturing. */
    667 /* (ie call outside of XRayStartFrame() / XRayStopFrame() pair) */
    668 int XRayGetLastFrame(struct XRayTraceCapture* capture) {
    669   assert(capture);
    670   assert(capture->initialized);
    671   assert(!capture->recording);
    672   assert(0 == capture->disabled);
    673   assert(1 == capture->stack_depth);
    674   int last_frame = XRayFrameGetPrev(capture, capture->frame.head);
    675   return last_frame;
    676 }
    677 
    678 
    679 /* Disables capturing until a paired XRayEnableCapture() is called */
    680 /* This call can be nested, but must be paired with an enable */
    681 /* (If you need to just exclude a specific function and not its */
    682 /* children, the XRAY_NO_INSTRUMENT modifier might be better) */
    683 /* Must be called from same thread as XRayBeginFrame() / XRayEndFrame() */
    684 void XRayDisableCapture(struct XRayTraceCapture* capture) {
    685   assert(capture);
    686   assert(capture == g_xray_capture);
    687   assert(capture->initialized);
    688   ++capture->disabled;
    689   capture->recording = false;
    690 }
    691 
    692 
    693 /* Re-enables capture.  Must be paired with XRayDisableCapture() */
    694 void XRayEnableCapture(struct XRayTraceCapture* capture) {
    695   assert(capture);
    696   assert(capture == g_xray_capture);
    697   assert(capture->initialized);
    698   assert(0 < capture->disabled);
    699   --capture->disabled;
    700   if (0 == capture->disabled) {
    701     capture->recording = true;
    702   }
    703 }
    704 
    705 
    706 
    707 struct XRaySymbolTable* XRayGetSymbolTable(struct XRayTraceCapture* capture) {
    708   return capture->symbols;
    709 }
    710 
    711 
    712 /* Initialize XRay */
    713 struct XRayTraceCapture* XRayInit(int stack_depth,
    714                                   int buffer_size,
    715                                   int frame_count,
    716                                   const char* mapfilename) {
    717   struct XRayTraceCapture* capture;
    718   capture = (struct XRayTraceCapture*)XRayMalloc(
    719       sizeof(struct XRayTraceCapture));
    720   int adj_frame_count = frame_count + 1;
    721   size_t buffer_size_in_bytes =
    722       sizeof(capture->buffer[0]) * buffer_size;
    723   size_t frame_size_in_bytes =
    724       sizeof(capture->frame.entry[0]) * adj_frame_count;
    725   capture->buffer =
    726       (struct XRayTraceBufferEntry *)XRayMalloc(buffer_size_in_bytes);
    727   capture->frame.entry =
    728       (struct XRayTraceFrameEntry *)XRayMalloc(frame_size_in_bytes);
    729   capture->buffer_size = buffer_size;
    730   capture->frame.count = adj_frame_count;
    731   capture->frame.head = 0;
    732   capture->frame.tail = 0;
    733   capture->disabled = 0;
    734   capture->annotation_filter = 0xFFFFFFFF;
    735   capture->guard0 = XRAY_GUARD_VALUE_0x12345678;
    736   capture->guard1 = XRAY_GUARD_VALUE_0x12345678;
    737   capture->guard2 = XRAY_GUARD_VALUE_0x87654321;
    738   capture->guard3 = XRAY_GUARD_VALUE_0x12345678;
    739   capture->initialized = true;
    740   capture->recording = false;
    741   XRaySetMaxStackDepth(capture, stack_depth);
    742   XRayReset(capture);
    743 
    744   /* Mapfile is optional; we don't need it for captures, only for reports. */
    745   capture->symbols =
    746       XRaySymbolTableCreate(XRAY_DEFAULT_SYMBOL_TABLE_SIZE);
    747   if (NULL != mapfilename)
    748     XRaySymbolTableParseMapfile(capture->symbols, mapfilename);
    749 
    750 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION
    751   /* Use the address of a thread local variable as a fake thread id. */
    752   capture->thread_id = (int32_t)(&g_xray_thread_id_placeholder);
    753 #endif
    754 
    755   return capture;
    756 }
    757 
    758 
    759 /* Shut down and free memory used by XRay. */
    760 void XRayShutdown(struct XRayTraceCapture* capture) {
    761   assert(capture);
    762   assert(capture->initialized);
    763   assert(!capture->recording);
    764   XRayCheckGuards(capture);
    765   if (NULL != capture->symbols) {
    766     XRaySymbolTableFree(capture->symbols);
    767   }
    768   XRayFree(capture->frame.entry);
    769   XRayFree(capture->buffer);
    770   capture->initialized = false;
    771   XRayFree(capture);
    772 }
    773 
    774 #endif  /* XRAY */
    775