Skip to content

Commit 31306d1

Browse files
committed
Adding a payload version to become compatible with extra output tensors in 2.2.1
1 parent 12d17ef commit 31306d1

File tree

5 files changed

+63
-14
lines changed

5 files changed

+63
-14
lines changed

backends/nxp/neutron_node_extraction.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class NeutronNodeArtifacts:
2121
microcode: np.ndarray
2222
weights: np.ndarray
2323
kernels: np.ndarray
24+
payload_version: int
2425

2526

2627
def extract_artifacts_from_neutron_node(
@@ -123,7 +124,12 @@ def extract_artifacts_from_neutron_node(
123124
output_names = []
124125
output_indices = []
125126
graph_outputs = sub_graph.OutputsAsNumpy()
127+
payload_version = 0
128+
# Ignore the extra outputs: scratch and eventually also profile and debug
126129
node_outputs = neutron_node.OutputsAsNumpy()[:-1]
130+
if len(graph_outputs) == len(node_outputs) - 2:
131+
payload_version = 1
132+
node_outputs = node_outputs[:-2]
127133
for tensor_idx in node_outputs:
128134
which_graph_output = np.where(graph_outputs == tensor_idx)[0]
129135
assert (
@@ -142,4 +148,5 @@ def extract_artifacts_from_neutron_node(
142148
microcode,
143149
weights,
144150
kernels,
151+
payload_version,
145152
)

backends/nxp/nxp_backend.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ def _create_payload_header(
283283
+----------------------------------------+------------------------------------------+
284284
| 1st output map (1B) | [nth* output map (1B)] |
285285
+----------------------------------------+------------------------------------------+
286+
| Payload version (1B) |
287+
+-----------------------------------------------------------------------------------+
286288
287289
:param io_formats: IO tensors formats.
288290
:return: Bytes representation of payload header.
@@ -325,6 +327,7 @@ def _create_payload_header(
325327

326328
header_data.extend(neutron_artifacts.input_indices)
327329
header_data.extend(neutron_artifacts.output_indices)
330+
header_data.append(neutron_artifacts.payload_version)
328331

329332
# noinspection PyTypeChecker
330333
return np.array(header_data, dtype=np.uint8)

backends/nxp/runtime/NeutronBackend.cpp

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ namespace neutron {
3838
+----------------------------------------+------------------------------------------+
3939
| 1st output map (1B) | [nth* output map (1B)] |
4040
+----------------------------------------+------------------------------------------+
41+
| Payload version (1B) |
42+
+-----------------------------------------------------------------------------------+
4143
*/
4244
// clang-format on
4345
#define ITEM_SIZE 1 // 1 Byte
@@ -53,10 +55,13 @@ namespace neutron {
5355
#define OUTPUT_TENSOR_MAP_ARRAY_ADDR(base) \
5456
(base + 3 * ITEM_SIZE + 2 * base[INPUT_TENSOR_FORMAT_LEN_POS] + \
5557
1 * base[OUTPUT_TENSOR_FORMAT_LEN_POS])
58+
#define PAYLOAD_VERSION_ADDR(base) \
59+
(base + 3 * ITEM_SIZE + 2 * base[INPUT_TENSOR_FORMAT_LEN_POS] + \
60+
2 * base[OUTPUT_TENSOR_FORMAT_LEN_POS])
5661
#define PAYLOAD_ADDR(base) \
5762
(base + \
5863
ALIGN_SIZE( \
59-
3 * ITEM_SIZE + 2 * base[INPUT_TENSOR_FORMAT_LEN_POS] + \
64+
4 * ITEM_SIZE + 2 * base[INPUT_TENSOR_FORMAT_LEN_POS] + \
6065
2 * base[OUTPUT_TENSOR_FORMAT_LEN_POS]))
6166

6267
// Aggregate neutron model handle and data structures into one.
@@ -65,6 +70,8 @@ typedef struct {
6570
int numOutputs = 0;
6671
int numInputArgs = 0;
6772
uint32_t scratchSize = 0;
73+
uint32_t profileSize = 0;
74+
uint32_t debugSize = 0;
6875
NeutronModelConfig mcfg;
6976
NeutronDataConfig dcfg;
7077
NeutronModelHandle nmh = NULL;
@@ -269,6 +276,7 @@ class NeutronBackend final : public PyTorchBackendInterface {
269276
OUTPUT_TENSOR_FORMAT_ARRAY_ADDR(payloadFlags);
270277
cfg->inputMap = INPUT_TENSOR_MAP_ARRAY_ADDR(payloadFlags);
271278
cfg->outputMap = OUTPUT_TENSOR_MAP_ARRAY_ADDR(payloadFlags);
279+
uint8_t payloadVersion = *PAYLOAD_VERSION_ADDR(payloadFlags);
272280

273281
const uint32_t* buffer = static_cast<const uint32_t*>(
274282
static_cast<const void*> PAYLOAD_ADDR(payloadFlags));
@@ -282,9 +290,28 @@ class NeutronBackend final : public PyTorchBackendInterface {
282290
}
283291
uint32_t microcodeSize = buffer[6];
284292
uint32_t weightsSize = buffer[7];
285-
cfg->scratchSize = buffer[9];
286-
cfg->numInputs = buffer[11];
287-
cfg->numOutputs = buffer[12];
293+
switch (payloadVersion) {
294+
case 0:
295+
cfg->scratchSize = buffer[9];
296+
cfg->profileSize = 0;
297+
cfg->debugSize = 0;
298+
cfg->numInputs = buffer[11];
299+
cfg->numOutputs = buffer[12];
300+
break;
301+
case 1:
302+
cfg->scratchSize = buffer[9];
303+
cfg->profileSize = buffer[10];
304+
cfg->debugSize = buffer[11];
305+
cfg->numInputs = buffer[13];
306+
cfg->numOutputs = buffer[14];
307+
break;
308+
default:
309+
ET_LOG(
310+
Error,
311+
"Unknown payload version %d. Please update the backend",
312+
payloadVersion);
313+
return Error::InvalidProgram;
314+
}
288315
if (cfg->numInputs != numInputs) {
289316
ET_LOG(
290317
Error,
@@ -336,10 +363,16 @@ class NeutronBackend final : public PyTorchBackendInterface {
336363
// Allocate place for input and output pointers.
337364
cfg->dcfg.inputs = static_cast<const void**>(
338365
context.allocate(cfg->numInputs * sizeof(void*)));
339-
cfg->dcfg.outputs =
340-
static_cast<void**>(context.allocate(cfg->numOutputs * sizeof(void*)));
366+
// There are 3 extra entries: scratch, profile and debug. The scratch
367+
// pointer was allocated implicitly in the previous versions.
368+
cfg->dcfg.outputs = static_cast<void**>(
369+
context.allocate((cfg->numOutputs + 3) * sizeof(void*)));
341370
cfg->dcfg.outputs[cfg->numOutputs] =
342371
static_cast<void*>(context.allocate(cfg->scratchSize, 16));
372+
cfg->dcfg.outputs[cfg->numOutputs + 1] =
373+
static_cast<void*>(context.allocate(cfg->profileSize, 16));
374+
cfg->dcfg.outputs[cfg->numOutputs + 2] =
375+
static_cast<void*>(context.allocate(cfg->debugSize, 16));
343376

344377
// Set inputs from args.
345378
// Transpose inputs if needed.
@@ -352,7 +385,7 @@ class NeutronBackend final : public PyTorchBackendInterface {
352385
return Error::InvalidProgram;
353386
}
354387
// Allocate buffer, the allocator is reset after each PTE instruction.
355-
void* buffer = context.allocate(arg.nbytes());
388+
void* buffer = context.allocate(arg.nbytes(), 16);
356389
transposeInput(
357390
arg.const_data_ptr(), buffer, arg.sizes(), arg.element_size());
358391
cfg->dcfg.inputs[i] = buffer;
@@ -368,7 +401,7 @@ class NeutronBackend final : public PyTorchBackendInterface {
368401
if (cfg->outputTranspositionFlags[i] &&
369402
multipleChannelsPresent(arg.sizes())) {
370403
// Allocate buffer, the allocator is reset after each PTE instruction.
371-
void* buffer = context.allocate(arg.nbytes());
404+
void* buffer = context.allocate(arg.nbytes(), 16);
372405
cfg->dcfg.outputs[i] = buffer;
373406
} else {
374407
cfg->dcfg.outputs[i] = arg.mutable_data_ptr();

backends/nxp/tests/test_neutron_backend.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ def test_neutron_backend__single_conv_model__payload_header_channels_last():
3636
assert payload[4] == 0x1 # Channels last 0-th Neutron output
3737
assert payload[5] == 0x0 # Map 0-th Neutron input to 0-th model input
3838
assert payload[6] == 0x0 # Map 0-th Neutron output to 0-th model output
39-
assert all(byte == 0x0 for byte in payload[7:16]) # Aligned to 16 bytes
39+
assert (
40+
payload[7] == 0x0 or payload[7] == 0x1
41+
) # Payload version is 0 or 1 depending on the Neutron Software
42+
assert all(byte == 0x0 for byte in payload[8:16]) # Aligned to 16 bytes
4043
assert payload[17] != 0x0 # Followed by non-zero content
4144

4245

@@ -53,5 +56,8 @@ def test_neutron_backend__linear_softmax_model__payload_header_formatless():
5356
assert payload[4] == 0x0 # Formatless 0-th Neutron output
5457
assert payload[5] == 0x0 # Map 0-th Neutron input to 0-th model input
5558
assert payload[6] == 0x0 # Map 0-th Neutron output to 0-th model output
56-
assert all(byte == 0x0 for byte in payload[7:16]) # Aligned to 16 bytes
59+
assert (
60+
payload[7] == 0x0 or payload[7] == 0x1
61+
) # Payload version is 0 or 1 depending on the Neutron Software
62+
assert all(byte == 0x0 for byte in payload[8:16]) # Aligned to 16 bytes
5763
assert payload[17] != 0x0 # Followed by non-zero content

backends/nxp/tests/test_neutron_backend_executor.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ def test_delegating_format_related_transpose_operators__unsupported_shapes(mocke
156156

157157
# Get the header of the payload for the delegated partition.
158158
payload_header = payload_header_spy.spy_return
159-
assert payload_header.size == 7
159+
assert payload_header.size == 8
160160
# the 4th and 5th bytes indicate the format. `1` means `channels_last`, which means the runtime will transpose the data.
161161
assert all(payload_header[3:5] == [1, 1]) # [<input_byte>, <output_byte>]
162162

@@ -214,7 +214,7 @@ def test_delegating_format_related_transpose_operators__supported_case(mocker):
214214

215215
# Get the header of the payload for the delegated partition.
216216
payload_header = payload_header_spy.spy_return
217-
assert payload_header.size == 7
217+
assert payload_header.size == 8
218218
# the 4th and 5th bytes indicate the format. `0` means `channels_last`, which means the runtime will NOT transpose the data.
219219
assert all(payload_header[3:5] == [0, 0]) # [<input_byte>, <output_byte>]
220220

@@ -270,7 +270,7 @@ def test_delegating_format_related_transpose_operators__supported_output__unsupp
270270

271271
# Get the header of the payload for the delegated partition.
272272
payload_header = payload_header_spy.spy_return
273-
assert payload_header.size == 7
273+
assert payload_header.size == 8
274274
# the 4th and 5th bytes indicate the format. `1` means `channels_last`, which means the runtime will transpose the data.
275275
assert all(payload_header[3:5] == [1, 0]) # [<input_byte>, <output_byte>]
276276

@@ -322,6 +322,6 @@ def test_delegating_format_related_transpose_operators__supported_input__unsuppo
322322

323323
# Get the header of the payload for the delegated partition.
324324
payload_header = payload_header_spy.spy_return
325-
assert payload_header.size == 7
325+
assert payload_header.size == 8
326326
# the 4th and 5th bytes indicate the format. `1` means `channels_last`, which means the runtime will transpose the data.
327327
assert all(payload_header[3:5] == [0, 1]) # [<input_byte>, <output_byte>]

0 commit comments

Comments
 (0)