root/native_client_sdk/src/libraries/xray/xray.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. RDTSC64
  2. GTOD
  3. XRayCheckGuards
  4. XRayTraceDecrementIndexInline
  5. XRayTraceIncrementIndexInline
  6. XRayTraceIsAnnotation
  7. XRayTraceIncrementIndex
  8. XRayTraceDecrementIndex
  9. XRayTraceSkipAnnotation
  10. XRayTraceGetEntry
  11. XRayTraceNextEntry
  12. XRayFrameGetTraceStartIndex
  13. XRayFrameGetTraceEndIndex
  14. XRayFrameGetTraceCount
  15. XRayTraceAppendString
  16. XRayTraceCopyToString
  17. XRayMalloc
  18. XRayFree
  19. __pnacl_profile_func_enter
  20. __cyg_profile_func_enter
  21. __pnacl_profile_func_exit
  22. __cyg_profile_func_exit
  23. XRayGetTSC
  24. XRayGetSavedThreadID
  25. XRayFrameGetStartTimestampPair
  26. XRayFrameGetEndTimestampPair
  27. __xray_profile_append_annotation
  28. __XRayAnnotate
  29. __XRayAnnotateFiltered
  30. XRaySetAnnotationFilter
  31. XRayReset
  32. XRaySetMaxStackDepth
  33. XRayFrameGetCount
  34. XRayFrameGetTail
  35. XRayFrameGetHead
  36. XRayFrameGetPrev
  37. XRayFrameGetNext
  38. XRayFrameIsValid
  39. XRayFrameGetTotalTicks
  40. XRayFrameGetAnnotationCount
  41. XRayFrameMakeLabel
  42. XRayFrameFindTail
  43. XRayStartFrame
  44. XRayEndFrame
  45. XRayGetLastFrame
  46. XRayDisableCapture
  47. XRayEnableCapture
  48. XRayGetSymbolTable
  49. XRayInit
  50. XRayShutdown

/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file. */


/* XRay -- a simple profiler for Native Client */

#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include "xray/xray_priv.h"

#if defined(XRAY)

/* GTSC - Get Time Stamp Counter */
#if defined(__amd64__) && !defined(XRAY_NO_RDTSC)
XRAY_INLINE uint64_t RDTSC64();
uint64_t RDTSC64() {
  uint64_t a, d;
  __asm__ __volatile__("rdtsc" : "=a" (a), "=d" (d));
  return ((uint64_t)a) | (((uint64_t)d) << 32);
}
#define GTSC(_x) _x = RDTSC64()
#elif defined(__i386__) && !defined(XRAY_NO_RDTSC)
#define GTSC(_x)      __asm__ __volatile__ ("rdtsc" : "=A" (_x));
#else
XRAY_INLINE uint64_t GTOD();
uint64_t GTOD() {
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec;
}
#define GTSC(_x) _x = GTOD();
#endif

/* Use a TLS variable for cheap thread uid. */
__thread struct XRayTraceCapture* g_xray_capture = NULL;
__thread int g_xray_thread_id_placeholder = 0;


struct XRayTraceStackEntry {
  uint32_t depth_addr;
  uint64_t tsc;
  uint32_t dest;
  uint32_t annotation_index;
};


struct XRayTraceFrameEntry {
  /* Indices into global tracebuffer */
  int start;
  int end;
  uint64_t start_tsc;
  uint64_t end_tsc;
  uint64_t total_ticks;
  int annotation_count;
  bool valid;

#ifndef XRAY_DISABLE_BROWSER_INTEGRATION
  struct XRayTimestampPair start_time;
  struct XRayTimestampPair end_time;
#endif
};


struct XRayTraceFrame {
  struct XRayTraceFrameEntry* entry;
  int head;
  int tail;
  int count;
};


struct XRayTraceCapture {
  /* Common variables share cache line */
  bool recording;
  uint32_t stack_depth;
  uint32_t max_stack_depth;
  int buffer_index;
  int buffer_size;
  int disabled;
  int annotation_count;
  struct XRaySymbolTable* symbols;
  bool initialized;
  uint32_t annotation_filter;
  uint32_t guard0;
  struct XRayTraceStackEntry stack[XRAY_TRACE_STACK_SIZE] XRAY_ALIGN64;
  uint32_t guard1;
  uint32_t guard2;
  char annotation[XRAY_ANNOTATION_STACK_SIZE] XRAY_ALIGN64;
  uint32_t guard3;
  struct XRayTraceBufferEntry* buffer;
  struct XRayTraceFrame frame;

#ifndef XRAY_DISABLE_BROWSER_INTEGRATION
  int32_t thread_id;
#endif
} XRAY_ALIGN64;


#ifdef __cplusplus
extern "C" {
#endif

#if defined(__pnacl__)
XRAY_NO_INSTRUMENT void __pnacl_profile_func_enter(const char* fname);
XRAY_NO_INSTRUMENT void __pnacl_profile_func_exit(const char* fname);
#else
XRAY_NO_INSTRUMENT void __cyg_profile_func_enter(void* this_fn,
                                                 void* call_site);
XRAY_NO_INSTRUMENT void __cyg_profile_func_exit(void* this_fn,
                                                void* call_site);
#endif

XRAY_INLINE int XRayTraceDecrementIndexInline(
    struct XRayTraceCapture* capture, int index);
XRAY_INLINE int XRayTraceIncrementIndexInline(
    struct XRayTraceCapture* capture, int index);


XRAY_NO_INSTRUMENT void __xray_profile_append_annotation(
    struct XRayTraceCapture* capture,
    struct XRayTraceStackEntry* se,
    struct XRayTraceBufferEntry* be);

#ifdef __cplusplus
}
#endif

/* Asserts that the guard values haven't changed. */
void XRayCheckGuards(struct XRayTraceCapture* capture) {
  assert(capture->guard0 == XRAY_GUARD_VALUE_0x12345678);
  assert(capture->guard1 == XRAY_GUARD_VALUE_0x12345678);
  assert(capture->guard2 == XRAY_GUARD_VALUE_0x87654321);
  assert(capture->guard3 == XRAY_GUARD_VALUE_0x12345678);
}

/* Decrements the trace index, wrapping around if needed. */
int XRayTraceDecrementIndexInline(
    struct XRayTraceCapture* capture, int index) {
  --index;
  if (index < 0)
    index = capture->buffer_size - 1;
  return index;
}

/* Increments the trace index, wrapping around if needed. */
int XRayTraceIncrementIndexInline(
    struct XRayTraceCapture* capture, int index) {
  ++index;
  if (index >= capture->buffer_size)
    index = 0;
  return index;
}

/* Returns true if the trace entry is an annotation string. */
bool XRayTraceIsAnnotation(
    struct XRayTraceCapture* capture, int index) {
  struct XRayTraceBufferEntry* be = &capture->buffer[index];
  char* dst = (char*)be;
  return 0 == *dst;
}

int XRayTraceIncrementIndex(struct XRayTraceCapture* capture, int index) {
  return XRayTraceIncrementIndexInline(capture, index);
}

int XRayTraceDecrementIndex(struct XRayTraceCapture* capture, int index) {
  return XRayTraceDecrementIndexInline(capture, index);
}

/* The entry in the tracebuffer at index is an annotation string. */
/* Calculate the next index value representing the next trace entry. */
int XRayTraceSkipAnnotation(struct XRayTraceCapture* capture, int index) {
  /* Annotations are strings embedded in the trace buffer. */
  /* An annotation string can span multiple trace entries. */
  /* Skip over the string by looking for zero termination. */
  assert(capture);
  assert(XRayTraceIsAnnotation(capture, index));
  bool done = false;
  int start_index = 1;
  int i;
  while (!done) {
    char* str = (char*) &capture->buffer[index];
    const int num = sizeof(capture->buffer[index]);
    for (i = start_index; i < num; ++i) {
      if (0 == str[i]) {
        done = true;
        break;
      }
    }
    index = XRayTraceIncrementIndexInline(capture, index);
    start_index = 0;
  }
  return index;
}


struct XRayTraceBufferEntry* XRayTraceGetEntry(
    struct XRayTraceCapture* capture, int index) {
  return &capture->buffer[index];
}

/* Starting at index, return the index into the trace buffer */
/* for the next trace entry.  Index can wrap (ringbuffer) */
int XRayTraceNextEntry(struct XRayTraceCapture* capture, int index) {
  if (XRayTraceIsAnnotation(capture, index))
    index = XRayTraceSkipAnnotation(capture, index);
  else
    index = XRayTraceIncrementIndexInline(capture, index);
  return index;
}

int XRayFrameGetTraceStartIndex(struct XRayTraceCapture* capture, int frame) {
  assert(capture);
  assert(capture->initialized);
  assert(!capture->recording);
  return capture->frame.entry[frame].start;
}

int XRayFrameGetTraceEndIndex(struct XRayTraceCapture* capture, int frame) {
  assert(capture);
  assert(capture->initialized);
  assert(!capture->recording);
  return capture->frame.entry[frame].end;
}

/* Not very accurate, annotation strings will also be counted as "entries" */
int XRayFrameGetTraceCount(
    struct XRayTraceCapture* capture, int frame) {
  assert(true == capture->initialized);
  assert(frame >= 0);
  assert(frame < capture->frame.count);
  assert(!capture->recording);
  int start = capture->frame.entry[frame].start;
  int end = capture->frame.entry[frame].end;
  int num;
  if (start < end)
    num = end - start;
  else
    num = capture->buffer_size - (start - end);
  return num;
}

/* Append a string to trace buffer. */
void XRayTraceAppendString(struct XRayTraceCapture* capture, char* src) {
  int index = capture->buffer_index;
  bool done = false;
  int start_index = 1;
  int s = 0;
  int i;
  char* dst = (char*)&capture->buffer[index];
  const int num = sizeof(capture->buffer[index]);
  dst[0] = 0;
  while (!done) {
    for (i = start_index; i < num; ++i) {
      dst[i] = src[s];
      if (0 == src[s]) {
        dst[i] = 0;
        done = true;
        break;
      }
      ++s;
    }
    index = XRayTraceIncrementIndexInline(capture, index);
    dst = (char*)&capture->buffer[index];
    start_index = 0;
  }
  capture->buffer_index = index;
}

/* Copies annotation from trace buffer to output string. */
int XRayTraceCopyToString(
    struct XRayTraceCapture* capture, int index, char* dst) {
  assert(XRayTraceIsAnnotation(capture, index));
  bool done = false;
  int i;
  int d = 0;
  int start_index = 1;
  while (!done) {
    char* src = (char*) &capture->buffer[index];
    const int num = sizeof(capture->buffer[index]);
    for (i = start_index; i < num; ++i) {
      dst[d] = src[i];
      if (0 == src[i]) {
        done = true;
        break;
      }
      ++d;
    }
    index = XRayTraceIncrementIndexInline(capture, index);
    start_index = 0;
  }
  return index;
}


/* Generic memory malloc for XRay */
/* validates pointer returned by malloc */
/* memsets memory block to zero */
void* XRayMalloc(size_t t) {
  void* data;
  data = calloc(1, t);
  if (NULL == data) {
    printf("XRay: malloc(%d) failed, panic shutdown!\n", t);
    exit(-1);
  }
  return data;
}


/* Generic memory free for XRay */
void XRayFree(void* data) {
  assert(NULL != data);
  free(data);
}


/* Main profile capture function that is called at the start */
/* of every instrumented function.  This function is implicitly */
/* called when code is compilied with the -finstrument-functions option */
#if defined(__pnacl__)
void __pnacl_profile_func_enter(const char* this_fn) {
#else
void __cyg_profile_func_enter(void* this_fn, void* call_site) {
#endif
  struct XRayTraceCapture* capture = g_xray_capture;
  if (capture && capture->recording) {
    uint32_t depth = capture->stack_depth;
    if (depth < capture->max_stack_depth) {
      struct XRayTraceStackEntry* se = &capture->stack[depth];
      uint32_t addr = (uint32_t)(uintptr_t)this_fn;
      se->depth_addr = XRAY_PACK_DEPTH_ADDR(depth, addr);
      se->dest = capture->buffer_index;
      se->annotation_index = 0;
      GTSC(se->tsc);
      capture->buffer_index =
        XRayTraceIncrementIndexInline(capture, capture->buffer_index);
    }
    ++capture->stack_depth;
  }
}


/* Main profile capture function that is called at the exit of */
/* every instrumented function.  This function is implicity called */
/* when the code is compiled with the -finstrument-functions option */
#if defined(__pnacl__)
void __pnacl_profile_func_exit(const char* this_fn) {
#else
void __cyg_profile_func_exit(void* this_fn, void* call_site) {
#endif
  struct XRayTraceCapture* capture = g_xray_capture;
  if (capture && capture->recording) {
    --capture->stack_depth;
    if (capture->stack_depth < capture->max_stack_depth) {
      uint32_t depth = capture->stack_depth;
      struct XRayTraceStackEntry* se = &capture->stack[depth];
      uint32_t buffer_index = se->dest;
      uint64_t tsc;
      struct XRayTraceBufferEntry* be = &capture->buffer[buffer_index];
      GTSC(tsc);
      be->depth_addr = se->depth_addr;
      be->start_tick = se->tsc;
      be->end_tick = tsc;
      be->annotation_index = 0;
      if (0 != se->annotation_index)
        __xray_profile_append_annotation(capture, se, be);
    }
  }
}

#ifndef XRAY_DISABLE_BROWSER_INTEGRATION
void XRayGetTSC(uint64_t* tsc) {
  GTSC(*tsc);
}

int32_t XRayGetSavedThreadID(struct XRayTraceCapture* capture) {
  return capture->thread_id;
}

struct XRayTimestampPair XRayFrameGetStartTimestampPair(
    struct XRayTraceCapture* capture, int frame) {
  return capture->frame.entry[frame].start_time;
}

struct XRayTimestampPair XRayFrameGetEndTimestampPair(
    struct XRayTraceCapture* capture, int frame) {
  return capture->frame.entry[frame].end_time;
}
#endif

/* Special case appending annotation string to trace buffer */
/* this function should only ever be called from __cyg_profile_func_exit() */
void __xray_profile_append_annotation(struct XRayTraceCapture* capture,
                                      struct XRayTraceStackEntry* se,
                                      struct XRayTraceBufferEntry* be) {
  struct XRayTraceStackEntry* parent = se - 1;
  int start = parent->annotation_index;
  be->annotation_index = capture->buffer_index;
  char* str = &capture->annotation[start];
  XRayTraceAppendString(capture, str);
  *str = 0;
  ++capture->annotation_count;
}



/* Annotates the trace buffer. no filtering. */
void __XRayAnnotate(const char* fmt, ...) {
  va_list args;
  struct XRayTraceCapture* capture = g_xray_capture;
  /* Only annotate functions recorded in the trace buffer. */
  if (capture && capture->initialized) {
    if (0 == capture->disabled) {
      if (capture->recording) {
        char buffer[1024];
        int r;
        va_start(args, fmt);
        r = vsnprintf(buffer, sizeof(buffer), fmt, args);
        va_end(args);
        {
          /* Get current string ptr */
          int depth = capture->stack_depth - 1;
          struct XRayTraceStackEntry* se = &capture->stack[depth];
          if (0 == se->annotation_index) {
            struct XRayTraceStackEntry* parent = se - 1;
            se->annotation_index = parent->annotation_index;
          }
          char* dst = &capture->annotation[se->annotation_index];
          strcpy(dst, buffer);
          int len = strlen(dst);
          se->annotation_index += len;
        }
      }
    }
  }
}


/* Annotates the trace buffer with user strings.  Can be filtered. */
void __XRayAnnotateFiltered(const uint32_t filter, const char* fmt, ...) {
  va_list args;
  struct XRayTraceCapture* capture = g_xray_capture;
  if (capture && capture->initialized) {
    if (0 != (filter & capture->annotation_filter)) {
      if (0 == capture->disabled) {
        if (capture->recording) {
          char buffer[XRAY_TRACE_ANNOTATION_LENGTH];
          int r;
          va_start(args, fmt);
          r = vsnprintf(buffer, sizeof(buffer), fmt, args);
          va_end(args);
          {
            /* get current string ptr */
            int depth = capture->stack_depth - 1;
            struct XRayTraceStackEntry* se = &capture->stack[depth];
            if (0 == se->annotation_index) {
              struct XRayTraceStackEntry* parent = se - 1;
              se->annotation_index = parent->annotation_index;
            }
            char* dst = &capture->annotation[se->annotation_index];
            strcpy(dst, buffer);
            int len = strlen(dst);
            se->annotation_index += len;
          }
        }
      }
    }
  }
}


/* Allows user to specify annotation filter value, a 32 bit mask. */
void XRaySetAnnotationFilter(struct XRayTraceCapture* capture,
                             uint32_t filter) {
  capture->annotation_filter = filter;
}


/* Reset xray profiler. */
void XRayReset(struct XRayTraceCapture* capture) {
  assert(capture);
  assert(capture->initialized);
  assert(!capture->recording);
  capture->buffer_index = 0;
  capture->stack_depth = 0;
  capture->disabled = 0;
  capture->frame.head = 0;
  capture->frame.tail = 0;
  memset(capture->frame.entry, 0,
    sizeof(capture->frame.entry[0]) * capture->frame.count);
  memset(&capture->stack, 0,
    sizeof(capture->stack[0]) * XRAY_TRACE_STACK_SIZE);
  XRayCheckGuards(capture);
}


/* Change the maximum stack depth captures are made. */
void XRaySetMaxStackDepth(struct XRayTraceCapture* capture, int stack_depth) {
  assert(capture);
  assert(capture->initialized);
  assert(!capture->recording);
  if (stack_depth < 1)
    stack_depth = 1;
  if (stack_depth >= XRAY_TRACE_STACK_SIZE)
    stack_depth = (XRAY_TRACE_STACK_SIZE - 1);
  capture->max_stack_depth = stack_depth;
}


int XRayFrameGetCount(struct XRayTraceCapture* capture) {
  return capture->frame.count;
}

int XRayFrameGetTail(struct XRayTraceCapture* capture) {
  return capture->frame.tail;
}

int XRayFrameGetHead(struct XRayTraceCapture* capture) {
  return capture->frame.head;
}

int XRayFrameGetPrev(struct XRayTraceCapture* capture, int i) {
  i = i - 1;
  if (i < 0)
    i = capture->frame.count - 1;
  return i;
}

int XRayFrameGetNext(struct XRayTraceCapture* capture, int i) {
  i = i + 1;
  if (i >= capture->frame.count)
    i = 0;
  return i;
}

bool XRayFrameIsValid(struct XRayTraceCapture* capture, int i) {
  return capture->frame.entry[i].valid;
}

uint64_t XRayFrameGetTotalTicks(struct XRayTraceCapture* capture, int i) {
  return capture->frame.entry[i].total_ticks;
}

int XRayFrameGetAnnotationCount(struct XRayTraceCapture* capture, int i) {
  return capture->frame.entry[i].annotation_count;
}

void XRayFrameMakeLabel(struct XRayTraceCapture* capture,
                        int counter,
                        char* label) {
  snprintf(label, XRAY_MAX_LABEL, "@@@frame%d@@@", counter);
}


/* Scans the ring buffer going backwards to find last valid complete frame. */
/* Will mark whether frames are valid or invalid during the traversal. */
int XRayFrameFindTail(struct XRayTraceCapture* capture) {
  int head = capture->frame.head;
  int index = XRayFrameGetPrev(capture, head);
  int total_capture = 0;
  int last_valid_frame = index;
  /* Check for no captures */
  if (capture->frame.head == capture->frame.tail)
    return capture->frame.head;
  /* Go back and invalidate all captures that have been stomped. */
  while (index != head) {
    bool valid = capture->frame.entry[index].valid;
    if (valid) {
      total_capture += XRayFrameGetTraceCount(capture, index) + 1;
      if (total_capture < capture->buffer_size) {
        last_valid_frame = index;
        capture->frame.entry[index].valid = true;
      } else {
        capture->frame.entry[index].valid = false;
      }
    }
    index = XRayFrameGetPrev(capture, index);
  }
  return last_valid_frame;
}


/* Starts a new frame and enables capturing, and must be paired with */
/* XRayEndFrame()  Trace capturing only occurs on the thread which called */
/* XRayBeginFrame() and each instance of capture can only trace one thread */
/* at a time. */
void XRayStartFrame(struct XRayTraceCapture* capture) {
  int i;
  assert(NULL == g_xray_capture);
  assert(capture->initialized);
  assert(!capture->recording);
  i = capture->frame.head;
  XRayCheckGuards(capture);
  /* Add a trace entry marker so we can detect wrap around stomping */
  struct XRayTraceBufferEntry* be = &capture->buffer[capture->buffer_index];
  be->depth_addr = XRAY_FRAME_MARKER;
  capture->buffer_index =
      XRayTraceIncrementIndex(capture, capture->buffer_index);
  /* Set start of the frame we're about to trace */
  capture->frame.entry[i].start = capture->buffer_index;
  capture->disabled = 0;
  capture->stack_depth = 1;

  /* The trace stack[0] is reserved */
  memset(&capture->stack[0], 0, sizeof(capture->stack[0]));
  /* Annotation index 0 is reserved to indicate no annotation */
  capture->stack[0].annotation_index = 1;
  capture->annotation[0] = 0;
  capture->annotation[1] = 0;
  capture->annotation_count = 0;
  capture->recording = true;
  GTSC(capture->frame.entry[i].start_tsc);
  g_xray_capture = capture;

#ifndef XRAY_DISABLE_BROWSER_INTEGRATION
  capture->frame.entry[i].start_time = XRayGenerateTimestampsNow();
#endif
}


/* Ends a frame and disables capturing. Advances to the next frame. */
/* Must be paired with XRayStartFrame(), and called from the same thread. */
void XRayEndFrame(struct XRayTraceCapture* capture) {
  int i;
  assert(capture);
  assert(capture->initialized);
  assert(capture->recording);
  assert(g_xray_capture == capture);
  assert(0 == capture->disabled);
  assert(1 == capture->stack_depth);
  i = capture->frame.head;
  GTSC(capture->frame.entry[i].end_tsc);
  capture->frame.entry[i].total_ticks =
    capture->frame.entry[i].end_tsc - capture->frame.entry[i].start_tsc;
  capture->recording = NULL;
  capture->frame.entry[i].end = capture->buffer_index;
  capture->frame.entry[i].valid = true;
  capture->frame.entry[i].annotation_count = capture->annotation_count;
  capture->frame.head = XRayFrameGetNext(capture, capture->frame.head);
  /* If the table is filled, bump the tail. */
  if (capture->frame.head == capture->frame.tail)
    capture->frame.tail = XRayFrameGetNext(capture, capture->frame.tail);
  capture->frame.tail = XRayFrameFindTail(capture);
  /* Check that we didn't stomp over trace entry marker. */
  int marker = XRayTraceDecrementIndex(capture, capture->frame.entry[i].start);
  struct XRayTraceBufferEntry* be = &capture->buffer[marker];
  if (be->depth_addr != XRAY_FRAME_MARKER) {
    fprintf(stderr,
      "XRay: XRayStopFrame() detects insufficient trace buffer size!\n");
    XRayReset(capture);
  } else {
    /* Replace marker with an empty annotation string. */
    be->depth_addr = XRAY_NULL_ANNOTATION;
    XRayCheckGuards(capture);
  }
  g_xray_capture = NULL;

#ifndef XRAY_DISABLE_BROWSER_INTEGRATION
  capture->frame.entry[i].end_time = XRayGenerateTimestampsNow();
#endif
}


/* Get the last frame captured.  Do not call while capturing. */
/* (ie call outside of XRayStartFrame() / XRayStopFrame() pair) */
int XRayGetLastFrame(struct XRayTraceCapture* capture) {
  assert(capture);
  assert(capture->initialized);
  assert(!capture->recording);
  assert(0 == capture->disabled);
  assert(1 == capture->stack_depth);
  int last_frame = XRayFrameGetPrev(capture, capture->frame.head);
  return last_frame;
}


/* Disables capturing until a paired XRayEnableCapture() is called */
/* This call can be nested, but must be paired with an enable */
/* (If you need to just exclude a specific function and not its */
/* children, the XRAY_NO_INSTRUMENT modifier might be better) */
/* Must be called from same thread as XRayBeginFrame() / XRayEndFrame() */
void XRayDisableCapture(struct XRayTraceCapture* capture) {
  assert(capture);
  assert(capture == g_xray_capture);
  assert(capture->initialized);
  ++capture->disabled;
  capture->recording = false;
}


/* Re-enables capture.  Must be paired with XRayDisableCapture() */
void XRayEnableCapture(struct XRayTraceCapture* capture) {
  assert(capture);
  assert(capture == g_xray_capture);
  assert(capture->initialized);
  assert(0 < capture->disabled);
  --capture->disabled;
  if (0 == capture->disabled) {
    capture->recording = true;
  }
}



struct XRaySymbolTable* XRayGetSymbolTable(struct XRayTraceCapture* capture) {
  return capture->symbols;
}


/* Initialize XRay */
struct XRayTraceCapture* XRayInit(int stack_depth,
                                  int buffer_size,
                                  int frame_count,
                                  const char* mapfilename) {
  struct XRayTraceCapture* capture;
  capture = (struct XRayTraceCapture*)XRayMalloc(
      sizeof(struct XRayTraceCapture));
  int adj_frame_count = frame_count + 1;
  size_t buffer_size_in_bytes =
      sizeof(capture->buffer[0]) * buffer_size;
  size_t frame_size_in_bytes =
      sizeof(capture->frame.entry[0]) * adj_frame_count;
  capture->buffer =
      (struct XRayTraceBufferEntry *)XRayMalloc(buffer_size_in_bytes);
  capture->frame.entry =
      (struct XRayTraceFrameEntry *)XRayMalloc(frame_size_in_bytes);
  capture->buffer_size = buffer_size;
  capture->frame.count = adj_frame_count;
  capture->frame.head = 0;
  capture->frame.tail = 0;
  capture->disabled = 0;
  capture->annotation_filter = 0xFFFFFFFF;
  capture->guard0 = XRAY_GUARD_VALUE_0x12345678;
  capture->guard1 = XRAY_GUARD_VALUE_0x12345678;
  capture->guard2 = XRAY_GUARD_VALUE_0x87654321;
  capture->guard3 = XRAY_GUARD_VALUE_0x12345678;
  capture->initialized = true;
  capture->recording = false;
  XRaySetMaxStackDepth(capture, stack_depth);
  XRayReset(capture);

  /* Mapfile is optional; we don't need it for captures, only for reports. */
  capture->symbols =
      XRaySymbolTableCreate(XRAY_DEFAULT_SYMBOL_TABLE_SIZE);
  if (NULL != mapfilename)
    XRaySymbolTableParseMapfile(capture->symbols, mapfilename);

#ifndef XRAY_DISABLE_BROWSER_INTEGRATION
  /* Use the address of a thread local variable as a fake thread id. */
  capture->thread_id = (int32_t)(&g_xray_thread_id_placeholder);
#endif

  return capture;
}


/* Shut down and free memory used by XRay. */
void XRayShutdown(struct XRayTraceCapture* capture) {
  assert(capture);
  assert(capture->initialized);
  assert(!capture->recording);
  XRayCheckGuards(capture);
  if (NULL != capture->symbols) {
    XRaySymbolTableFree(capture->symbols);
  }
  XRayFree(capture->frame.entry);
  XRayFree(capture->buffer);
  capture->initialized = false;
  XRayFree(capture);
}

#endif  /* XRAY */

/* [<][>][^][v][top][bottom][index][help] */