xref: /6.0.3/phosphor/src/trace_event.cc (revision cd658760)
1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2016 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17
18#include "phosphor/trace_event.h"
19
20#include "phosphor/platform/thread.h"
21#include "utils/string_utils.h"
22
23namespace phosphor {
24
25    using namespace std::chrono;
26
27    TraceEvent::TraceEvent(
28        const tracepoint_info* _tpi,
29        Type _type,
30        uint32_t _thread_id,
31        std::array<TraceArgument, arg_count>&& _args,
32        std::array<TraceArgument::Type, arg_count>&& _arg_types)
33        : tpi(_tpi),
34          args(_args),
35          time(
36              duration_cast<nanoseconds>(steady_clock::now().time_since_epoch())
37                  .count()),
38          duration(0),
39          thread_id(_thread_id),
40          arg_types(_arg_types),
41          type(_type) {}
42
43    TraceEvent::TraceEvent(
44            const tracepoint_info* _tpi,
45            uint32_t _thread_id,
46            std::chrono::steady_clock::time_point _start,
47            std::chrono::steady_clock::duration _duration,
48            std::array<TraceArgument, arg_count>&& _args,
49            std::array<TraceArgument::Type, arg_count>&& _arg_types)
50        : tpi(_tpi),
51          args(_args),
52          time(_start.time_since_epoch().count()),
53          duration(_duration.count()),
54          thread_id(_thread_id),
55          arg_types(_arg_types),
56          type(Type::Complete) {
57    }
58
59    std::string TraceEvent::to_string() const {
60        typedef std::chrono::duration<
61            int,
62            std::ratio_multiply<hours::period, std::ratio<24> >::type>
63            days;
64
65        nanoseconds ttime(time);
66        auto d = duration_cast<days>(ttime);
67        ttime -= d;
68        auto h = duration_cast<hours>(ttime);
69        ttime -= h;
70        auto m = duration_cast<minutes>(ttime);
71        ttime -= m;
72        auto s = duration_cast<seconds>(ttime);
73        ttime -= s;
74        auto us = duration_cast<nanoseconds>(ttime);
75
76        return utils::format_string(
77            "TraceEvent<%dd %02ld:%02ld:%02lld.%09lld, %s, %s, type=%s, "
78            "thread_id=%d, arg1=%s, arg2=%s>",
79            d.count(),
80            h.count(),
81            m.count(),
82            s.count(),
83            us.count(),
84            getCategory(),
85            getName(),
86            typeToString(type),
87            thread_id,
88            args[0].to_string(arg_types[0]).c_str(),
89            args[1].to_string(arg_types[1]).c_str());
90    }
91
92    std::string TraceEvent::to_json() const {
93        std::string output;
94        output += "{\"name\":" + utils::to_json(getName());
95        output += ",\"cat\":" + utils::to_json(getCategory());
96
97        auto type_converted = typeToJSON();
98        output += ",\"ph\":\"" + std::string(type_converted.type) + "\"";
99        output += type_converted.extras;
100
101        output += ",\"ts\":" + std::to_string(time / 1000);
102        output += ",\"pid\":" + std::to_string(platform::getCurrentProcessID()),
103        output += ",\"tid\":" + std::to_string(thread_id);
104
105        output += ",\"args\":{";
106        for (int i = 0; i < arg_count; ++i) {
107            if (arg_types[i] == TraceArgument::Type::is_none) {
108                break;
109            }
110            if (i != 0) {
111                output += ",";
112            }
113
114            output += utils::to_json(tpi->argument_names[i]) + ":";
115            output += args[i].to_string(arg_types[i]);
116        }
117        output += "}";
118
119        output += "}";
120        return output;
121    }
122
123    const char* TraceEvent::typeToString(Type type) {
124        switch (type) {
125        case Type::AsyncStart:
126            return "AsyncStart";
127        case Type::AsyncEnd:
128            return "AsyncEnd";
129        case Type::SyncStart:
130            return "SyncStart";
131        case Type::SyncEnd:
132            return "SyncEnd";
133        case Type::Instant:
134            return "Instant";
135        case Type::GlobalInstant:
136            return "GlobalInstant";
137        case Type::Complete:
138            return "Complete";
139        }
140        throw std::invalid_argument(
141            "TraceEvent::typeToString: "
142            "Invalid TraceEvent type");
143    }
144
145    const char* TraceEvent::getName() const {
146        return tpi->name;
147    }
148
149    const char* TraceEvent::getCategory() const {
150        return tpi->category;
151    }
152
153    TraceEvent::Type TraceEvent::getType() const {
154        return type;
155    }
156
157    uint64_t TraceEvent::getThreadID() const {
158        return thread_id;
159    }
160
161    const std::array<TraceArgument, arg_count>& TraceEvent::getArgs() const {
162        return args;
163    }
164
165    const std::array<TraceArgument::Type, arg_count>& TraceEvent::getArgTypes() const {
166        return arg_types;
167    }
168
169    const std::array<const char*, arg_count>&
170            TraceEvent::getArgNames() const {
171        return tpi->argument_names;
172    }
173
174    int64_t TraceEvent::getTime() const {
175        return time;
176    }
177
178    uint64_t TraceEvent::getDuration() const {
179        return duration;
180    }
181
182    TraceEvent::ToJsonResult TraceEvent::typeToJSON() const {
183        TraceEvent::ToJsonResult res;
184
185        switch (type) {
186        case Type::AsyncStart:
187            res.type = "b";
188            res.extras =
189                utils::format_string(",\"id\": \"0x%X\"", args[0].as_int);
190            return res;
191        case Type::AsyncEnd:
192            res.type = "e";
193            res.extras =
194                utils::format_string(",\"id\": \"0x%X\"", args[0].as_int);
195            return res;
196        case Type::SyncStart:
197            res.type = "B";
198            res.extras = "";
199            return res;
200        case Type::SyncEnd:
201            res.type = "E";
202            res.extras = "";
203            return res;
204        case Type::Instant:
205            res.type = "i";
206            res.extras = ",\"s\":\"t\"";
207            return res;
208        case Type::GlobalInstant:
209            res.type = "i";
210            res.extras = ",\"s\":\"g\"";
211            return res;
212        case Type::Complete:
213            res.type = "X";
214            const double duration_us = duration / 1000.0;
215            res.extras = utils::format_string(",\"dur\":%.3f", duration_us);
216            return res;
217        }
218        throw std::invalid_argument(
219            "TraceEvent::typeToJSON: Invalid TraceArgument type");
220    }
221
222    std::ostream& operator<<(std::ostream& os, const TraceEvent& te) {
223        os << te.to_string();
224        return os;
225    }
226}
227