1 // Copyright 2019 Google LLC
2 //
3 // This source code is licensed under the BSD-style license found in the
4 // LICENSE file in the root directory of this source tree.
5
6 #include <math.h>
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include <xnnpack.h>
13 #include <xnnpack/allocator.h>
14 #include <xnnpack/log.h>
15 #include <xnnpack/operator.h>
16 #include <xnnpack/params-init.h>
17 #include <xnnpack/params.h>
18
19
xnn_create_prelu_nc_f32(size_t channels,size_t input_stride,size_t output_stride,const float * negative_slope,uint32_t flags,xnn_operator_t * prelu_op_out)20 enum xnn_status xnn_create_prelu_nc_f32(
21 size_t channels,
22 size_t input_stride,
23 size_t output_stride,
24 const float* negative_slope,
25 uint32_t flags,
26 xnn_operator_t* prelu_op_out)
27 {
28 xnn_operator_t prelu_op = NULL;
29 enum xnn_status status = xnn_status_uninitialized;
30
31 if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
32 xnn_log_error("failed to create %s operator: XNNPACK is not initialized",
33 xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32));
34 goto error;
35 }
36
37 status = xnn_status_invalid_parameter;
38
39 if (channels == 0) {
40 xnn_log_error(
41 "failed to create %s operator with %zu channels: number of channels must be non-zero",
42 xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32), channels);
43 goto error;
44 }
45
46 if (input_stride < channels) {
47 xnn_log_error(
48 "failed to create %s operator with input element stride of %zu: "
49 "stride must be at least as large as the number of channels (%zu)",
50 xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32), input_stride, channels);
51 goto error;
52 }
53
54 if (output_stride < channels) {
55 xnn_log_error(
56 "failed to create %s operator with output element stride of %zu: "
57 "stride must be at least as large as the number of channels (%zu)",
58 xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32), output_stride, channels);
59 goto error;
60 }
61
62 status = xnn_status_out_of_memory;
63
64 prelu_op = xnn_allocate_zero_simd_memory(sizeof(struct xnn_operator));
65 if (prelu_op == NULL) {
66 xnn_log_error(
67 "failed to allocate %zu bytes for %s operator descriptor",
68 sizeof(struct xnn_operator), xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32));
69 goto error;
70 }
71
72 const size_t packed_weights_size = channels * sizeof(float) + XNN_EXTRA_BYTES;
73 prelu_op->packed_weights = xnn_allocate_simd_memory(packed_weights_size);
74 if (prelu_op->packed_weights == NULL) {
75 xnn_log_error(
76 "failed to allocate %zu bytes for %s operator packed weights",
77 packed_weights_size, xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32));
78 goto error;
79 }
80 memcpy(prelu_op->packed_weights, negative_slope, channels * sizeof(float));
81
82 prelu_op->channels = channels;
83 prelu_op->input_pixel_stride = input_stride;
84 prelu_op->output_pixel_stride = output_stride;
85
86 prelu_op->type = xnn_operator_type_prelu_nc_f32;
87
88 prelu_op->state = xnn_run_state_invalid;
89
90 *prelu_op_out = prelu_op;
91 return xnn_status_success;
92
93 error:
94 xnn_delete_operator(prelu_op);
95 return status;
96 }
97
xnn_setup_prelu_nc_f32(xnn_operator_t prelu_op,size_t batch_size,const float * input,float * output,pthreadpool_t threadpool)98 enum xnn_status xnn_setup_prelu_nc_f32(
99 xnn_operator_t prelu_op,
100 size_t batch_size,
101 const float* input,
102 float* output,
103 pthreadpool_t threadpool)
104 {
105 if (prelu_op->type != xnn_operator_type_prelu_nc_f32) {
106 xnn_log_error("failed to setup operator: operator type mismatch (expected %s, got %s)",
107 xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32),
108 xnn_operator_type_to_string(prelu_op->type));
109 return xnn_status_invalid_parameter;
110 }
111 prelu_op->state = xnn_run_state_invalid;
112
113 if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
114 xnn_log_error("failed to setup %s operator: XNNPACK is not initialized",
115 xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32));
116 return xnn_status_uninitialized;
117 }
118
119 if (batch_size == 0) {
120 prelu_op->state = xnn_run_state_skip;
121 return xnn_status_success;
122 }
123
124 const size_t channels = prelu_op->channels;
125 prelu_op->context.prelu = (struct prelu_context) {
126 .n = channels * sizeof(float),
127 .x = input,
128 .x_stride = prelu_op->input_pixel_stride * sizeof(float),
129 .w = prelu_op->packed_weights,
130 .y = output,
131 .y_stride = prelu_op->output_pixel_stride * sizeof(float),
132 .ukernel = xnn_params.f32.prelu.ukernel,
133 };
134
135 size_t batch_tile = batch_size;
136 const size_t num_threads = pthreadpool_get_threads_count(threadpool);
137 if (num_threads > 1) {
138 const size_t target_tiles_per_thread = 5;
139 const size_t max_batch_tile = divide_round_up(batch_size, num_threads * target_tiles_per_thread);
140 if (max_batch_tile < batch_tile) {
141 const uint32_t row_tile = xnn_params.f32.prelu.row_tile;
142 batch_tile = min(batch_tile, divide_round_up(batch_tile, max_batch_tile * row_tile) * row_tile);
143 }
144 }
145 prelu_op->compute.type = xnn_parallelization_type_1d_tile_1d;
146 prelu_op->compute.task_1d_tile_1d = (pthreadpool_task_1d_tile_1d_t) xnn_compute_prelu;
147 prelu_op->compute.range[0] = batch_size;
148 prelu_op->compute.tile[0] = batch_tile;
149 prelu_op->state = xnn_run_state_ready;
150
151 return xnn_status_success;
152 }
153