blob: b9707a9427712dbb058306ac21ddc61cbb537dda [file] [log] [blame]
Kristofer Jonsson116a6352020-08-20 17:25:23 +02001/*
2 * Copyright (c) 2020 Arm Limited. All rights reserved.
3 *
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>
26#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 {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020033int defaultTimeout = 60;
34
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";
41 cerr << " -i --ifm File to read IFM from.\n";
42 cerr << " -o --ofm File to write IFM to.\n";
Per Åstrand716546a2020-10-24 20:17:32 +020043 cerr << " -P --pmu [0.." << Inference::getMaxPmuEventCounters() << "] eventid.\n";
44 cerr << " PMU counter to enable followed by eventid, can be passed multiple times.\n";
45 cerr << " -C --cycles Enable cycle counter for inference.\n";
Kristofer Jonsson116a6352020-08-20 17:25:23 +020046 cerr << " -t --timeout Timeout in seconds (default " << defaultTimeout << ").\n";
47 cerr << " -p Print OFM.\n";
48 cerr << endl;
49}
50
Kristofer Jonsson79689c52020-10-16 14:42:19 +020051void rangeCheck(const int i, const int argc, const string arg) {
52 if (i >= argc) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020053 cerr << "Error: Missing argument to '" << arg << "'" << endl;
54 exit(1);
55 }
56}
57
Kristofer Jonsson79689c52020-10-16 14:42:19 +020058shared_ptr<Buffer> allocAndFill(Device &device, const string filename) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020059 ifstream stream(filename, ios::binary);
Kristofer Jonsson79689c52020-10-16 14:42:19 +020060 if (!stream.is_open()) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020061 cerr << "Error: Failed to open '" << filename << "'" << endl;
62 exit(1);
63 }
64
65 stream.seekg(0, ios_base::end);
66 size_t size = stream.tellg();
67 stream.seekg(0, ios_base::beg);
68
69 shared_ptr<Buffer> buffer = make_shared<Buffer>(device, size);
70 buffer->resize(size);
71 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);
103 buffer->resize(size);
104 stream.read(buffer->data(), size);
105
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200106 if (!stream) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200107 cerr << "Error: Failed to read IFM" << endl;
108 exit(1);
109 }
110
111 ifm.push_back(buffer);
112 }
113
114 // Create OFM buffers
115 vector<shared_ptr<Buffer>> ofm;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200116 for (auto size : network->getOfmDims()) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200117 ofm.push_back(make_shared<Buffer>(device, size));
118 }
119
Per Åstrand716546a2020-10-24 20:17:32 +0200120 return make_shared<Inference>(
121 network, ifm.begin(), ifm.end(), ofm.begin(), ofm.end(), counters, enableCycleCounter);
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200122}
123
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200124ostream &operator<<(ostream &os, Buffer &buf) {
125 char *c = buf.data();
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200126 const char *end = c + buf.size();
127
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200128 while (c < end) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200129 os << hex << setw(2) << static_cast<int>(*c++) << " " << dec;
130 }
131
132 return os;
133}
134
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200135} // namespace
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200136
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200137int main(int argc, char *argv[]) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200138 const string exe = argv[0];
139 string networkArg;
140 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;
Per Åstrand716546a2020-10-24 20:17:32 +0200143 int timeout = defaultTimeout;
144 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 Jonsson79689c52020-10-16 14:42:19 +0200156 } else if (arg == "--ifm" || arg == "-i") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200157 rangeCheck(++i, argc, arg);
158 ifmArg.push_back(argv[i]);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200159 } else if (arg == "--ofm" || arg == "-o") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200160 rangeCheck(++i, argc, arg);
161 ofmArg = argv[i];
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200162 } else if (arg == "--timeout" || arg == "-t") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200163 rangeCheck(++i, argc, arg);
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200164 timeout = stoi(argv[i]);
Per Åstrand716546a2020-10-24 20:17:32 +0200165 } else if (arg == "--pmu" || arg == "-P") {
166 unsigned pmu = 0, event = 0;
167 rangeCheck(++i, argc, arg);
168 pmu = stoi(argv[i]);
169
170 rangeCheck(++i, argc, arg);
171 event = stoi(argv[i]);
172
173 if (pmu >= enabledCounters.size()) {
174 cerr << "PMU out of bounds!" << endl;
175 help(exe);
176 exit(1);
177 }
178 cout << argv[i] << " -> Enabling " << pmu << " with event " << event << endl;
179 enabledCounters[pmu] = event;
180 } else if (arg == "--cycles" || arg == "-C") {
181 enableCycleCounter = true;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200182 } else if (arg == "-p") {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200183 print = true;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200184 } else {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200185 cerr << "Error: Invalid argument '" << arg << "'" << endl;
186 help(exe);
187 exit(1);
188 }
189 }
190
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200191 if (networkArg.empty()) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200192 cerr << "Error: Missing 'network' argument" << endl;
193 exit(1);
194 }
195
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200196 if (ifmArg.empty()) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200197 cerr << "Error: Missing 'ifm' argument" << endl;
198 exit(1);
199 }
200
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200201 if (ofmArg.empty()) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200202 cerr << "Error: Missing 'ofm' argument" << endl;
203 exit(1);
204 }
205
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200206 try {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200207 Device device;
208
209 cout << "Send ping" << endl;
210 device.ioctl(ETHOSU_IOCTL_PING);
211
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200212 /* Create network */
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200213 cout << "Create network" << endl;
214 shared_ptr<Buffer> networkBuffer = allocAndFill(device, networkArg);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200215 shared_ptr<Network> network = make_shared<Network>(device, networkBuffer);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200216
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200217 /* Create one inference per IFM */
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200218 list<shared_ptr<Inference>> inferences;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200219 for (auto &filename : ifmArg) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200220 cout << "Create inference" << endl;
Per Åstrand716546a2020-10-24 20:17:32 +0200221 inferences.push_back(createInference(device, network, filename, enabledCounters, enableCycleCounter));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200222 }
223
224 cout << "Wait for inferences" << endl;
225
226 int ofmIndex = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200227 for (auto &inference : inferences) {
Per Åstrand716546a2020-10-24 20:17:32 +0200228
229 /* make sure the wait completes ok */
230 if (inference->wait(timeout) <= 0) {
231 cout << "Failed to wait for inference completion" << endl;
232 exit(1);
233 }
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200234
235 string status = inference->failed() ? "failed" : "success";
236 cout << "Inference status: " << status << endl;
237
238 string ofmFilename = ofmArg + "." + to_string(ofmIndex);
239 ofstream ofmStream(ofmFilename, ios::binary);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200240 if (!ofmStream.is_open()) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200241 cerr << "Error: Failed to open '" << ofmFilename << "'" << endl;
242 exit(1);
243 }
244
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200245 if (!inference->failed()) {
Per Åstrand716546a2020-10-24 20:17:32 +0200246 /* The inference completed and has ok status */
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200247 for (auto &ofmBuffer : inference->getOfmBuffers()) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200248 cout << "OFM size: " << ofmBuffer->size() << endl;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200249
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200250 if (print) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200251 cout << "OFM data: " << *ofmBuffer << endl;
252 }
253
254 ofmStream.write(ofmBuffer->data(), ofmBuffer->size());
255 }
Per Åstrand716546a2020-10-24 20:17:32 +0200256
257 /* Read out PMU counters if configured */
258 if (std::count(enabledCounters.begin(), enabledCounters.end(), 0) <
259 Inference::getMaxPmuEventCounters()) {
260
261 const std::vector<uint32_t> pmus = inference->getPmuCounters();
262 cout << "PMUs : [";
263 for (auto p : pmus) {
264 cout << " " << p;
265 }
266 cout << " ]" << endl;
267 }
268 if (enableCycleCounter)
269 cout << "Cycle counter: " << inference->getCycleCounter() << endl;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200270 }
271
272 ofmIndex++;
273 }
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200274 } catch (Exception &e) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200275 cerr << "Error: " << e.what() << endl;
276 return 1;
277 }
278
279 return 0;
280}