blob: 17969daba3e4e1f0ad349257ed847068bf56555f [file] [log] [blame]
Kristofer Jonsson116a6352020-08-20 17:25:23 +02001/*
Anton Moberg4e5e0562021-03-31 11:11:36 +02002 * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
Kristofer Jonsson116a6352020-08-20 17:25:23 +02003 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020019#include <ethosu.hpp>
Kristofer Jonsson116a6352020-08-20 17:25:23 +020020#include <uapi/ethosu.h>
21
Kristofer Jonsson116a6352020-08-20 17:25:23 +020022#include <fstream>
23#include <iomanip>
24#include <iostream>
25#include <list>
Davide Grohmann35ce6c82021-06-01 15:03:51 +020026#include <stdio.h>
Kristofer Jonsson116a6352020-08-20 17:25:23 +020027#include <string>
Kristofer Jonsson79689c52020-10-16 14:42:19 +020028#include <unistd.h>
Kristofer Jonsson116a6352020-08-20 17:25:23 +020029
30using namespace std;
31using namespace EthosU;
32
Kristofer Jonsson79689c52020-10-16 14:42:19 +020033namespace {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020034int defaultTimeout = 60;
35
Kristofer Jonsson79689c52020-10-16 14:42:19 +020036void help(const string exe) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020037 cerr << "Usage: " << exe << " [ARGS]\n";
38 cerr << "\n";
39 cerr << "Arguments:\n";
40 cerr << " -h --help Print this help message.\n";
41 cerr << " -n --network File to read network from.\n";
42 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";
Kristofer Jonsson116a6352020-08-20 17:25:23 +020047 cerr << " -t --timeout Timeout in seconds (default " << defaultTimeout << ").\n";
48 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);
71 buffer->resize(size);
72 stream.read(buffer->data(), size);
73
74 return buffer;
75}
76
Per Åstrand716546a2020-10-24 20:17:32 +020077shared_ptr<Inference> createInference(Device &device,
78 shared_ptr<Network> &network,
79 const string &filename,
80 const std::vector<uint8_t> &counters,
81 bool enableCycleCounter) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020082 // Open IFM file
83 ifstream stream(filename, ios::binary);
Kristofer Jonsson79689c52020-10-16 14:42:19 +020084 if (!stream.is_open()) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020085 cerr << "Error: Failed to open '" << filename << "'" << endl;
86 exit(1);
87 }
88
89 // Get IFM file size
90 stream.seekg(0, ios_base::end);
91 size_t size = stream.tellg();
92 stream.seekg(0, ios_base::beg);
93
Kristofer Jonsson79689c52020-10-16 14:42:19 +020094 if (size != network->getIfmSize()) {
95 cerr << "Error: IFM size does not match network size. filename=" << filename << ", size=" << size
96 << ", network=" << network->getIfmSize() << endl;
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020097 exit(1);
98 }
99
100 // Create IFM buffers
101 vector<shared_ptr<Buffer>> ifm;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200102 for (auto size : network->getIfmDims()) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200103 shared_ptr<Buffer> buffer = make_shared<Buffer>(device, size);
104 buffer->resize(size);
105 stream.read(buffer->data(), size);
106
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200107 if (!stream) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200108 cerr << "Error: Failed to read IFM" << endl;
109 exit(1);
110 }
111
112 ifm.push_back(buffer);
113 }
114
115 // Create OFM buffers
116 vector<shared_ptr<Buffer>> ofm;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200117 for (auto size : network->getOfmDims()) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200118 ofm.push_back(make_shared<Buffer>(device, size));
119 }
120
Per Åstrand716546a2020-10-24 20:17:32 +0200121 return make_shared<Inference>(
122 network, ifm.begin(), ifm.end(), ofm.begin(), ofm.end(), counters, enableCycleCounter);
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200123}
124
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200125ostream &operator<<(ostream &os, Buffer &buf) {
126 char *c = buf.data();
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200127 const char *end = c + buf.size();
128
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200129 while (c < end) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200130 os << hex << setw(2) << static_cast<int>(*c++) << " " << dec;
131 }
132
133 return os;
134}
135
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200136} // namespace
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200137
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200138int main(int argc, char *argv[]) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200139 const string exe = argv[0];
140 string networkArg;
141 list<string> ifmArg;
Per Åstrand716546a2020-10-24 20:17:32 +0200142 vector<uint8_t> enabledCounters(Inference::getMaxPmuEventCounters());
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200143 string ofmArg;
Per Åstrand716546a2020-10-24 20:17:32 +0200144 int timeout = defaultTimeout;
145 bool print = false;
146 bool enableCycleCounter = false;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200147
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200148 for (int i = 1; i < argc; ++i) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200149 const string arg(argv[i]);
150
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200151 if (arg == "-h" || arg == "--help") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200152 help(exe);
153 exit(1);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200154 } else if (arg == "--network" || arg == "-n") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200155 rangeCheck(++i, argc, arg);
156 networkArg = argv[i];
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200157 } else if (arg == "--ifm" || arg == "-i") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200158 rangeCheck(++i, argc, arg);
159 ifmArg.push_back(argv[i]);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200160 } else if (arg == "--ofm" || arg == "-o") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200161 rangeCheck(++i, argc, arg);
162 ofmArg = argv[i];
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200163 } else if (arg == "--timeout" || arg == "-t") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200164 rangeCheck(++i, argc, arg);
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200165 timeout = stoi(argv[i]);
Per Åstrand716546a2020-10-24 20:17:32 +0200166 } else if (arg == "--pmu" || arg == "-P") {
167 unsigned pmu = 0, event = 0;
168 rangeCheck(++i, argc, arg);
169 pmu = stoi(argv[i]);
170
171 rangeCheck(++i, argc, arg);
172 event = stoi(argv[i]);
173
174 if (pmu >= enabledCounters.size()) {
175 cerr << "PMU out of bounds!" << endl;
176 help(exe);
177 exit(1);
178 }
179 cout << argv[i] << " -> Enabling " << pmu << " with event " << event << endl;
180 enabledCounters[pmu] = event;
181 } else if (arg == "--cycles" || arg == "-C") {
182 enableCycleCounter = true;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200183 } else if (arg == "-p") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200184 print = true;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200185 } else {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200186 cerr << "Error: Invalid argument '" << arg << "'" << endl;
187 help(exe);
188 exit(1);
189 }
190 }
191
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200192 if (networkArg.empty()) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200193 cerr << "Error: Missing 'network' argument" << endl;
194 exit(1);
195 }
196
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200197 if (ifmArg.empty()) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200198 cerr << "Error: Missing 'ifm' argument" << endl;
199 exit(1);
200 }
201
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200202 if (ofmArg.empty()) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200203 cerr << "Error: Missing 'ofm' argument" << endl;
204 exit(1);
205 }
206
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200207 try {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200208 Device device;
209
Jonny Svärd7c24c772021-01-14 19:53:17 +0100210 cout << "Send version request" << endl;
211 device.ioctl(ETHOSU_IOCTL_VERSION_REQ);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200212
Davide Grohmann35ce6c82021-06-01 15:03:51 +0200213 cout << "Send capabilities request" << endl;
214 Capabilities capabilities = device.capabilities();
215
216 cout << "Capabilities:" << endl
217 << "\tversion_status:" << unsigned(capabilities.hwId.versionStatus) << endl
218 << "\tversion:" << capabilities.hwId.version << endl
219 << "\tproduct:" << capabilities.hwId.product << endl
220 << "\tarchitecture:" << capabilities.hwId.architecture << endl
221 << "\tdriver:" << capabilities.driver << endl
222 << "\tmacs_per_cc:" << unsigned(capabilities.hwCfg.macsPerClockCycle) << endl
223 << "\tcmd_stream_version:" << unsigned(capabilities.hwCfg.cmdStreamVersion) << endl
224 << "\tshram_size:" << unsigned(capabilities.hwCfg.shramSize) << endl
225 << "\tcustom_dma:" << std::boolalpha << capabilities.hwCfg.customDma << endl;
226
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200227 /* Create network */
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200228 cout << "Create network" << endl;
229 shared_ptr<Buffer> networkBuffer = allocAndFill(device, networkArg);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200230 shared_ptr<Network> network = make_shared<Network>(device, networkBuffer);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200231
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200232 /* Create one inference per IFM */
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200233 list<shared_ptr<Inference>> inferences;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200234 for (auto &filename : ifmArg) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200235 cout << "Create inference" << endl;
Per Åstrand716546a2020-10-24 20:17:32 +0200236 inferences.push_back(createInference(device, network, filename, enabledCounters, enableCycleCounter));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200237 }
238
239 cout << "Wait for inferences" << endl;
240
241 int ofmIndex = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200242 for (auto &inference : inferences) {
Per Åstrand716546a2020-10-24 20:17:32 +0200243
244 /* make sure the wait completes ok */
245 if (inference->wait(timeout) <= 0) {
246 cout << "Failed to wait for inference completion" << endl;
247 exit(1);
248 }
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200249
250 string status = inference->failed() ? "failed" : "success";
251 cout << "Inference status: " << status << endl;
252
253 string ofmFilename = ofmArg + "." + to_string(ofmIndex);
254 ofstream ofmStream(ofmFilename, ios::binary);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200255 if (!ofmStream.is_open()) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200256 cerr << "Error: Failed to open '" << ofmFilename << "'" << endl;
257 exit(1);
258 }
259
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200260 if (!inference->failed()) {
Per Åstrand716546a2020-10-24 20:17:32 +0200261 /* The inference completed and has ok status */
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200262 for (auto &ofmBuffer : inference->getOfmBuffers()) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200263 cout << "OFM size: " << ofmBuffer->size() << endl;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200264
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200265 if (print) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200266 cout << "OFM data: " << *ofmBuffer << endl;
267 }
268
269 ofmStream.write(ofmBuffer->data(), ofmBuffer->size());
270 }
Per Åstrand716546a2020-10-24 20:17:32 +0200271
272 /* Read out PMU counters if configured */
273 if (std::count(enabledCounters.begin(), enabledCounters.end(), 0) <
274 Inference::getMaxPmuEventCounters()) {
275
276 const std::vector<uint32_t> pmus = inference->getPmuCounters();
277 cout << "PMUs : [";
278 for (auto p : pmus) {
279 cout << " " << p;
280 }
281 cout << " ]" << endl;
282 }
283 if (enableCycleCounter)
284 cout << "Cycle counter: " << inference->getCycleCounter() << endl;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200285 }
286
287 ofmIndex++;
288 }
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200289 } catch (Exception &e) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200290 cerr << "Error: " << e.what() << endl;
291 return 1;
292 }
293
294 return 0;
295}