]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - tidl/tidl-api.git/blob - examples/test/main.cpp
Merge branch 'hotfix/v01.00.00.03'
[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 <iomanip>
32 #include <fstream>
33 #include <cassert>
34 #include <string>
35 #include <functional>
36 #include <algorithm>
37 #include <time.h>
39 #include "executor.h"
40 #include "execution_object.h"
41 #include "configuration.h"
43 bool __TI_show_debug_ = false;
45 using namespace tidl;
47 bool RunMultipleExecutors(const std::string& config_file_1,
48                           const std::string& config_file_2,
49                           uint32_t num_devices_available);
51 bool RunConfiguration(const std::string& config_file, int num_devices,
52                       DeviceType device_type);
53 bool RunAllConfigurations(int32_t num_devices, DeviceType device_type);
55 bool ReadFrame(ExecutionObject&     eo,
56                int                  frame_idx,
57                const Configuration& configuration,
58                std::istream&        input_file);
60 bool WriteFrame(const ExecutionObject &eo,
61                 std::ostream& output_file);
63 static void ProcessArgs(int argc, char *argv[],
64                         std::string& config_file,
65                         int& num_devices,
66                         DeviceType& device_type);
68 static void DisplayHelp();
70 static double ms_diff(struct timespec &t0, struct timespec &t1)
71 { return (t1.tv_sec - t0.tv_sec) * 1e3 + (t1.tv_nsec - t0.tv_nsec) / 1e6; }
74 int main(int argc, char *argv[])
75 {
76     // Catch ctrl-c to ensure a clean exit
77     signal(SIGABRT, exit);
78     signal(SIGTERM, exit);
80     // If there are no devices capable of offloading TIDL on the SoC, exit
81     uint32_t num_eve = Executor::GetNumDevices(DeviceType::EVE);
82     uint32_t num_dsp = Executor::GetNumDevices(DeviceType::DSP);
83     if (num_eve == 0 && num_dsp == 0)
84     {
85         std::cout << "TI DL not supported on this SoC." << std::endl;
86         return EXIT_SUCCESS;
87     }
88     std::cout << "API Version: " << Executor::GetAPIVersion() << std::endl;
90     // Process arguments
91     std::string config_file;
92     int         num_devices = 1;
93     DeviceType  device_type = DeviceType::EVE;
94     ProcessArgs(argc, argv, config_file, num_devices, device_type);
96     bool status = true;
97     if (!config_file.empty())
98         status = RunConfiguration(config_file, num_devices, device_type);
99     else
100     {
101         if (num_eve > 0)
102         {
103             // Run on 2 devices because there is not enough CMEM available by
104             // default
105             if (num_eve = 4)
106             {
107                 std::cout
108                  << "Running on 2 EVE devices instead of the available 4 "
109                  << "due to insufficient OpenCL global memory. Refer the "
110                  << "TIDL API User's Guide, Frequently Asked Questions, "
111                  << "Section \"Insufficient OpenCL global memory\" for details "
112                  << "on increasing the amount of CMEM available for OpenCL."
113                  << std::endl;
114                 num_eve = 2;
115             }
116             status = RunAllConfigurations(num_eve, DeviceType::EVE);
117             status &= RunMultipleExecutors(
118                      "testvecs/config/infer/tidl_config_j11_v2.txt",
119                      "testvecs/config/infer/tidl_config_j11_cifar.txt",
120                      num_eve);
121         }
123         if (num_dsp > 0)
124         {
125             status &= RunAllConfigurations(num_dsp, DeviceType::DSP);
126         }
127     }
129     if (!status)
130     {
131         std::cout << "tidl FAILED" << std::endl;
132         return EXIT_FAILURE;
133     }
135     std::cout << "tidl PASSED" << std::endl;
136     return EXIT_SUCCESS;
139 bool RunConfiguration(const std::string& config_file, int num_devices,
140                       DeviceType device_type)
142     DeviceIds ids;
143     for (int i = 0; i < num_devices; i++)
144         ids.insert(static_cast<DeviceId>(i));
146     // Read the TI DL configuration file
147     Configuration configuration;
148     bool status = configuration.ReadFromFile(config_file);
149     if (!status)
150     {
151         std::cerr << "Error in configuration file: " << config_file
152                   << std::endl;
153         return false;
154     }
156     // Open input and output files
157     std::ifstream input_data_file(configuration.inData, std::ios::binary);
158     std::ofstream output_data_file(configuration.outData, std::ios::binary);
159     assert (input_data_file.good());
160     assert (output_data_file.good());
162     try
163     {
164         // Create a executor with the approriate core type, number of cores
165         // and configuration specified
166         Executor executor(device_type, ids, configuration);
168         // Query Executor for set of ExecutionObjects created
169         const ExecutionObjects& execution_objects =
170                                                 executor.GetExecutionObjects();
171         int num_eos = execution_objects.size();
173         // Allocate input and output buffers for each execution object
174         std::vector<void *> buffers;
175         for (auto &eo : execution_objects)
176         {
177             size_t in_size  = eo->GetInputBufferSizeInBytes();
178             size_t out_size = eo->GetOutputBufferSizeInBytes();
179             ArgInfo in  = { ArgInfo(malloc(in_size),  in_size)};
180             ArgInfo out = { ArgInfo(malloc(out_size), out_size)};
181             eo->SetInputOutputBuffer(in, out);
183             buffers.push_back(in.ptr());
184             buffers.push_back(out.ptr());
185         }
187         #define MAX_NUM_EOS  4
188         struct timespec t0[MAX_NUM_EOS], t1;
190         // Process frames with available execution objects in a pipelined manner
191         // additional num_eos iterations to flush the pipeline (epilogue)
192         for (int frame_idx = 0;
193              frame_idx < configuration.numFrames + num_eos; frame_idx++)
194         {
195             ExecutionObject* eo = execution_objects[frame_idx % num_eos].get();
197             // Wait for previous frame on the same eo to finish processing
198             if (eo->ProcessFrameWait())
199             {
200                 clock_gettime(CLOCK_MONOTONIC, &t1);
201                 double elapsed_host =
202                                 ms_diff(t0[eo->GetFrameIndex() % num_eos], t1);
203                 double elapsed_device = eo->GetProcessTimeInMilliSeconds();
204                 double overhead = 100 - (elapsed_device/elapsed_host*100);
206                 std::cout << "frame[" << eo->GetFrameIndex() << "]: "
207                           << "Time on device: "
208                           << std::setw(6) << std::setprecision(4)
209                           << elapsed_device << "ms, "
210                           << "host: "
211                           << std::setw(6) << std::setprecision(4)
212                           << elapsed_host << "ms ";
213                 std::cout << "API overhead: "
214                           << std::setw(6) << std::setprecision(3)
215                           << overhead << " %" << std::endl;
217                 WriteFrame(*eo, output_data_file);
218             }
220             // Read a frame and start processing it with current eo
221             if (ReadFrame(*eo, frame_idx, configuration, input_data_file))
222             {
223                 clock_gettime(CLOCK_MONOTONIC, &t0[frame_idx % num_eos]);
224                 eo->ProcessFrameStartAsync();
225             }
226         }
228         for (auto b : buffers)
229             free(b);
231     }
232     catch (tidl::Exception &e)
233     {
234         std::cerr << e.what() << std::endl;
235         status = false;
236     }
239     input_data_file.close();
240     output_data_file.close();
242     return status;
245 namespace tidl {
246 extern bool CompareFiles (const std::string &F1, const std::string &F2);
247 extern bool CompareFrames(const std::string &F1, const std::string &F2,
248                           int numFrames, int width, int height);
251 bool RunAllConfigurations(int32_t num_devices, DeviceType device_type)
253     std::vector<std::string> configurations;
255     if (device_type == DeviceType::EVE)
256         configurations = {"dense_1x1",  "j11_bn", "j11_cifar",
257                           "j11_controlLayers", "j11_prelu", "j11_v2",
258                           "jseg21", "jseg21_tiscapes", "smallRoi", "squeeze1_1"};
259     else
260         configurations = {"j11_bn",
261                           "j11_controlLayers", "j11_v2",
262                           "jseg21", "jseg21_tiscapes", "smallRoi", "squeeze1_1"};
264     int errors = 0;
265     for (auto config : configurations)
266     {
267         std::string config_file = "testvecs/config/infer/tidl_config_"
268                                   + config + ".txt";
269         std::cout << "Running " << config << " on " << num_devices
270                   << " devices, type "
271                   << ((device_type == DeviceType::EVE) ? "EVE" : "DSP")
272                   << std::endl;
274         Configuration configuration;
275         bool status = configuration.ReadFromFile(config_file);
276         if (!status) { errors++; continue; }
278         status = RunConfiguration(config_file, num_devices, device_type);
280         if (!status) { errors++; continue; }
282         // Check output against reference output
283         std::string reference_output = "testvecs/reference/"
284                                        + config + "_ref.bin";
286         // Reference for jseg21_tiscapes only has one frame
287         if (config.compare("jseg21_tiscapes") == 0)
288             status = CompareFrames(configuration.outData, reference_output,
289                                    1, 1024, 512);
290         else
291             status = CompareFiles(configuration.outData, reference_output);
293         if (status) std::cout << config << " : PASSED" << std::endl;
294         else        std::cout << config << " : FAILED" << std::endl;
296         if (!status) errors++;
297     }
299     if (errors > 0) return false;
301     return true;
306 bool ReadFrame(ExecutionObject &eo, int frame_idx,
307                const Configuration& configuration,
308                std::istream& input_file)
310     if (frame_idx >= configuration.numFrames)
311         return false;
313     char*  frame_buffer = eo.GetInputBufferPtr();
314     assert (frame_buffer != nullptr);
316     input_file.read(eo.GetInputBufferPtr(),
317                     eo.GetInputBufferSizeInBytes());
319     if (input_file.eof())
320         return false;
322     assert (input_file.good());
324     // Set the frame index  being processed by the EO. This is used to
325     // sort the frames before they are output
326     eo.SetFrameIndex(frame_idx);
328     if (input_file.good())
329         return true;
331     return false;
334 bool WriteFrame(const ExecutionObject &eo, std::ostream& output_file)
336     output_file.write(
337             eo.GetOutputBufferPtr(), eo.GetOutputBufferSizeInBytes());
338     assert(output_file.good() == true);
340     if (output_file.good())
341         return true;
343     return false;
347 void ProcessArgs(int argc, char *argv[], std::string& config_file,
348                  int& num_devices, DeviceType& device_type)
350     const struct option long_options[] =
351     {
352         {"config_file", required_argument, 0, 'c'},
353         {"num_devices", required_argument, 0, 'n'},
354         {"device_type", required_argument, 0, 't'},
355         {"help",        no_argument,       0, 'h'},
356         {"verbose",     no_argument,       0, 'v'},
357         {0, 0, 0, 0}
358     };
360     int option_index = 0;
362     while (true)
363     {
364         int c = getopt_long(argc, argv, "c:n:t:hv", long_options, &option_index);
366         if (c == -1)
367             break;
369         switch (c)
370         {
371             case 'c': config_file = optarg;
372                       break;
374             case 'n': num_devices = atoi(optarg);
375                       assert (num_devices > 0 && num_devices <= 4);
376                       break;
378             case 't': if (*optarg == 'e')
379                           device_type = DeviceType::EVE;
380                       else if (*optarg == 'd')
381                           device_type = DeviceType::DSP;
382                       else
383                       {
384                           std::cerr << "Invalid argument to -t, only e or d"
385                                        " allowed" << std::endl;
386                           exit(EXIT_FAILURE);
387                       }
388                       break;
390             case 'v': __TI_show_debug_ = true;
391                       break;
393             case 'h': DisplayHelp();
394                       exit(EXIT_SUCCESS);
395                       break;
397             case '?': // Error in getopt_long
398                       exit(EXIT_FAILURE);
399                       break;
401             default:
402                       std::cerr << "Unsupported option: " << c << std::endl;
403                       break;
404         }
405     }
408 void DisplayHelp()
410     std::cout << "Usage: test_tidl\n"
411                  "  Will run all available networks if invoked without"
412                  " any arguments.\n  Use -c to run a single network.\n"
413                  "Optional arguments:\n"
414                  " -c                   Path to the configuration file\n"
415                  " -n <number of cores> Number of cores to use (1 - 4)\n"
416                  " -t <d|e>             Type of core. d -> DSP, e -> EVE\n"
417                  " -v                   Verbose output during execution\n"
418                  " -h                   Help\n";