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
7/* XRay -- a simple profiler for Native Client */
8
9#ifndef XRAY_DISABLE_BROWSER_INTEGRATION
10
11#include <alloca.h>
12#include <assert.h>
13#include <errno.h>
14#include <stdarg.h>
15#include <stdint.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <unistd.h>
20#include "ppapi/c/dev/ppb_trace_event_dev.h"
21#include "xray/xray_priv.h"
22
23
24#if defined(XRAY)
25static PPB_Trace_Event_Dev* ppb_trace_event_interface = NULL;
26
27static const char* XRayGetName(struct XRaySymbolTable* symbols,
28      struct XRayTraceBufferEntry* e) {
29  uint32_t addr = XRAY_EXTRACT_ADDR(e->depth_addr);
30  struct XRaySymbol* symbol = XRaySymbolTableLookup(symbols, addr);
31  return XRaySymbolGetName(symbol);
32}
33
34struct XRayTimestampPair XRayGenerateTimestampsNow(void) {
35  struct XRayTimestampPair pair;
36  assert(ppb_trace_event_interface);
37
38  XRayGetTSC(&pair.xray);
39  pair.pepper = ppb_trace_event_interface->Now();
40  return pair;
41}
42
43/* see chromium/src/base/debug/trace_event.h */
44#define TRACE_VALUE_TYPE_UINT (2)
45#define TRACE_VALUE_TYPE_DOUBLE (4)
46#define TRACE_VALUE_TYPE_COPY_STRING (7)
47
48union TraceValue {
49    bool as_bool;
50    unsigned long long as_uint;
51    long long as_int;
52    double as_double;
53    const void* as_pointer;
54    const char* as_string;
55  };
56
57void XRayBrowserTraceReport(struct XRayTraceCapture* capture) {
58
59  const void* cat_enabled = ppb_trace_event_interface->GetCategoryEnabled(
60      "xray");
61  struct XRaySymbolTable* symbols = XRayGetSymbolTable(capture);
62
63  int32_t thread_id = XRayGetSavedThreadID(capture);
64
65  int head = XRayFrameGetHead(capture);
66  int frame = XRayFrameGetTail(capture);
67  while(frame != head) {
68
69    struct XRayTimestampPair start_time = XRayFrameGetStartTimestampPair(
70        capture, frame);
71    struct XRayTimestampPair end_time = XRayFrameGetEndTimestampPair(
72        capture, frame);
73
74    double pdiff = (end_time.pepper - start_time.pepper);
75    double odiff = (end_time.xray - start_time.xray);
76    double scale_a = pdiff / odiff;
77    double scale_b = ((double)end_time.pepper) - (scale_a * end_time.xray);
78    printf("Xray timestamp calibration frame %d: %f %f\n",
79        frame, scale_a, scale_b);
80
81    int start = XRayFrameGetTraceStartIndex(capture, frame);
82    int end = XRayFrameGetTraceEndIndex(capture, frame);
83
84    struct XRayTraceBufferEntry** stack_base = XRayMalloc(
85      sizeof(struct XRayTraceBufferEntry*) * (XRAY_TRACE_STACK_SIZE + 1));
86    struct XRayTraceBufferEntry** stack_top = stack_base;
87    *stack_top = NULL;
88
89    uint32_t num_args = 0;
90    const char* arg_names[] = {"annotation"};
91    uint8_t arg_types[] = {TRACE_VALUE_TYPE_COPY_STRING};
92    uint64_t arg_values[] = {0};
93    char annotation[XRAY_TRACE_ANNOTATION_LENGTH];
94
95    int i;
96    for(i = start; i != end; i = XRayTraceNextEntry(capture, i)) {
97      if (XRayTraceIsAnnotation(capture, i)) {
98        continue;
99      }
100
101      uint32_t depth = XRAY_EXTRACT_DEPTH(
102          XRayTraceGetEntry(capture, i)->depth_addr);
103
104      while(*stack_top &&
105          XRAY_EXTRACT_DEPTH((*stack_top)->depth_addr) >= depth) {
106        struct XRayTraceBufferEntry* e = *(stack_top--);
107        ppb_trace_event_interface->AddTraceEventWithThreadIdAndTimestamp(
108            'E', cat_enabled,
109            XRayGetName(symbols, e),
110            0, thread_id,
111            (scale_a * e->end_tick) + scale_b,
112            0, NULL, NULL, NULL, 0
113        );
114      }
115
116      num_args = 0;
117      struct XRayTraceBufferEntry* e = XRayTraceGetEntry(capture, i);
118      uint32_t annotation_index = e->annotation_index;
119      if (annotation_index) {
120        XRayTraceCopyToString(capture, annotation_index, annotation);
121
122        union TraceValue val;
123        val.as_string = (const char*)annotation;
124
125        arg_values[0] = val.as_uint;
126        num_args = 1;
127      }
128
129      ppb_trace_event_interface->AddTraceEventWithThreadIdAndTimestamp(
130          'B', cat_enabled,
131          XRayGetName(symbols, e),
132          0, thread_id,
133          (scale_a * e->start_tick) + scale_b,
134          num_args, arg_names, arg_types, arg_values, 0
135      );
136
137      *(++stack_top) = e;
138    }
139
140    while(*stack_top) {
141      struct XRayTraceBufferEntry* e = *(stack_top--);
142      ppb_trace_event_interface->AddTraceEventWithThreadIdAndTimestamp(
143          'E', cat_enabled,
144          XRayGetName(symbols, e),
145          0, thread_id,
146          (scale_a * e->end_tick) + scale_b,
147          0, NULL, NULL, NULL, 0
148      );
149    }
150
151    frame = XRayFrameGetNext(capture, frame);
152    XRayFree(stack_base);
153  }
154}
155
156void XRayRegisterBrowserInterface(PPB_GetInterface interface) {
157  ppb_trace_event_interface = (PPB_Trace_Event_Dev*)interface(
158      PPB_TRACE_EVENT_DEV_INTERFACE);
159  assert(ppb_trace_event_interface);
160}
161
162#endif  /* XRAY */
163#endif  /* XRAY_DISABLE_BROWSER_INTEGRATION */