• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
RDTSC64()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
GTOD()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. */
XRayCheckGuards(struct XRayTraceCapture * capture)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. */
XRayTraceDecrementIndexInline(struct XRayTraceCapture * capture,int index)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. */
XRayTraceIncrementIndexInline(struct XRayTraceCapture * capture,int index)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. */
XRayTraceIsAnnotation(struct XRayTraceCapture * capture,int index)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 
XRayTraceIncrementIndex(struct XRayTraceCapture * capture,int index)164 int XRayTraceIncrementIndex(struct XRayTraceCapture* capture, int index) {
165   return XRayTraceIncrementIndexInline(capture, index);
166 }
167 
XRayTraceDecrementIndex(struct XRayTraceCapture * capture,int index)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. */
XRayTraceSkipAnnotation(struct XRayTraceCapture * capture,int index)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 
XRayTraceGetEntry(struct XRayTraceCapture * capture,int index)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) */
XRayTraceNextEntry(struct XRayTraceCapture * capture,int index)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 
XRayFrameGetTraceStartIndex(struct XRayTraceCapture * capture,int frame)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 
XRayFrameGetTraceEndIndex(struct XRayTraceCapture * capture,int frame)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" */
XRayFrameGetTraceCount(struct XRayTraceCapture * capture,int frame)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. */
XRayTraceAppendString(struct XRayTraceCapture * capture,char * src)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. */
XRayTraceCopyToString(struct XRayTraceCapture * capture,int index,char * dst)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 */
XRayMalloc(size_t t)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 */
XRayFree(void * data)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__)
__pnacl_profile_func_enter(const char * this_fn)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