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)
23XRAY_INLINE uint64_t RDTSC64();
24uint64_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
33XRAY_INLINE uint64_t GTOD();
34uint64_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
47struct XRayTraceStackEntry {
48  uint32_t depth_addr;
49  uint64_t tsc;
50  uint32_t dest;
51  uint32_t annotation_index;
52};
53
54
55struct 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
72struct XRayTraceFrame {
73  struct XRayTraceFrameEntry* entry;
74  int head;
75  int tail;
76  int count;
77};
78
79
80struct 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
108extern "C" {
109#endif
110
111#if defined(__pnacl__)
112XRAY_NO_INSTRUMENT void __pnacl_profile_func_enter(const char* fname);
113XRAY_NO_INSTRUMENT void __pnacl_profile_func_exit(const char* fname);
114#else
115XRAY_NO_INSTRUMENT void __cyg_profile_func_enter(void* this_fn,
116                                                 void* call_site);
117XRAY_NO_INSTRUMENT void __cyg_profile_func_exit(void* this_fn,
118                                                void* call_site);
119#endif
120
121XRAY_INLINE int XRayTraceDecrementIndexInline(
122    struct XRayTraceCapture* capture, int index);
123XRAY_INLINE int XRayTraceIncrementIndexInline(
124    struct XRayTraceCapture* capture, int index);
125
126
127XRAY_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. */
137void 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. */
145int 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. */
154int 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. */
163bool 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
170int XRayTraceIncrementIndex(struct XRayTraceCapture* capture, int index) {
171  return XRayTraceIncrementIndexInline(capture, index);
172}
173
174int 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. */
180int 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
205struct 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) */
212int 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
220int 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
227int 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" */
235int 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. */
252void 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. */
279int 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 */
307void* 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 */
319void 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__)
329void __pnacl_profile_func_enter(const char* this_fn) {
330#else
331void __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__)
355void __pnacl_profile_func_exit(const char* this_fn) {
356#else
357void __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
380void XRayGetTSC(uint64_t* tsc) {
381  GTSC(*tsc);
382}
383
384int32_t XRayGetSavedThreadID(struct XRayTraceCapture* capture) {
385  return capture->thread_id;
386}
387
388struct XRayTimestampPair XRayFrameGetStartTimestampPair(
389    struct XRayTraceCapture* capture, int frame) {
390  return capture->frame.entry[frame].start_time;
391}
392
393struct 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() */
401void __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. */
416void __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. */
448void __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. */
481void XRaySetAnnotationFilter(struct XRayTraceCapture* capture,
482                             uint32_t filter) {
483  capture->annotation_filter = filter;
484}
485
486
487/* Reset xray profiler. */
488void 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. */
506void 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
518int XRayFrameGetCount(struct XRayTraceCapture* capture) {
519  return capture->frame.count;
520}
521
522int XRayFrameGetTail(struct XRayTraceCapture* capture) {
523  return capture->frame.tail;
524}
525
526int XRayFrameGetHead(struct XRayTraceCapture* capture) {
527  return capture->frame.head;
528}
529
530int 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
537int XRayFrameGetNext(struct XRayTraceCapture* capture, int i) {
538  i = i + 1;
539  if (i >= capture->frame.count)
540    i = 0;
541  return i;
542}
543
544bool XRayFrameIsValid(struct XRayTraceCapture* capture, int i) {
545  return capture->frame.entry[i].valid;
546}
547
548uint64_t XRayFrameGetTotalTicks(struct XRayTraceCapture* capture, int i) {
549  return capture->frame.entry[i].total_ticks;
550}
551
552int XRayFrameGetAnnotationCount(struct XRayTraceCapture* capture, int i) {
553  return capture->frame.entry[i].annotation_count;
554}
555
556void 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. */
565int 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. */
595void 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. */
631void 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) */
674int 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() */
690void 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() */
700void 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
713struct XRaySymbolTable* XRayGetSymbolTable(struct XRayTraceCapture* capture) {
714  return capture->symbols;
715}
716
717
718/* Initialize XRay */
719struct 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. */
766void 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