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 *****************************************************************************/
29 //
30 // This example illustrates using multiple EOs to process a single frame
31 // For details, refer http://downloads.ti.com/mctools/esd/docs/tidl-api/
32 //
33 #include <signal.h>
34 #include <iostream>
35 #include <fstream>
36 #include <cassert>
37 #include <string>
39 #include "executor.h"
40 #include "execution_object.h"
41 #include "execution_object_pipeline.h"
42 #include "configuration.h"
43 #include "utils.h"
45 using namespace tidl;
46 using std::string;
47 using std::unique_ptr;
48 using std::vector;
50 using EOP = tidl::ExecutionObjectPipeline;
52 bool Run(int num_eve,int num_dsp, const char* ref_output);
54 Executor* CreateExecutor(DeviceType dt, int num, const Configuration& c,
55 int layer_group_id);
57 void AllocateMemory(const vector<EOP *>& EOPs);
58 void FreeMemory (const vector<EOP *>& EOPs);
61 int main(int argc, char *argv[])
62 {
63 // Catch ctrl-c to ensure a clean exit
64 signal(SIGABRT, exit);
65 signal(SIGTERM, exit);
67 // This example requires both EVE and C66x
68 uint32_t num_eve = Executor::GetNumDevices(DeviceType::EVE);
69 uint32_t num_dsp = Executor::GetNumDevices(DeviceType::DSP);
70 if (num_eve == 0 || num_dsp == 0)
71 {
72 std::cout << "TI DL not supported on this SoC." << std::endl;
73 return EXIT_SUCCESS;
74 }
76 string ref_file ="../test/testvecs/reference/j11_v2_ref.bin";
77 unique_ptr<const char> reference_output(ReadReferenceOutput(ref_file));
79 bool status = Run(num_eve, num_dsp, reference_output.get());
81 if (!status)
82 {
83 std::cout << "FAILED" << std::endl;
84 return EXIT_FAILURE;
85 }
87 std::cout << "PASSED" << std::endl;
88 return EXIT_SUCCESS;
89 }
91 bool Run(int num_eve, int num_dsp, const char* ref_output)
92 {
93 string config_file ="../test/testvecs/config/infer/tidl_config_j11_v2.txt";
95 Configuration c;
96 if (!c.ReadFromFile(config_file))
97 return false;
99 // Heap sizes for this network determined using Configuration::showHeapStats
100 c.PARAM_HEAP_SIZE = (3 << 20); // 3MB
101 c.NETWORK_HEAP_SIZE = (20 << 20); // 20MB
103 c.numFrames = 16;
105 // Assign layers 12, 13 and 14 to layer group 2
106 c.layerIndex2LayerGroupId = { {12, 2}, {13, 2}, {14, 2} };
108 // Open input file for reading
109 std::ifstream input(c.inData, std::ios::binary);
111 bool status = true;
112 try
113 {
114 // Create Executors - use all the DSP and EVE cores available
115 // Layer group 1 will be executed on EVE, 2 on DSP
116 unique_ptr<Executor> eve(CreateExecutor(DeviceType::EVE,num_eve,c,1));
117 unique_ptr<Executor> dsp(CreateExecutor(DeviceType::DSP,num_dsp,c,2));
119 // Create pipelines. Each pipeline has 1 EVE and 1 DSP. If there are
120 // more EVEs than DSPs, the DSPs are shared across multiple
121 // pipelines. E.g.
122 // 2 EVE, 2 DSP: EVE1 -> DSP1, EVE2 -> DSP2
123 // 4 EVE, 2 DSP: EVE1 -> DSP1, EVE2 -> DSP2, EVE3 -> DSP1, EVE4 ->DSP2
124 std::vector<EOP *> EOPs;
125 uint32_t num_pipe = std::max(num_eve, num_dsp);
126 for (uint32_t i = 0; i < num_pipe; i++)
127 EOPs.push_back(new EOP( { (*eve)[i % num_eve],
128 (*dsp)[i % num_dsp] } ));
130 AllocateMemory(EOPs);
132 // Process frames with EOs in a pipelined manner
133 // additional num_eos iterations to flush the pipeline (epilogue)
134 int num_eops = EOPs.size();
135 for (int frame_idx = 0; frame_idx < c.numFrames + num_eops; frame_idx++)
136 {
137 EOP* eop = EOPs[frame_idx % num_eops];
139 // Wait for previous frame on the same eo to finish processing
140 if (eop->ProcessFrameWait())
141 {
142 ReportTime(eop);
144 // The reference output is valid only for the first frame
145 // processed on each EOP
146 if (frame_idx < num_eops && !CheckFrame(eop, ref_output))
147 status = false;
148 }
150 // Read a frame and start processing it with current eo
151 if (ReadFrame(eop, frame_idx, c, input))
152 eop->ProcessFrameStartAsync();
153 }
155 FreeMemory(EOPs);
157 }
158 catch (tidl::Exception &e)
159 {
160 std::cerr << e.what() << std::endl;
161 status = false;
162 }
164 input.close();
166 return status;
167 }
169 // Create an Executor with the specified type and number of EOs
170 Executor* CreateExecutor(DeviceType dt, int num, const Configuration& c,
171 int layer_group_id)
172 {
173 if (num == 0) return nullptr;
175 DeviceIds ids;
176 for (int i = 0; i < num; i++)
177 ids.insert(static_cast<DeviceId>(i));
179 return new Executor(dt, ids, c, layer_group_id);
180 }
182 // Allocate input and output memory for each EO
183 void AllocateMemory(const vector<EOP *>& EOPs)
184 {
185 // Allocate input and output buffers for each execution object
186 for (auto eop : EOPs)
187 {
188 size_t in_size = eop->GetInputBufferSizeInBytes();
189 size_t out_size = eop->GetOutputBufferSizeInBytes();
190 ArgInfo in = { ArgInfo(malloc(in_size), in_size)};
191 ArgInfo out = { ArgInfo(malloc(out_size), out_size)};
192 eop->SetInputOutputBuffer(in, out);
193 }
194 }
196 // Free the input and output memory associated with each EO
197 void FreeMemory(const vector<EOP *>& EOPs)
198 {
199 for (auto eop : EOPs)
200 {
201 free(eop->GetInputBufferPtr());
202 free(eop->GetOutputBufferPtr());
203 }
205 }