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