Blender  V2.93
cycles_cubin_cc.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdint.h>
18 #include <stdio.h>
19 
20 #include <string>
21 #include <vector>
22 
23 #include <OpenImageIO/argparse.h>
24 #include <OpenImageIO/filesystem.h>
25 
26 #include "cuew.h"
27 
28 #ifdef _MSC_VER
29 # include <Windows.h>
30 #endif
31 
32 using std::string;
33 using std::vector;
34 
35 namespace std {
36 template<typename T> std::string to_string(const T &n)
37 {
38  std::ostringstream s;
39  s << n;
40  return s.str();
41 }
42 } // namespace std
43 
45  public:
47  : target_arch(0), bits(64), verbose(false), fast_math(false), ptx_only(false)
48  {
49  }
50 
52  string input_file;
53  string output_file;
54  string ptx_file;
58  int bits;
59  bool verbose;
60  bool fast_math;
61  bool ptx_only;
62 };
63 
64 static bool compile_cuda(CompilationSettings &settings)
65 {
66  const char *headers[] = {"stdlib.h", "float.h", "math.h", "stdio.h", "stddef.h"};
67  const char *header_content[] = {"\n", "\n", "\n", "\n", "\n"};
68 
69  printf("Building %s\n", settings.input_file.c_str());
70 
71  string code;
72  if (!OIIO::Filesystem::read_text_file(settings.input_file, code)) {
73  fprintf(stderr, "Error: unable to read %s\n", settings.input_file.c_str());
74  return false;
75  }
76 
78  for (size_t i = 0; i < settings.includes.size(); i++) {
79  options.push_back("-I" + settings.includes[i]);
80  }
81 
82  for (size_t i = 0; i < settings.defines.size(); i++) {
83  options.push_back("-D" + settings.defines[i]);
84  }
85  options.push_back("-D__KERNEL_CUDA_VERSION__=" + std::to_string(cuewNvrtcVersion()));
86  options.push_back("-arch=compute_" + std::to_string(settings.target_arch));
87  options.push_back("--device-as-default-execution-space");
88  options.push_back("-DCYCLES_CUBIN_CC");
89  options.push_back("--std=c++11");
90  if (settings.fast_math)
91  options.push_back("--use_fast_math");
92 
93  nvrtcProgram prog;
94  nvrtcResult result = nvrtcCreateProgram(&prog,
95  code.c_str(), // buffer
96  NULL, // name
97  sizeof(headers) / sizeof(void *), // numHeaders
98  header_content, // headers
99  headers); // includeNames
100 
101  if (result != NVRTC_SUCCESS) {
102  fprintf(stderr, "Error: nvrtcCreateProgram failed (%d)\n\n", (int)result);
103  return false;
104  }
105 
106  /* Transfer options to a classic C array. */
107  vector<const char *> opts(options.size());
108  for (size_t i = 0; i < options.size(); i++) {
109  opts[i] = options[i].c_str();
110  }
111 
112  result = nvrtcCompileProgram(prog, options.size(), &opts[0]);
113 
114  if (result != NVRTC_SUCCESS) {
115  fprintf(stderr, "Error: nvrtcCompileProgram failed (%d)\n\n", (int)result);
116 
117  size_t log_size;
118  nvrtcGetProgramLogSize(prog, &log_size);
119 
120  vector<char> log(log_size);
121  nvrtcGetProgramLog(prog, &log[0]);
122  fprintf(stderr, "%s\n", &log[0]);
123 
124  return false;
125  }
126 
127  /* Retrieve the ptx code. */
128  size_t ptx_size;
129  result = nvrtcGetPTXSize(prog, &ptx_size);
130  if (result != NVRTC_SUCCESS) {
131  fprintf(stderr, "Error: nvrtcGetPTXSize failed (%d)\n\n", (int)result);
132  return false;
133  }
134 
135  vector<char> ptx_code(ptx_size);
136  result = nvrtcGetPTX(prog, &ptx_code[0]);
137  if (result != NVRTC_SUCCESS) {
138  fprintf(stderr, "Error: nvrtcGetPTX failed (%d)\n\n", (int)result);
139  return false;
140  }
141  if (settings.ptx_only) {
142  settings.ptx_file = settings.output_file;
143  }
144  else {
145  /* Write a file in the temp folder with the ptx code. */
146  settings.ptx_file = OIIO::Filesystem::temp_directory_path() + "/" +
147  OIIO::Filesystem::unique_path();
148  }
149  FILE *f = fopen(settings.ptx_file.c_str(), "wb");
150  fwrite(&ptx_code[0], 1, ptx_size, f);
151  fclose(f);
152 
153  return true;
154 }
155 
156 static bool link_ptxas(CompilationSettings &settings)
157 {
158  string cudapath = "";
159  if (settings.cuda_toolkit_dir.size())
160  cudapath = settings.cuda_toolkit_dir + "/bin/";
161 
162  string ptx = "\"" + cudapath + "ptxas\" " + settings.ptx_file + " -o " + settings.output_file +
163  " --gpu-name sm_" + std::to_string(settings.target_arch) + " -m" +
164  std::to_string(settings.bits);
165 
166  if (settings.verbose) {
167  ptx += " --verbose";
168  printf("%s\n", ptx.c_str());
169  }
170 
171  int pxresult = system(ptx.c_str());
172  if (pxresult) {
173  fprintf(stderr, "Error: ptxas failed (%d)\n\n", pxresult);
174  return false;
175  }
176 
177  if (!OIIO::Filesystem::remove(settings.ptx_file)) {
178  fprintf(stderr, "Error: removing %s\n\n", settings.ptx_file.c_str());
179  }
180 
181  return true;
182 }
183 
184 static bool init(CompilationSettings &settings)
185 {
186 #ifdef _MSC_VER
187  if (settings.cuda_toolkit_dir.size()) {
188  SetDllDirectory((settings.cuda_toolkit_dir + "/bin").c_str());
189  }
190 #else
191  (void)settings;
192 #endif
193 
194  int cuewresult = cuewInit(CUEW_INIT_NVRTC);
195  if (cuewresult != CUEW_SUCCESS) {
196  fprintf(stderr, "Error: cuew init fialed (0x%d)\n\n", cuewresult);
197  return false;
198  }
199 
200  if (cuewNvrtcVersion() < 80) {
201  fprintf(stderr, "Error: only cuda 8 and higher is supported, %d\n\n", cuewCompilerVersion());
202  return false;
203  }
204 
205  if (!nvrtcCreateProgram) {
206  fprintf(stderr, "Error: nvrtcCreateProgram not resolved\n");
207  return false;
208  }
209 
210  if (!nvrtcCompileProgram) {
211  fprintf(stderr, "Error: nvrtcCompileProgram not resolved\n");
212  return false;
213  }
214 
215  if (!nvrtcGetProgramLogSize) {
216  fprintf(stderr, "Error: nvrtcGetProgramLogSize not resolved\n");
217  return false;
218  }
219 
220  if (!nvrtcGetProgramLog) {
221  fprintf(stderr, "Error: nvrtcGetProgramLog not resolved\n");
222  return false;
223  }
224 
225  if (!nvrtcGetPTXSize) {
226  fprintf(stderr, "Error: nvrtcGetPTXSize not resolved\n");
227  return false;
228  }
229 
230  if (!nvrtcGetPTX) {
231  fprintf(stderr, "Error: nvrtcGetPTX not resolved\n");
232  return false;
233  }
234 
235  return true;
236 }
237 
238 static bool parse_parameters(int argc, const char **argv, CompilationSettings &settings)
239 {
240  OIIO::ArgParse ap;
241  ap.options("Usage: cycles_cubin_cc [options]",
242  "-target %d",
243  &settings.target_arch,
244  "target shader model",
245  "-m %d",
246  &settings.bits,
247  "Cuda architecture bits",
248  "-i %s",
249  &settings.input_file,
250  "Input source filename",
251  "-o %s",
252  &settings.output_file,
253  "Output cubin filename",
254  "-I %L",
255  &settings.includes,
256  "Add additional includepath",
257  "-D %L",
258  &settings.defines,
259  "Add additional defines",
260  "-ptx",
261  &settings.ptx_only,
262  "emit PTX code",
263  "-v",
264  &settings.verbose,
265  "Use verbose logging",
266  "--use_fast_math",
267  &settings.fast_math,
268  "Use fast math",
269  "-cuda-toolkit-dir %s",
270  &settings.cuda_toolkit_dir,
271  "path to the cuda toolkit binary directory",
272  NULL);
273 
274  if (ap.parse(argc, argv) < 0) {
275  fprintf(stderr, "%s\n", ap.geterror().c_str());
276  ap.usage();
277  return false;
278  }
279 
280  if (!settings.output_file.size()) {
281  fprintf(stderr, "Error: Output file not set(-o), required\n\n");
282  return false;
283  }
284 
285  if (!settings.input_file.size()) {
286  fprintf(stderr, "Error: Input file not set(-i, required\n\n");
287  return false;
288  }
289 
290  if (!settings.target_arch) {
291  fprintf(stderr, "Error: target shader model not set (-target), required\n\n");
292  return false;
293  }
294 
295  return true;
296 }
297 
298 int main(int argc, const char **argv)
299 {
300  CompilationSettings settings;
301 
302  if (!parse_parameters(argc, argv, settings)) {
303  fprintf(stderr, "Error: invalid parameters, exiting\n");
304  exit(EXIT_FAILURE);
305  }
306 
307  if (!init(settings)) {
308  fprintf(stderr, "Error: initialization error, exiting\n");
309  exit(EXIT_FAILURE);
310  }
311 
312  if (!compile_cuda(settings)) {
313  fprintf(stderr, "Error: compilation error, exiting\n");
314  exit(EXIT_FAILURE);
315  }
316 
317  if (!settings.ptx_only) {
318  if (!link_ptxas(settings)) {
319  exit(EXIT_FAILURE);
320  }
321  }
322 
323  return 0;
324 }
vector< string > includes
vector< string > defines
int main(int argc, const char **argv)
static bool init(CompilationSettings &settings)
static bool link_ptxas(CompilationSettings &settings)
static bool parse_parameters(int argc, const char **argv, CompilationSettings &settings)
static bool compile_cuda(CompilationSettings &settings)
CCL_NAMESPACE_BEGIN struct Options options
#define T
INLINE Rall1d< T, V, S > log(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:303
std::vector< ElementType, Eigen::aligned_allocator< ElementType > > vector
Definition: vector.h:39
std::string to_string(const T &n)