summaryrefslogtreecommitdiffstats
path: root/native_client_sdk/src/libraries/xray/browser.c
blob: 7f124592102f57da138bf101dfc5f909e9eef73c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/* 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 */

#ifndef XRAY_DISABLE_BROWSER_INTEGRATION

#include <alloca.h>
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ppapi/c/dev/ppb_trace_event_dev.h"
#include "xray/xray_priv.h"


#if defined(XRAY)
static PPB_Trace_Event_Dev* ppb_trace_event_interface = NULL;

static const char* XRayGetName(struct XRaySymbolTable* symbols,
      struct XRayTraceBufferEntry* e) {
  uint32_t addr = XRAY_EXTRACT_ADDR(e->depth_addr);
  struct XRaySymbol* symbol = XRaySymbolTableLookup(symbols, addr);
  return XRaySymbolGetName(symbol);
}

struct XRayTimestampPair XRayGenerateTimestampsNow(void) {
  struct XRayTimestampPair pair;
  assert(ppb_trace_event_interface);

  XRayGetTSC(&pair.xray);
  pair.pepper = ppb_trace_event_interface->Now();
  return pair;
}

/* see chromium/src/base/debug/trace_event.h */
#define TRACE_VALUE_TYPE_UINT (2)
#define TRACE_VALUE_TYPE_DOUBLE (4)
#define TRACE_VALUE_TYPE_COPY_STRING (7)

union TraceValue {
    bool as_bool;
    unsigned long long as_uint;
    long long as_int;
    double as_double;
    const void* as_pointer;
    const char* as_string;
  };

void XRayBrowserTraceReport(struct XRayTraceCapture* capture) {

  const void* cat_enabled = ppb_trace_event_interface->GetCategoryEnabled(
      "xray");
  struct XRaySymbolTable* symbols = XRayGetSymbolTable(capture);

  int32_t thread_id = XRayGetSavedThreadID(capture);

  int head = XRayFrameGetHead(capture);
  int frame = XRayFrameGetTail(capture);
  while(frame != head) {

    struct XRayTimestampPair start_time = XRayFrameGetStartTimestampPair(
        capture, frame);
    struct XRayTimestampPair end_time = XRayFrameGetEndTimestampPair(
        capture, frame);

    double pdiff = (end_time.pepper - start_time.pepper);
    double odiff = (end_time.xray - start_time.xray);
    double scale_a = pdiff / odiff;
    double scale_b = ((double)end_time.pepper) - (scale_a * end_time.xray);
    printf("Xray timestamp calibration frame %d: %f %f\n",
        frame, scale_a, scale_b);

    int start = XRayFrameGetTraceStartIndex(capture, frame);
    int end = XRayFrameGetTraceEndIndex(capture, frame);

    struct XRayTraceBufferEntry** stack_base = XRayMalloc(
      sizeof(struct XRayTraceBufferEntry*) * (XRAY_TRACE_STACK_SIZE + 1));
    struct XRayTraceBufferEntry** stack_top = stack_base;
    *stack_top = NULL;

    uint32_t num_args = 0;
    const char* arg_names[] = {"annotation"};
    uint8_t arg_types[] = {TRACE_VALUE_TYPE_COPY_STRING};
    uint64_t arg_values[] = {0};
    char annotation[XRAY_TRACE_ANNOTATION_LENGTH];

    int i;
    for(i = start; i != end; i = XRayTraceNextEntry(capture, i)) {
      if (XRayTraceIsAnnotation(capture, i)) {
        continue;
      }

      uint32_t depth = XRAY_EXTRACT_DEPTH(
          XRayTraceGetEntry(capture, i)->depth_addr);

      while(*stack_top &&
          XRAY_EXTRACT_DEPTH((*stack_top)->depth_addr) >= depth) {
        struct XRayTraceBufferEntry* e = *(stack_top--);
        ppb_trace_event_interface->AddTraceEventWithThreadIdAndTimestamp(
            'E', cat_enabled,
            XRayGetName(symbols, e),
            0, thread_id,
            (scale_a * e->end_tick) + scale_b,
            0, NULL, NULL, NULL, 0
        );
      }

      num_args = 0;
      struct XRayTraceBufferEntry* e = XRayTraceGetEntry(capture, i);
      uint32_t annotation_index = e->annotation_index;
      if (annotation_index) {
        XRayTraceCopyToString(capture, annotation_index, annotation);

        union TraceValue val;
        val.as_string = (const char*)annotation;

        arg_values[0] = val.as_uint;
        num_args = 1;
      }

      ppb_trace_event_interface->AddTraceEventWithThreadIdAndTimestamp(
          'B', cat_enabled,
          XRayGetName(symbols, e),
          0, thread_id,
          (scale_a * e->start_tick) + scale_b,
          num_args, arg_names, arg_types, arg_values, 0
      );

      *(++stack_top) = e;
    }

    while(*stack_top) {
      struct XRayTraceBufferEntry* e = *(stack_top--);
      ppb_trace_event_interface->AddTraceEventWithThreadIdAndTimestamp(
          'E', cat_enabled,
          XRayGetName(symbols, e),
          0, thread_id,
          (scale_a * e->end_tick) + scale_b,
          0, NULL, NULL, NULL, 0
      );
    }

    frame = XRayFrameGetNext(capture, frame);
    XRayFree(stack_base);
  }
}

void XRayRegisterBrowserInterface(PPB_GetInterface interface) {
  ppb_trace_event_interface = (PPB_Trace_Event_Dev*)interface(
      PPB_TRACE_EVENT_DEV_INTERFACE);
  assert(ppb_trace_event_interface);
}

#endif  /* XRAY */
#endif  /* XRAY_DISABLE_BROWSER_INTEGRATION */