1 #include <assert.h>
2 #include "executor.h"
3 #include "executor_impl.h"
4 #include "parameters.h"
5 #include "util.h"
6 #include "trace.h"
9 using namespace tinn;
11 using std::unique_ptr;
13 Executor::Executor(DeviceType core_type, const DeviceIds& ids,
14 const Configuration& configuration)
15 {
16 pimpl_m = unique_ptr<ExecutorImpl>
17 { new ExecutorImpl(core_type, ids) };
18 pimpl_m->Initialize(configuration);
19 }
23 // Pointer to implementation idiom: https://herbsutter.com/gotw/_100/:
24 // Both unique_ptr and shared_ptr can be instantiated with an incomplete type
25 // unique_ptr's destructor requires a complete type in order to invoke delete
26 // By writing it yourself in the implementation file, you force it to be
27 // defined in a place where impl is already defined, and this successfully
28 // prevents the compiler from trying to automatically generate the destructor
29 // on demand in the caller’s code where impl is not defined.
30 Executor::~Executor() = default;
32 uint32_t Executor::GetNumDevices(DeviceType device_type)
33 {
34 return Device::GetNumDevices(device_type);
35 }
37 #define STRING(S) XSTRING(S)
38 #define XSTRING(S) #S
39 std::string Executor::GetAPIVersion()
40 {
41 static std::string version = STRING(_BUILD_VER);
42 version += ".";
43 version += STRING(_BUILD_SHA);
44 return version;
45 }
48 ExecutorImpl::ExecutorImpl(DeviceType core_type, const DeviceIds& ids):
49 configuration_m(),
50 shared_networkparam_heap_m(nullptr, &__free_ddr),
51 device_ids_m(ids),
52 core_type_m(core_type)
53 {
54 std::string name;
55 if (core_type_m == DeviceType::DSP)
56 name = "ocl_wrapper.out";
57 else if (core_type_m == DeviceType::DLA)
58 name = STRING(SETUP_KERNEL) ";" STRING(INIT_KERNEL) ";" STRING(PROCESS_KERNEL) ";" STRING(CLEANUP_KERNEL);
60 device_m = Device::Create(core_type_m, ids, name);
61 }
64 const ExecutionObjects& Executor::GetExecutionObjects() const
65 {
66 return pimpl_m->execution_objects_m;
67 }
69 bool ExecutorImpl::Initialize(const Configuration& configuration)
70 {
71 configuration_m = configuration;
73 // Allocate, initialize TIDL_CreateParams object
74 up_malloc_ddr<TIDL_CreateParams> shared_createparam(
75 malloc_ddr<TIDL_CreateParams>(),
76 &__free_ddr);
77 InitializeNetworkCreateParam(shared_createparam.get());
79 // Read network from file into network struct in TIDL_CreateParams
80 sTIDL_Network_t *net = &(shared_createparam.get())->net;
82 bool status = ReadBinary(configuration_m.netBinFile,
83 reinterpret_cast<char *>(net),
84 sizeof(sTIDL_Network_t));
85 assert(status != false);
87 //TODO: Why is this set here?
88 net->interElementSize = 4;
90 // Call a setup kernel to allocate and fill network parameters
91 InitializeNetworkParams(shared_createparam.get());
93 const ArgInfo create_arg(shared_createparam.get(),
94 sizeof(TIDL_CreateParams));
95 const ArgInfo param_heap_arg(shared_networkparam_heap_m.get(),
96 configuration_m.PARAM_HEAP_SIZE);
97 for (auto ids : device_ids_m)
98 {
99 uint8_t index = static_cast<uint8_t>(ids);
100 execution_objects_m.push_back(
101 unique_ptr<ExecutionObject>
102 {new ExecutionObject(device_m.get(), index,
103 create_arg, param_heap_arg,
104 configuration_m.EXTMEM_HEAP_SIZE)} );
105 }
107 for (auto &eo : execution_objects_m)
108 eo->RunAsync(ExecutionObject::CallType::INIT);
110 for (auto &eo : execution_objects_m)
111 eo->Wait(ExecutionObject::CallType::INIT);
113 return true;
114 }
117 bool ExecutorImpl::InitializeNetworkParams(TIDL_CreateParams *cp)
118 {
119 // Determine size of network parameters buffer, allocate it
120 size_t networkparam_size =
121 GetBinaryFileSize(configuration_m.paramsBinFile);
123 up_malloc_ddr<char> networkparam(malloc_ddr<char>(networkparam_size),
124 &__free_ddr);
126 // Read network parameters from bin file into buffer
127 bool status = ReadBinary(configuration_m.paramsBinFile,
128 networkparam.get(),
129 networkparam_size);
130 assert(status != false);
132 // Allocate a buffer for passing parameters to the kernel
133 up_malloc_ddr<OCL_TIDL_SetupParams> setupParams(
134 malloc_ddr<OCL_TIDL_SetupParams>(),
135 &__free_ddr);
137 setupParams->enableTrace = OCL_TIDL_TRACE_OFF;
138 setupParams->networkParamHeapSize = configuration_m.PARAM_HEAP_SIZE;
139 setupParams->noZeroCoeffsPercentage = configuration_m.noZeroCoeffsPercentage;
140 setupParams->sizeofTIDL_CreateParams = sizeof(TIDL_CreateParams);
141 setupParams->offsetofNet = offsetof(TIDL_CreateParams, net);
143 // Allocate buffer for a network parameter heap. Used by the setup
144 // kernel to allocate and initialize network parameters for the layers
145 shared_networkparam_heap_m.reset(malloc_ddr<char>(setupParams->networkParamHeapSize));
147 KernelArgs args = { ArgInfo(cp, sizeof(TIDL_CreateParams)),
148 ArgInfo(networkparam.get(), networkparam_size),
149 ArgInfo(shared_networkparam_heap_m.get(),
150 setupParams->networkParamHeapSize),
151 ArgInfo(setupParams.get(),
152 sizeof(OCL_TIDL_SetupParams)) };
154 // Execute kernel on first available device in the Executor
155 uint8_t id = static_cast<uint8_t>(*(device_ids_m.cbegin()));
156 unique_ptr<Kernel> K {new Kernel(device_m.get(), STRING(SETUP_KERNEL),
157 args, id)};
158 K->RunAsync();
159 K->Wait();
161 if (setupParams->errorCode != OCL_TIDL_SUCCESS)
162 throw Exception(setupParams->errorCode,
163 __FILE__, __FUNCTION__, __LINE__);
165 return status;
166 }
169 void ExecutorImpl::Cleanup()
170 {
171 for (auto &eo : execution_objects_m)
172 eo->RunAsync(ExecutionObject::CallType::CLEANUP);
174 for (auto &eo : execution_objects_m)
175 eo->Wait(ExecutionObject::CallType::CLEANUP);
176 }
179 void ExecutorImpl::InitializeNetworkCreateParam(TIDL_CreateParams *CP)
180 {
181 CP->currCoreId = tinn::internal::CURR_CORE_ID;
182 CP->currLayersGroupId = tinn::internal::CURR_LAYERS_GROUP_ID;
183 CP->l1MemSize = tinn::internal::DMEM0_SIZE;
184 CP->l2MemSize = tinn::internal::DMEM1_SIZE;
185 CP->l3MemSize = tinn::internal::OCMC_SIZE;
187 CP->quantHistoryParam1 = tinn::internal::QUANT_HISTORY_PARAM1;
188 CP->quantHistoryParam2 = tinn::internal::QUANT_HISTORY_PARAM2;
189 CP->quantMargin = tinn::internal::QUANT_MARGIN;
190 CP->optimiseExtMem = TIDL_optimiseExtMemL1;
191 }
193 Exception::Exception(const std::string& error, const std::string& file,
194 const std::string& func, uint32_t line_no)
195 {
197 message_m = "TIDL Error: [";
198 message_m += file;
199 message_m += ", ";
200 message_m += func;
201 message_m += ", ";
202 message_m += std::to_string(line_no);
203 message_m += "]: ";
204 message_m += error;
205 }
207 Exception::Exception(int32_t errorCode, const std::string& file,
208 const std::string& func, uint32_t line_no)
209 {
210 message_m = "TIDL Error: [";
211 message_m += file;
212 message_m += ", ";
213 message_m += func;
214 message_m += ", ";
215 message_m += std::to_string(line_no);
216 message_m += "]: ";
218 if (errorCode == OCL_TIDL_ERROR)
219 message_m += "";
220 else if (errorCode == OCL_TIDL_ALLOC_FAIL)
221 message_m += "Allocation failed on device";
222 else if (errorCode == OCL_TIDL_MEMREC_ALLOC_FAIL)
223 message_m += "Memrec allocation failed on device";
224 else if (errorCode == OCL_TIDL_PROCESS_FAIL)
225 message_m += "Process call failed on device";
226 else if (errorCode == OCL_TIDL_CREATE_PARAMS_MISMATCH)
227 message_m += "TIDL_CreateParams definition inconsistent across host"
228 "and device.";
229 else
230 message_m += std::to_string(errorCode);
232 }
234 const char* Exception::what() const noexcept
235 {
236 return message_m.c_str();
237 }