#![deny(unsafe_op_in_unsafe_fn, missing_docs)]
#![cfg_attr(not(feature = "enable"), allow(unused_variables, unused_imports))]
pub use crate::frame::{frame_mark, Frame, FrameName};
pub use crate::plot::PlotName;
pub use crate::span::{Span, SpanLocation};
use std::alloc;
use std::ffi::CString;
pub use sys;
mod frame;
mod plot;
mod span;
mod state;
#[doc(hidden)]
pub mod internal {
pub use crate::{span::SpanLocation, sys};
pub use once_cell::sync::Lazy;
pub use std::any::type_name;
use std::ffi::CString;
#[inline(always)]
pub fn make_span_location(
type_name: &'static str,
span_name: *const u8,
file: *const u8,
line: u32,
) -> crate::SpanLocation {
#[cfg(feature = "enable")]
{
let function_name = CString::new(&type_name[..type_name.len() - 3]).unwrap();
crate::SpanLocation {
data: crate::sys::___tracy_source_location_data {
name: span_name.cast(),
function: function_name.as_ptr(),
file: file.cast(),
line,
color: 0,
},
_function_name: function_name,
}
}
#[cfg(not(feature = "enable"))]
crate::SpanLocation { _internal: () }
}
#[inline(always)]
pub const unsafe fn create_frame_name(name: &'static str) -> crate::frame::FrameName {
crate::frame::FrameName(name)
}
#[inline(always)]
pub const unsafe fn create_plot(name: &'static str) -> crate::plot::PlotName {
crate::plot::PlotName(name)
}
#[inline(always)]
pub unsafe fn set_thread_name(name: *const u8) {
#[cfg(feature = "enable")]
unsafe {
sys::___tracy_set_thread_name(name.cast())
}
}
}
pub struct Client(());
impl Client {
pub fn message(&self, message: &str, callstack_depth: u16) {
#[cfg(feature = "enable")]
unsafe {
let stack_depth = adjust_stack_depth(callstack_depth).into();
sys::___tracy_emit_message(message.as_ptr().cast(), message.len(), stack_depth)
}
}
pub fn color_message(&self, message: &str, rgba: u32, callstack_depth: u16) {
#[cfg(feature = "enable")]
unsafe {
let depth = adjust_stack_depth(callstack_depth).into();
sys::___tracy_emit_messageC(message.as_ptr().cast(), message.len(), rgba >> 8, depth)
}
}
}
impl Client {
pub fn set_thread_name(&self, name: &str) {
#[cfg(feature = "enable")]
unsafe {
let name = CString::new(name).unwrap();
internal::set_thread_name(name.as_ptr().cast());
}
}
}
#[macro_export]
macro_rules! set_thread_name {
($name: literal) => {{
$crate::Client::running().expect("set_thread_name! without a running Client");
unsafe {
$crate::internal::set_thread_name(concat!($name, "\0").as_ptr().cast())
}
}};
}
pub struct ProfiledAllocator<T>(T, u16);
impl<T> ProfiledAllocator<T> {
pub const fn new(inner_allocator: T, callstack_depth: u16) -> Self {
Self(inner_allocator, adjust_stack_depth(callstack_depth))
}
fn emit_alloc(&self, ptr: *mut u8, size: usize) {
#[cfg(feature = "enable")]
unsafe {
Client::start();
if self.1 == 0 {
sys::___tracy_emit_memory_alloc(ptr.cast(), size, 1);
} else {
sys::___tracy_emit_memory_alloc_callstack(ptr.cast(), size, self.1.into(), 1);
}
}
}
fn emit_free(&self, ptr: *mut u8) {
#[cfg(feature = "enable")]
unsafe {
if self.1 == 0 {
sys::___tracy_emit_memory_free(ptr.cast(), 1);
} else {
sys::___tracy_emit_memory_free_callstack(ptr.cast(), self.1.into(), 1);
}
}
}
}
unsafe impl<T: alloc::GlobalAlloc> alloc::GlobalAlloc for ProfiledAllocator<T> {
unsafe fn alloc(&self, layout: alloc::Layout) -> *mut u8 {
let alloc = unsafe {
self.0.alloc(layout)
};
self.emit_alloc(alloc, layout.size());
alloc
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: alloc::Layout) {
self.emit_free(ptr);
unsafe {
self.0.dealloc(ptr, layout)
}
}
unsafe fn alloc_zeroed(&self, layout: alloc::Layout) -> *mut u8 {
let alloc = unsafe {
self.0.alloc_zeroed(layout)
};
self.emit_alloc(alloc, layout.size());
alloc
}
unsafe fn realloc(&self, ptr: *mut u8, layout: alloc::Layout, new_size: usize) -> *mut u8 {
self.emit_free(ptr);
let alloc = unsafe {
self.0.realloc(ptr, layout, new_size)
};
self.emit_alloc(alloc, new_size);
alloc
}
}
#[inline(always)]
pub(crate) const fn adjust_stack_depth(depth: u16) -> u16 {
#[cfg(windows)]
{
62 ^ ((depth ^ 62) & 0u16.wrapping_sub((depth < 62) as _))
}
#[cfg(not(windows))]
{
depth
}
}