xref: /aosp_15_r20/external/tensorflow/tensorflow/lite/delegates/gpu/cl/cl_program.cc (revision b6fb3261f9314811a0f4371741dbb8839866f948)
1 /* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #include "tensorflow/lite/delegates/gpu/cl/cl_program.h"
17 
18 #include <cstdint>
19 #include <cstring>
20 #include <string>
21 #include <vector>
22 
23 #include "absl/strings/str_cat.h"
24 #include "absl/types/span.h"
25 #include "tensorflow/lite/delegates/gpu/cl/util.h"
26 #include "tensorflow/lite/delegates/gpu/common/status.h"
27 
28 namespace tflite {
29 namespace gpu {
30 namespace cl {
31 namespace {
32 
GetProgramBuildInfo(cl_program program,cl_device_id id,cl_program_build_info info)33 std::string GetProgramBuildInfo(cl_program program, cl_device_id id,
34                                 cl_program_build_info info) {
35   size_t size;
36   cl_int error_code =
37       clGetProgramBuildInfo(program, id, info, 0, nullptr, &size);
38   if (error_code != CL_SUCCESS) {
39     return absl::StrCat("Failed to GetProgramBuildInfo - ",
40                         CLErrorCodeToString(error_code));
41   }
42 
43   std::string result(size - 1, 0);
44   error_code =
45       clGetProgramBuildInfo(program, id, info, size, &result[0], nullptr);
46   if (error_code != CL_SUCCESS) {
47     return absl::StrCat("Failed to GetProgramBuildInfo - ",
48                         CLErrorCodeToString(error_code));
49   }
50   return result;
51 }
52 
GetBinarySize(cl_program program,size_t * binary_size)53 absl::Status GetBinarySize(cl_program program, size_t* binary_size) {
54   cl_int error_code = clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES,
55                                        sizeof(size_t), binary_size, nullptr);
56   if (error_code != CL_SUCCESS) {
57     return absl::UnknownError(
58         absl::StrCat("Failed to get program binary size - ",
59                      CLErrorCodeToString(error_code)));
60   }
61   return absl::OkStatus();
62 }
63 
BuildProgram(cl_program program,const CLDevice & device,const std::string & compiler_options)64 absl::Status BuildProgram(cl_program program, const CLDevice& device,
65                           const std::string& compiler_options) {
66   const int error_code = clBuildProgram(
67       program, 0, nullptr, compiler_options.c_str(), nullptr, nullptr);
68   if (error_code != CL_SUCCESS) {
69     return absl::UnknownError(absl::StrCat(
70         "Failed to build program executable - ",
71         CLErrorCodeToString(error_code),
72         GetProgramBuildInfo(program, device.id(), CL_PROGRAM_BUILD_LOG)));
73   }
74 
75   return absl::OkStatus();
76 }
77 
CompilerOptionToString(const GpuInfo & gpu_info,CompilerOptions option)78 std::string CompilerOptionToString(const GpuInfo& gpu_info,
79                                    CompilerOptions option) {
80   switch (option) {
81     case CompilerOptions::kAdrenoFullSimd:
82       if (gpu_info.IsAdreno()) {
83         if (gpu_info.adreno_info.IsAdreno3xx() ||
84             gpu_info.adreno_info.IsAdreno4xx()) {
85           return "-qcom-accelerate-16-bit";
86         } else {
87           return "-qcom-accelerate-16-bit=true";
88         }
89       } else {
90         return "unsupported";
91       }
92     case CompilerOptions::kAdrenoMoreWaves:
93       if (gpu_info.IsAdreno()) {
94         if (!(gpu_info.adreno_info.IsAdreno3xx() ||
95               gpu_info.adreno_info.IsAdreno4xx())) {
96           return "-qcom-accelerate-16-bit=false";
97         } else {
98           return "";
99         }
100       } else {
101         return "unsupported";
102       }
103     case CompilerOptions::kClFastRelaxedMath:
104       return "-cl-fast-relaxed-math";
105     case CompilerOptions::kClDisableOptimizations:
106       return "-cl-opt-disable";
107     case CompilerOptions::kCl20:
108       return "-cl-std=CL2.0";
109     case CompilerOptions::kCl30:
110       return "-cl-std=CL3.0";
111   }
112 }
113 
114 }  // namespace
115 
CompilerOptionsToString(const GpuInfo & gpu_info,const std::vector<CompilerOptions> & compiler_options)116 std::string CompilerOptionsToString(
117     const GpuInfo& gpu_info,
118     const std::vector<CompilerOptions>& compiler_options) {
119   std::string result;
120   for (auto option : compiler_options) {
121     absl::StrAppend(&result, CompilerOptionToString(gpu_info, option), " ");
122   }
123   return result;
124 }
125 
CLProgram(cl_program program,cl_device_id device_id)126 CLProgram::CLProgram(cl_program program, cl_device_id device_id)
127     : program_(program), device_id_(device_id) {}
128 
CLProgram(CLProgram && program)129 CLProgram::CLProgram(CLProgram&& program)
130     : program_(program.program_), device_id_(program.device_id_) {
131   program.program_ = nullptr;
132 }
133 
operator =(CLProgram && program)134 CLProgram& CLProgram::operator=(CLProgram&& program) {
135   if (this != &program) {
136     Release();
137     std::swap(program_, program.program_);
138     std::swap(device_id_, program.device_id_);
139   }
140   return *this;
141 }
142 
~CLProgram()143 CLProgram::~CLProgram() { Release(); }
144 
Release()145 void CLProgram::Release() {
146   if (program_) {
147     clReleaseProgram(program_);
148     program_ = nullptr;
149   }
150 }
151 
GetBinary(std::vector<uint8_t> * result) const152 absl::Status CLProgram::GetBinary(std::vector<uint8_t>* result) const {
153   size_t binary_size;
154   RETURN_IF_ERROR(GetBinarySize(program_, &binary_size));
155   result->resize(result->size() + binary_size);
156   uint8_t* binary_ptr = result->data() + result->size() - binary_size;
157   cl_int error_code =
158       clGetProgramInfo(program_, CL_PROGRAM_BINARIES, sizeof(unsigned char*),
159                        &binary_ptr, nullptr);
160   if (error_code != CL_SUCCESS) {
161     return absl::UnknownError(absl::StrCat("Failed to get program binary - ",
162                                            CLErrorCodeToString(error_code)));
163   }
164   return absl::OkStatus();
165 }
166 
CreateCLProgram(const std::string & code,const std::string & compiler_options,const CLContext & context,const CLDevice & device,CLProgram * result)167 absl::Status CreateCLProgram(const std::string& code,
168                              const std::string& compiler_options,
169                              const CLContext& context, const CLDevice& device,
170                              CLProgram* result) {
171   int error_code;
172   const char* source = code.c_str();
173 
174   cl_program program = clCreateProgramWithSource(context.context(), 1, &source,
175                                                  nullptr, &error_code);
176   if (!program || error_code != CL_SUCCESS) {
177     return absl::UnknownError(
178         absl::StrCat("Failed to create compute program - ",
179                      CLErrorCodeToString(error_code)));
180   }
181 
182   *result = CLProgram(program, device.id());
183   RETURN_IF_ERROR(BuildProgram(program, device, compiler_options));
184   return absl::OkStatus();
185 }
186 
CreateCLProgramFromBinary(const CLContext & context,const CLDevice & device,absl::Span<const uint8_t> binary,CLProgram * result)187 absl::Status CreateCLProgramFromBinary(const CLContext& context,
188                                        const CLDevice& device,
189                                        absl::Span<const uint8_t> binary,
190                                        CLProgram* result) {
191   cl_int binary_status;
192   cl_int error_code;
193   cl_device_id devices_list[] = {device.id()};
194   size_t binary_size = binary.size();
195   const uint8_t* binary_pointer = binary.data();
196   cl_program program = clCreateProgramWithBinary(
197       context.context(), 1, devices_list, &binary_size, &binary_pointer,
198       &binary_status, &error_code);
199   if (binary_status != CL_SUCCESS) {
200     return absl::UnknownError(absl::StrCat(
201         "Something wrong with binary after clCreateProgramWithBinary - ",
202         binary_status));
203   }
204   if (error_code != CL_SUCCESS) {
205     return absl::UnknownError(absl::StrCat("Failed to create program - ",
206                                            CLErrorCodeToString(error_code)));
207   }
208   *result = CLProgram(program, device.id());
209   return BuildProgram(program, device, "");
210 }
211 
212 }  // namespace cl
213 }  // namespace gpu
214 }  // namespace tflite
215