Conversation
| ptr | ||
| } | ||
|
|
||
| unsafe fn realloc(&self, ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut u8 { |
There was a problem hiding this comment.
We should be reporting the deallocation as well.
| unsafe fn realloc(&self, ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut u8 { | |
| unsafe fn realloc(&self, ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut u8 { | |
| self.tracy_dealloc(ptr); |
There was a problem hiding this comment.
I'm following the example of tracy-client here:
It made sense to me since the ptr uniquely identifies the allocation until it gets freed. So if the client sees a multiple alloc events on the same ptr it must mean a realloc. (Whether the Tracy client actually does this, I don't know).
There was a problem hiding this comment.
nvm, I'm blind. tracy-client does emit a free right here:
| .current | ||
| .fetch_add(size, Ordering::SeqCst) | ||
| .wrapping_add(size); | ||
| self.max.fetch_max(current, Ordering::SeqCst); |
There was a problem hiding this comment.
Nit, between fetch_add and fetch_max, another thread could update max, causing the local current calculation to be stale, we can avoid this by using fetch_update
| self.max.fetch_max(current, Ordering::SeqCst); | |
| self.max.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |max_val| { | |
| let new_current = self.current.load(Ordering::SeqCst); | |
| (new_current > max_val).then_some(new_current) | |
| }).ok(); |
There was a problem hiding this comment.
Thought about this, it should be fine! The current value computed here is always accurate at that sequence point. Some thread might compute an earlier or a later value of current, but the max operation is a join, so doesn't matter if it gets sequenced as
self.max.fetch_max(current_old, Ordering::SeqCst);
self.max.fetch_max(current_new, Ordering::SeqCst);
self.max.fetch_max(current_new, Ordering::SeqCst);
self.max.fetch_max(current_old, Ordering::SeqCst);
The end result is going to be that max contains max(old_max, current_old, current_new). Similarly if there are more parallel threads.
The one exception to this may be if a concurrent thread resets the maximum.
| /// enable tracy allocation tracking with provided stack depth | ||
| #[cfg(feature = "tracy")] | ||
| #[argh(option)] | ||
| pub tracy_allocations: Option<usize>, |
There was a problem hiding this comment.
UX improvement
| pub tracy_allocations: Option<usize>, | |
| #[argh(option, default = "0")] | |
| pub tracy_allocations: usize, |
and in main.rs
if args.tracy {
if args.tracy_allocations > 0 {
info!("Tracy enabled with allocation tracking (depth {}).", args.tracy_allocations);
ALLOCATOR.enable_tracy(args.tracy_allocations);
} else {
info!("Tracy enabled (no allocation tracking).");
}
}There was a problem hiding this comment.
There's actually a difference between 'off' and 'zero depth'. With zero depth we still collect allocation events, but we do not include stack traces (in fact, there is special code in the Allocator to handle this). With 'off' we do not collect allocation events in Tracy at all.
| unsafe { | ||
| tracy_client_sys::___tracy_shutdown_profiler(); | ||
| // | ||
| // @recmo: This is not safe. tracing_tracy may still |
There was a problem hiding this comment.
I think to handle this we can do one of the two things,
- Remove it
Pro: No crashes. Con: Lose last ~100ms of trace data. - Grace period (~100 ms)
Pro: Usually works. Con: Still has race condition, just smaller window.
There was a problem hiding this comment.
Con: Lose last ~100ms of trace data.
It's worse unfortunately. There could be an unbounded backlog of data still to be transmitted. This actually happened all the time before this PR when we did 100-depth stacktraces on each allocation (times 90M allocations is gigabytes of data to transfer over what seems a very poorly implemented IPC bus).
I checked, but there doesn't seem to be a 'flush' function that keeps the Tracy client alive, but clears the backlog.
There was a problem hiding this comment.
I guess the best solution here is to manually implement TRACY_NO_EXIT with something like "Keeping alive for Tracy connections. Press any key to exit."
|
LGTM |




Before, the default features disabled all logging. To enable even basic logging you'd had to enable
profilngwhich also enabled a very expensive Tracy stack trace for each allocation, blowing up runtime by 4x. This changes:tracing_tracyto avoid version mismatch.