1 /*
2 * Copyright (c) 2021 Arm Limited.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24 #ifndef ARM_COMPUTE_ACL_HPP_
25 #define ARM_COMPUTE_ACL_HPP_
26
27 #include "arm_compute/Acl.h"
28
29 #include <cstdlib>
30 #include <memory>
31 #include <string>
32 #include <vector>
33
34 #if defined(ARM_COMPUTE_EXCEPTIONS_ENABLED)
35 #include <exception>
36 #endif /* defined(ARM_COMPUTE_EXCEPTIONS_ENABLED) */
37
38 // Helper Macros
39 #define ARM_COMPUTE_IGNORE_UNUSED(x) (void)(x)
40
41 namespace acl
42 {
43 // Forward declarations
44 class Context;
45 class Queue;
46 class Tensor;
47 class TensorPack;
48
49 /**< Status code enum */
50 enum class StatusCode
51 {
52 Success = AclSuccess,
53 RuntimeError = AclRuntimeError,
54 OutOfMemory = AclOutOfMemory,
55 Unimplemented = AclUnimplemented,
56 UnsupportedTarget = AclUnsupportedTarget,
57 InvalidArgument = AclInvalidArgument,
58 InvalidTarget = AclInvalidTarget,
59 UnsupportedConfig = AclUnsupportedConfig,
60 InvalidObjectState = AclInvalidObjectState,
61 };
62
63 /**< Utility namespace containing helpers functions */
64 namespace detail
65 {
66 /** Construct to handle destruction of objects
67 *
68 * @tparam T Object base type
69 */
70 template <typename T>
71 struct ObjectDeleter
72 {
73 };
74
75 #define OBJECT_DELETER(obj, func) \
76 template <> \
77 struct ObjectDeleter<obj> \
78 \
79 { \
80 static inline AclStatus Destroy(obj v) \
81 { \
82 return func(v); \
83 } \
84 };
85
OBJECT_DELETER(AclContext,AclDestroyContext)86 OBJECT_DELETER(AclContext, AclDestroyContext)
87 OBJECT_DELETER(AclQueue, AclDestroyQueue)
88 OBJECT_DELETER(AclTensor, AclDestroyTensor)
89 OBJECT_DELETER(AclTensorPack, AclDestroyTensorPack)
90 OBJECT_DELETER(AclOperator, AclDestroyOperator)
91
92 #undef OBJECT_DELETER
93
94 /** Convert a strongly typed enum to an old plain c enum
95 *
96 * @tparam E Plain old C enum
97 * @tparam SE Strongly typed resulting enum
98 *
99 * @param[in] v Value to convert
100 *
101 * @return A corresponding plain old C enumeration
102 */
103 template <typename E, typename SE>
104 constexpr E as_cenum(SE v) noexcept
105 {
106 return static_cast<E>(static_cast<typename std::underlying_type<SE>::type>(v));
107 }
108
109 /** Convert plain old enumeration to a strongly typed enum
110 *
111 * @tparam SE Strongly typed resulting enum
112 * @tparam E Plain old C enum
113 *
114 * @param[in] val Value to convert
115 *
116 * @return A corresponding strongly typed enumeration
117 */
118 template <typename SE, typename E>
as_enum(E val)119 constexpr SE as_enum(E val) noexcept
120 {
121 return static_cast<SE>(val);
122 }
123
124 /** Object base class for library objects
125 *
126 * Class is defining basic common interface for all the library objects
127 *
128 * @tparam T Object type to be templated on
129 */
130 template <typename T>
131 class ObjectBase
132 {
133 public:
134 /** Destructor */
135 ~ObjectBase() = default;
136 /** Copy constructor */
137 ObjectBase(const ObjectBase<T> &) = default;
138 /** Move Constructor */
139 ObjectBase(ObjectBase<T> &&) = default;
140 /** Copy assignment operator */
141 ObjectBase<T> &operator=(const ObjectBase<T> &) = default;
142 /** Move assignment operator */
143 ObjectBase<T> &operator=(ObjectBase<T> &&) = default;
144 /** Reset object value
145 *
146 * @param [in] val Value to set
147 */
reset(T * val)148 void reset(T *val)
149 {
150 _object.reset(val, detail::ObjectDeleter<T *>::Destroy);
151 }
152 /** Access uderlying object
153 *
154 * @return Underlying object
155 */
get() const156 const T *get() const
157 {
158 return _object.get();
159 }
160 /** Access uderlying object
161 *
162 * @return Underlying object
163 */
get()164 T *get()
165 {
166 return _object.get();
167 }
168
169 protected:
170 /** Constructor */
171 ObjectBase() = default;
172
173 protected:
174 std::shared_ptr<T> _object{ nullptr }; /**< Library object */
175 };
176
177 /** Equality operator for library object
178 *
179 * @tparam T Parameter to template on
180 *
181 * @param[in] lhs Left hand-side argument
182 * @param[in] rhs Right hand-side argument
183 *
184 * @return True if objects are equal, else false
185 */
186 template <typename T>
operator ==(const ObjectBase<T> & lhs,const ObjectBase<T> & rhs)187 bool operator==(const ObjectBase<T> &lhs, const ObjectBase<T> &rhs)
188 {
189 return lhs.get() == rhs.get();
190 }
191
192 /** Inequality operator for library object
193 *
194 * @tparam T Parameter to template on
195 *
196 * @param[in] lhs Left hand-side argument
197 * @param[in] rhs Right hand-side argument
198 *
199 * @return True if objects are equal, else false
200 */
201 template <typename T>
operator !=(const ObjectBase<T> & lhs,const ObjectBase<T> & rhs)202 bool operator!=(const ObjectBase<T> &lhs, const ObjectBase<T> &rhs)
203 {
204 return !(lhs == rhs);
205 }
206 } // namespace detail
207
208 #if defined(ARM_COMPUTE_EXCEPTIONS_ENABLED)
209 /** Status class
210 *
211 * Class is an extension of std::exception and contains the underlying
212 * status construct and an error explanatory message to be reported.
213 *
214 * @note Class is visible only when exceptions are enabled during compilation
215 */
216 class Status : public std::exception
217 {
218 public:
219 /** Constructor
220 *
221 * @param[in] status Status returned
222 * @param[in] msg Error message to be bound with the exception
223 */
Status(StatusCode status,const std::string & msg)224 Status(StatusCode status, const std::string &msg)
225 : _status(status), _msg(msg)
226 {
227 }
228 /** Returns an explanatory exception message
229 *
230 * @return Status message
231 */
what() const232 const char *what() const noexcept override
233 {
234 return _msg.c_str();
235 }
236 /** Underlying status accessor
237 *
238 * @return Status code
239 */
status() const240 StatusCode status() const
241 {
242 return _status;
243 }
244 /** Explicit status converter
245 *
246 * @return Status code
247 */
operator StatusCode() const248 explicit operator StatusCode() const
249 {
250 return _status;
251 }
252
253 private:
254 StatusCode _status; /**< Status code */
255 std::string _msg; /**< Status message */
256 };
257
258 /** Reports an error status and throws an exception object in case of failure
259 *
260 * @note This implementation is used when exceptions are enabled during compilation
261 *
262 * @param[in] status Status to report
263 * @param[in] msg Explanatory error messaged
264 *
265 * @return Status code
266 */
report_status(StatusCode status,const std::string & msg)267 static inline void report_status(StatusCode status, const std::string &msg)
268 {
269 if(status != StatusCode::Success)
270 {
271 throw Status(status, msg);
272 }
273 }
274 #else /* defined(ARM_COMPUTE_EXCEPTIONS_ENABLED) */
275 /** Reports a status code
276 *
277 * @note This implementation is used when exceptions are disabled during compilation
278 * @note Message is surpressed and not reported in this case
279 *
280 * @param[in] status Status to report
281 * @param[in] msg Explanatory error messaged
282 *
283 * @return Status code
284 */
report_status(StatusCode status,const std::string & msg)285 static inline void report_status(StatusCode status, const std::string &msg)
286 {
287 ARM_COMPUTE_IGNORE_UNUSED(status);
288 ARM_COMPUTE_IGNORE_UNUSED(msg);
289 }
290 #endif /* defined(ARM_COMPUTE_EXCEPTIONS_ENABLED) */
291
292 /**< Target enum */
293 enum class Target
294 {
295 Cpu = AclCpu, /**< Cpu target that leverages SIMD */
296 GpuOcl = AclGpuOcl /**< Gpu target that leverages OpenCL */
297 };
298
299 /**< Available execution modes */
300 enum class ExecutionMode
301 {
302 FastRerun = AclPreferFastRerun, /**< Prefer minimum latency in consecutive runs, might introduce higher startup times */
303 FastStart = AclPreferFastStart, /**< Prefer minimizing startup time */
304 };
305
306 /** Context class
307 *
308 * Context acts as a central aggregate service for further objects created from it.
309 * It provides, internally, common facilities in order to avoid the use of global
310 * statically initialized objects that can lead to important side-effect under
311 * specific execution contexts.
312 *
313 * For example context contains allocators for object creation, for further backing memory allocation,
314 * any serialization interfaces and other modules that affect the construction of objects,
315 * like program caches for OpenCL.
316 */
317 class Context : public detail::ObjectBase<AclContext_>
318 {
319 public:
320 /**< Context options */
321 struct Options
322 {
323 static constexpr int32_t num_threads_auto = -1; /**< Allow runtime to specify number of threads */
324
325 /** Default Constructor
326 *
327 * @note By default no precision loss is enabled for operators
328 * @note By default the preferred execution mode is to favor multiple consecutive reruns of an operator
329 */
Optionsacl::Context::Options330 Options()
331 : Options(ExecutionMode::FastRerun /* mode */,
332 AclCpuCapabilitiesAuto /* caps */,
333 false /* enable_fast_math */,
334 nullptr /* kernel_config */,
335 num_threads_auto /* max_compute_units */,
336 nullptr /* allocator */)
337 {
338 }
339 /** Constructor
340 *
341 * @param[in] mode Execution mode to be used
342 * @param[in] caps Capabilities to be used
343 * @param[in] enable_fast_math Allow precision loss in favor of performance
344 * @param[in] kernel_config Kernel configuration file containing construction tuning meta-data
345 * @param[in] max_compute_units Max compute units that are expected to used
346 * @param[in] allocator Allocator to be used for internal memory allocation
347 */
Optionsacl::Context::Options348 Options(ExecutionMode mode,
349 AclTargetCapabilities caps,
350 bool enable_fast_math,
351 const char *kernel_config,
352 int32_t max_compute_units,
353 AclAllocator *allocator)
354 {
355 copts.mode = detail::as_cenum<AclExecutionMode>(mode);
356 copts.capabilities = caps;
357 copts.enable_fast_math = enable_fast_math;
358 copts.kernel_config_file = kernel_config;
359 copts.max_compute_units = max_compute_units;
360 copts.allocator = allocator;
361 }
362
363 AclContextOptions copts{};
364 };
365
366 public:
367 /** Constructor
368 *
369 * @note Serves as a simpler delegate constructor
370 * @note As context options, default conservative options will be used
371 *
372 * @param[in] target Target to create context for
373 * @param[out] status Status information if requested
374 */
Context(Target target,StatusCode * status=nullptr)375 explicit Context(Target target, StatusCode *status = nullptr)
376 : Context(target, Options(), status)
377 {
378 }
379 /** Constructor
380 *
381 * @param[in] target Target to create context for
382 * @param[in] options Context construction options
383 * @param[out] status Status information if requested
384 */
Context(Target target,const Options & options,StatusCode * status=nullptr)385 Context(Target target, const Options &options, StatusCode *status = nullptr)
386 {
387 AclContext ctx;
388 const auto st = detail::as_enum<StatusCode>(AclCreateContext(&ctx, detail::as_cenum<AclTarget>(target), &options.copts));
389 reset(ctx);
390 report_status(st, "[Compute Library] Failed to create context");
391 if(status)
392 {
393 *status = st;
394 }
395 }
396 };
397
398 /**< Available tuning modes */
399 enum class TuningMode
400 {
401 Rapid = AclRapid,
402 Normal = AclNormal,
403 Exhaustive = AclExhaustive
404 };
405
406 /** Queue class
407 *
408 * Queue is responsible for the execution related aspects, with main responsibilities those of
409 * scheduling and tuning operators.
410 *
411 * Multiple queues can be created from the same context, and the same operator can be scheduled on each concurrently.
412 *
413 * @note An operator might depend on the maximum possible compute units that are provided in the context,
414 * thus in cases where the number of the scheduling units of the queue are greater might lead to errors.
415 */
416 class Queue : public detail::ObjectBase<AclQueue_>
417 {
418 public:
419 /**< Queue options */
420 struct Options
421 {
422 /** Default Constructor
423 *
424 * As default options, no tuning will be performed, and the number of scheduling units will
425 * depends on internal device discovery functionality
426 */
Optionsacl::Queue::Options427 Options()
428 : opts{ AclTuningModeNone, 0 } {};
429 /** Constructor
430 *
431 * @param[in] mode Tuning mode to be used
432 * @param[in] compute_units Number of scheduling units to be used
433 */
Optionsacl::Queue::Options434 Options(TuningMode mode, int32_t compute_units)
435 : opts{ detail::as_cenum<AclTuningMode>(mode), compute_units }
436 {
437 }
438
439 AclQueueOptions opts;
440 };
441
442 public:
443 /** Constructor
444 *
445 * @note Serves as a simpler delegate constructor
446 * @note As queue options, default conservative options will be used
447 *
448 * @param[in] ctx Context to create queue for
449 * @param[out] status Status information if requested
450 */
Queue(Context & ctx,StatusCode * status=nullptr)451 explicit Queue(Context &ctx, StatusCode *status = nullptr)
452 : Queue(ctx, Options(), status)
453 {
454 }
455 /** Constructor
456 *
457 * @note As queue options, default conservative options will be used
458 *
459 * @param[in] ctx Context from where the queue will be created from
460 * @param[in] options Queue options to be used
461 * @param[out] status Status information if requested
462 */
Queue(Context & ctx,const Options & options=Options (),StatusCode * status=nullptr)463 explicit Queue(Context &ctx, const Options &options = Options(), StatusCode *status = nullptr)
464 {
465 AclQueue queue;
466 const auto st = detail::as_enum<StatusCode>(AclCreateQueue(&queue, ctx.get(), &options.opts));
467 reset(queue);
468 report_status(st, "[Compute Library] Failed to create queue!");
469 if(status)
470 {
471 *status = st;
472 }
473 }
474 /** Block until all the tasks of the queue have been marked as finished
475 *
476 * @return Status code
477 */
finish()478 StatusCode finish()
479 {
480 return detail::as_enum<StatusCode>(AclQueueFinish(_object.get()));
481 }
482 };
483
484 /**< Data type enumeration */
485 enum class DataType
486 {
487 Unknown = AclDataTypeUnknown,
488 UInt8 = AclUInt8,
489 Int8 = AclInt8,
490 UInt16 = AclUInt16,
491 Int16 = AclInt16,
492 UInt32 = AclUint32,
493 Int32 = AclInt32,
494 Float16 = AclFloat16,
495 BFloat16 = AclBFloat16,
496 Float32 = AclFloat32,
497 };
498
499 /** Tensor Descriptor class
500 *
501 * Structure that contains all the required meta-data to represent a tensor
502 */
503 class TensorDescriptor
504 {
505 public:
506 /** Constructor
507 *
508 * @param[in] shape Shape of the tensor
509 * @param[in] data_type Data type of the tensor
510 */
TensorDescriptor(const std::vector<int32_t> & shape,DataType data_type)511 TensorDescriptor(const std::vector<int32_t> &shape, DataType data_type)
512 : _shape(shape), _data_type(data_type)
513 {
514 _cdesc.ndims = _shape.size();
515 _cdesc.shape = _shape.data();
516 _cdesc.data_type = detail::as_cenum<AclDataType>(_data_type);
517 _cdesc.strides = nullptr;
518 _cdesc.boffset = 0;
519 }
520 /** Constructor
521 *
522 * @param[in] desc C-type descriptor
523 */
TensorDescriptor(const AclTensorDescriptor & desc)524 explicit TensorDescriptor(const AclTensorDescriptor &desc)
525 {
526 _cdesc = desc;
527 _data_type = detail::as_enum<DataType>(desc.data_type);
528 _shape.reserve(desc.ndims);
529 for(int32_t d = 0; d < desc.ndims; ++d)
530 {
531 _shape.emplace_back(desc.shape[d]);
532 }
533 }
534 /** Get underlying C tensor descriptor
535 *
536 * @return Underlying structure
537 */
get() const538 const AclTensorDescriptor *get() const
539 {
540 return &_cdesc;
541 }
542 /** Operator to compare two TensorDescriptor
543 *
544 * @param[in] other The instance to compare against
545 *
546 * @return True if two instances have the same shape and data type
547 */
operator ==(const TensorDescriptor & other)548 bool operator==(const TensorDescriptor &other)
549 {
550 bool is_same = true;
551
552 is_same &= _data_type == other._data_type;
553 is_same &= _shape.size() == other._shape.size();
554
555 if(is_same)
556 {
557 for(uint32_t d = 0; d < _shape.size(); ++d)
558 {
559 is_same &= _shape[d] == other._shape[d];
560 }
561 }
562
563 return is_same;
564 }
565
566 private:
567 std::vector<int32_t> _shape{};
568 DataType _data_type{};
569 AclTensorDescriptor _cdesc{};
570 };
571
572 /** Import memory types */
573 enum class ImportType
574 {
575 Host = AclImportMemoryType::AclHostPtr
576 };
577
578 /** Tensor class
579 *
580 * Tensor is an mathematical construct that can represent an N-Dimensional space.
581 *
582 * @note Maximum dimensionality support is 6 internally at the moment
583 */
584 class Tensor : public detail::ObjectBase<AclTensor_>
585 {
586 public:
587 /** Constructor
588 *
589 * @note Tensor memory is allocated
590 *
591 * @param[in] ctx Context from where the tensor will be created from
592 * @param[in] desc Tensor descriptor to be used
593 * @param[out] status Status information if requested
594 */
Tensor(Context & ctx,const TensorDescriptor & desc,StatusCode * status=nullptr)595 Tensor(Context &ctx, const TensorDescriptor &desc, StatusCode *status = nullptr)
596 : Tensor(ctx, desc, true, status)
597 {
598 }
599 /** Constructor
600 *
601 * @param[in] ctx Context from where the tensor will be created from
602 * @param[in] desc Tensor descriptor to be used
603 * @param[in] allocate Flag to indicate if the tensor needs to be allocated
604 * @param[out] status Status information if requested
605 */
Tensor(Context & ctx,const TensorDescriptor & desc,bool allocate,StatusCode * status)606 Tensor(Context &ctx, const TensorDescriptor &desc, bool allocate, StatusCode *status)
607 {
608 AclTensor tensor;
609 const auto st = detail::as_enum<StatusCode>(AclCreateTensor(&tensor, ctx.get(), desc.get(), allocate));
610 reset(tensor);
611 report_status(st, "[Compute Library] Failed to create tensor!");
612 if(status)
613 {
614 *status = st;
615 }
616 }
617 /** Maps the backing memory of a given tensor that can be used by the host to access any contents
618 *
619 * @return A valid non-zero pointer in case of success else nullptr
620 */
map()621 void *map()
622 {
623 void *handle = nullptr;
624 const auto st = detail::as_enum<StatusCode>(AclMapTensor(_object.get(), &handle));
625 report_status(st, "[Compute Library] Failed to map the tensor and extract the tensor's backing memory!");
626 return handle;
627 }
628 /** Unmaps tensor's memory
629 *
630 * @param[in] handle Handle to unmap
631 *
632 * @return Status code
633 */
unmap(void * handle)634 StatusCode unmap(void *handle)
635 {
636 const auto st = detail::as_enum<StatusCode>(AclUnmapTensor(_object.get(), handle));
637 report_status(st, "[Compute Library] Failed to unmap the tensor!");
638 return st;
639 }
640 /** Import external memory to a given tensor object
641 *
642 * @param[in] handle External memory handle
643 * @param[in] type Type of memory to be imported
644 *
645 * @return Status code
646 */
import(void * handle,ImportType type)647 StatusCode import(void *handle, ImportType type)
648 {
649 const auto st = detail::as_enum<StatusCode>(AclTensorImport(_object.get(), handle, detail::as_cenum<AclImportMemoryType>(type)));
650 report_status(st, "[Compute Library] Failed to import external memory to tensor!");
651 return st;
652 }
653 /** Get the size of the tensor in byte
654 *
655 * @note The size isn't based on allocated memory, but based on information in its descriptor (dimensions, data type, etc.).
656 *
657 * @return The size of the tensor in byte
658 */
get_size()659 uint64_t get_size()
660 {
661 uint64_t size{ 0 };
662 const auto st = detail::as_enum<StatusCode>(AclGetTensorSize(_object.get(), &size));
663 report_status(st, "[Compute Library] Failed to get the size of the tensor");
664 return size;
665 }
666 /** Get the descriptor of this tensor
667 *
668 * @return The descriptor describing the characteristics of this tensor
669 */
get_descriptor()670 TensorDescriptor get_descriptor()
671 {
672 AclTensorDescriptor desc;
673 const auto st = detail::as_enum<StatusCode>(AclGetTensorDescriptor(_object.get(), &desc));
674 report_status(st, "[Compute Library] Failed to get the descriptor of the tensor");
675 return TensorDescriptor(desc);
676 }
677 };
678
679 /** Tensor pack class
680 *
681 * Pack is a utility construct that is used to create a collection of tensors that can then
682 * be passed into operator as inputs.
683 */
684 class TensorPack : public detail::ObjectBase<AclTensorPack_>
685 {
686 public:
687 /** Pack pair construct */
688 struct PackPair
689 {
690 /** Constructor
691 *
692 * @param[in] tensor_ Tensor to pack
693 * @param[in] slot_id_ Slot identification of the tensor in respect with the operator
694 */
PackPairacl::TensorPack::PackPair695 PackPair(Tensor *tensor_, int32_t slot_id_)
696 : tensor(tensor_), slot_id(slot_id_)
697 {
698 }
699
700 Tensor *tensor{ nullptr }; /**< Tensor object */
701 int32_t slot_id{ AclSlotUnknown }; /**< Slot id in respect with the operator */
702 };
703
704 public:
705 /** Constructor
706 *
707 * @param[in] ctx Context from where the tensor pack will be created from
708 * @param[out] status Status information if requested
709 */
TensorPack(Context & ctx,StatusCode * status=nullptr)710 explicit TensorPack(Context &ctx, StatusCode *status = nullptr)
711 {
712 AclTensorPack pack;
713 const auto st = detail::as_enum<StatusCode>(AclCreateTensorPack(&pack, ctx.get()));
714 reset(pack);
715 report_status(st, "[Compute Library] Failure during tensor pack creation");
716 if(status)
717 {
718 *status = st;
719 }
720 }
721 /** Add tensor to tensor pack
722 *
723 * @param[in] slot_id Slot id of the tensor in respect with the operator
724 * @param[in] tensor Tensor to be added in the pack
725 *
726 * @return Status code
727 */
add(Tensor & tensor,int32_t slot_id)728 StatusCode add(Tensor &tensor, int32_t slot_id)
729 {
730 return detail::as_enum<StatusCode>(AclPackTensor(_object.get(), tensor.get(), slot_id));
731 }
732 /** Add a list of tensors to a tensor pack
733 *
734 * @param[in] packed Pair packs to be added
735 *
736 * @return Status code
737 */
add(std::initializer_list<PackPair> packed)738 StatusCode add(std::initializer_list<PackPair> packed)
739 {
740 const size_t size = packed.size();
741 std::vector<int32_t> slots(size);
742 std::vector<AclTensor> tensors(size);
743 int i = 0;
744 for(auto &p : packed)
745 {
746 slots[i] = p.slot_id;
747 tensors[i] = AclTensor(p.tensor);
748 ++i;
749 }
750 return detail::as_enum<StatusCode>(AclPackTensors(_object.get(), tensors.data(), slots.data(), size));
751 }
752 };
753
754 /** Operator class
755 *
756 * Operators are the basic algorithmic blocks responsible for performing distinct operations
757 */
758 class Operator : public detail::ObjectBase<AclOperator_>
759 {
760 public:
761 /** Run an operator on a given input list
762 *
763 * @param[in,out] queue Queue to scheduler the operator on
764 * @param pack Tensor list to be used as input
765 *
766 * @return Status Code
767 */
run(Queue & queue,TensorPack & pack)768 StatusCode run(Queue &queue, TensorPack &pack)
769 {
770 return detail::as_cenum<StatusCode>(AclRunOperator(_object.get(), queue.get(), pack.get()));
771 }
772
773 protected:
774 /** Constructor */
775 Operator() = default;
776 };
777
778 /// Operators
779 using ActivationDesc = AclActivationDescriptor;
780 class Activation : public Operator
781 {
782 public:
Activation(Context & ctx,const TensorDescriptor & src,const TensorDescriptor & dst,const ActivationDesc & desc,StatusCode * status=nullptr)783 Activation(Context &ctx, const TensorDescriptor &src, const TensorDescriptor &dst, const ActivationDesc &desc, StatusCode *status = nullptr)
784 {
785 AclOperator op;
786 const auto st = detail::as_enum<StatusCode>(AclActivation(&op, ctx.get(), src.get(), dst.get(), desc));
787 reset(op);
788 report_status(st, "[Compute Library] Failure during Activation operator creation");
789 if(status)
790 {
791 *status = st;
792 }
793 }
794 };
795 } // namespace acl
796 #undef ARM_COMPUTE_IGNORE_UNUSED
797 #endif /* ARM_COMPUTE_ACL_HPP_ */
798