aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/trace/SkChromeTracingTracer.cpp
blob: 0cfb1bf5f918df41d4ca2684874c2766a92a6a57 (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
/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkChromeTracingTracer.h"
#include "SkThreadID.h"
#include "SkTraceEvent.h"
#include "SkOSFile.h"
#include "SkOSPath.h"
#include "SkStream.h"

#include <chrono>

SkEventTracer::Handle SkChromeTracingTracer::addTraceEvent(char phase,
                                                           const uint8_t* categoryEnabledFlag,
                                                           const char* name,
                                                           uint64_t id,
                                                           int numArgs,
                                                           const char** argNames,
                                                           const uint8_t* argTypes,
                                                           const uint64_t* argValues,
                                                           uint8_t flags) {
    // TODO: Respect flags (or assert). INSTANT events encode scope in flags, should be stored
    // using "s" key in JSON. COPY flag should be supported or rejected.

    Json::Value traceEvent;
    char phaseString[2] = { phase, 0 };
    traceEvent["ph"] = phaseString;
    traceEvent["name"] = name;
    traceEvent["cat"] = this->getCategoryGroupName(categoryEnabledFlag);
    auto now = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double, std::nano> ns = now.time_since_epoch();
    traceEvent["ts"] = ns.count() * 1E-3;
    traceEvent["tid"] = static_cast<Json::Int64>(SkGetThreadID());

    // Trace events *must* include a process ID, but for internal tools this isn't particularly
    // important (and certainly not worth adding a cross-platform API to get it).
    traceEvent["pid"] = 0;

    if (numArgs) {
        Json::Value args;
        skia::tracing_internals::TraceValueUnion value;
        for (int i = 0; i < numArgs; ++i) {
            value.as_uint = argValues[i];
            switch (argTypes[i]) {
                case TRACE_VALUE_TYPE_BOOL:
                    args[argNames[i]] = value.as_bool;
                    break;
                case TRACE_VALUE_TYPE_UINT:
                    args[argNames[i]] = static_cast<Json::UInt64>(argValues[i]);
                    break;
                case TRACE_VALUE_TYPE_INT:
                    args[argNames[i]] = static_cast<Json::Int64>(argValues[i]);
                    break;
                case TRACE_VALUE_TYPE_DOUBLE:
                    args[argNames[i]] = value.as_double;
                    break;
                case TRACE_VALUE_TYPE_POINTER:
                    args[argNames[i]] = value.as_pointer;
                    break;
                case TRACE_VALUE_TYPE_STRING:
                case TRACE_VALUE_TYPE_COPY_STRING:
                    args[argNames[i]] = value.as_string;
                    break;
                default:
                    args[argNames[i]] = "<unknown type>";
                    break;
            }
        }
        traceEvent["args"] = args;
    }
    Json::Value& newValue(fRoot.append(traceEvent));
    return reinterpret_cast<Handle>(&newValue);
}

void SkChromeTracingTracer::updateTraceEventDuration(const uint8_t* categoryEnabledFlag,
                                                     const char* name,
                                                     SkEventTracer::Handle handle) {
    Json::Value* traceEvent = reinterpret_cast<Json::Value*>(handle);
    auto now = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double, std::nano> ns = now.time_since_epoch();
    auto us = ns.count() * 1E-3;
    (*traceEvent)["dur"] = us - (*traceEvent)["ts"].asDouble();
}

void SkChromeTracingTracer::flush() {
    SkString dirname = SkOSPath::Dirname(fFilename.c_str());
    if (!sk_exists(dirname.c_str(), kWrite_SkFILE_Flag)) {
        if (!sk_mkdir(dirname.c_str())) {
            SkDebugf("Failed to create directory.");
        }
    }
    SkFILEWStream stream(fFilename.c_str());
    stream.writeText(Json::StyledWriter().write(fRoot).c_str());
    stream.flush();
}