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 tidl;
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::GetNumDevicesSupportingTIDL(DeviceType device_type)
33 {
34 return Device::GetNumDevicesSupportingTIDL(device_type);
35 }
37 ExecutorImpl::ExecutorImpl(DeviceType core_type, const DeviceIds& ids):
38 configuration_m(),
39 shared_networkparam_heap_m(nullptr, &__free_ddr),
40 device_ids_m(ids),
41 core_type_m(core_type)
42 {
43 std::string name;
44 if (core_type_m == DeviceType::DSP)
45 name = "ocl_wrapper.out";
46 else if (core_type_m == DeviceType::DLA)
47 name = STRING(SETUP_KERNEL) ";" STRING(INIT_KERNEL) ";" STRING(PROCESS_KERNEL) ";" STRING(CLEANUP_KERNEL);
49 device_m = Device::Create(core_type_m, ids, name);
51 }
54 const ExecutionObjects& Executor::GetExecutionObjects() const
55 {
56 return pimpl_m->execution_objects_m;
57 }
59 bool ExecutorImpl::Initialize(const Configuration& configuration)
60 {
61 configuration_m = configuration;
63 // Allocate, initialize TIDL_CreateParams object
64 up_malloc_ddr<TIDL_CreateParams> shared_createparam(
65 malloc_ddr<TIDL_CreateParams>(),
66 &__free_ddr);
67 InitializeNetworkCreateParam(shared_createparam.get());
69 // Read network from file into network struct in TIDL_CreateParams
70 sTIDL_Network_t *net = &(shared_createparam.get())->net;
72 bool status = ReadBinary(configuration_m.netBinFile,
73 reinterpret_cast<char *>(net),
74 sizeof(sTIDL_Network_t));
75 assert(status != false);
77 //TODO: Why is this set here?
78 net->interElementSize = 4;
80 // Call a setup kernel to allocate and fill network parameters
81 InitializeNetworkParams(shared_createparam.get());
83 const ArgInfo create_arg(shared_createparam.get(),
84 sizeof(TIDL_CreateParams));
85 const ArgInfo param_heap_arg(shared_networkparam_heap_m.get(),
86 configuration_m.PARAM_HEAP_SIZE);
87 for (auto ids : device_ids_m)
88 {
89 uint8_t index = static_cast<uint8_t>(ids);
90 execution_objects_m.push_back(
91 unique_ptr<ExecutionObject>
92 {new ExecutionObject(device_m.get(), index,
93 create_arg, param_heap_arg,
94 configuration_m.EXTMEM_HEAP_SIZE)} );
95 }
97 for (auto &eo : execution_objects_m)
98 eo->RunAsync(ExecutionObject::CallType::INIT);
100 for (auto &eo : execution_objects_m)
101 eo->Wait(ExecutionObject::CallType::INIT);
103 return true;
104 }
107 bool ExecutorImpl::InitializeNetworkParams(TIDL_CreateParams *cp)
108 {
109 // Determine size of network parameters buffer, allocate it
110 size_t networkparam_size =
111 GetBinaryFileSize(configuration_m.paramsBinFile);
113 up_malloc_ddr<char> networkparam(malloc_ddr<char>(networkparam_size),
114 &__free_ddr);
116 // Read network parameters from bin file into buffer
117 bool status = ReadBinary(configuration_m.paramsBinFile,
118 networkparam.get(),
119 networkparam_size);
120 assert(status != false);
122 // Allocate a buffer for passing parameters to the kernel
123 up_malloc_ddr<OCL_TIDL_SetupParams> setupParams(
124 malloc_ddr<OCL_TIDL_SetupParams>(),
125 &__free_ddr);
127 setupParams->enableTrace = OCL_TIDL_TRACE_OFF;
128 setupParams->networkParamHeapSize = configuration_m.PARAM_HEAP_SIZE;
129 setupParams->noZeroCoeffsPercentage = configuration_m.noZeroCoeffsPercentage;
130 setupParams->sizeofTIDL_CreateParams = sizeof(TIDL_CreateParams);
131 setupParams->offsetofNet = offsetof(TIDL_CreateParams, net);
133 // Allocate buffer for a network parameter heap. Used by the setup
134 // kernel to allocate and initialize network parameters for the layers
135 shared_networkparam_heap_m.reset(malloc_ddr<char>(setupParams->networkParamHeapSize));
137 KernelArgs args = { ArgInfo(cp, sizeof(TIDL_CreateParams)),
138 ArgInfo(networkparam.get(), networkparam_size),
139 ArgInfo(shared_networkparam_heap_m.get(),
140 setupParams->networkParamHeapSize),
141 ArgInfo(setupParams.get(),
142 sizeof(OCL_TIDL_SetupParams)) };
144 // Execute kernel on first available device in the Executor
145 uint8_t id = static_cast<uint8_t>(*(device_ids_m.cbegin()));
146 unique_ptr<Kernel> K {new Kernel(device_m.get(), STRING(SETUP_KERNEL),
147 args, id)};
148 K->RunAsync();
149 K->Wait();
151 if (setupParams->errorCode != OCL_TIDL_SUCCESS)
152 throw Exception(setupParams->errorCode,
153 __FILE__, __FUNCTION__, __LINE__);
155 return status;
156 }
159 void ExecutorImpl::Cleanup()
160 {
161 for (auto &eo : execution_objects_m)
162 eo->RunAsync(ExecutionObject::CallType::CLEANUP);
164 for (auto &eo : execution_objects_m)
165 eo->Wait(ExecutionObject::CallType::CLEANUP);
166 }
169 void ExecutorImpl::InitializeNetworkCreateParam(TIDL_CreateParams *CP)
170 {
171 CP->currCoreId = tidl::internal::CURR_CORE_ID;
172 CP->currLayersGroupId = tidl::internal::CURR_LAYERS_GROUP_ID;
173 CP->l1MemSize = tidl::internal::DMEM0_SIZE;
174 CP->l2MemSize = tidl::internal::DMEM1_SIZE;
175 CP->l3MemSize = tidl::internal::OCMC_SIZE;
177 CP->quantHistoryParam1 = tidl::internal::QUANT_HISTORY_PARAM1;
178 CP->quantHistoryParam2 = tidl::internal::QUANT_HISTORY_PARAM2;
179 CP->quantMargin = tidl::internal::QUANT_MARGIN;
180 CP->optimiseExtMem = TIDL_optimiseExtMemL1;
181 }
183 Exception::Exception(const std::string& error, const std::string& file,
184 const std::string& func, uint32_t line_no)
185 {
187 message_m = "TIDL Error: [";
188 message_m += file;
189 message_m += ", ";
190 message_m += func;
191 message_m += ", ";
192 message_m += std::to_string(line_no);
193 message_m += "]: ";
194 message_m += error;
195 }
197 Exception::Exception(int32_t errorCode, const std::string& file,
198 const std::string& func, uint32_t line_no)
199 {
200 message_m = "TIDL Error: [";
201 message_m += file;
202 message_m += ", ";
203 message_m += func;
204 message_m += ", ";
205 message_m += std::to_string(line_no);
206 message_m += "]: ";
208 if (errorCode == OCL_TIDL_ERROR)
209 message_m += "";
210 else if (errorCode == OCL_TIDL_ALLOC_FAIL)
211 message_m += "Allocation failed on device";
212 else if (errorCode == OCL_TIDL_MEMREC_ALLOC_FAIL)
213 message_m += "Memrec allocation failed on device";
214 else if (errorCode == OCL_TIDL_PROCESS_FAIL)
215 message_m += "Process call failed on device";
216 else if (errorCode == OCL_TIDL_CREATE_PARAMS_MISMATCH)
217 message_m += "TIDL_CreateParams definition inconsistent across host"
218 "and device.";
219 else
220 message_m += std::to_string(errorCode);
222 }
224 const char* Exception::what() const noexcept
225 {
226 return message_m.c_str();
227 }