Skip to content

Commit 5c8e81b

Browse files
authored
Merge pull request #651 from vlovich/fix-cpu-performance-debug-builds
Fix cpu performance debug builds
2 parents 04e9e31 + 5a4dbd4 commit 5c8e81b

File tree

1 file changed

+112
-50
lines changed

1 file changed

+112
-50
lines changed

llama-cpp-sys-2/build.rs

Lines changed: 112 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,23 @@ use std::path::{Path, PathBuf};
55
use std::process::Command;
66
use walkdir::DirEntry;
77

8+
enum WindowsVariant {
9+
Msvc,
10+
Other,
11+
}
12+
13+
enum AppleVariant {
14+
MacOS,
15+
Other,
16+
}
17+
18+
enum TargetOs {
19+
Windows(WindowsVariant),
20+
Apple(AppleVariant),
21+
Linux,
22+
Android,
23+
}
24+
825
macro_rules! debug_log {
926
($($arg:tt)*) => {
1027
if std::env::var("BUILD_DEBUG").is_ok() {
@@ -13,6 +30,30 @@ macro_rules! debug_log {
1330
};
1431
}
1532

33+
fn parse_target_os() -> Result<(TargetOs, String), String> {
34+
let target = env::var("TARGET").unwrap();
35+
36+
if target.contains("windows") {
37+
if target.ends_with("-windows-msvc") {
38+
Ok((TargetOs::Windows(WindowsVariant::Msvc), target))
39+
} else {
40+
Ok((TargetOs::Windows(WindowsVariant::Other), target))
41+
}
42+
} else if target.contains("linux") {
43+
Ok((TargetOs::Linux, target))
44+
} else if target.contains("apple") {
45+
if target.ends_with("-apple-darwin") {
46+
Ok((TargetOs::Apple(AppleVariant::MacOS), target))
47+
} else {
48+
Ok((TargetOs::Apple(AppleVariant::Other), target))
49+
}
50+
} else if target.contains("android") {
51+
Ok((TargetOs::Android, target))
52+
} else {
53+
Err(target)
54+
}
55+
}
56+
1657
fn get_cargo_target_dir() -> Result<PathBuf, Box<dyn std::error::Error>> {
1758
let out_dir = env::var("OUT_DIR")?;
1859
let path = PathBuf::from(out_dir);
@@ -132,7 +173,8 @@ fn is_hidden(e: &DirEntry) -> bool {
132173
fn main() {
133174
println!("cargo:rerun-if-changed=build.rs");
134175

135-
let target = env::var("TARGET").unwrap();
176+
let (target_os, target_triple) =
177+
parse_target_os().unwrap_or_else(|t| panic!("Failed to parse target os {t}"));
136178
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
137179

138180
let target_dir = get_cargo_target_dir().unwrap();
@@ -152,7 +194,7 @@ fn main() {
152194
println!("cargo:rerun-if-env-changed=LLAMA_BUILD_SHARED_LIBS");
153195
println!("cargo:rerun-if-env-changed=LLAMA_STATIC_CRT");
154196

155-
debug_log!("TARGET: {}", target);
197+
debug_log!("TARGET: {}", target_triple);
156198
debug_log!("CARGO_MANIFEST_DIR: {}", manifest_dir);
157199
debug_log!("TARGET_DIR: {}", target_dir.display());
158200
debug_log!("OUT_DIR: {}", out_dir.display());
@@ -232,15 +274,29 @@ fn main() {
232274
if build_shared_libs { "ON" } else { "OFF" },
233275
);
234276

235-
if cfg!(target_os = "macos") {
277+
if matches!(target_os, TargetOs::Apple(_)) {
236278
config.define("GGML_BLAS", "OFF");
237279
}
238280

239-
if cfg!(windows) {
240-
config.static_crt(static_crt);
281+
if (cfg!(debug_assertions)
282+
|| std::env::var("PROFILE").as_ref().map(String::as_str) == Ok("debug"))
283+
&& matches!(target_os, TargetOs::Windows(WindowsVariant::Msvc))
284+
&& profile == "Release"
285+
{
286+
// Debug Rust builds under MSVC turn off optimization even though we're ideally building the release profile of llama.cpp.
287+
// Looks like an upstream bug:
288+
// https://github.com/rust-lang/cmake-rs/issues/240
289+
// For now explicitly reinject the optimization flags that a CMake Release build is expected to have on in this scenario.
290+
// This fixes CPU inference performance when part of a Rust debug build.
291+
for flag in &["/O2", "/DNDEBUG", "/Ob2"] {
292+
config.cflag(flag);
293+
config.cxxflag(flag);
294+
}
241295
}
242296

243-
if target.contains("android") {
297+
config.static_crt(static_crt);
298+
299+
if matches!(target_os, TargetOs::Android) {
244300
// build flags for android taken from this doc
245301
// https://github.com/ggerganov/llama.cpp/blob/master/docs/android.md
246302
let android_ndk = env::var("ANDROID_NDK")
@@ -257,21 +313,21 @@ fn main() {
257313
} else {
258314
config.define("ANDROID_PLATFORM", "android-28");
259315
}
260-
if target.contains("aarch64") {
316+
if target_triple.contains("aarch64") {
261317
config.cflag("-march=armv8.7a");
262318
config.cxxflag("-march=armv8.7a");
263-
} else if target.contains("armv7") {
319+
} else if target_triple.contains("armv7") {
264320
config.cflag("-march=armv8.7a");
265321
config.cxxflag("-march=armv8.7a");
266-
} else if target.contains("x86_64") {
322+
} else if target_triple.contains("x86_64") {
267323
config.cflag("-march=x86-64");
268324
config.cxxflag("-march=x86-64");
269-
} else if target.contains("i686") {
325+
} else if target_triple.contains("i686") {
270326
config.cflag("-march=i686");
271327
config.cxxflag("-march=i686");
272328
} else {
273329
// Rather than guessing just fail.
274-
panic!("Unsupported Android target {target}");
330+
panic!("Unsupported Android target {target_triple}");
275331
}
276332
config.define("GGML_LLAMAFILE", "OFF");
277333
if cfg!(feature = "shared-stdcxx") {
@@ -282,16 +338,19 @@ fn main() {
282338

283339
if cfg!(feature = "vulkan") {
284340
config.define("GGML_VULKAN", "ON");
285-
if cfg!(windows) {
286-
let vulkan_path = env::var("VULKAN_SDK")
287-
.expect("Please install Vulkan SDK and ensure that VULKAN_SDK env variable is set");
288-
let vulkan_lib_path = Path::new(&vulkan_path).join("Lib");
289-
println!("cargo:rustc-link-search={}", vulkan_lib_path.display());
290-
println!("cargo:rustc-link-lib=vulkan-1");
291-
}
292-
293-
if cfg!(target_os = "linux") {
294-
println!("cargo:rustc-link-lib=vulkan");
341+
match target_os {
342+
TargetOs::Windows(_) => {
343+
let vulkan_path = env::var("VULKAN_SDK").expect(
344+
"Please install Vulkan SDK and ensure that VULKAN_SDK env variable is set",
345+
);
346+
let vulkan_lib_path = Path::new(&vulkan_path).join("Lib");
347+
println!("cargo:rustc-link-search={}", vulkan_lib_path.display());
348+
println!("cargo:rustc-link-lib=vulkan-1");
349+
}
350+
TargetOs::Linux => {
351+
println!("cargo:rustc-link-lib=vulkan");
352+
}
353+
_ => (),
295354
}
296355
}
297356

@@ -302,7 +361,7 @@ fn main() {
302361
// Android doesn't have OpenMP support AFAICT and openmp is a default feature. Do this here
303362
// rather than modifying the defaults in Cargo.toml just in case someone enables the OpenMP feature
304363
// and tries to build for Android anyway.
305-
if cfg!(feature = "openmp") && !target.contains("android") {
364+
if cfg!(feature = "openmp") && !matches!(target_os, TargetOs::Android) {
306365
config.define("GGML_OPENMP", "ON");
307366
} else {
308367
config.define("GGML_OPENMP", "OFF");
@@ -341,38 +400,41 @@ fn main() {
341400
}
342401

343402
// OpenMP
344-
if cfg!(feature = "openmp") && target.contains("gnu") {
403+
if cfg!(feature = "openmp") && target_triple.contains("gnu") {
345404
println!("cargo:rustc-link-lib=gomp");
346405
}
347406

348-
// Windows debug
349-
if cfg!(all(debug_assertions, windows)) {
350-
println!("cargo:rustc-link-lib=dylib=msvcrtd");
351-
}
352-
353-
// // macOS
354-
if cfg!(target_os = "macos") {
355-
println!("cargo:rustc-link-lib=framework=Foundation");
356-
println!("cargo:rustc-link-lib=framework=Metal");
357-
println!("cargo:rustc-link-lib=framework=MetalKit");
358-
println!("cargo:rustc-link-lib=framework=Accelerate");
359-
println!("cargo:rustc-link-lib=c++");
360-
}
361-
362-
// Linux
363-
if cfg!(target_os = "linux") {
364-
println!("cargo:rustc-link-lib=dylib=stdc++");
365-
}
366-
367-
if target.contains("apple") {
368-
// On (older) OSX we need to link against the clang runtime,
369-
// which is hidden in some non-default path.
370-
//
371-
// More details at https://github.com/alexcrichton/curl-rust/issues/279.
372-
if let Some(path) = macos_link_search_path() {
373-
println!("cargo:rustc-link-lib=clang_rt.osx");
374-
println!("cargo:rustc-link-search={}", path);
407+
match target_os {
408+
TargetOs::Windows(WindowsVariant::Msvc) => {
409+
if cfg!(debug_assertions) {
410+
println!("cargo:rustc-link-lib=dylib=msvcrtd");
411+
}
412+
}
413+
TargetOs::Linux => {
414+
println!("cargo:rustc-link-lib=dylib=stdc++");
415+
}
416+
TargetOs::Apple(variant) => {
417+
println!("cargo:rustc-link-lib=framework=Foundation");
418+
println!("cargo:rustc-link-lib=framework=Metal");
419+
println!("cargo:rustc-link-lib=framework=MetalKit");
420+
println!("cargo:rustc-link-lib=framework=Accelerate");
421+
println!("cargo:rustc-link-lib=c++");
422+
423+
match variant {
424+
AppleVariant::MacOS => {
425+
// On (older) OSX we need to link against the clang runtime,
426+
// which is hidden in some non-default path.
427+
//
428+
// More details at https://github.com/alexcrichton/curl-rust/issues/279.
429+
if let Some(path) = macos_link_search_path() {
430+
println!("cargo:rustc-link-lib=clang_rt.osx");
431+
println!("cargo:rustc-link-search={}", path);
432+
}
433+
}
434+
AppleVariant::Other => (),
435+
}
375436
}
437+
_ => (),
376438
}
377439

378440
// copy DLLs to target

0 commit comments

Comments
 (0)