Add option to specify object classes list file
[tidl/tidl-api.git] / examples / test / main.cpp
1 /******************************************************************************
2  * Copyright (c) 2017-2018  Texas Instruments Incorporated - http://www.ti.com/
3  *   All rights reserved.
4  *
5  *   Redistribution and use in source and binary forms, with or without
6  *   modification, are permitted provided that the following conditions are met:
7  *       * Redistributions of source code must retain the above copyright
8  *         notice, this list of conditions and the following disclaimer.
9  *       * Redistributions in binary form must reproduce the above copyright
10  *         notice, this list of conditions and the following disclaimer in the
11  *         documentation and/or other materials provided with the distribution.
12  *       * Neither the name of Texas Instruments Incorporated nor the
13  *         names of its contributors may be used to endorse or promote products
14  *         derived from this software without specific prior written permission.
15  *
16  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  *   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  *   THE POSSIBILITY OF SUCH DAMAGE.
27  *****************************************************************************/
28 #include <signal.h>
29 #include <getopt.h>
30 #include <iostream>
31 #include <fstream>
32 #include <cassert>
33 #include <string>
34 #include <vector>
36 #include "executor.h"
37 #include "execution_object.h"
38 #include "configuration.h"
39 #include "utils.h"
41 using namespace tidl;
42 using std::string;
44 bool RunMultipleExecutors(const string& config_file_1,
45                           const string& config_file_2,
46                           uint32_t      num_devices_available);
48 bool RunConfiguration(const string& config_file,
49                       int           num_devices,
50                       DeviceType    device_type);
52 bool RunAllConfigurations(int32_t    num_devices,
53                           DeviceType device_type);
55 bool RunNetwork(DeviceType           device_type,
56                 const DeviceIds&     ids,
57                 const Configuration& c,
58                 std::istream&        input,
59                 std::ostream&        output);
61 static void ProcessArgs(int argc, char *argv[],
62                         string&     config_file,
63                         int&        num_devices,
64                         DeviceType& device_type);
66 static void DisplayHelp();
68 bool verbose = false;
70 int main(int argc, char *argv[])
71 {
72     // Catch ctrl-c to ensure a clean exit
73     signal(SIGABRT, exit);
74     signal(SIGTERM, exit);
76     // If there are no devices capable of offloading TIDL on the SoC, exit
77     uint32_t num_eve = Executor::GetNumDevices(DeviceType::EVE);
78     uint32_t num_dsp = Executor::GetNumDevices(DeviceType::DSP);
79     if (num_eve == 0 && num_dsp == 0)
80     {
81         std::cout << "TI DL not supported on this processor." << std::endl;
82         return EXIT_SUCCESS;
83     }
85     // Process arguments
86     string      config_file;
87     int         num_devices = 1;
88     DeviceType  device_type = DeviceType::EVE;
89     ProcessArgs(argc, argv, config_file, num_devices, device_type);
91     bool status = true;
92     if (!config_file.empty())
93         status = RunConfiguration(config_file, num_devices, device_type);
94     else
95     {
96         if (num_eve > 0)
97         {
98             // Run on 2 devices because there is not enough CMEM available by
99             // default
100             if (num_eve == 4)
101             {
102                 std::cout
103                  << "Running on 2 EVE devices instead of the available 4 "
104                  << "due to insufficient OpenCL global memory. Refer the "
105                  << "TIDL API User's Guide, Frequently Asked Questions, "
106                  << "Section \"Insufficient OpenCL global memory\" for details "
107                  << "on increasing the amount of CMEM available for OpenCL."
108                  << std::endl;
109                 num_eve = 2;
110             }
111             status = RunAllConfigurations(num_eve, DeviceType::EVE);
112             status &= RunMultipleExecutors(
113                      "testvecs/config/infer/tidl_config_j11_v2.txt",
114                      "testvecs/config/infer/tidl_config_j11_cifar.txt",
115                      num_eve);
116         }
118         if (num_dsp > 0)
119         {
120             status &= RunAllConfigurations(num_dsp, DeviceType::DSP);
121         }
122     }
124     if (!status)
125     {
126         std::cout << "tidl FAILED" << std::endl;
127         return EXIT_FAILURE;
128     }
130     std::cout << "tidl PASSED" << std::endl;
131     return EXIT_SUCCESS;
134 bool RunConfiguration(const std::string& config_file, int num_devices,
135                       DeviceType device_type)
137     DeviceIds ids;
138     for (int i = 0; i < num_devices; i++)
139         ids.insert(static_cast<DeviceId>(i));
141     // Read the TI DL configuration file
142     Configuration c;
143     if (!c.ReadFromFile(config_file)) return false;
144     if (verbose)                      c.enableApiTrace = true;
146     // Open input and output files
147     std::ifstream input_data_file(c.inData, std::ios::binary);
148     std::ofstream output_data_file(c.outData, std::ios::binary);
149     assert (input_data_file.good());
150     assert (output_data_file.good());
152     bool status = RunNetwork(device_type, ids, c,
153                              input_data_file, output_data_file);
155     input_data_file.close();
156     output_data_file.close();
158     return status;
161 bool RunNetwork(DeviceType           device_type,
162                 const DeviceIds&     ids,
163                 const Configuration& c,
164                 std::istream&        input,
165                 std::ostream&        output)
167     bool status = true;
169     try
170     {
171         // Create a executor with the specified core type, number of cores
172         // and configuration
173         Executor E(device_type, ids, c);
175         std::vector<ExecutionObject *> EOs;
176         for (unsigned int i = 0; i < E.GetNumExecutionObjects(); i++)
177             EOs.push_back(E[i]);
179         int num_eos = EOs.size();
181         // Allocate input and output buffers for each execution object
182         for (auto eo : EOs)
183         {
184             size_t in_size  = eo->GetInputBufferSizeInBytes();
185             size_t out_size = eo->GetOutputBufferSizeInBytes();
186             ArgInfo in  = { ArgInfo(malloc(in_size),  in_size)};
187             ArgInfo out = { ArgInfo(malloc(out_size), out_size)};
188             eo->SetInputOutputBuffer(in, out);
189         }
191         // Process frames with available execution objects in a pipelined manner
192         // additional num_eos iterations to flush the pipeline (epilogue)
193         for (int frame_idx = 0; frame_idx < c.numFrames + num_eos; frame_idx++)
194         {
195             ExecutionObject* eo = EOs[frame_idx % num_eos];
197             // Wait for previous frame on the same eo to finish processing
198             if (eo->ProcessFrameWait())
199             {
200                 ReportTime(eo);
201                 WriteFrame(eo, output);
202             }
204             // Read a frame and start processing it with current eo
205             if (ReadFrame(eo, frame_idx, c, input))
206                 eo->ProcessFrameStartAsync();
207         }
209         for (auto eo : EOs)
210         {
211             free(eo->GetInputBufferPtr());
212             free(eo->GetOutputBufferPtr());
213         }
214     }
215     catch (tidl::Exception &e)
216     {
217         std::cerr << e.what() << std::endl;
218         status = false;
219     }
221     return status;
225 namespace tidl {
226 extern bool CompareFiles (const std::string &F1, const std::string &F2);
227 extern bool CompareFrames(const std::string &F1, const std::string &F2,
228                           int numFrames, int width, int height);
231 bool RunAllConfigurations(int32_t num_devices, DeviceType device_type)
233     std::vector<std::string> configurations;
235     if (device_type == DeviceType::EVE)
236         configurations = {"dense_1x1",  "j11_bn", "j11_cifar",
237                           "j11_controlLayers", "j11_prelu", "j11_v2",
238                           "jseg21", "jseg21_tiscapes", "smallRoi", "squeeze1_1"};
239     else
240         configurations = {"dense_1x1",  "j11_bn", "j11_cifar",
241                           "j11_controlLayers", "j11_v2",
242                           "jseg21", "jseg21_tiscapes", "smallRoi", "squeeze1_1"};
244     int errors = 0;
245     for (auto config : configurations)
246     {
247         std::string config_file = "testvecs/config/infer/tidl_config_"
248                                   + config + ".txt";
249         std::cout << "Running " << config << " on " << num_devices
250                   << " devices, type "
251                   << ((device_type == DeviceType::EVE) ? "EVE" : "DSP")
252                   << std::endl;
254         Configuration configuration;
255         bool status = configuration.ReadFromFile(config_file);
256         if (!status) { errors++; continue; }
258         status = RunConfiguration(config_file, num_devices, device_type);
260         if (!status) { errors++; continue; }
262         // Check output against reference output
263         std::string reference_output = "testvecs/reference/"
264                                        + config + "_ref.bin";
266         // Reference for jseg21_tiscapes only has one frame
267         if (config.compare("jseg21_tiscapes") == 0)
268             status = CompareFrames(configuration.outData, reference_output,
269                                    1, 1024, 512);
270         else
271             status = CompareFiles(configuration.outData, reference_output);
273         if (status) std::cout << config << " : PASSED" << std::endl;
274         else        std::cout << config << " : FAILED" << std::endl;
276         if (!status) errors++;
277     }
279     if (errors > 0) return false;
281     return true;
284 void ProcessArgs(int argc, char *argv[], std::string& config_file,
285                  int& num_devices, DeviceType& device_type)
287     const struct option long_options[] =
288     {
289         {"config_file", required_argument, 0, 'c'},
290         {"num_devices", required_argument, 0, 'n'},
291         {"device_type", required_argument, 0, 't'},
292         {"help",        no_argument,       0, 'h'},
293         {"verbose",     no_argument,       0, 'v'},
294         {0, 0, 0, 0}
295     };
297     int option_index = 0;
299     while (true)
300     {
301         int c = getopt_long(argc, argv, "c:n:t:hv", long_options, &option_index);
303         if (c == -1)
304             break;
306         switch (c)
307         {
308             case 'c': config_file = optarg;
309                       break;
311             case 'n': num_devices = atoi(optarg);
312                       assert (num_devices > 0 && num_devices <= 4);
313                       break;
315             case 't': if (*optarg == 'e')
316                           device_type = DeviceType::EVE;
317                       else if (*optarg == 'd')
318                           device_type = DeviceType::DSP;
319                       else
320                       {
321                           std::cerr << "Invalid argument to -t, only e or d"
322                                        " allowed" << std::endl;
323                           exit(EXIT_FAILURE);
324                       }
325                       break;
327             case 'v': verbose = true;
328                       break;
330             case 'h': DisplayHelp();
331                       exit(EXIT_SUCCESS);
332                       break;
334             case '?': // Error in getopt_long
335                       exit(EXIT_FAILURE);
336                       break;
338             default:
339                       std::cerr << "Unsupported option: " << c << std::endl;
340                       break;
341         }
342     }
345 void DisplayHelp()
347     std::cout << "Usage: test_tidl\n"
348                  "  Will run all available networks if invoked without"
349                  " any arguments.\n  Use -c to run a single network.\n"
350                  "Optional arguments:\n"
351                  " -c                   Path to the configuration file\n"
352                  " -n <number of cores> Number of cores to use (1 - 4)\n"
353                  " -t <d|e>             Type of core. d -> DSP, e -> EVE\n"
354                  " -v                   Verbose output during execution\n"
355                  " -h                   Help\n";