ptx_details/
ptx_details.rs1use std::{
2 env,
3 path::{Path, PathBuf},
4 process::Command,
5};
6
7use clap::Parser;
8use openvm_scripts::{find_cuda_include_dirs, get_cuda_dep_common_include_dirs};
9use tempfile::Builder as TempfileBuilder;
10
11#[derive(Parser)]
12#[command(author, version, about = "Compile CUDA code with nvcc")]
13struct Args {
14 #[arg(long)]
16 out: Option<PathBuf>,
17
18 #[arg(long, default_value = "nvcc")]
20 nvcc: String,
21
22 #[arg(long, env = "CUDA_PATH", default_value = "/usr/local/cuda")]
24 cuda_path: String,
25
26 #[arg(long, default_value = "89")]
28 cuda_arch: String,
29
30 #[arg(long, default_value_t = 16)]
32 threads: u32,
33
34 input: PathBuf,
36}
37
38fn add_if_exists(cmd: &mut Command, include_dir: &Path) {
39 if include_dir.exists() {
40 cmd.arg(format!("-I{}", include_dir.display()));
41 }
42}
43
44fn main() -> eyre::Result<()> {
45 let args = Args::parse();
46 let workspace_root = env::current_dir()?;
47
48 let mut include_dirs = find_cuda_include_dirs(&workspace_root);
50 include_dirs.extend(get_cuda_dep_common_include_dirs());
51
52 let (out_path, _tmp_file_guard) = match args.out {
53 Some(p) => (p, None),
54 None => {
55 let tmp = TempfileBuilder::new().suffix(".ptx").tempfile()?;
56 let path = tmp.path().to_path_buf();
57 (path, Some(tmp))
58 }
59 };
60
61 let cuda_include = PathBuf::from(&args.cuda_path).join("include");
62 let cccl_include = cuda_include.join("cccl");
63
64 let mut cmd = Command::new(&args.nvcc);
65 cmd.env("LC_ALL", "C");
66
67 cmd.args([
69 "-ccbin=c++",
70 "-Xcompiler",
71 "-O3",
72 "-Xcompiler",
73 "-ffunction-sections",
74 "-Xcompiler",
75 "-fdata-sections",
76 "-Xcompiler",
77 "-fPIC",
78 "-m64",
79 ]);
80
81 for dir in &include_dirs {
82 cmd.arg(format!("-I{}", dir.display()));
83 }
84
85 add_if_exists(&mut cmd, &cuda_include);
86 add_if_exists(&mut cmd, &cccl_include);
87
88 cmd.args([
89 "-Xcompiler",
90 "-Wall",
91 "-Xcompiler",
92 "-Wextra",
93 "--std=c++17",
94 "--expt-relaxed-constexpr",
95 "-Xfatbin=-compress-all",
96 ]);
97
98 cmd.arg("-gencode")
99 .arg(format!("arch=compute_{a},code=sm_{a}", a = args.cuda_arch));
100 cmd.arg("-gencode").arg(format!(
101 "arch=compute_{a},code=compute_{a}",
102 a = args.cuda_arch
103 ));
104 cmd.arg(format!("-t{}", args.threads));
105
106 cmd.args(["--ptxas-options=-v", "-O3"]);
107 cmd.arg("-o").arg(&out_path);
108 cmd.args(["-c", "--device-c"]);
109
110 let input = if args.input.is_absolute() {
112 args.input
113 } else {
114 workspace_root.join(args.input)
115 };
116 cmd.arg(input);
117
118 let status = cmd.status()?;
119 if !status.success() {
120 return Err(eyre::eyre!("nvcc failed with status: {status}"));
121 }
122
123 Ok(())
124}