Update TIDL network data structure
[tidl/tidl-api.git] / tidl_api / src / executor.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  *****************************************************************************/
29 #include <assert.h>
30 #include "executor.h"
31 #include "executor_impl.h"
32 #include "parameters.h"
33 #include "util.h"
34 #include "trace.h"
37 using namespace tidl;
39 using std::unique_ptr;
41 Executor::Executor(DeviceType core_type, const DeviceIds& ids,
42                    const Configuration& configuration, int layers_group_id)
43 {
44     TRACE::enabled = configuration.enableApiTrace;
46     TRACE::print("-> Executor::Executor()\n");
48     pimpl_m = unique_ptr<ExecutorImpl>
49               { new ExecutorImpl(core_type, ids, layers_group_id) };
50     pimpl_m->Initialize(configuration);
52     TRACE::print("<- Executor::Executor()\n");
53 }
57 // Pointer to implementation idiom: https://herbsutter.com/gotw/_100/:
58 // Both unique_ptr and shared_ptr can be instantiated with an incomplete type
59 // unique_ptr's destructor requires a complete type in order to invoke delete
60 // By writing it yourself in the implementation file, you force it to be
61 // defined in a place where impl is already defined, and this successfully
62 // prevents the compiler from trying to automatically generate the destructor
63 // on demand in the caller’s code where impl is not defined.
64 Executor::~Executor() = default;
66 uint32_t Executor::GetNumDevices(DeviceType device_type)
67 {
68     return Device::GetNumDevices(device_type);
69 }
71 #define STRING(S)  XSTRING(S)
72 #define XSTRING(S) #S
73 std::string Executor::GetAPIVersion()
74 {
75     static std::string version = STRING(_BUILD_VER);
76     version += ".";
77     version += STRING(_BUILD_SHA);
78     return version;
79 }
82 ExecutorImpl::ExecutorImpl(DeviceType core_type, const DeviceIds& ids,
83                            int layers_group_id):
84     configuration_m(),
85     shared_networkparam_heap_m(nullptr, &__free_ddr),
86     device_ids_m(ids),
87     core_type_m(core_type),
88     layers_group_id_m(layers_group_id)
89 {
90     std::string name;
91     if (core_type_m == DeviceType::DSP)
92         name  = "";
93     else if (core_type_m == DeviceType::EVE)
94         name = STRING(SETUP_KERNEL) ";" STRING(INIT_KERNEL) ";" STRING(PROCESS_KERNEL) ";" STRING(CLEANUP_KERNEL);
96     device_m = Device::Create(core_type_m, ids, name);
97 }
99 ExecutionObject* Executor::operator[](uint32_t index) const
101     assert(index < pimpl_m->execution_objects_m.size());
102     return pimpl_m->execution_objects_m[index].get();
105 uint32_t Executor::GetNumExecutionObjects() const
107     return pimpl_m->execution_objects_m.size();
110 bool ExecutorImpl::Initialize(const Configuration& configuration)
112     configuration_m = configuration;
114     // Allocate, initialize TIDL_CreateParams object
115     up_malloc_ddr<TIDL_CreateParams> shared_createparam(
116                                             malloc_ddr<TIDL_CreateParams>(),
117                                             &__free_ddr);
118     InitializeNetworkCreateParam(shared_createparam.get(), configuration);
120     // Read network from file into network struct in TIDL_CreateParams
121     sTIDL_Network_t *net = &(shared_createparam.get())->net;
123     bool status = ReadNetworkBinary(configuration_m.netBinFile,
124                                     reinterpret_cast<char *>(net));
125     assert(status != false);
127     // Force to run full network if runFullNet is set
128     if (configuration.runFullNet)
129     {
130         for (int i = 0; i < net->numLayers; i++)
131             if (net->TIDLLayers[i].layerType != TIDL_DataLayer)
132                 net->TIDLLayers[i].layersGroupId = layers_group_id_m;
133     }
135     // If the user has specified an override mapping, apply it
136     else if (!configuration.layerIndex2LayerGroupId.empty())
137     {
138         for (const auto &item : configuration.layerIndex2LayerGroupId)
139             if (item.first < net->numLayers)
140                 net->TIDLLayers[item.first].layersGroupId = item.second;
141     }
143     // Call a setup kernel to allocate and fill network parameters
144     InitializeNetworkParams(shared_createparam.get());
146     const ArgInfo create_arg(shared_createparam.get(),
147                              sizeof(TIDL_CreateParams));
148     const ArgInfo param_heap_arg(shared_networkparam_heap_m.get(),
149                                  configuration_m.PARAM_HEAP_SIZE);
150     for (auto ids : device_ids_m)
151     {
152         uint8_t index = static_cast<uint8_t>(ids);
153         execution_objects_m.push_back(
154              unique_ptr<ExecutionObject>
155              {new ExecutionObject(device_m.get(), core_type_m, index,
156                                   create_arg, param_heap_arg,
157                                   configuration_m,
158                                   layers_group_id_m)} );
159     }
161     for (auto &eo : execution_objects_m)
162         eo->RunAsync(ExecutionObject::CallType::INIT);
164     for (auto &eo : execution_objects_m)
165         eo->Wait(ExecutionObject::CallType::INIT);
167     return true;
171 bool ExecutorImpl::InitializeNetworkParams(TIDL_CreateParams *cp)
173     // Determine size of network parameters buffer, allocate it
174     size_t networkparam_size =
175                         GetBinaryFileSize(configuration_m.paramsBinFile);
177     up_malloc_ddr<char> networkparam(malloc_ddr<char>(networkparam_size),
178                                 &__free_ddr);
180     // Read network parameters from bin file into buffer
181     bool status = ReadBinary(configuration_m.paramsBinFile,
182                              networkparam.get(),
183                              networkparam_size);
184     assert(status != false);
186     // Allocate a buffer for passing parameters to the kernel
187     up_malloc_ddr<OCL_TIDL_SetupParams> setupParams(
188                                             malloc_ddr<OCL_TIDL_SetupParams>(),
189                                             &__free_ddr);
191     // Set up execution trace specified in the configuration
192     EnableExecutionTrace(configuration_m, &setupParams->enableTrace);
194     setupParams->networkParamHeapSize = configuration_m.PARAM_HEAP_SIZE;
195     setupParams->noZeroCoeffsPercentage = configuration_m.noZeroCoeffsPercentage;
196     setupParams->sizeofTIDL_CreateParams = sizeof(TIDL_CreateParams);
197     setupParams->offsetofNet = offsetof(TIDL_CreateParams, net);
199     // Allocate buffer for a network parameter heap. Used by the setup
200     // kernel to allocate and initialize network parameters for the layers
201     shared_networkparam_heap_m.reset(malloc_ddr<char>(setupParams->networkParamHeapSize));
203     KernelArgs args = { DeviceArgInfo(cp, sizeof(TIDL_CreateParams),
204                                       DeviceArgInfo::Kind::BUFFER),
205                         DeviceArgInfo(networkparam.get(), networkparam_size,
206                                       DeviceArgInfo::Kind::BUFFER),
207                         DeviceArgInfo(shared_networkparam_heap_m.get(),
208                                       setupParams->networkParamHeapSize,
209                                       DeviceArgInfo::Kind::BUFFER),
210                         DeviceArgInfo(setupParams.get(),
211                                       sizeof(OCL_TIDL_SetupParams),
212                                       DeviceArgInfo::Kind::BUFFER) };
214     // Execute kernel on first available device in the Executor
215     uint8_t id = static_cast<uint8_t>(*(device_ids_m.cbegin()));
216     unique_ptr<Kernel> K {new Kernel(device_m.get(), STRING(SETUP_KERNEL),
217                                      args, id)};
218     K->RunAsync();
219     K->Wait();
221     if (setupParams->errorCode != OCL_TIDL_SUCCESS)
222         throw Exception(setupParams->errorCode,
223                         __FILE__, __FUNCTION__, __LINE__);
225     return status;
229 void ExecutorImpl::Cleanup()
231     for (auto &eo : execution_objects_m)
232         eo->RunAsync(ExecutionObject::CallType::CLEANUP);
234     for (auto &eo : execution_objects_m)
235         eo->Wait(ExecutionObject::CallType::CLEANUP);
239 void ExecutorImpl::InitializeNetworkCreateParam(TIDL_CreateParams *CP,
240                                                 const Configuration& c)
242     CP->currCoreId           = layers_group_id_m;
243     CP->currLayersGroupId    = layers_group_id_m;
244     CP->l1MemSize            = tidl::internal::DMEM0_SIZE;
245     CP->l2MemSize            = tidl::internal::DMEM1_SIZE;
246     CP->l3MemSize            = tidl::internal::OCMC_SIZE;
248     CP->quantHistoryParam1   = c.quantHistoryParam1;
249     CP->quantHistoryParam2   = c.quantHistoryParam2;
250     CP->quantMargin          = c.quantMargin;
252     // If trace is enabled, setup the device TIDL library to allocate separate
253     // output buffers for each layer. This makes it possible for the host
254     // to access the output of each layer after a frame is processed.
255     if (configuration_m.enableOutputTrace)
256         CP->optimiseExtMem       = TIDL_optimiseExtMemL0;
257     else
258         CP->optimiseExtMem       = TIDL_optimiseExtMemL1;
261 Exception::Exception(const std::string& error, const std::string& file,
262                      const std::string& func, uint32_t line_no)
265     message_m = "TIDL Error: [";
266     message_m += file;
267     message_m += ", ";
268     message_m += func;
269     message_m += ", ";
270     message_m += std::to_string(line_no);
271     message_m += "]: ";
272     message_m += error;
275 // Refer ti-opencl/builtins/include/custom.h for error codes
276 Exception::Exception(int32_t errorCode, const std::string& file,
277                      const std::string& func, uint32_t line_no)
279     message_m = "TIDL Error: [";
280     message_m += file;
281     message_m += ", ";
282     message_m += func;
283     message_m += ", ";
284     message_m += std::to_string(line_no);
285     message_m += "]: ";
287     switch (errorCode)
288     {
289         case OCL_TIDL_ERROR:
290         message_m += "";
291             break;
292         case OCL_TIDL_ALLOC_FAIL:
293         case OCL_TIDL_MEMREC_ALLOC_FAIL:
294             message_m += "Memory allocation failed on device";
295             break;
296         case OCL_TIDL_PROCESS_FAIL:
297         message_m += "Process call failed on device";
298             break;
299         case OCL_TIDL_CREATE_PARAMS_MISMATCH:
300             message_m += "TIDL API headers inconsistent with OpenCL";
301             break;
302         case OCL_TIDL_INIT_FAIL:
303             message_m += "Initialization failed on device";
304             break;
305         default:
306         message_m += std::to_string(errorCode);
307             break;
308     }
311 const char* Exception::what() const noexcept
313     return message_m.c_str();