Imported Upstream version 1.25.0
[platform/core/ml/nnfw.git] / runtime / onert / core / src / exec / ExecutionObservers.cc
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
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
7  *
8  *    http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "ExecutionObservers.h"
18
19 #include "../util/EventWriter.h"
20
21 #include "util/logging.h"
22
23 #include <misc/polymorphic_downcast.h>
24
25 #include <string>
26 #include <sstream>
27
28 namespace
29 {
30
31 void setUserData(const onert::ir::Graph &g, const onert::ir::IOperation *op,
32                  decltype(EventCollector::Event::userData) &data)
33 {
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++)
41     {
42       if (i == 0)
43         shape_str = "shape(" + std::to_string(shape.dim(i));
44       else
45         shape_str += " " + std::to_string(shape.dim(i));
46     }
47     shape_str += ")";
48
49     return shape_str;
50   };
51
52   auto &inputs = op->getInputs();
53   auto size = inputs.size();
54   for (size_t i = 0; i < size; i++)
55   {
56     auto operand_idx = inputs.at(i);
57     if (operand_idx.undefined())
58       continue;
59
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));
63   }
64
65   // add other userData as needed
66 }
67
68 } // namespace
69
70 namespace onert
71 {
72
73 namespace exec
74 {
75
76 void ProfileObserver::handleJobBegin(onert::exec::IExecutor *, ir::SubgraphIndex,
77                                      ir::OperationIndex, const onert::backend::Backend *backend)
78 {
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();
83 }
84
85 void ProfileObserver::handleJobEnd(IExecutor *exec, ir::SubgraphIndex,
86                                    const ir::OperationIndex op_ind, const backend::Backend *backend)
87 {
88   _timer->handleEnd();
89   const auto timer_res = _timer->getTime();
90
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;
95
96   // fill ExecTime:
97   bool is_quantized = exec->graph().operands().at(node.getInputs().at(0)).typeInfo().type() ==
98                       ir::DataType::QUANT_UINT8_ASYMM;
99
100   uint32_t size = 0;
101   for (const auto &ind : (node.getInputs() + node.getOutputs()) | ir::Remove::UNDEFINED)
102   {
103     size += exec->graph().operands().at(ind).info().total_size();
104   }
105   if (node_name == "Permute")
106   {
107     // TODO Change it to updateOperationExecTime()
108     _et->updatePermuteTime(backend, backend, is_quantized, size, timer_res);
109   }
110   else
111   {
112     _et->updateOperationExecTime(backend, node_name, is_quantized, size, timer_res);
113   }
114 };
115
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}
120 {
121   _event_writer = EventWriter::get(filepath);
122   _event_writer->startToUse();
123 }
124
125 TracingObserver::~TracingObserver()
126 {
127   try
128   {
129     _event_writer->readyToFlush(std::move(_recorder));
130   }
131   catch (const std::exception &e)
132   {
133     std::cerr << "E: Fail to record event in TracingObserver: " << e.what() << std::endl;
134   }
135 }
136
137 void TracingObserver::handleSubgraphBegin(ir::SubgraphIndex subg_ind)
138 {
139   _collector.onEvent(
140     EventCollector::SubgEvent{_tracing_ctx, EventCollector::Edge::BEGIN, subg_ind.value()});
141 }
142
143 void TracingObserver::handleJobBegin(IExecutor *, ir::SubgraphIndex subg_ind,
144                                      ir::OperationIndex op_ind, const backend::Backend *backend)
145 {
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);
154 }
155
156 void TracingObserver::handleJobEnd(IExecutor *, ir::SubgraphIndex subg_ind,
157                                    ir::OperationIndex op_ind, const backend::Backend *backend)
158 {
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()});
163 }
164
165 void TracingObserver::handleSubgraphEnd(ir::SubgraphIndex subg_ind)
166 {
167   _collector.onEvent(
168     EventCollector::SubgEvent{_tracing_ctx, EventCollector::Edge::END, subg_ind.value()});
169 }
170
171 } // namespace exec
172
173 } // namespace onert