2 * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "util/EventRecorder.h"
21 #include <unordered_map>
22 #include <json/json.h>
28 std::string quote(const std::string &value)
31 ss << '"' << value << '"';
35 std::string field(const std::string &k, const std::string &v)
38 ss << quote(k) << " : " << quote(v);
42 struct Content // One Entry in Chrome Event Trace
44 std::vector<std::pair<std::string, std::string>> flds;
45 std::vector<std::pair<std::string, std::string>> args;
48 std::string object(const Content &content)
54 ss << field(content.flds[0].first, content.flds[0].second);
56 for (uint32_t n = 1; n < content.flds.size(); ++n)
58 ss << ", " << field(content.flds.at(n).first, content.flds.at(n).second);
61 if (content.args.size() > 0)
63 ss << ", " << quote("args") << " : { ";
64 ss << field(content.args.at(0).first, content.args.at(0).second);
66 for (uint32_t n = 1; n < content.args.size(); ++n)
68 ss << ", " << field(content.args.at(n).first, content.args.at(n).second);
79 void fill(Content &content, const Event &evt)
81 content.flds.emplace_back("name", evt.name);
82 content.flds.emplace_back("pid", "0");
83 content.flds.emplace_back("tid", evt.tid);
84 content.flds.emplace_back("ph", evt.ph);
85 content.flds.emplace_back("ts", evt.ts);
88 std::string object(const DurationEvent &evt)
94 return ::object(content);
97 std::string object(const CounterEvent &evt)
103 for (auto it = evt.values.begin(); it != evt.values.end(); ++it)
105 content.args.emplace_back(it->first, it->second);
108 return ::object(content);
113 void EventRecorder::emit(const DurationEvent &evt)
115 std::lock_guard<std::mutex> lock{_mu};
117 _duration_events.push_back(evt);
120 void EventRecorder::emit(const CounterEvent &evt)
122 std::lock_guard<std::mutex> lock{_mu};
124 _counter_events.push_back(evt);
127 void EventRecorder::writeToFile(std::ostream &os)
129 std::lock_guard<std::mutex> lock{_mu};
131 switch (_write_format)
133 case WriteFormat::CHROME_TRACING:
134 writeChromeTrace(os);
136 case WriteFormat::SNPE_BENCHMARK:
137 writeSNPEBenchmark(os);
140 assert(!"Invalid value");
145 void EventRecorder::writeSNPEBenchmark(std::ostream &os)
148 auto &exec_data = root["Execution_Data"] = Json::Value{Json::objectValue};
155 uint64_t min = std::numeric_limits<uint64_t>::max();
157 void accumulate(uint64_t val)
161 max = std::max(max, val);
162 min = std::min(min, val);
168 std::unordered_map<std::string, Stat> mem_stats;
169 for (auto &evt : _counter_events)
171 auto &mem_stat = mem_stats[evt.name];
172 uint64_t val = std::stoull(evt.values["value"]);
173 mem_stat.accumulate(val);
176 auto &mem = exec_data["memory"] = Json::Value{Json::objectValue};
177 for (auto &kv : mem_stats)
179 auto &key = kv.first;
180 auto &val = kv.second;
181 mem[key]["Avg_Size"] = val.sum / val.count;
182 mem[key]["Max_Size"] = val.max;
183 mem[key]["Min_Size"] = val.min;
184 mem[key]["Runtime"] = "NA";
188 // Operation Execution Time
190 // NOTE This assumes _duration_events is sorted by "ts" ascending
192 // 2D keys : stats[tid][name]
193 std::unordered_map<std::string, std::unordered_map<std::string, Stat>> stats;
194 std::unordered_map<std::string, std::unordered_map<std::string, uint64_t>> begin_timestamps;
195 for (auto &evt : _duration_events)
197 auto &stat = stats[evt.tid][evt.name];
198 auto &begin_ts = begin_timestamps[evt.tid][evt.name];
199 uint64_t timestamp = std::stoull(evt.ts);
203 throw std::runtime_error{"Invalid Data"};
204 begin_ts = timestamp;
206 else if (evt.ph == "E")
208 if (begin_ts == 0 || timestamp < begin_ts)
209 throw std::runtime_error{"Invalid Data"};
210 stat.accumulate(timestamp - begin_ts);
214 throw std::runtime_error{"Invalid Data - invalid value for \"ph\" : \"" + evt.ph + "\""};
217 for (auto &kv : begin_timestamps)
218 for (auto &kv2 : kv.second)
220 throw std::runtime_error{"Invalid Data - B and E pair does not match."};
222 for (auto &kv : stats)
224 auto &tid = kv.first;
225 auto &map = kv.second;
226 auto &json_tid = exec_data[tid] = Json::Value{Json::objectValue};
229 auto &name = kv.first;
230 auto &val = kv.second;
231 json_tid[name]["Avg_Time"] = val.sum / val.count;
232 json_tid[name]["Max_Time"] = val.max;
233 json_tid[name]["Min_Time"] = val.min;
234 json_tid[name]["Runtime"] = tid;
242 void EventRecorder::writeChromeTrace(std::ostream &os)
245 os << " " << quote("traceEvents") << ": [\n";
247 for (auto &evt : _duration_events)
249 os << " " << object(evt) << ",\n";
252 for (auto &evt : _counter_events)
254 os << " " << object(evt) << ",\n";