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 "ExecutionObservers.h"
19 #include "../util/EventWriter.h"
21 #include "util/logging.h"
23 #include <misc/polymorphic_downcast.h>
31 void setUserData(const onert::ir::Graph &g, const onert::ir::IOperation *op,
32 decltype(EventCollector::Event::userData) &data)
34 // From a tensor of shape [a, b, c], this will return a string "shape(a b c)".
35 // String like "[1, 2, 3]" looks better but this will be considered as a list in Json
36 // so text search (e.g., Ctrl-F in Chrome Tracing) could be difficult
37 auto build_shape_str = [&](onert::ir::OperandIndex operand_idx) {
38 std::string shape_str;
39 auto &shape = g.operands().at(operand_idx).info().shape();
40 for (int i = 0; i < shape.rank(); i++)
43 shape_str = "shape(" + std::to_string(shape.dim(i));
45 shape_str += " " + std::to_string(shape.dim(i));
52 auto &inputs = op->getInputs();
53 auto size = inputs.size();
54 for (size_t i = 0; i < size; i++)
56 auto operand_idx = inputs.at(i);
57 if (operand_idx.undefined())
60 std::string key("input_shape_" + std::to_string(i));
61 std::string value = build_shape_str(operand_idx);
62 data.emplace_back(std::make_pair(key, value));
65 // add other userData as needed
76 void ProfileObserver::handleJobBegin(onert::exec::IExecutor *, ir::SubgraphIndex,
77 ir::OperationIndex, const onert::backend::Backend *backend)
79 _timer = backend->config()->timer();
80 if (_timer == nullptr)
81 throw std::runtime_error("To profile backend timer() method must be implemented");
82 _timer->handleBegin();
85 void ProfileObserver::handleJobEnd(IExecutor *exec, ir::SubgraphIndex,
86 const ir::OperationIndex op_ind, const backend::Backend *backend)
89 const auto timer_res = _timer->getTime();
91 // NOTE This assumes there is just one operation in a op
92 const auto &node = _graph.operations().at(op_ind);
93 auto node_name = node.name();
94 VERBOSE(ProfileInfo) << "Time for " << node_name << " : " << timer_res << std::endl;
97 bool is_quantized = exec->graph().operands().at(node.getInputs().at(0)).typeInfo().type() ==
98 ir::DataType::QUANT_UINT8_ASYMM;
101 for (const auto &ind : (node.getInputs() + node.getOutputs()) | ir::Remove::UNDEFINED)
103 size += exec->graph().operands().at(ind).info().total_size();
105 if (node_name == "Permute")
107 // TODO Change it to updateOperationExecTime()
108 _et->updatePermuteTime(backend, backend, is_quantized, size, timer_res);
112 _et->updateOperationExecTime(backend, node_name, is_quantized, size, timer_res);
116 TracingObserver::TracingObserver(const std::string &filepath, const ir::Graph &graph,
117 const util::TracingCtx *tracing_ctx)
118 : _recorder{std::make_unique<EventRecorder>()}, _collector{_recorder.get()}, _graph{graph},
119 _tracing_ctx{tracing_ctx}
121 _event_writer = EventWriter::get(filepath);
122 _event_writer->startToUse();
125 TracingObserver::~TracingObserver()
129 _event_writer->readyToFlush(std::move(_recorder));
131 catch (const std::exception &e)
133 std::cerr << "E: Fail to record event in TracingObserver: " << e.what() << std::endl;
137 void TracingObserver::handleSubgraphBegin(ir::SubgraphIndex subg_ind)
140 EventCollector::SubgEvent{_tracing_ctx, EventCollector::Edge::BEGIN, subg_ind.value()});
143 void TracingObserver::handleJobBegin(IExecutor *, ir::SubgraphIndex subg_ind,
144 ir::OperationIndex op_ind, const backend::Backend *backend)
146 std::string backend_id = backend->config()->id();
147 const auto &op = _graph.operations().at(op_ind);
148 auto ev = EventCollector::OpSeqEvent{_tracing_ctx, EventCollector::Edge::BEGIN,
149 subg_ind.value(), backend_id,
150 op_ind.value(), op.name()};
151 // add shape of inputs
152 setUserData(_graph, &op, ev.userData);
153 _collector.onEvent(ev);
156 void TracingObserver::handleJobEnd(IExecutor *, ir::SubgraphIndex subg_ind,
157 ir::OperationIndex op_ind, const backend::Backend *backend)
159 std::string backend_id = backend->config()->id();
160 _collector.onEvent(EventCollector::OpSeqEvent{_tracing_ctx, EventCollector::Edge::END,
161 subg_ind.value(), backend_id, op_ind.value(),
162 _graph.operations().at(op_ind).name()});
165 void TracingObserver::handleSubgraphEnd(ir::SubgraphIndex subg_ind)
168 EventCollector::SubgEvent{_tracing_ctx, EventCollector::Edge::END, subg_ind.value()});