blob: c7a18b040f9ca7b1b0643095a163921e55e3c0f1 [file] [log] [blame]
Kristofer Jonsson116a6352020-08-20 17:25:23 +02001/*
Mikael Olsson07545152023-10-17 13:05:38 +02002 * SPDX-FileCopyrightText: Copyright 2020-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
Kristofer Jonsson116a6352020-08-20 17:25:23 +02003 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the License); you may
6 * not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * 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, WITHOUT
13 * 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
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020018#include <ethosu.hpp>
Kristofer Jonsson116a6352020-08-20 17:25:23 +020019#include <uapi/ethosu.h>
20
Kristofer Jonsson116a6352020-08-20 17:25:23 +020021#include <fstream>
22#include <iomanip>
23#include <iostream>
24#include <list>
Davide Grohmann35ce6c82021-06-01 15:03:51 +020025#include <stdio.h>
Kristofer Jonsson116a6352020-08-20 17:25:23 +020026#include <string>
Kristofer Jonsson79689c52020-10-16 14:42:19 +020027#include <unistd.h>
Kristofer Jonsson116a6352020-08-20 17:25:23 +020028
29using namespace std;
30using namespace EthosU;
31
Kristofer Jonsson79689c52020-10-16 14:42:19 +020032namespace {
Davide Grohmanne446b422021-10-19 15:33:23 +020033int64_t defaultTimeout = 60000000000;
Kristofer Jonsson116a6352020-08-20 17:25:23 +020034
Kristofer Jonsson79689c52020-10-16 14:42:19 +020035void help(const string exe) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020036 cerr << "Usage: " << exe << " [ARGS]\n";
37 cerr << "\n";
38 cerr << "Arguments:\n";
39 cerr << " -h --help Print this help message.\n";
40 cerr << " -n --network File to read network from.\n";
Kristofer Jonsson35de9e62022-03-08 13:25:45 +010041 cerr << " --index Network model index, stored in firmware binary.\n";
Kristofer Jonsson116a6352020-08-20 17:25:23 +020042 cerr << " -i --ifm File to read IFM from.\n";
43 cerr << " -o --ofm File to write IFM to.\n";
Per Åstrand716546a2020-10-24 20:17:32 +020044 cerr << " -P --pmu [0.." << Inference::getMaxPmuEventCounters() << "] eventid.\n";
45 cerr << " PMU counter to enable followed by eventid, can be passed multiple times.\n";
46 cerr << " -C --cycles Enable cycle counter for inference.\n";
Davide Grohmanne446b422021-10-19 15:33:23 +020047 cerr << " -t --timeout Timeout in nanoseconds (default " << defaultTimeout << ").\n";
Kristofer Jonsson116a6352020-08-20 17:25:23 +020048 cerr << " -p Print OFM.\n";
49 cerr << endl;
50}
51
Kristofer Jonsson79689c52020-10-16 14:42:19 +020052void rangeCheck(const int i, const int argc, const string arg) {
53 if (i >= argc) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020054 cerr << "Error: Missing argument to '" << arg << "'" << endl;
55 exit(1);
56 }
57}
58
Kristofer Jonsson79689c52020-10-16 14:42:19 +020059shared_ptr<Buffer> allocAndFill(Device &device, const string filename) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020060 ifstream stream(filename, ios::binary);
Kristofer Jonsson79689c52020-10-16 14:42:19 +020061 if (!stream.is_open()) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020062 cerr << "Error: Failed to open '" << filename << "'" << endl;
63 exit(1);
64 }
65
66 stream.seekg(0, ios_base::end);
67 size_t size = stream.tellg();
68 stream.seekg(0, ios_base::beg);
69
70 shared_ptr<Buffer> buffer = make_shared<Buffer>(device, size);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020071 stream.read(buffer->data(), size);
72
73 return buffer;
74}
75
Per Åstrand716546a2020-10-24 20:17:32 +020076shared_ptr<Inference> createInference(Device &device,
77 shared_ptr<Network> &network,
78 const string &filename,
79 const std::vector<uint8_t> &counters,
80 bool enableCycleCounter) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020081 // Open IFM file
82 ifstream stream(filename, ios::binary);
Kristofer Jonsson79689c52020-10-16 14:42:19 +020083 if (!stream.is_open()) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020084 cerr << "Error: Failed to open '" << filename << "'" << endl;
85 exit(1);
86 }
87
88 // Get IFM file size
89 stream.seekg(0, ios_base::end);
90 size_t size = stream.tellg();
91 stream.seekg(0, ios_base::beg);
92
Kristofer Jonsson79689c52020-10-16 14:42:19 +020093 if (size != network->getIfmSize()) {
94 cerr << "Error: IFM size does not match network size. filename=" << filename << ", size=" << size
95 << ", network=" << network->getIfmSize() << endl;
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020096 exit(1);
97 }
98
99 // Create IFM buffers
100 vector<shared_ptr<Buffer>> ifm;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200101 for (auto size : network->getIfmDims()) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200102 shared_ptr<Buffer> buffer = make_shared<Buffer>(device, size);
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200103 stream.read(buffer->data(), size);
104
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200105 if (!stream) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200106 cerr << "Error: Failed to read IFM" << endl;
107 exit(1);
108 }
109
110 ifm.push_back(buffer);
111 }
112
113 // Create OFM buffers
114 vector<shared_ptr<Buffer>> ofm;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200115 for (auto size : network->getOfmDims()) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200116 ofm.push_back(make_shared<Buffer>(device, size));
117 }
118
Per Åstrand716546a2020-10-24 20:17:32 +0200119 return make_shared<Inference>(
120 network, ifm.begin(), ifm.end(), ofm.begin(), ofm.end(), counters, enableCycleCounter);
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200121}
122
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200123ostream &operator<<(ostream &os, Buffer &buf) {
124 char *c = buf.data();
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200125 const char *end = c + buf.size();
126
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200127 while (c < end) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200128 os << hex << setw(2) << static_cast<int>(*c++) << " " << dec;
129 }
130
131 return os;
132}
133
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200134} // namespace
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200135
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200136int main(int argc, char *argv[]) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200137 const string exe = argv[0];
138 string networkArg;
Kristofer Jonsson35de9e62022-03-08 13:25:45 +0100139 int networkIndex = -1;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200140 list<string> ifmArg;
Per Åstrand716546a2020-10-24 20:17:32 +0200141 vector<uint8_t> enabledCounters(Inference::getMaxPmuEventCounters());
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200142 string ofmArg;
Davide Grohmanne446b422021-10-19 15:33:23 +0200143 int64_t timeout = defaultTimeout;
Per Åstrand716546a2020-10-24 20:17:32 +0200144 bool print = false;
145 bool enableCycleCounter = false;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200146
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200147 for (int i = 1; i < argc; ++i) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200148 const string arg(argv[i]);
149
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200150 if (arg == "-h" || arg == "--help") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200151 help(exe);
152 exit(1);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200153 } else if (arg == "--network" || arg == "-n") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200154 rangeCheck(++i, argc, arg);
155 networkArg = argv[i];
Kristofer Jonsson35de9e62022-03-08 13:25:45 +0100156 } else if (arg == "--index") {
157 rangeCheck(++i, argc, arg);
158 networkIndex = stoi(argv[i]);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200159 } else if (arg == "--ifm" || arg == "-i") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200160 rangeCheck(++i, argc, arg);
161 ifmArg.push_back(argv[i]);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200162 } else if (arg == "--ofm" || arg == "-o") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200163 rangeCheck(++i, argc, arg);
164 ofmArg = argv[i];
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200165 } else if (arg == "--timeout" || arg == "-t") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200166 rangeCheck(++i, argc, arg);
Davide Grohmanne446b422021-10-19 15:33:23 +0200167 timeout = stoll(argv[i]);
Per Åstrand716546a2020-10-24 20:17:32 +0200168 } else if (arg == "--pmu" || arg == "-P") {
169 unsigned pmu = 0, event = 0;
170 rangeCheck(++i, argc, arg);
171 pmu = stoi(argv[i]);
172
173 rangeCheck(++i, argc, arg);
174 event = stoi(argv[i]);
175
176 if (pmu >= enabledCounters.size()) {
177 cerr << "PMU out of bounds!" << endl;
178 help(exe);
179 exit(1);
180 }
181 cout << argv[i] << " -> Enabling " << pmu << " with event " << event << endl;
182 enabledCounters[pmu] = event;
183 } else if (arg == "--cycles" || arg == "-C") {
184 enableCycleCounter = true;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200185 } else if (arg == "-p") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200186 print = true;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200187 } else {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200188 cerr << "Error: Invalid argument '" << arg << "'" << endl;
189 help(exe);
190 exit(1);
191 }
192 }
193
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200194 if (networkArg.empty()) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200195 cerr << "Error: Missing 'network' argument" << endl;
196 exit(1);
197 }
198
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200199 if (ifmArg.empty()) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200200 cerr << "Error: Missing 'ifm' argument" << endl;
201 exit(1);
202 }
203
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200204 if (ofmArg.empty()) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200205 cerr << "Error: Missing 'ofm' argument" << endl;
206 exit(1);
207 }
208
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200209 try {
Mikael Olssone9c3f072023-06-12 15:58:10 +0200210 cout << "Driver library version:" << getLibraryVersion() << endl;
211
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200212 Device device;
Mikael Olssone9c3f072023-06-12 15:58:10 +0200213 cout << "Kernel driver version:" << device.getDriverVersion() << endl;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200214
Davide Grohmann1c26baa2021-06-15 13:21:15 +0200215 cout << "Send Ping" << endl;
216 device.ioctl(ETHOSU_IOCTL_PING);
217
Davide Grohmann35ce6c82021-06-01 15:03:51 +0200218 cout << "Send capabilities request" << endl;
219 Capabilities capabilities = device.capabilities();
220
221 cout << "Capabilities:" << endl
222 << "\tversion_status:" << unsigned(capabilities.hwId.versionStatus) << endl
223 << "\tversion:" << capabilities.hwId.version << endl
224 << "\tproduct:" << capabilities.hwId.product << endl
225 << "\tarchitecture:" << capabilities.hwId.architecture << endl
226 << "\tdriver:" << capabilities.driver << endl
227 << "\tmacs_per_cc:" << unsigned(capabilities.hwCfg.macsPerClockCycle) << endl
228 << "\tcmd_stream_version:" << unsigned(capabilities.hwCfg.cmdStreamVersion) << endl
Davide Grohmann35ce6c82021-06-01 15:03:51 +0200229 << "\tcustom_dma:" << std::boolalpha << capabilities.hwCfg.customDma << endl;
230
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200231 /* Create network */
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200232 cout << "Create network" << endl;
Kristofer Jonsson35de9e62022-03-08 13:25:45 +0100233
234 shared_ptr<Network> network;
235
236 if (networkIndex < 0) {
237 shared_ptr<Buffer> networkBuffer = allocAndFill(device, networkArg);
238 network = make_shared<Network>(device, networkBuffer);
239 } else {
Kristofer Jonsson3c6a2602022-03-10 11:17:29 +0100240 network = make_shared<Network>(device, networkIndex);
Kristofer Jonsson35de9e62022-03-08 13:25:45 +0100241 }
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200242
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200243 /* Create one inference per IFM */
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200244 list<shared_ptr<Inference>> inferences;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200245 for (auto &filename : ifmArg) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200246 cout << "Create inference" << endl;
Per Åstrand716546a2020-10-24 20:17:32 +0200247 inferences.push_back(createInference(device, network, filename, enabledCounters, enableCycleCounter));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200248 }
249
250 cout << "Wait for inferences" << endl;
251
252 int ofmIndex = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200253 for (auto &inference : inferences) {
Davide Grohmann82d22582022-04-25 12:52:38 +0200254 cout << "Inference status: " << inference->status() << endl;
Per Åstrand716546a2020-10-24 20:17:32 +0200255
256 /* make sure the wait completes ok */
Davide Grohmanne446b422021-10-19 15:33:23 +0200257 try {
Davide Grohmann82d22582022-04-25 12:52:38 +0200258 cout << "Wait for inference" << endl;
Davide Grohmann7e8f5082022-03-23 12:48:45 +0100259 bool timedout = inference->wait(timeout);
260 if (timedout) {
261 cout << "Inference timed out, cancelling it" << endl;
262 bool aborted = inference->cancel();
263 if (!aborted || inference->status() != InferenceStatus::ABORTED) {
264 cout << "Inference cancellation failed" << endl;
265 }
266 }
Davide Grohmanne446b422021-10-19 15:33:23 +0200267 } catch (std::exception &e) {
Davide Grohmann7e8f5082022-03-23 12:48:45 +0100268 cout << "Failed to wait for or to cancel inference: " << e.what() << endl;
Per Åstrand716546a2020-10-24 20:17:32 +0200269 exit(1);
270 }
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200271
Davide Grohmann82d22582022-04-25 12:52:38 +0200272 cout << "Inference status: " << inference->status() << endl;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200273
Davide Grohmann82d22582022-04-25 12:52:38 +0200274 if (inference->status() == InferenceStatus::OK) {
Davide Grohmann7e8f5082022-03-23 12:48:45 +0100275 string ofmFilename = ofmArg + "." + to_string(ofmIndex);
276 ofstream ofmStream(ofmFilename, ios::binary);
277 if (!ofmStream.is_open()) {
278 cerr << "Error: Failed to open '" << ofmFilename << "'" << endl;
279 exit(1);
280 }
281
Per Åstrand716546a2020-10-24 20:17:32 +0200282 /* The inference completed and has ok status */
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200283 for (auto &ofmBuffer : inference->getOfmBuffers()) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200284 cout << "OFM size: " << ofmBuffer->size() << endl;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200285
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200286 if (print) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200287 cout << "OFM data: " << *ofmBuffer << endl;
288 }
289
290 ofmStream.write(ofmBuffer->data(), ofmBuffer->size());
291 }
Per Åstrand716546a2020-10-24 20:17:32 +0200292
Davide Grohmann7e8f5082022-03-23 12:48:45 +0100293 ofmStream.flush();
294
Per Åstrand716546a2020-10-24 20:17:32 +0200295 /* Read out PMU counters if configured */
296 if (std::count(enabledCounters.begin(), enabledCounters.end(), 0) <
297 Inference::getMaxPmuEventCounters()) {
298
299 const std::vector<uint32_t> pmus = inference->getPmuCounters();
300 cout << "PMUs : [";
301 for (auto p : pmus) {
302 cout << " " << p;
303 }
304 cout << " ]" << endl;
305 }
306 if (enableCycleCounter)
307 cout << "Cycle counter: " << inference->getCycleCounter() << endl;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200308 }
309
310 ofmIndex++;
311 }
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200312 } catch (Exception &e) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200313 cerr << "Error: " << e.what() << endl;
314 return 1;
315 }
316
317 return 0;
318}