1 /* 2 * Copyright (c) 2022-2023 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 SRC_DYNAMIC_FUSION_SKETCH_GPU_GPUWORKLOADSOURCECODE 25 #define SRC_DYNAMIC_FUSION_SKETCH_GPU_GPUWORKLOADSOURCECODE 26 27 #include "arm_compute/core/experimental/Types.h" 28 #include "arm_compute/dynamic_fusion/sketch/MemoryDescriptor.h" 29 #include "src/dynamic_fusion/sketch/gpu/GpuKernelSourceCode.h" 30 31 namespace arm_compute 32 { 33 namespace experimental 34 { 35 namespace dynamic_fusion 36 { 37 /** Uniquely identifies a @ref GpuUnitWorkload within a @ref GpuWorkloadSourceCode */ 38 using UnitWorkloadId = int32_t; 39 40 /** Describes all the info related to a kernel in order to: 41 * - be used by runtime to configure gpu kernel argument 42 * - be used by memory managers to allocate required memory 43 */ 44 class GpuWorkloadArgument 45 { 46 public: 47 /** Default constructor */ 48 GpuWorkloadArgument() = default; 49 /** Constructor 50 * 51 * @param[in] tensor_info @ref ITensorInfo of the workload argument 52 * @param[in] mem_desc @ref MemoryDescriptor of the workload argument 53 * @param[in] kernel_arg_info @ref GpuKernelArgumentInfo of the workload argument 54 */ GpuWorkloadArgument(const ITensorInfo & tensor_info,const MemoryDescriptor & mem_desc,const GpuKernelArgumentInfo & kernel_arg_info)55 GpuWorkloadArgument(const ITensorInfo &tensor_info, 56 const MemoryDescriptor &mem_desc, 57 const GpuKernelArgumentInfo &kernel_arg_info) 58 : _tensor_info{ tensor_info }, 59 _mem_desc{ mem_desc }, 60 _kernel_arg_info{ kernel_arg_info } 61 { 62 } 63 /** Get tensor id within workload */ id()64 ITensorInfo::Id id() const 65 { 66 return _tensor_info.id(); 67 } 68 /** Get @ref ITensorInfo of the argument */ tensor_info()69 ITensorInfo *tensor_info() 70 { 71 return &_tensor_info; 72 } 73 /** Get @ref ITensorInfo of the argument */ tensor_info()74 const ITensorInfo *tensor_info() const 75 { 76 return &_tensor_info; 77 } 78 /** Get @ref MemoryDescriptor of the argument */ memory_descriptor()79 MemoryDescriptor *memory_descriptor() 80 { 81 return &_mem_desc; 82 } 83 /** Get @ref MemoryDescriptor of the argument */ memory_descriptor()84 const MemoryDescriptor *memory_descriptor() const 85 { 86 return &_mem_desc; 87 } 88 /** Get @ref GpuKernelArgumentInfo of the argument */ kernel_argument_info()89 GpuKernelArgumentInfo *kernel_argument_info() 90 { 91 return &_kernel_arg_info; 92 } 93 /** Get @ref GpuKernelArgumentInfo of the argument */ kernel_argument_info()94 const GpuKernelArgumentInfo *kernel_argument_info() const 95 { 96 return &_kernel_arg_info; 97 } 98 /** Check if the workload argument has valid id 99 * 100 * @return true If has valid id 101 * @return false Otherwise 102 */ has_valid_id()103 bool has_valid_id() const 104 { 105 return _tensor_info.has_valid_id(); 106 } 107 108 private: 109 TensorInfo _tensor_info{}; 110 MemoryDescriptor _mem_desc{}; 111 GpuKernelArgumentInfo _kernel_arg_info{}; 112 }; 113 114 /** Describes when a unit workload is run. 115 */ 116 struct UnitWorkloadStage 117 { 118 enum class Stage 119 { 120 Prepare, /**< Only run once at the beginning. */ 121 Run, /**< Run every time after the first time. */ 122 }; 123 Stage stage{ Stage::Run }; 124 }; 125 126 inline bool operator==(const UnitWorkloadStage &stage0, const UnitWorkloadStage &stage1) 127 { 128 return stage0.stage == stage1.stage; 129 } 130 131 /** The atomic unit in a Gpu workload. It contains exactly one kernel to run. 132 */ 133 class GpuUnitWorkload 134 { 135 public: 136 /** Default constructor */ 137 GpuUnitWorkload() = default; 138 /** Constructor 139 * 140 * @param[in] id Id that uniquely identifies this unit workload in a workload 141 * @param[in] kernel_code @ref GpuKernelSourceCode contained within 142 * @param[in] stage Stage of the unit workload 143 */ GpuUnitWorkload(UnitWorkloadId id,const GpuKernelSourceCode & kernel_code,const UnitWorkloadStage & stage)144 GpuUnitWorkload(UnitWorkloadId id, const GpuKernelSourceCode &kernel_code, const UnitWorkloadStage &stage) 145 : _id{ id }, _kernel_code{ kernel_code }, _stage{ stage } 146 { 147 } 148 /** Get the id of the unit workload */ id()149 UnitWorkloadId id() const 150 { 151 return _id; 152 } 153 /** Get reference to the underlying @ref GpuKernelSourceCode */ code()154 const GpuKernelSourceCode &code() const 155 { 156 return _kernel_code; 157 } 158 /** Get the stage of the unit workload */ stage()159 UnitWorkloadStage stage() const 160 { 161 return _stage; 162 } 163 164 private: 165 UnitWorkloadId _id{}; 166 GpuKernelSourceCode _kernel_code{}; 167 UnitWorkloadStage _stage{}; 168 }; 169 170 /** Hold the generated kernel source code and other information required to compile and run the workload. 171 */ 172 class GpuWorkloadSourceCode 173 { 174 public: 175 /** Default constructor */ 176 GpuWorkloadSourceCode() = default; 177 /** Add a unit workload to the workload code 178 * 179 * @param[in] kernel_code @ref GpuKernelSourceCode to be contained within the unit workload 180 * @param[in] stage Stage of the unit workload 181 * @param[in] mem_map @ref MemoryDescriptor map for all tensors within the unit workload 182 * 183 * @return UnitWorkloadId Allocated unit workload id 184 */ add_unit_workload(const GpuKernelSourceCode & kernel_code,const UnitWorkloadStage & stage,const MemoryDescriptorMap & mem_map)185 UnitWorkloadId add_unit_workload(const GpuKernelSourceCode &kernel_code, const UnitWorkloadStage &stage, const MemoryDescriptorMap &mem_map) 186 { 187 // Use the size of the kernel codes as Id 188 const auto uwk_id = static_cast<UnitWorkloadId>(_unit_workloads.size()); 189 const auto unit_work = GpuUnitWorkload(uwk_id, kernel_code, stage); 190 _unit_workloads.push_back(unit_work); 191 // Assemble kernel argument with memory descriptor to form workload argument 192 for(const auto &id_arg : kernel_code.arguments()) 193 { 194 const auto arg_id = id_arg.first; 195 const auto arg = id_arg.second; 196 _workload_arguments[arg_id] = GpuWorkloadArgument{ *arg.tensor_info(), mem_map.at(arg_id), *arg.kernel_argument_info() }; 197 if(_tensor_uwork_map.find(arg_id) == _tensor_uwork_map.end()) 198 { 199 _tensor_uwork_map[arg_id] = std::set<UnitWorkloadId>(); 200 } 201 _tensor_uwork_map[arg_id].insert(uwk_id); 202 } 203 return uwk_id; 204 } 205 /** Get a unit workload from its id */ query_unit_workload(UnitWorkloadId id)206 const GpuUnitWorkload &query_unit_workload(UnitWorkloadId id) const 207 { 208 ARM_COMPUTE_ERROR_ON(id < 0); 209 return _unit_workloads.at(id); 210 } 211 /** Get all unit workloads sorted in topological order */ unit_workloads()212 std::vector<UnitWorkloadId> unit_workloads() const 213 { 214 std::vector<UnitWorkloadId> ids{}; 215 216 for(const auto &uwk : _unit_workloads) 217 { 218 ids.push_back(uwk.id()); 219 } 220 return ids; 221 } 222 /** Get a @ref GpuWorkloadArgument from its associated tensor id */ query_tensor(ITensorInfo::Id t_id)223 const GpuWorkloadArgument *query_tensor(ITensorInfo::Id t_id) const 224 { 225 return &_workload_arguments.at(t_id); 226 } 227 /** Get all tensors in the entire workload */ tensors()228 std::vector<ITensorInfo::Id> tensors() const 229 { 230 std::vector<ITensorInfo::Id> ids{}; 231 for(const auto &id_tensor : _workload_arguments) 232 { 233 ids.push_back(id_tensor.first); 234 } 235 return ids; 236 } 237 /** Get all unit workloads connected to the tensor with @p t_id */ get_unit_workloads_from_tensor(ITensorInfo::Id t_id)238 std::vector<UnitWorkloadId> get_unit_workloads_from_tensor(ITensorInfo::Id t_id) const 239 { 240 const auto unit_work_set = _tensor_uwork_map.at(t_id); 241 return std::vector<UnitWorkloadId>(unit_work_set.begin(), unit_work_set.end()); 242 } 243 244 private: 245 std::vector<GpuUnitWorkload> _unit_workloads{}; 246 std::map<ITensorInfo::Id, GpuWorkloadArgument> _workload_arguments{}; 247 std::map<ITensorInfo::Id, std::set<UnitWorkloadId>> _tensor_uwork_map{}; 248 }; 249 } // namespace dynamic_fusion 250 } // namespace experimental 251 } // namespace arm_compute 252 #endif /* SRC_DYNAMIC_FUSION_SKETCH_GPU_GPUWORKLOADSOURCECODE */ 253