2 * Copyright (c) 2020 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 "EventWriter.h"
24 #include <unordered_map>
32 void writeMDTableRow(std::ostream &os, const std::vector<std::string> &list)
35 for (const auto &key : list)
49 uint32_t min_page_reclaims;
50 uint32_t max_page_reclaims;
53 : begin_ts(0), end_ts(0), min_rss(UINT32_MAX), max_rss(0), min_page_reclaims(UINT32_MAX),
59 virtual ~MDContent() = default;
61 void updateRss(uint32_t rss)
63 if (min_rss == UINT32_MAX)
70 else if (max_rss < rss)
74 void updateMinflt(uint32_t minflt)
76 if (min_page_reclaims == UINT32_MAX)
77 min_page_reclaims = minflt;
78 if (max_page_reclaims == 0)
79 max_page_reclaims = minflt;
81 if (min_page_reclaims > minflt)
82 min_page_reclaims = minflt;
83 else if (max_page_reclaims < minflt)
84 max_page_reclaims = minflt;
87 virtual void write(std::ostream &os) const = 0;
90 struct Operation : public MDContent
93 uint64_t graph_latency;
97 bool operator()(const Operation &lhs, const Operation &rhs) const
99 return lhs.begin_ts < rhs.begin_ts;
101 bool operator()(const Operation &lhs, const Operation &rhs)
103 return lhs.begin_ts < rhs.begin_ts;
105 bool operator()(Operation &lhs, Operation &rhs) { return lhs.begin_ts < rhs.begin_ts; }
108 void write(std::ostream &os) const override
110 uint64_t op_latency = end_ts - begin_ts;
111 double op_per = static_cast<double>(op_latency) / graph_latency * 100.0;
112 writeMDTableRow(os, {name, backend, std::to_string(op_latency), std::to_string(op_per),
113 std::to_string(min_rss), std::to_string(max_rss),
114 std::to_string(min_page_reclaims), std::to_string(max_page_reclaims)});
118 struct Graph : public MDContent
120 std::set<Operation, Operation::OperationCmp> ops;
121 std::string session_index;
122 std::string subgraph_index;
124 void setOperations(const std::map<std::string, Operation> &name_to_op)
126 uint64_t graph_latency = end_ts - begin_ts;
127 for (auto &&it : name_to_op)
130 op.graph_latency = graph_latency;
134 updateRss(op.min_rss);
135 updateRss(op.max_rss);
136 updateMinflt(op.min_page_reclaims);
137 updateMinflt(op.max_page_reclaims);
141 void write(std::ostream &os) const override
143 static std::vector<std::string> graph_headers{"latency(us)", "rss_min(kb)", "rss_max(kb)",
144 "page_reclaims_min", "page_reclaims_max"};
146 static std::vector<std::string> graph_headers_line{"-----------", "-------", "-------",
147 "-----------------", "-----------------"};
150 writeMDTableRow(os, graph_headers);
151 writeMDTableRow(os, graph_headers_line);
154 writeMDTableRow(os, {std::to_string(end_ts - begin_ts), std::to_string(min_rss),
155 std::to_string(max_rss), std::to_string(min_page_reclaims),
156 std::to_string(max_page_reclaims)});
160 static std::vector<std::string> op_headers{
161 "Op name", "backend", "latency(us)", "latency(%)",
162 "rss_min(kb)", "rss_max(kb)", "page_reclaims_min", "page_reclaims_max"};
164 static std::vector<std::string> op_headers_line{
165 "-------", "-------", "-----------", "-----------",
166 "-------", "-------", "-----------------", "-----------------"};
170 // Operation's Header
171 writeMDTableRow(os, op_headers);
172 writeMDTableRow(os, op_headers_line);
174 // Operation's contents
175 for (auto &&op : ops)
184 std::string getLabel(const OpSeqDurationEvent &evt)
186 std::string subg_label("$" + std::to_string(evt.subg_index) + " subgraph");
187 std::string op_label("@" + std::to_string(evt.op_index) + " " + evt.op_name);
189 return subg_label + " " + op_label;
192 struct MDTableBuilder
194 MDTableBuilder(const std::vector<std::unique_ptr<DurationEvent>> &duration_events,
195 const std::vector<CounterEvent> &counter_events)
196 : _duration_events(duration_events), _counter_events(counter_events)
198 // when ready with low overhead in release build
200 for (const auto &evt : _counter_events)
202 uint64_t ts = std::stoull(evt.ts);
203 auto &name = evt.name;
204 assert(name.compare("maxrss") == 0 || name.compare("minflt") == 0);
205 assert(evt.values.size() == 1);
206 auto &val = evt.values.begin()->second;
207 if (_ts_to_values.find(ts) == _ts_to_values.end())
209 std::pair<uint32_t, uint32_t> values;
210 if (name.compare("maxrss") == 0)
211 values.first = std::stoul(val);
213 values.second = std::stoul(val);
214 _ts_to_values.insert({ts, values});
218 auto &values = _ts_to_values.at(ts);
219 if (name.compare("maxrss") == 0)
220 values.first = std::stoul(val);
222 values.second = std::stoul(val);
228 MDTableBuilder &build()
230 for (const auto &it : divideGraph())
232 size_t begin_idx = it.first;
233 size_t end_idx = it.second;
234 std::map<std::string, Operation> name_to_op;
235 for (size_t i = begin_idx + 1; i < end_idx; ++i)
237 const auto *evt = dynamic_cast<const OpSeqDurationEvent *>(_duration_events[i].get());
241 const std::string evt_name = getLabel(*evt);
242 assert(evt->ph.compare("B") == 0 || evt->ph.compare("E") == 0);
243 if (evt->ph.compare("B") == 0)
245 assert(name_to_op.find(evt_name) == name_to_op.end());
246 name_to_op.insert({evt_name, makeOperation(*evt)});
250 assert(name_to_op.find(evt_name) != name_to_op.end());
251 auto &op = name_to_op.at(evt_name);
252 updateOperation(op, *evt);
256 _graphs.emplace_back(makeGraph(begin_idx, end_idx, name_to_op));
262 std::vector<std::pair<size_t, size_t>> divideGraph()
264 std::vector<std::pair<size_t, size_t>> graph_idx_list; // pair<begin_idx, end_idx>
265 for (size_t i = 0, begin_idx = 0; i < _duration_events.size(); ++i)
267 const auto subg_evt = dynamic_cast<const SubgDurationEvent *>(_duration_events.at(i).get());
268 if (subg_evt == nullptr)
271 if (subg_evt->ph.compare("B") == 0)
274 graph_idx_list.emplace_back(begin_idx, i);
276 return graph_idx_list;
279 Operation makeOperation(const OpSeqDurationEvent &evt)
282 const std::string &evt_name = getLabel(evt);
284 op.begin_ts = std::stoull(evt.ts);
285 op.backend = evt.backend;
287 op.updateRss(_ts_to_values.at(op.begin_ts).first);
288 op.updateMinflt(_ts_to_values.at(op.begin_ts).second);
296 void updateOperation(Operation &op, const DurationEvent &evt)
298 op.end_ts = std::stoull(evt.ts);
300 op.updateRss(_ts_to_values.at(op.end_ts).first);
301 op.updateMinflt(_ts_to_values.at(op.end_ts).second);
308 Graph makeGraph(size_t begin_idx, size_t end_idx,
309 const std::map<std::string, Operation> &name_to_op)
312 graph.name = "Subgraph";
313 graph.begin_ts = std::stoull(_duration_events[begin_idx]->ts);
314 graph.end_ts = std::stoull(_duration_events[end_idx]->ts);
315 graph.setOperations(name_to_op);
317 for (const auto &arg : _duration_events[end_idx]->args)
319 if (arg.first == "session")
320 graph.session_index = arg.second;
321 if (arg.first == "subgraph")
322 graph.subgraph_index = arg.second;
326 graph.updateRss(_ts_to_values.at(graph.begin_ts).first);
327 graph.updateMinflt(_ts_to_values.at(graph.begin_ts).second);
328 graph.updateRss(_ts_to_values.at(graph.end_ts).first);
329 graph.updateMinflt(_ts_to_values.at(graph.end_ts).second);
332 graph.updateMinflt(0);
337 void write(std::ostream &os)
340 for (size_t i = 0; i < _graphs.size(); ++i)
342 auto &graph = _graphs.at(i);
343 os << "# Session: " << graph.session_index << ", Subgraph: " << graph.subgraph_index
344 << ", Running count: " << i << "\n";
345 _graphs.at(i).write(os);
349 const std::vector<std::unique_ptr<DurationEvent>> &_duration_events;
350 const std::vector<CounterEvent> &_counter_events;
352 // timestamp to std::pair<maxrss, minflt>
353 std::unordered_map<uint64_t, std::pair<uint32_t, uint32_t>> _ts_to_values;
354 std::vector<Graph> _graphs;
359 void MDTableWriter::flush(const std::vector<std::unique_ptr<EventRecorder>> &records)
361 for (const auto &recorder : records)
363 MDTableBuilder(recorder->duration_events(), recorder->counter_events()).build().write(_os);