Skip to main content

gpu_allocator/allocator/dedicated_block_allocator/
mod.rs

1#![deny(unsafe_code, clippy::unwrap_used)]
2#[cfg(feature = "std")]
3use alloc::sync::Arc;
4use alloc::{
5    borrow::ToOwned,
6    string::{String, ToString},
7    vec::Vec,
8};
9#[cfg(feature = "std")]
10use std::backtrace::Backtrace;
11
12use log::{log, Level};
13
14#[cfg(feature = "visualizer")]
15pub(crate) mod visualizer;
16
17use super::{AllocationReport, AllocationType, SubAllocator, SubAllocatorBase};
18use crate::{AllocationError, Result};
19
20#[derive(Debug)]
21pub(crate) struct DedicatedBlockAllocator {
22    size: u64,
23    allocated: u64,
24    /// Only used if [`crate::AllocatorDebugSettings::store_stack_traces`] is [`true`]
25    name: Option<String>,
26    #[cfg(feature = "std")]
27    backtrace: Arc<Backtrace>,
28}
29
30impl DedicatedBlockAllocator {
31    pub(crate) fn new(size: u64) -> Self {
32        Self {
33            size,
34            allocated: 0,
35            name: None,
36            #[cfg(feature = "std")]
37            backtrace: Arc::new(Backtrace::disabled()),
38        }
39    }
40}
41
42impl SubAllocatorBase for DedicatedBlockAllocator {}
43impl SubAllocator for DedicatedBlockAllocator {
44    fn allocate(
45        &mut self,
46        size: u64,
47        _alignment: u64,
48        _allocation_type: AllocationType,
49        _granularity: u64,
50        name: &str,
51        #[cfg(feature = "std")] backtrace: Arc<Backtrace>,
52    ) -> Result<(u64, core::num::NonZeroU64)> {
53        if self.allocated != 0 {
54            return Err(AllocationError::OutOfMemory);
55        }
56
57        if self.size != size {
58            return Err(AllocationError::Internal(
59                "DedicatedBlockAllocator size must match allocation size.".into(),
60            ));
61        }
62
63        self.allocated = size;
64        self.name = Some(name.to_string());
65        #[cfg(feature = "std")]
66        {
67            self.backtrace = backtrace;
68        }
69
70        #[allow(clippy::unwrap_used)]
71        let dummy_id = core::num::NonZeroU64::new(1).unwrap();
72        Ok((0, dummy_id))
73    }
74
75    fn free(&mut self, chunk_id: Option<core::num::NonZeroU64>) -> Result<()> {
76        if chunk_id != core::num::NonZeroU64::new(1) {
77            Err(AllocationError::Internal("Chunk ID must be 1.".into()))
78        } else {
79            self.allocated = 0;
80            Ok(())
81        }
82    }
83
84    fn rename_allocation(
85        &mut self,
86        chunk_id: Option<core::num::NonZeroU64>,
87        name: &str,
88    ) -> Result<()> {
89        if chunk_id != core::num::NonZeroU64::new(1) {
90            Err(AllocationError::Internal("Chunk ID must be 1.".into()))
91        } else {
92            self.name = Some(name.into());
93            Ok(())
94        }
95    }
96
97    fn report_memory_leaks(
98        &self,
99        log_level: Level,
100        memory_type_index: usize,
101        memory_block_index: usize,
102    ) {
103        let empty = "".to_string();
104        let name = self.name.as_ref().unwrap_or(&empty);
105        let backtrace_info;
106        #[cfg(feature = "std")]
107        {
108            // TODO: Allocation could be avoided here if https://github.com/rust-lang/rust/pull/139135 is merged and stabilized.
109            backtrace_info = format!(
110                ",
111        backtrace: {}",
112                self.backtrace
113            )
114        }
115        #[cfg(not(feature = "std"))]
116        {
117            backtrace_info = ""
118        }
119
120        log!(
121            log_level,
122            r#"leak detected: {{
123    memory type: {}
124    memory block: {}
125    dedicated allocation: {{
126        size: 0x{:x},
127        name: {}{backtrace_info}
128    }}
129}}"#,
130            memory_type_index,
131            memory_block_index,
132            self.size,
133            name,
134        );
135    }
136
137    fn report_allocations(&self) -> Vec<AllocationReport> {
138        vec![AllocationReport {
139            name: self
140                .name
141                .clone()
142                .unwrap_or_else(|| "<Unnamed Dedicated allocation>".to_owned()),
143            offset: 0,
144            size: self.size,
145            #[cfg(feature = "visualizer")]
146            backtrace: self.backtrace.clone(),
147        }]
148    }
149
150    fn allocated(&self) -> u64 {
151        self.allocated
152    }
153
154    fn supports_general_allocations(&self) -> bool {
155        false
156    }
157}