1*523fa7a6SAndroid Build Coastguard Worker /*
2*523fa7a6SAndroid Build Coastguard Worker * Copyright (c) 2024 MediaTek Inc.
3*523fa7a6SAndroid Build Coastguard Worker *
4*523fa7a6SAndroid Build Coastguard Worker * Licensed under the BSD License (the "License"); you may not use this file
5*523fa7a6SAndroid Build Coastguard Worker * except in compliance with the License. See the license file in the root
6*523fa7a6SAndroid Build Coastguard Worker * directory of this source tree for more details.
7*523fa7a6SAndroid Build Coastguard Worker */
8*523fa7a6SAndroid Build Coastguard Worker
9*523fa7a6SAndroid Build Coastguard Worker #include "NeuronBackend.h"
10*523fa7a6SAndroid Build Coastguard Worker #include "NeuronBufferAllocator.h"
11*523fa7a6SAndroid Build Coastguard Worker #include "NeuronLog.h"
12*523fa7a6SAndroid Build Coastguard Worker #include "NeuronPayloadHeader.h"
13*523fa7a6SAndroid Build Coastguard Worker #include "api/NeuronAdapter.h"
14*523fa7a6SAndroid Build Coastguard Worker
15*523fa7a6SAndroid Build Coastguard Worker #include "executorch/runtime/core/error.h"
16*523fa7a6SAndroid Build Coastguard Worker
17*523fa7a6SAndroid Build Coastguard Worker #include <algorithm>
18*523fa7a6SAndroid Build Coastguard Worker #include <memory>
19*523fa7a6SAndroid Build Coastguard Worker #include <new>
20*523fa7a6SAndroid Build Coastguard Worker #include <unordered_set>
21*523fa7a6SAndroid Build Coastguard Worker
22*523fa7a6SAndroid Build Coastguard Worker namespace executorch {
23*523fa7a6SAndroid Build Coastguard Worker namespace backends {
24*523fa7a6SAndroid Build Coastguard Worker namespace neuron {
25*523fa7a6SAndroid Build Coastguard Worker
26*523fa7a6SAndroid Build Coastguard Worker using executorch::runtime::ArrayRef;
27*523fa7a6SAndroid Build Coastguard Worker using executorch::runtime::BackendExecutionContext;
28*523fa7a6SAndroid Build Coastguard Worker using executorch::runtime::BackendInitContext;
29*523fa7a6SAndroid Build Coastguard Worker using executorch::runtime::CompileSpec;
30*523fa7a6SAndroid Build Coastguard Worker using executorch::runtime::DelegateHandle;
31*523fa7a6SAndroid Build Coastguard Worker using executorch::runtime::Error;
32*523fa7a6SAndroid Build Coastguard Worker using executorch::runtime::EValue;
33*523fa7a6SAndroid Build Coastguard Worker using executorch::runtime::FreeableBuffer;
34*523fa7a6SAndroid Build Coastguard Worker using executorch::runtime::MemoryAllocator;
35*523fa7a6SAndroid Build Coastguard Worker using executorch::runtime::Result;
36*523fa7a6SAndroid Build Coastguard Worker
37*523fa7a6SAndroid Build Coastguard Worker const char kHighAddrKey[] = "HighAddr";
38*523fa7a6SAndroid Build Coastguard Worker const char kImportForeverKey[] = "ImportForever";
39*523fa7a6SAndroid Build Coastguard Worker
init(BackendInitContext & context,FreeableBuffer * processed,ArrayRef<CompileSpec> compile_specs) const40*523fa7a6SAndroid Build Coastguard Worker Result<DelegateHandle*> NeuronBackend::init(
41*523fa7a6SAndroid Build Coastguard Worker BackendInitContext& context,
42*523fa7a6SAndroid Build Coastguard Worker FreeableBuffer* processed,
43*523fa7a6SAndroid Build Coastguard Worker ArrayRef<CompileSpec> compile_specs) const {
44*523fa7a6SAndroid Build Coastguard Worker NeuronDelegateSetting setting;
45*523fa7a6SAndroid Build Coastguard Worker for (auto& compile_spec : compile_specs) {
46*523fa7a6SAndroid Build Coastguard Worker if (std::strcmp(compile_spec.key, kHighAddrKey) == 0) {
47*523fa7a6SAndroid Build Coastguard Worker setting.mHighAddr = *static_cast<char*>(compile_spec.value.buffer);
48*523fa7a6SAndroid Build Coastguard Worker LogInfo("NeuronBackend", "IsHighAddr Enable : %d", setting.mHighAddr);
49*523fa7a6SAndroid Build Coastguard Worker } else if (std::strcmp(compile_spec.key, kImportForeverKey) == 0) {
50*523fa7a6SAndroid Build Coastguard Worker setting.mImportForever = *static_cast<char*>(compile_spec.value.buffer);
51*523fa7a6SAndroid Build Coastguard Worker LogInfo(
52*523fa7a6SAndroid Build Coastguard Worker "NeuronBackend",
53*523fa7a6SAndroid Build Coastguard Worker "IsImportForever Enable : %d",
54*523fa7a6SAndroid Build Coastguard Worker setting.mImportForever);
55*523fa7a6SAndroid Build Coastguard Worker } else {
56*523fa7a6SAndroid Build Coastguard Worker LogWarn("NeuronBackend", "unknown compile spec: %s", compile_spec.key);
57*523fa7a6SAndroid Build Coastguard Worker }
58*523fa7a6SAndroid Build Coastguard Worker }
59*523fa7a6SAndroid Build Coastguard Worker auto Payload = NeuronPayload(processed->data(), processed->size());
60*523fa7a6SAndroid Build Coastguard Worker LogInfo(
61*523fa7a6SAndroid Build Coastguard Worker "NeuronBackend",
62*523fa7a6SAndroid Build Coastguard Worker "version %u, input %u, output %u, length %u, payload size: %zu",
63*523fa7a6SAndroid Build Coastguard Worker Payload.Header.Version,
64*523fa7a6SAndroid Build Coastguard Worker Payload.Header.InputCount,
65*523fa7a6SAndroid Build Coastguard Worker Payload.Header.OutputCount,
66*523fa7a6SAndroid Build Coastguard Worker Payload.Header.DataLen,
67*523fa7a6SAndroid Build Coastguard Worker processed->size());
68*523fa7a6SAndroid Build Coastguard Worker
69*523fa7a6SAndroid Build Coastguard Worker MemoryAllocator* runtime_allocator = context.get_runtime_allocator();
70*523fa7a6SAndroid Build Coastguard Worker NeuronExecuTorchDelegate* delegate = ET_ALLOCATE_INSTANCE_OR_RETURN_ERROR(
71*523fa7a6SAndroid Build Coastguard Worker runtime_allocator, NeuronExecuTorchDelegate);
72*523fa7a6SAndroid Build Coastguard Worker new (delegate) NeuronExecuTorchDelegate();
73*523fa7a6SAndroid Build Coastguard Worker
74*523fa7a6SAndroid Build Coastguard Worker if (delegate == nullptr) {
75*523fa7a6SAndroid Build Coastguard Worker return nullptr;
76*523fa7a6SAndroid Build Coastguard Worker }
77*523fa7a6SAndroid Build Coastguard Worker auto res = delegate->LoadCompiledNetwork(Payload, setting);
78*523fa7a6SAndroid Build Coastguard Worker return res == NEURON_NO_ERROR ? delegate : nullptr;
79*523fa7a6SAndroid Build Coastguard Worker }
80*523fa7a6SAndroid Build Coastguard Worker
execute(ET_UNUSED BackendExecutionContext & context,DelegateHandle * handle,EValue ** args) const81*523fa7a6SAndroid Build Coastguard Worker Error NeuronBackend::execute(
82*523fa7a6SAndroid Build Coastguard Worker ET_UNUSED BackendExecutionContext& context,
83*523fa7a6SAndroid Build Coastguard Worker DelegateHandle* handle,
84*523fa7a6SAndroid Build Coastguard Worker EValue** args) const {
85*523fa7a6SAndroid Build Coastguard Worker NeuronExecuTorchDelegate* delegate =
86*523fa7a6SAndroid Build Coastguard Worker reinterpret_cast<NeuronExecuTorchDelegate*>(handle);
87*523fa7a6SAndroid Build Coastguard Worker return delegate->execute(context, args);
88*523fa7a6SAndroid Build Coastguard Worker }
89*523fa7a6SAndroid Build Coastguard Worker
destroy(DelegateHandle * handle) const90*523fa7a6SAndroid Build Coastguard Worker void NeuronBackend::destroy(DelegateHandle* handle) const {
91*523fa7a6SAndroid Build Coastguard Worker if (handle != nullptr) {
92*523fa7a6SAndroid Build Coastguard Worker NeuronExecuTorchDelegate* delegate =
93*523fa7a6SAndroid Build Coastguard Worker reinterpret_cast<NeuronExecuTorchDelegate*>(handle);
94*523fa7a6SAndroid Build Coastguard Worker delegate->~NeuronExecuTorchDelegate();
95*523fa7a6SAndroid Build Coastguard Worker }
96*523fa7a6SAndroid Build Coastguard Worker }
97*523fa7a6SAndroid Build Coastguard Worker
is_available() const98*523fa7a6SAndroid Build Coastguard Worker bool NeuronBackend::is_available() const {
99*523fa7a6SAndroid Build Coastguard Worker return true;
100*523fa7a6SAndroid Build Coastguard Worker }
101*523fa7a6SAndroid Build Coastguard Worker
execute(BackendExecutionContext & context,EValue ** args) const102*523fa7a6SAndroid Build Coastguard Worker Error NeuronExecuTorchDelegate::execute(
103*523fa7a6SAndroid Build Coastguard Worker BackendExecutionContext& context,
104*523fa7a6SAndroid Build Coastguard Worker EValue** args) const {
105*523fa7a6SAndroid Build Coastguard Worker if (HintNeuronBackend(args) != NEURON_NO_ERROR) {
106*523fa7a6SAndroid Build Coastguard Worker return Error::InvalidState;
107*523fa7a6SAndroid Build Coastguard Worker };
108*523fa7a6SAndroid Build Coastguard Worker
109*523fa7a6SAndroid Build Coastguard Worker auto allocator = dynamic_cast<torch::executor::neuron::BufferAllocator*>(
110*523fa7a6SAndroid Build Coastguard Worker context.get_temp_allocator());
111*523fa7a6SAndroid Build Coastguard Worker size_t inputCount = mInputSizes.size(), outputCount = mOutputSizes.size();
112*523fa7a6SAndroid Build Coastguard Worker
113*523fa7a6SAndroid Build Coastguard Worker for (int i = 0; i < inputCount; i++) {
114*523fa7a6SAndroid Build Coastguard Worker auto data_ptr = args[i]->toTensor().data_ptr();
115*523fa7a6SAndroid Build Coastguard Worker auto data_size = args[i]->toTensor().nbytes();
116*523fa7a6SAndroid Build Coastguard Worker if (IsCached</*isInput=*/true>(i, data_ptr)) {
117*523fa7a6SAndroid Build Coastguard Worker continue;
118*523fa7a6SAndroid Build Coastguard Worker };
119*523fa7a6SAndroid Build Coastguard Worker auto unit = allocator != nullptr ? allocator->Find(data_ptr) : nullptr;
120*523fa7a6SAndroid Build Coastguard Worker if (unit) {
121*523fa7a6SAndroid Build Coastguard Worker UpdateCache<true>(i, data_ptr);
122*523fa7a6SAndroid Build Coastguard Worker size_t offset = (char*)data_ptr - (char*)unit->GetAddress();
123*523fa7a6SAndroid Build Coastguard Worker mExecutor.SetInputOutputFromMemory</*isInput*/ true>(
124*523fa7a6SAndroid Build Coastguard Worker i, unit->GetNeuronMemory(), offset, data_size);
125*523fa7a6SAndroid Build Coastguard Worker } else {
126*523fa7a6SAndroid Build Coastguard Worker mExecutor.SetInputOutput</*isInput=*/true>(i, data_ptr, data_size);
127*523fa7a6SAndroid Build Coastguard Worker }
128*523fa7a6SAndroid Build Coastguard Worker }
129*523fa7a6SAndroid Build Coastguard Worker
130*523fa7a6SAndroid Build Coastguard Worker for (int o = inputCount; o < inputCount + outputCount; o++) {
131*523fa7a6SAndroid Build Coastguard Worker auto data_ptr = args[o]->toTensor().data_ptr();
132*523fa7a6SAndroid Build Coastguard Worker auto data_size = args[o]->toTensor().nbytes();
133*523fa7a6SAndroid Build Coastguard Worker auto output_index = o - inputCount;
134*523fa7a6SAndroid Build Coastguard Worker if (IsCached</*isInput=*/false>(output_index, data_ptr)) {
135*523fa7a6SAndroid Build Coastguard Worker continue;
136*523fa7a6SAndroid Build Coastguard Worker };
137*523fa7a6SAndroid Build Coastguard Worker auto unit = allocator != nullptr ? allocator->Find(data_ptr) : nullptr;
138*523fa7a6SAndroid Build Coastguard Worker if (unit) {
139*523fa7a6SAndroid Build Coastguard Worker UpdateCache</*isInput=*/false>(output_index, data_ptr);
140*523fa7a6SAndroid Build Coastguard Worker size_t offset = (char*)data_ptr - (char*)unit->GetAddress();
141*523fa7a6SAndroid Build Coastguard Worker mExecutor.SetInputOutputFromMemory</*isInput*/ false>(
142*523fa7a6SAndroid Build Coastguard Worker output_index, unit->GetNeuronMemory(), offset, data_size);
143*523fa7a6SAndroid Build Coastguard Worker } else {
144*523fa7a6SAndroid Build Coastguard Worker mExecutor.SetInputOutput</*isInput=*/false>(
145*523fa7a6SAndroid Build Coastguard Worker output_index, data_ptr, data_size);
146*523fa7a6SAndroid Build Coastguard Worker }
147*523fa7a6SAndroid Build Coastguard Worker }
148*523fa7a6SAndroid Build Coastguard Worker
149*523fa7a6SAndroid Build Coastguard Worker return mExecutor.Compute() == NEURON_NO_ERROR ? Error::Ok
150*523fa7a6SAndroid Build Coastguard Worker : Error::InvalidState;
151*523fa7a6SAndroid Build Coastguard Worker };
152*523fa7a6SAndroid Build Coastguard Worker
HintNeuronBackend(EValue ** args) const153*523fa7a6SAndroid Build Coastguard Worker int NeuronExecuTorchDelegate::HintNeuronBackend(EValue** args) const {
154*523fa7a6SAndroid Build Coastguard Worker auto HintImportForever = [this](EValue** args) -> int {
155*523fa7a6SAndroid Build Coastguard Worker auto& allocator = GET_NEURON_ALLOCATOR;
156*523fa7a6SAndroid Build Coastguard Worker size_t inputCount = mInputSizes.size(), outputCount = mOutputSizes.size();
157*523fa7a6SAndroid Build Coastguard Worker for (int i = 0; i < inputCount; i++) {
158*523fa7a6SAndroid Build Coastguard Worker auto data_ptr = args[i]->toTensor().data_ptr();
159*523fa7a6SAndroid Build Coastguard Worker if (mHasImported.count(data_ptr)) {
160*523fa7a6SAndroid Build Coastguard Worker continue;
161*523fa7a6SAndroid Build Coastguard Worker }
162*523fa7a6SAndroid Build Coastguard Worker auto unit = allocator.Find(data_ptr);
163*523fa7a6SAndroid Build Coastguard Worker if (unit) {
164*523fa7a6SAndroid Build Coastguard Worker mExecutor.SetInputOutputFromMemory</*isInput*/ true>(
165*523fa7a6SAndroid Build Coastguard Worker i, unit->GetNeuronMemory(), 0, unit->GetSize());
166*523fa7a6SAndroid Build Coastguard Worker mHasImported.insert(data_ptr);
167*523fa7a6SAndroid Build Coastguard Worker }
168*523fa7a6SAndroid Build Coastguard Worker }
169*523fa7a6SAndroid Build Coastguard Worker for (int o = inputCount; o < inputCount + outputCount; o++) {
170*523fa7a6SAndroid Build Coastguard Worker auto data_ptr = args[o]->toTensor().data_ptr();
171*523fa7a6SAndroid Build Coastguard Worker if (mHasImported.count(data_ptr)) {
172*523fa7a6SAndroid Build Coastguard Worker continue;
173*523fa7a6SAndroid Build Coastguard Worker }
174*523fa7a6SAndroid Build Coastguard Worker auto output_index = o - inputCount;
175*523fa7a6SAndroid Build Coastguard Worker auto unit = allocator.Find(data_ptr);
176*523fa7a6SAndroid Build Coastguard Worker if (unit) {
177*523fa7a6SAndroid Build Coastguard Worker mExecutor.SetInputOutputFromMemory</*isInput*/ false>(
178*523fa7a6SAndroid Build Coastguard Worker output_index, unit->GetNeuronMemory(), 0, unit->GetSize());
179*523fa7a6SAndroid Build Coastguard Worker mHasImported.insert(data_ptr);
180*523fa7a6SAndroid Build Coastguard Worker }
181*523fa7a6SAndroid Build Coastguard Worker }
182*523fa7a6SAndroid Build Coastguard Worker return NEURON_NO_ERROR;
183*523fa7a6SAndroid Build Coastguard Worker };
184*523fa7a6SAndroid Build Coastguard Worker if (mSettings.mImportForever) {
185*523fa7a6SAndroid Build Coastguard Worker CHECK_NO_ERROR(HintImportForever(args));
186*523fa7a6SAndroid Build Coastguard Worker }
187*523fa7a6SAndroid Build Coastguard Worker return NEURON_NO_ERROR;
188*523fa7a6SAndroid Build Coastguard Worker }
189*523fa7a6SAndroid Build Coastguard Worker
190*523fa7a6SAndroid Build Coastguard Worker } // namespace neuron
191*523fa7a6SAndroid Build Coastguard Worker } // namespace backends
192*523fa7a6SAndroid Build Coastguard Worker } // namespace executorch
193*523fa7a6SAndroid Build Coastguard Worker
194*523fa7a6SAndroid Build Coastguard Worker namespace {
195*523fa7a6SAndroid Build Coastguard Worker auto cls = executorch::backends::neuron::NeuronBackend();
196*523fa7a6SAndroid Build Coastguard Worker executorch::runtime::Backend backend{"NeuropilotBackend", &cls};
197*523fa7a6SAndroid Build Coastguard Worker static auto success_with_compiler =
198*523fa7a6SAndroid Build Coastguard Worker executorch::runtime::register_backend(backend);
199*523fa7a6SAndroid Build Coastguard Worker } // namespace
200