• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <vector>
21 
22 #include "absl/strings/str_cat.h"
23 #include "absl/types/span.h"
24 #include "tensorflow/lite/delegates/gpu/cl/util.h"
25 #include "tensorflow/lite/delegates/gpu/common/status.h"
26 
27 namespace tflite {
28 namespace gpu {
29 namespace cl {
30 namespace {
31 
GetProgramBuildInfo(cl_program program,cl_device_id id,cl_program_build_info info)32 std::string GetProgramBuildInfo(cl_program program, cl_device_id id,
33                                 cl_program_build_info info) {
34   size_t size;
35   cl_int error_code =
36       clGetProgramBuildInfo(program, id, info, 0, nullptr, &size);
37   if (error_code != CL_SUCCESS) {
38     return absl::StrCat("Failed to GetProgramBuildInfo - ",
39                         CLErrorCodeToString(error_code));
40   }
41 
42   std::string result(size - 1, 0);
43   error_code =
44       clGetProgramBuildInfo(program, id, info, size, &result[0], nullptr);
45   if (error_code != CL_SUCCESS) {
46     return absl::StrCat("Failed to GetProgramBuildInfo - ",
47                         CLErrorCodeToString(error_code));
48   }
49   return result;
50 }
51 
GetBinarySize(cl_program program,size_t * binary_size)52 Status GetBinarySize(cl_program program, size_t* binary_size) {
53   cl_int error_code = clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES,
54                                        sizeof(size_t), binary_size, nullptr);
55   if (error_code != CL_SUCCESS) {
56     return UnknownError(absl::StrCat("Failed to get program binary size - ",
57                                      CLErrorCodeToString(error_code)));
58   }
59   return OkStatus();
60 }
61 
BuildProgram(cl_program program,const CLDevice & device,const std::string & compiler_options)62 Status BuildProgram(cl_program program, const CLDevice& device,
63                     const std::string& compiler_options) {
64   const int error_code = clBuildProgram(
65       program, 0, nullptr, compiler_options.c_str(), nullptr, nullptr);
66   if (error_code != CL_SUCCESS) {
67     return UnknownError(absl::StrCat(
68         "Failed to build program executable - ",
69         CLErrorCodeToString(error_code),
70         GetProgramBuildInfo(program, device.id(), CL_PROGRAM_BUILD_LOG)));
71   }
72 
73   return OkStatus();
74 }
75 
CompilerOptionToString(const CLDevice & device,CompilerOptions option)76 std::string CompilerOptionToString(const CLDevice& device,
77                                    CompilerOptions option) {
78   switch (option) {
79     case CompilerOptions::ADRENO_FULL_SIMD_LINE:
80       if (device.GetInfo().adreno_info.gpu_version < 500) {
81         return "-qcom-accelerate-16-bit";
82       } else {
83         return "-qcom-accelerate-16-bit=true";
84       }
85     case CompilerOptions::POWERVR_FP16:
86       return "-cl-fast-relaxed-math";
87     case CompilerOptions::CL_OPT_DISABLE:
88       return "-cl-opt-disable";
89   }
90 }
91 
92 }  // namespace
93 
CompilerOptionsToString(const CLDevice & device,const std::vector<CompilerOptions> & compiler_options)94 std::string CompilerOptionsToString(
95     const CLDevice& device,
96     const std::vector<CompilerOptions>& compiler_options) {
97   std::string result;
98   for (auto option : compiler_options) {
99     absl::StrAppend(&result, CompilerOptionToString(device, option), " ");
100   }
101   return result;
102 }
103 
CLProgram(cl_program program,cl_device_id device_id)104 CLProgram::CLProgram(cl_program program, cl_device_id device_id)
105     : program_(program), device_id_(device_id) {}
106 
CLProgram(CLProgram && program)107 CLProgram::CLProgram(CLProgram&& program)
108     : program_(program.program_), device_id_(program.device_id_) {
109   program.program_ = nullptr;
110 }
111 
operator =(CLProgram && program)112 CLProgram& CLProgram::operator=(CLProgram&& program) {
113   if (this != &program) {
114     Release();
115     std::swap(program_, program.program_);
116     std::swap(device_id_, program.device_id_);
117   }
118   return *this;
119 }
120 
~CLProgram()121 CLProgram::~CLProgram() { Release(); }
122 
Release()123 void CLProgram::Release() {
124   if (program_) {
125     clReleaseProgram(program_);
126     program_ = nullptr;
127   }
128 }
129 
GetBinary(std::vector<uint8_t> * result) const130 Status CLProgram::GetBinary(std::vector<uint8_t>* result) const {
131   size_t binary_size;
132   RETURN_IF_ERROR(GetBinarySize(program_, &binary_size));
133   result->resize(result->size() + binary_size);
134   uint8_t* binary_ptr = result->data() + result->size() - binary_size;
135   cl_int error_code = clGetProgramInfo(program_, CL_PROGRAM_BINARIES,
136                                        binary_size, &binary_ptr, nullptr);
137   if (error_code != CL_SUCCESS) {
138     return UnknownError(absl::StrCat("Failed to get program binary - ",
139                                      CLErrorCodeToString(error_code)));
140   }
141   return OkStatus();
142 }
143 
CreateCLProgram(const std::string & code,const std::string & compiler_options,const CLContext & context,const CLDevice & device,CLProgram * result)144 Status CreateCLProgram(const std::string& code,
145                        const std::string& compiler_options,
146                        const CLContext& context, const CLDevice& device,
147                        CLProgram* result) {
148   int error_code;
149   const char* source = code.c_str();
150 
151   cl_program program = clCreateProgramWithSource(context.context(), 1, &source,
152                                                  nullptr, &error_code);
153   if (!program || error_code != CL_SUCCESS) {
154     return UnknownError(absl::StrCat("Failed to create compute program - ",
155                                      CLErrorCodeToString(error_code)));
156   }
157 
158   *result = CLProgram(program, device.id());
159   RETURN_IF_ERROR(BuildProgram(program, device, compiler_options));
160   return OkStatus();
161 }
162 
CreateCLProgramFromBinary(const CLContext & context,const CLDevice & device,absl::Span<const uint8_t> binary,CLProgram * result)163 Status CreateCLProgramFromBinary(const CLContext& context,
164                                  const CLDevice& device,
165                                  absl::Span<const uint8_t> binary,
166                                  CLProgram* result) {
167   cl_int binary_status;
168   cl_int error_code;
169   cl_device_id devices_list[] = {device.id()};
170   size_t binary_size = binary.size();
171   const uint8_t* binary_pointer = binary.data();
172   cl_program program = clCreateProgramWithBinary(
173       context.context(), 1, devices_list, &binary_size, &binary_pointer,
174       &binary_status, &error_code);
175   if (binary_status != CL_SUCCESS) {
176     return UnknownError(absl::StrCat(
177         "Something wrong with binary after clCreateProgramWithBinary - ",
178         binary_status));
179   }
180   if (error_code != CL_SUCCESS) {
181     return UnknownError(absl::StrCat("Failed to create program - ",
182                                      CLErrorCodeToString(error_code)));
183   }
184   *result = CLProgram(program, device.id());
185   return BuildProgram(program, device, "");
186 }
187 
188 }  // namespace cl
189 }  // namespace gpu
190 }  // namespace tflite
191