Renamed compute engine to EVE
[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     pimpl_m = unique_ptr<ExecutorImpl>
45               { new ExecutorImpl(core_type, ids, layers_group_id) };
46     pimpl_m->Initialize(configuration);
47 }
51 // Pointer to implementation idiom: https://herbsutter.com/gotw/_100/:
52 // Both unique_ptr and shared_ptr can be instantiated with an incomplete type
53 // unique_ptr's destructor requires a complete type in order to invoke delete
54 // By writing it yourself in the implementation file, you force it to be
55 // defined in a place where impl is already defined, and this successfully
56 // prevents the compiler from trying to automatically generate the destructor
57 // on demand in the caller’s code where impl is not defined.
58 Executor::~Executor() = default;
60 uint32_t Executor::GetNumDevices(DeviceType device_type)
61 {
62     return Device::GetNumDevices(device_type);
63 }
65 #define STRING(S)  XSTRING(S)
66 #define XSTRING(S) #S
67 std::string Executor::GetAPIVersion()
68 {
69     static std::string version = STRING(_BUILD_VER);
70     version += ".";
71     version += STRING(_BUILD_SHA);
72     return version;
73 }
76 ExecutorImpl::ExecutorImpl(DeviceType core_type, const DeviceIds& ids,
77                            int layers_group_id):
78     configuration_m(),
79     shared_networkparam_heap_m(nullptr, &__free_ddr),
80     device_ids_m(ids),
81     core_type_m(core_type),
82     layers_group_id_m(layers_group_id)
83 {
84     std::string name;
85     if (core_type_m == DeviceType::DSP)
86         name  = "";
87     else if (core_type_m == DeviceType::EVE)
88         name = STRING(SETUP_KERNEL) ";" STRING(INIT_KERNEL) ";" STRING(PROCESS_KERNEL) ";" STRING(CLEANUP_KERNEL);
90     device_m = Device::Create(core_type_m, ids, name);
91 }
94 const ExecutionObjects& Executor::GetExecutionObjects() const
95 {
96     return pimpl_m->execution_objects_m;
97 }
99 bool ExecutorImpl::Initialize(const Configuration& configuration)
101     configuration_m = configuration;
103     // Allocate, initialize TIDL_CreateParams object
104     up_malloc_ddr<TIDL_CreateParams> shared_createparam(
105                                             malloc_ddr<TIDL_CreateParams>(),
106                                             &__free_ddr);
107     InitializeNetworkCreateParam(shared_createparam.get(), configuration);
109     // Read network from file into network struct in TIDL_CreateParams
110     sTIDL_Network_t *net = &(shared_createparam.get())->net;
112     bool status = ReadBinary(configuration_m.netBinFile,
113                              reinterpret_cast<char *>(net),
114                              sizeof(sTIDL_Network_t));
115     assert(status != false);
117     //TODO: Why is this set here?
118     net->interElementSize = 4;
120     // Force to run full network if runFullNet is set
121     if (configuration.runFullNet)
122     {
123         for (int i = 0; i < net->numLayers; i++)
124             if (net->TIDLLayers[i].layerType != TIDL_DataLayer)
125                 net->TIDLLayers[i].layersGroupId = layers_group_id_m;
126     }
128     // Call a setup kernel to allocate and fill network parameters
129     InitializeNetworkParams(shared_createparam.get());
131     const ArgInfo create_arg(shared_createparam.get(),
132                              sizeof(TIDL_CreateParams));
133     const ArgInfo param_heap_arg(shared_networkparam_heap_m.get(),
134                                  configuration_m.PARAM_HEAP_SIZE);
135     for (auto ids : device_ids_m)
136     {
137         uint8_t index = static_cast<uint8_t>(ids);
138         execution_objects_m.push_back(
139              unique_ptr<ExecutionObject>
140              {new ExecutionObject(device_m.get(), index,
141                                   create_arg, param_heap_arg,
142                                   configuration_m.EXTMEM_HEAP_SIZE,
143                                   configuration_m.enableInternalInput)} );
144     }
146     for (auto &eo : execution_objects_m)
147         eo->RunAsync(ExecutionObject::CallType::INIT);
149     for (auto &eo : execution_objects_m)
150         eo->Wait(ExecutionObject::CallType::INIT);
152     return true;
156 bool ExecutorImpl::InitializeNetworkParams(TIDL_CreateParams *cp)
158     // Determine size of network parameters buffer, allocate it
159     size_t networkparam_size =
160                         GetBinaryFileSize(configuration_m.paramsBinFile);
162     up_malloc_ddr<char> networkparam(malloc_ddr<char>(networkparam_size),
163                                 &__free_ddr);
165     // Read network parameters from bin file into buffer
166     bool status = ReadBinary(configuration_m.paramsBinFile,
167                              networkparam.get(),
168                              networkparam_size);
169     assert(status != false);
171     // Allocate a buffer for passing parameters to the kernel
172     up_malloc_ddr<OCL_TIDL_SetupParams> setupParams(
173                                             malloc_ddr<OCL_TIDL_SetupParams>(),
174                                             &__free_ddr);
176     setupParams->enableTrace = OCL_TIDL_TRACE_OFF;
177     setupParams->networkParamHeapSize = configuration_m.PARAM_HEAP_SIZE;
178     setupParams->noZeroCoeffsPercentage = configuration_m.noZeroCoeffsPercentage;
179     setupParams->sizeofTIDL_CreateParams = sizeof(TIDL_CreateParams);
180     setupParams->offsetofNet = offsetof(TIDL_CreateParams, net);
182     // Allocate buffer for a network parameter heap. Used by the setup
183     // kernel to allocate and initialize network parameters for the layers
184     shared_networkparam_heap_m.reset(malloc_ddr<char>(setupParams->networkParamHeapSize));
186     KernelArgs args = { ArgInfo(cp, sizeof(TIDL_CreateParams)),
187                         ArgInfo(networkparam.get(), networkparam_size),
188                         ArgInfo(shared_networkparam_heap_m.get(),
189                                 setupParams->networkParamHeapSize),
190                         ArgInfo(setupParams.get(),
191                                 sizeof(OCL_TIDL_SetupParams)) };
193     // Execute kernel on first available device in the Executor
194     uint8_t id = static_cast<uint8_t>(*(device_ids_m.cbegin()));
195     unique_ptr<Kernel> K {new Kernel(device_m.get(), STRING(SETUP_KERNEL),
196                                      args, id)};
197     K->RunAsync();
198     K->Wait();
200     if (setupParams->errorCode != OCL_TIDL_SUCCESS)
201         throw Exception(setupParams->errorCode,
202                         __FILE__, __FUNCTION__, __LINE__);
204     return status;
208 void ExecutorImpl::Cleanup()
210     for (auto &eo : execution_objects_m)
211         eo->RunAsync(ExecutionObject::CallType::CLEANUP);
213     for (auto &eo : execution_objects_m)
214         eo->Wait(ExecutionObject::CallType::CLEANUP);
218 void ExecutorImpl::InitializeNetworkCreateParam(TIDL_CreateParams *CP,
219                                           const Configuration& configuration)
221     CP->currCoreId           = layers_group_id_m;
222     CP->currLayersGroupId    = layers_group_id_m;
223     CP->l1MemSize            = tidl::internal::DMEM0_SIZE;
224     CP->l2MemSize            = tidl::internal::DMEM1_SIZE;
225     CP->l3MemSize            = tidl::internal::OCMC_SIZE;
227     CP->quantHistoryParam1   = tidl::internal::QUANT_HISTORY_PARAM1;
228     CP->quantHistoryParam2   = tidl::internal::QUANT_HISTORY_PARAM2;
229     CP->quantMargin          = tidl::internal::QUANT_MARGIN;
230     CP->optimiseExtMem       = TIDL_optimiseExtMemL1;
233 Exception::Exception(const std::string& error, const std::string& file,
234                      const std::string& func, uint32_t line_no)
237     message_m = "TIDL Error: [";
238     message_m += file;
239     message_m += ", ";
240     message_m += func;
241     message_m += ", ";
242     message_m += std::to_string(line_no);
243     message_m += "]: ";
244     message_m += error;
247 Exception::Exception(int32_t errorCode, const std::string& file,
248                      const std::string& func, uint32_t line_no)
250     message_m = "TIDL Error: [";
251     message_m += file;
252     message_m += ", ";
253     message_m += func;
254     message_m += ", ";
255     message_m += std::to_string(line_no);
256     message_m += "]: ";
258     if (errorCode == OCL_TIDL_ERROR)
259         message_m += "";
260     else if (errorCode == OCL_TIDL_ALLOC_FAIL)
261         message_m += "Allocation failed on device";
262     else if (errorCode == OCL_TIDL_MEMREC_ALLOC_FAIL)
263         message_m += "Memrec allocation failed on device";
264     else if (errorCode == OCL_TIDL_PROCESS_FAIL)
265         message_m += "Process call failed on device";
266     else if (errorCode == OCL_TIDL_CREATE_PARAMS_MISMATCH)
267         message_m += "TIDL_CreateParams definition inconsistent across host"
268                      "and device.";
269     else
270         message_m += std::to_string(errorCode);
274 const char* Exception::what() const noexcept
276     return message_m.c_str();