Skip to content

Commit e45e25a

Browse files
authored
Replace backtrace crate with stabilized std::backtrace implementation (#186)
* Replace `backtrace` crate with stabilized `std::backtrace` implementation Rust 1.65 [stabilized `std::backtrace::Backtrace`], which we can use in place of the `backtrace` crate to reduce our dependency stack. Normally `Backtrace::capture()` would listen to the `RUST_BACKTRACE` and `RUST_LIB_BACKTRACE` environment variables, but this is unsuitable for us as capturing backtraces is configured via boolean debug feature flags in the `AllocatorDebugSettings` struct. Fortunately `Backtrace::force_capture()` exists which circumvents these env var checks and always returns a backtrace, and is hence used in the codebase here. Unfortuantely the type no longer implements `Clone` like `backtrace::Backtrace`, requiring us to wrap it in an `Arc` (because most of our types are thread-safe) to clone the `Backtrace` around various (sub)allocations and statistics reports. [stabilized `std::backtrace::Backtrace`]: https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#stabilized-apis * Test MSRV in CI * Bump edition to 2021 to match MSRV 1.65
1 parent 890786b commit e45e25a

File tree

12 files changed

+90
-65
lines changed

12 files changed

+90
-65
lines changed

.cargo/config.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ rustflags = [
7878
# END - Embark standard lints v6 for Rust 1.55+
7979

8080
# Our additional lints
81-
"-Wclippy::clone_on_ref_ptr",
8281
"-Wclippy::cognitive_complexity",
8382
"-Wclippy::needless_pass_by_value",
8483
"-Wclippy::option_if_let_else",

.github/workflows/ci.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,21 @@ jobs:
1818
- name: Cargo check
1919
run: cargo check --workspace --all-targets --features ${{ matrix.features }} --no-default-features
2020

21+
check_msrv:
22+
name: Check MSRV (1.65.0)
23+
strategy:
24+
matrix:
25+
include:
26+
- os: ubuntu-latest
27+
features: vulkan
28+
- os: windows-latest
29+
features: vulkan,d3d12
30+
runs-on: ${{ matrix.os }}
31+
steps:
32+
- uses: actions/checkout@v4
33+
- uses: dtolnay/rust-toolchain@1.65.0
34+
- run: cargo check --workspace --all-targets --features ${{ matrix.features }} --no-default-features
35+
2136
test:
2237
name: Test Suite
2338
strategy:

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
name = "gpu-allocator"
33
version = "0.24.0"
44
authors = ["Traverse Research <opensource@traverseresearch.nl>"]
5-
edition = "2018"
5+
edition = "2021"
66
license = "MIT OR Apache-2.0"
77
description = "Memory allocator for GPU memory in Vulkan and DirectX 12"
88
categories = ["rendering", "rendering::graphics-api"]
99
homepage = "https://github.com/Traverse-Research/gpu-allocator"
1010
repository = "https://github.com/Traverse-Research/gpu-allocator"
1111
keywords = ["vulkan", "memory", "allocator"]
1212
documentation = "https://docs.rs/gpu-allocator/"
13+
rust-version = "1.65"
1314

1415
include = [
1516
"/README.md",
@@ -19,7 +20,6 @@ include = [
1920
]
2021

2122
[dependencies]
22-
backtrace = "0.3"
2323
log = "0.4"
2424
thiserror = "1.0"
2525
presser = { version = "0.3" }

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE-MIT)
77
[![LICENSE](https://img.shields.io/badge/license-apache-blue.svg?logo=apache)](LICENSE-APACHE)
88
[![Contributor Covenant](https://img.shields.io/badge/contributor%20covenant-v1.4%20adopted-ff69b4.svg)](../main/CODE_OF_CONDUCT.md)
9+
[![MSRV](https://img.shields.io/badge/rustc-1.65.0+-ab6000.svg)](https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html)
910

1011
[![Banner](banner.png)](https://traverseresearch.nl)
1112

@@ -129,6 +130,10 @@ drop(resource);
129130
allocator.free(allocation).unwrap();
130131
```
131132

133+
## Minimum Supported Rust Version
134+
135+
The MSRV for this crate and the `vulkan` and `d3d12` features is Rust 1.65. Any other features such as the `visualizer` (with all the `egui` dependencies) may have a higher requirement and are not tested in our CI.
136+
132137
## License
133138

134139
Licensed under either of

README.tpl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE-MIT)
77
[![LICENSE](https://img.shields.io/badge/license-apache-blue.svg?logo=apache)](LICENSE-APACHE)
88
[![Contributor Covenant](https://img.shields.io/badge/contributor%20covenant-v1.4%20adopted-ff69b4.svg)](../main/CODE_OF_CONDUCT.md)
9+
[![MSRV](https://img.shields.io/badge/rustc-1.65.0+-ab6000.svg)](https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html)
910

1011
[![Banner](banner.png)](https://traverseresearch.nl)
1112

@@ -18,6 +19,10 @@ gpu-allocator = "0.24.0"
1819

1920
{{readme}}
2021

22+
## Minimum Supported Rust Version
23+
24+
The MSRV for this crate and the `vulkan` and `d3d12` features is Rust 1.65. Any other features such as the `visualizer` (with all the `egui` dependencies) may have a higher requirement and are not tested in our CI.
25+
2126
## License
2227

2328
Licensed under either of

src/allocator/dedicated_block_allocator/mod.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,20 @@
33
#[cfg(feature = "visualizer")]
44
pub(crate) mod visualizer;
55

6-
use super::{resolve_backtrace, AllocationReport, AllocationType, SubAllocator, SubAllocatorBase};
7-
use crate::{AllocationError, Result};
6+
use std::{backtrace::Backtrace, sync::Arc};
7+
88
use log::{log, Level};
99

10+
use super::{AllocationReport, AllocationType, SubAllocator, SubAllocatorBase};
11+
use crate::{AllocationError, Result};
12+
1013
#[derive(Debug)]
1114
pub(crate) struct DedicatedBlockAllocator {
1215
size: u64,
1316
allocated: u64,
17+
/// Only used if [`crate::AllocatorDebugSettings::store_stack_traces`] is [`true`]
1418
name: Option<String>,
15-
backtrace: Option<backtrace::Backtrace>,
19+
backtrace: Arc<Backtrace>,
1620
}
1721

1822
impl DedicatedBlockAllocator {
@@ -21,7 +25,7 @@ impl DedicatedBlockAllocator {
2125
size,
2226
allocated: 0,
2327
name: None,
24-
backtrace: None,
28+
backtrace: Arc::new(Backtrace::disabled()),
2529
}
2630
}
2731
}
@@ -35,7 +39,7 @@ impl SubAllocator for DedicatedBlockAllocator {
3539
_allocation_type: AllocationType,
3640
_granularity: u64,
3741
name: &str,
38-
backtrace: Option<backtrace::Backtrace>,
42+
backtrace: Arc<Backtrace>,
3943
) -> Result<(u64, std::num::NonZeroU64)> {
4044
if self.allocated != 0 {
4145
return Err(AllocationError::OutOfMemory);
@@ -86,7 +90,6 @@ impl SubAllocator for DedicatedBlockAllocator {
8690
) {
8791
let empty = "".to_string();
8892
let name = self.name.as_ref().unwrap_or(&empty);
89-
let backtrace = resolve_backtrace(&self.backtrace);
9093

9194
log!(
9295
log_level,
@@ -103,7 +106,7 @@ impl SubAllocator for DedicatedBlockAllocator {
103106
memory_block_index,
104107
self.size,
105108
name,
106-
backtrace
109+
self.backtrace
107110
)
108111
}
109112

src/allocator/free_list_allocator/mod.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@
33
#[cfg(feature = "visualizer")]
44
pub(crate) mod visualizer;
55

6-
use super::{resolve_backtrace, AllocationReport, AllocationType, SubAllocator, SubAllocatorBase};
7-
use crate::{AllocationError, Result};
6+
use std::{
7+
backtrace::Backtrace,
8+
collections::{HashMap, HashSet},
9+
sync::Arc,
10+
};
811

912
use log::{log, Level};
10-
use std::collections::{HashMap, HashSet};
13+
14+
use super::{AllocationReport, AllocationType, SubAllocator, SubAllocatorBase};
15+
use crate::{AllocationError, Result};
1116

1217
const USE_BEST_FIT: bool = true;
1318

@@ -26,7 +31,8 @@ pub(crate) struct MemoryChunk {
2631
pub(crate) offset: u64,
2732
pub(crate) allocation_type: AllocationType,
2833
pub(crate) name: Option<String>,
29-
pub(crate) backtrace: Option<backtrace::Backtrace>, // Only used if STORE_STACK_TRACES is true
34+
/// Only used if [`crate::AllocatorDebugSettings::store_stack_traces`] is [`true`]
35+
pub(crate) backtrace: Arc<Backtrace>,
3036
next: Option<std::num::NonZeroU64>,
3137
prev: Option<std::num::NonZeroU64>,
3238
}
@@ -73,7 +79,7 @@ impl FreeListAllocator {
7379
offset: 0,
7480
allocation_type: AllocationType::Free,
7581
name: None,
76-
backtrace: None,
82+
backtrace: Arc::new(Backtrace::disabled()),
7783
prev: None,
7884
next: None,
7985
},
@@ -156,7 +162,7 @@ impl SubAllocator for FreeListAllocator {
156162
allocation_type: AllocationType,
157163
granularity: u64,
158164
name: &str,
159-
backtrace: Option<backtrace::Backtrace>,
165+
backtrace: Arc<Backtrace>,
160166
) -> Result<(u64, std::num::NonZeroU64)> {
161167
let free_size = self.size - self.allocated;
162168
if size > free_size {
@@ -296,7 +302,7 @@ impl SubAllocator for FreeListAllocator {
296302
})?;
297303
chunk.allocation_type = AllocationType::Free;
298304
chunk.name = None;
299-
chunk.backtrace = None;
305+
chunk.backtrace = Arc::new(Backtrace::disabled());
300306

301307
self.allocated -= chunk.size;
302308

@@ -356,7 +362,6 @@ impl SubAllocator for FreeListAllocator {
356362
}
357363
let empty = "".to_string();
358364
let name = chunk.name.as_ref().unwrap_or(&empty);
359-
let backtrace = resolve_backtrace(&chunk.backtrace);
360365

361366
log!(
362367
log_level,
@@ -379,7 +384,7 @@ impl SubAllocator for FreeListAllocator {
379384
chunk.offset,
380385
chunk.allocation_type,
381386
name,
382-
backtrace
387+
chunk.backtrace
383388
);
384389
}
385390
}

src/allocator/mod.rs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
use std::{backtrace::Backtrace, sync::Arc};
2+
3+
use log::*;
4+
15
use crate::result::*;
26

37
pub(crate) mod dedicated_block_allocator;
@@ -6,8 +10,6 @@ pub(crate) use dedicated_block_allocator::DedicatedBlockAllocator;
610
pub(crate) mod free_list_allocator;
711
pub(crate) use free_list_allocator::FreeListAllocator;
812

9-
use log::*;
10-
1113
#[derive(PartialEq, Copy, Clone, Debug)]
1214
#[repr(u8)]
1315
pub(crate) enum AllocationType {
@@ -32,18 +34,7 @@ pub(crate) struct AllocationReport {
3234
pub(crate) name: String,
3335
pub(crate) size: u64,
3436
#[cfg(feature = "visualizer")]
35-
pub(crate) backtrace: Option<backtrace::Backtrace>,
36-
}
37-
38-
pub(crate) fn resolve_backtrace(backtrace: &Option<backtrace::Backtrace>) -> String {
39-
backtrace.as_ref().map_or_else(
40-
|| "".to_owned(),
41-
|bt| {
42-
let mut bt = bt.clone();
43-
bt.resolve();
44-
format!("{:?}", bt)
45-
},
46-
)
37+
pub(crate) backtrace: Arc<Backtrace>,
4738
}
4839

4940
#[cfg(feature = "visualizer")]
@@ -59,7 +50,7 @@ pub(crate) trait SubAllocator: SubAllocatorBase + std::fmt::Debug + Sync + Send
5950
allocation_type: AllocationType,
6051
granularity: u64,
6152
name: &str,
62-
backtrace: Option<backtrace::Backtrace>,
53+
backtrace: Arc<Backtrace>,
6354
) -> Result<(u64, std::num::NonZeroU64)>;
6455

6556
fn free(&mut self, chunk_id: Option<std::num::NonZeroU64>) -> Result<()>;

src/d3d12/mod.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![deny(clippy::unimplemented, clippy::unwrap_used, clippy::ok_expect)]
22

3-
use std::fmt;
3+
use std::{backtrace::Backtrace, fmt, sync::Arc};
44

55
use log::{debug, warn, Level};
66

@@ -421,7 +421,7 @@ impl MemoryType {
421421
&mut self,
422422
device: &ID3D12DeviceVersion,
423423
desc: &AllocationCreateDesc<'_>,
424-
backtrace: Option<backtrace::Backtrace>,
424+
backtrace: Arc<Backtrace>,
425425
allocation_sizes: &AllocationSizes,
426426
) -> Result<Allocation> {
427427
let allocation_type = AllocationType::Linear;
@@ -717,20 +717,20 @@ impl Allocator {
717717
let size = desc.size;
718718
let alignment = desc.alignment;
719719

720-
let backtrace = if self.debug_settings.store_stack_traces {
721-
Some(backtrace::Backtrace::new_unresolved())
720+
let backtrace = Arc::new(if self.debug_settings.store_stack_traces {
721+
Backtrace::force_capture()
722722
} else {
723-
None
724-
};
723+
Backtrace::disabled()
724+
});
725725

726726
if self.debug_settings.log_allocations {
727727
debug!(
728728
"Allocating `{}` of {} bytes with an alignment of {}.",
729729
&desc.name, size, alignment
730730
);
731731
if self.debug_settings.log_stack_traces {
732-
let backtrace = backtrace::Backtrace::new();
733-
debug!("Allocation stack trace: {:?}", &backtrace);
732+
let backtrace = Backtrace::force_capture();
733+
debug!("Allocation stack trace: {}", backtrace);
734734
}
735735
}
736736

@@ -761,8 +761,8 @@ impl Allocator {
761761
let name = allocation.name.as_deref().unwrap_or("<null>");
762762
debug!("Freeing `{}`.", name);
763763
if self.debug_settings.log_stack_traces {
764-
let backtrace = backtrace::Backtrace::new();
765-
debug!("Free stack trace: {:?}", backtrace);
764+
let backtrace = Backtrace::force_capture();
765+
debug!("Free stack trace: {}", backtrace);
766766
}
767767
}
768768

src/visualizer/allocation_reports.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
use std::backtrace::BacktraceStatus;
2+
13
use egui::{Label, Response, Sense, Ui, WidgetText};
24
use egui_extras::{Column, TableBuilder};
35

4-
use crate::allocator::{fmt_bytes, resolve_backtrace, AllocationReport};
6+
use crate::allocator::{fmt_bytes, AllocationReport};
57

68
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
79
pub(crate) enum AllocationReportVisualizeSorting {
@@ -121,9 +123,9 @@ pub(crate) fn render_allocation_reports_ui(
121123
ui.label(name);
122124
});
123125

124-
if backtrace.is_some() {
126+
if backtrace.status() == BacktraceStatus::Captured {
125127
resp.1.on_hover_ui(|ui| {
126-
ui.label(resolve_backtrace(&backtrace));
128+
ui.label(backtrace.to_string());
127129
});
128130
}
129131

0 commit comments

Comments
 (0)