Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
149
third-party/vendor/tracy-client/src/frame.rs
vendored
Normal file
149
third-party/vendor/tracy-client/src/frame.rs
vendored
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
use crate::Client;
|
||||
|
||||
/// A non-continuous frame region.
|
||||
///
|
||||
/// Create with the [`Client::non_continuous_frame`] function.
|
||||
pub struct Frame(Client, FrameName);
|
||||
|
||||
/// A name for secondary and non-continuous frames.
|
||||
///
|
||||
/// Create with the [`frame_name!`] macro.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct FrameName(pub(crate) &'static str);
|
||||
|
||||
/// Instrumentation for global frame indicators.
|
||||
impl Client {
|
||||
/// Indicate that rendering of a continuous frame has ended.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// In a traditional rendering scenarios a frame mark should be inserted after a buffer swap.
|
||||
///
|
||||
/// ```
|
||||
/// use tracy_client::Client;
|
||||
/// # fn swap_buffers() {}
|
||||
/// # let client = tracy_client::Client::start();
|
||||
/// // loop {
|
||||
/// // ...
|
||||
/// swap_buffers();
|
||||
/// Client::running().expect("client must be running").frame_mark();
|
||||
/// // }
|
||||
/// ```
|
||||
pub fn frame_mark(&self) {
|
||||
#[cfg(feature = "enable")]
|
||||
unsafe {
|
||||
sys::___tracy_emit_frame_mark(std::ptr::null());
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicate that rendering of a secondary (named) continuous frame has ended.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Much like with the primary frame mark, the secondary (named) frame mark should be inserted
|
||||
/// after some continuously repeating operation finishes one iteration of its processing.
|
||||
///
|
||||
/// ```
|
||||
/// use tracy_client::frame_name;
|
||||
/// # fn physics_tick() {}
|
||||
/// # let client = tracy_client::Client::start();
|
||||
/// // loop {
|
||||
/// // ...
|
||||
/// physics_tick();
|
||||
/// tracy_client::Client::running()
|
||||
/// .expect("client must be running")
|
||||
/// .secondary_frame_mark(frame_name!("physics"));
|
||||
/// // }
|
||||
/// ```
|
||||
pub fn secondary_frame_mark(&self, name: FrameName) {
|
||||
#[cfg(feature = "enable")]
|
||||
unsafe {
|
||||
// SAFE: We ensured that the name would be null-terminated.
|
||||
sys::___tracy_emit_frame_mark(name.0.as_ptr().cast());
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicate that a processing of a non-continuous frame has begun.
|
||||
///
|
||||
/// Dropping the returned [`Frame`] will terminate the non-continuous frame.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tracy_client::frame_name;
|
||||
/// # let client = tracy_client::Client::start();
|
||||
/// tracy_client::Client::running()
|
||||
/// .expect("client must be running")
|
||||
/// .non_continuous_frame(frame_name!("a frame"));
|
||||
/// ```
|
||||
pub fn non_continuous_frame(&self, name: FrameName) -> Frame {
|
||||
#[cfg(feature = "enable")]
|
||||
unsafe {
|
||||
// SAFE: We ensure that the name would be null-terminated.
|
||||
sys::___tracy_emit_frame_mark_start(name.0.as_ptr().cast());
|
||||
}
|
||||
Frame(self.clone(), name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a [`FrameName`].
|
||||
///
|
||||
/// The resulting value may be used as an argument for the the [`Client::secondary_frame_mark`] and
|
||||
/// [`Client::non_continuous_frame`] methods. The macro can be used in a `const` context.
|
||||
#[macro_export]
|
||||
macro_rules! frame_name {
|
||||
($name: literal) => {{
|
||||
unsafe { $crate::internal::create_frame_name(concat!($name, "\0")) }
|
||||
}};
|
||||
}
|
||||
|
||||
impl Drop for Frame {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(feature = "enable")]
|
||||
unsafe {
|
||||
// SAFE: We ensure that thena me would be null-terminated. We also still have an owned
|
||||
// Client handle.
|
||||
sys::___tracy_emit_frame_mark_end(self.1 .0.as_ptr().cast());
|
||||
std::convert::identity(&self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience shortcut for [`Client::frame_mark`] on the current client.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - If a `Client` isn't currently running.
|
||||
pub fn frame_mark() {
|
||||
Client::running()
|
||||
.expect("frame_mark! without a running Client")
|
||||
.frame_mark();
|
||||
}
|
||||
|
||||
/// Convenience macro for [`Client::secondary_frame_mark`] on the current client.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - If a `Client` isn't currently running.
|
||||
#[macro_export]
|
||||
macro_rules! secondary_frame_mark {
|
||||
($name: literal) => {{
|
||||
$crate::Client::running()
|
||||
.expect("secondary_frame_mark! without a running Client")
|
||||
.secondary_frame_mark($crate::frame_name!($name))
|
||||
}};
|
||||
}
|
||||
|
||||
/// Convenience macro for [`Client::non_continuous_frame`] on the current client.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - If a `Client` isn't currently running.
|
||||
#[macro_export]
|
||||
macro_rules! non_continuous_frame {
|
||||
($name: literal) => {{
|
||||
$crate::Client::running()
|
||||
.expect("non_continuous_frame! without a running Client")
|
||||
.non_continuous_frame($crate::frame_name!($name))
|
||||
}};
|
||||
}
|
||||
281
third-party/vendor/tracy-client/src/lib.rs
vendored
Normal file
281
third-party/vendor/tracy-client/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
#![deny(unsafe_op_in_unsafe_fn, missing_docs)]
|
||||
#![cfg_attr(not(feature = "enable"), allow(unused_variables, unused_imports))]
|
||||
//! This crate is a set of safe bindings to the client library of the [Tracy profiler].
|
||||
//!
|
||||
//! If you have already instrumented your application with `tracing`, consider the `tracing-tracy`
|
||||
//! crate.
|
||||
//!
|
||||
//! [Tracy profiler]: https://github.com/wolfpld/tracy
|
||||
//!
|
||||
//! # Important note
|
||||
//!
|
||||
//! Depending on the configuration Tracy may broadcast discovery packets to the local network and
|
||||
//! expose the data it collects in the background to that same network. Traces collected by Tracy
|
||||
//! may include source and assembly code as well.
|
||||
//!
|
||||
//! As thus, you may want make sure to only enable the `tracy-client` crate conditionally, via
|
||||
//! the `enable` feature flag provided by this crate.
|
||||
//!
|
||||
//! # Features
|
||||
//!
|
||||
//! The following crate features are provided to customize the functionality of the Tracy client:
|
||||
//!
|
||||
#![doc = include_str!("../FEATURES.mkd")]
|
||||
#![cfg_attr(tracy_client_docs, feature(doc_auto_cfg))]
|
||||
|
||||
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;
|
||||
|
||||
/// /!\ /!\ Please don't rely on anything in this module T_T /!\ /!\
|
||||
#[doc(hidden)]
|
||||
pub mod internal {
|
||||
pub use crate::{span::SpanLocation, sys};
|
||||
pub use once_cell::sync::Lazy;
|
||||
pub use std::any::type_name;
|
||||
pub use std::ptr::null;
|
||||
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)]
|
||||
/// Safety: `name` must be null-terminated, and a `Client` must be enabled
|
||||
pub unsafe fn set_thread_name(name: *const u8) {
|
||||
#[cfg(feature = "enable")]
|
||||
unsafe {
|
||||
sys::___tracy_set_thread_name(name.cast())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A type representing an enabled Tracy client.
|
||||
///
|
||||
/// Obtaining a `Client` is required in order to instrument the application.
|
||||
///
|
||||
/// Multiple copies of a Client may be live at once. As long as at least one `Client` value lives,
|
||||
/// the `Tracy` client is enabled globally. In addition to collecting information through the
|
||||
/// instrumentation inserted by you, the Tracy client may automatically collect information about
|
||||
/// execution of the program while it is enabled. All this information may be stored in memory
|
||||
/// until a profiler application connects to the client to read the data.
|
||||
///
|
||||
/// Depending on the build configuration, the client may collect and make available machine
|
||||
/// and source code of the application as well as other potentially sensitive information.
|
||||
///
|
||||
/// When all of the `Client` values are dropped, the underlying Tracy client will be shut down as
|
||||
/// well. Shutting down the `Client` will discard any information gathered up to that point that
|
||||
/// still hasn't been delivered to the profiler application.
|
||||
pub struct Client(());
|
||||
|
||||
/// Instrumentation methods for outputting events occurring at a specific instant.
|
||||
///
|
||||
/// Data provided by this instrumentation can largely be considered to be equivalent to logs.
|
||||
impl Client {
|
||||
/// Output a message.
|
||||
///
|
||||
/// Specifying a non-zero `callstack_depth` will enable collection of callstack for this
|
||||
/// message. The number provided will limit the number of call frames collected. Note that
|
||||
/// enabling callstack collection introduces a non-trivial amount of overhead to this call.
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/// Output a message with an associated color.
|
||||
///
|
||||
/// Specifying a non-zero `callstack_depth` will enable collection of callstack for this
|
||||
/// message. The number provided will limit the number of call frames collected. Note that
|
||||
/// enabling callstack collection introduces a non-trivial amount of overhead to this call.
|
||||
///
|
||||
/// The colour shall be provided as RGBA, where the least significant 8 bits represent the alpha
|
||||
/// component and most significant 8 bits represent the red component.
|
||||
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 {
|
||||
/// Set the current thread name to the provided value.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if the name contains interior null characters.
|
||||
pub fn set_thread_name(&self, name: &str) {
|
||||
#[cfg(feature = "enable")]
|
||||
unsafe {
|
||||
let name = CString::new(name).unwrap();
|
||||
// SAFE: `name` is a valid null-terminated string.
|
||||
internal::set_thread_name(name.as_ptr().cast());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience macro for [`Client::set_thread_name`] on the current client.
|
||||
///
|
||||
/// Note that any interior null characters terminate the name early. This is not checked for.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - If a `Client` isn't currently running.
|
||||
#[macro_export]
|
||||
macro_rules! set_thread_name {
|
||||
($name: literal) => {{
|
||||
$crate::Client::running().expect("set_thread_name! without a running Client");
|
||||
unsafe {
|
||||
// SAFE: `name` is a valid null-terminated string.
|
||||
$crate::internal::set_thread_name(concat!($name, "\0").as_ptr().cast())
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// A profiling wrapper around another allocator.
|
||||
///
|
||||
/// See documentation for [`std::alloc`](std::alloc) for more information about global allocators.
|
||||
///
|
||||
/// Note that this wrapper will start up the client on the first allocation, if not enabled
|
||||
/// already.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// In your executable, add:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tracy_client::*;
|
||||
/// #[global_allocator]
|
||||
/// static GLOBAL: ProfiledAllocator<std::alloc::System> =
|
||||
/// ProfiledAllocator::new(std::alloc::System, 100);
|
||||
/// ```
|
||||
pub struct ProfiledAllocator<T>(T, u16);
|
||||
|
||||
impl<T> ProfiledAllocator<T> {
|
||||
/// Construct a new `ProfiledAllocator`.
|
||||
///
|
||||
/// Specifying a non-zero `callstack_depth` will enable collection of callstack for this
|
||||
/// message. The number provided will limit the number of call frames collected. Note that
|
||||
/// enabling callstack collection introduces a non-trivial amount of overhead to each
|
||||
/// allocation and deallocation.
|
||||
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 {
|
||||
// SAFE: all invariants satisfied by the caller.
|
||||
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 {
|
||||
// SAFE: all invariants satisfied by the caller.
|
||||
self.0.dealloc(ptr, layout)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn alloc_zeroed(&self, layout: alloc::Layout) -> *mut u8 {
|
||||
let alloc = unsafe {
|
||||
// SAFE: all invariants satisfied by the caller.
|
||||
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 {
|
||||
// SAFE: all invariants satisfied by the caller.
|
||||
self.0.realloc(ptr, layout, new_size)
|
||||
};
|
||||
self.emit_alloc(alloc, new_size);
|
||||
alloc
|
||||
}
|
||||
}
|
||||
|
||||
/// Clamp the stack depth to the maximum supported by Tracy.
|
||||
#[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
|
||||
}
|
||||
}
|
||||
53
third-party/vendor/tracy-client/src/plot.rs
vendored
Normal file
53
third-party/vendor/tracy-client/src/plot.rs
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
use crate::Client;
|
||||
|
||||
/// Name of a plot.
|
||||
///
|
||||
/// Create with the [`plot_name!`](crate::plot_name) macro.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct PlotName(pub(crate) &'static str);
|
||||
|
||||
/// Instrumentation for drawing 2D plots.
|
||||
impl Client {
|
||||
/// Add a point with an y-axis value of `value` to the plot named `plot_name`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # let client = tracy_client::Client::start();
|
||||
/// tracy_client::Client::running()
|
||||
/// .expect("client must be running")
|
||||
/// .plot(tracy_client::plot_name!("temperature"), 37.0);
|
||||
/// ```
|
||||
pub fn plot(&self, plot_name: PlotName, value: f64) {
|
||||
#[cfg(feature = "enable")]
|
||||
unsafe {
|
||||
// SAFE: We made sure the `plot` refers to a null-terminated string.
|
||||
sys::___tracy_emit_plot(plot_name.0.as_ptr().cast(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a [`PlotName`].
|
||||
///
|
||||
/// The resulting value may be used as an argument for the [`Client::plot`] method. The macro can
|
||||
/// be used in a `const` context.
|
||||
#[macro_export]
|
||||
macro_rules! plot_name {
|
||||
($name: expr) => {
|
||||
unsafe { $crate::internal::create_plot(concat!($name, "\0")) }
|
||||
};
|
||||
}
|
||||
|
||||
/// Convenience macro for [`Client::plot`] on the current client.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - If a `Client` isn't currently running.
|
||||
#[macro_export]
|
||||
macro_rules! plot {
|
||||
($name: expr, $value: expr) => {{
|
||||
$crate::Client::running()
|
||||
.expect("plot! without a running Client")
|
||||
.plot($crate::plot_name!($name), $value)
|
||||
}};
|
||||
}
|
||||
275
third-party/vendor/tracy-client/src/span.rs
vendored
Normal file
275
third-party/vendor/tracy-client/src/span.rs
vendored
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
use crate::{adjust_stack_depth, Client};
|
||||
use std::ffi::CString;
|
||||
|
||||
/// A handle representing a span of execution.
|
||||
///
|
||||
/// The trace span will be ended when this type is dropped.
|
||||
pub struct Span {
|
||||
#[cfg(feature = "enable")]
|
||||
client: Client,
|
||||
#[cfg(feature = "enable")]
|
||||
zone: sys::___tracy_c_zone_context,
|
||||
#[cfg(feature = "enable")]
|
||||
_no_send_sync: std::marker::PhantomData<*mut sys::___tracy_c_zone_context>,
|
||||
#[cfg(not(feature = "enable"))]
|
||||
_no_send_sync: std::marker::PhantomData<*mut ()>,
|
||||
}
|
||||
|
||||
/// A statically allocated location information for a span.
|
||||
///
|
||||
/// Construct with the [`span_location!`](crate::span_location) macro.
|
||||
pub struct SpanLocation {
|
||||
#[cfg(feature = "enable")]
|
||||
pub(crate) _function_name: CString,
|
||||
#[cfg(feature = "enable")]
|
||||
pub(crate) data: sys::___tracy_source_location_data,
|
||||
#[cfg(not(feature = "enable"))]
|
||||
pub(crate) _internal: (),
|
||||
}
|
||||
|
||||
unsafe impl Send for SpanLocation {}
|
||||
unsafe impl Sync for SpanLocation {}
|
||||
|
||||
/// Instrumentation for timed regions, spans or zones of execution.
|
||||
impl Client {
|
||||
/// Start a new Tracy span/zone.
|
||||
///
|
||||
/// In order to obtain a [`SpanLocation`] value to provide to this function use the
|
||||
/// [`span_location!`](crate::span_location) macro.
|
||||
///
|
||||
/// Specifying a non-zero `callstack_depth` will enable collection of callstack for this
|
||||
/// message. The number provided will limit the number of call frames collected. Note that
|
||||
/// enabling callstack collection introduces a non-trivial amount of overhead to this call. On
|
||||
/// some systems this value may be clamped to a maximum value supported by the target.
|
||||
///
|
||||
/// The [`span!`](crate::span!) macro is a convenience wrapper over this method.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// In the following example the span is created with the location at which the
|
||||
/// `span_location!` macro appears and will measure the execution of the 100ms long sleep.
|
||||
///
|
||||
/// ```rust
|
||||
/// use tracy_client::{Client, span_location};
|
||||
/// let client = Client::start();
|
||||
/// {
|
||||
/// let _span = client.span(span_location!("sleeping"), 100);
|
||||
/// std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
/// } // _span ends
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn span(self, loc: &'static SpanLocation, callstack_depth: u16) -> Span {
|
||||
#[cfg(feature = "enable")]
|
||||
unsafe {
|
||||
let zone = if callstack_depth == 0 {
|
||||
sys::___tracy_emit_zone_begin(&loc.data, 1)
|
||||
} else {
|
||||
let stack_depth = adjust_stack_depth(callstack_depth).into();
|
||||
sys::___tracy_emit_zone_begin_callstack(&loc.data, stack_depth, 1)
|
||||
};
|
||||
Span {
|
||||
client: self,
|
||||
zone,
|
||||
_no_send_sync: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "enable"))]
|
||||
Span {
|
||||
_no_send_sync: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Start a new Tracy span/zone.
|
||||
///
|
||||
/// This function allocates the span information on the heap until it is read out by the
|
||||
/// profiler. Prefer the [`Client::span`] as a allocation-free and faster alternative when
|
||||
/// possible.
|
||||
///
|
||||
/// Specifying a non-zero `callstack_depth` will enable collection of callstack for this
|
||||
/// message. The number provided will limit the number of call frames collected. Note that
|
||||
/// enabling callstack collection introduces a non-trivial amount of overhead to this call. On
|
||||
/// some systems this value may be clamped to a maximum value supported by the target.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// In the following example the span is created with custom span source data and will measure
|
||||
/// the execution of the 100ms long sleep.
|
||||
///
|
||||
/// ```rust
|
||||
/// use tracy_client::Client;
|
||||
/// let client = Client::start();
|
||||
/// {
|
||||
/// let _span = client.span_alloc(Some("hello"), "my_function", "hello.rs", 42, 100);
|
||||
/// std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
/// } // _span ends
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn span_alloc(
|
||||
self,
|
||||
name: Option<&str>,
|
||||
function: &str,
|
||||
file: &str,
|
||||
line: u32,
|
||||
callstack_depth: u16,
|
||||
) -> Span {
|
||||
#[cfg(feature = "enable")]
|
||||
unsafe {
|
||||
let loc = sys::___tracy_alloc_srcloc_name(
|
||||
line,
|
||||
file.as_ptr().cast(),
|
||||
file.len(),
|
||||
function.as_ptr().cast(),
|
||||
function.len(),
|
||||
name.map(|n| n.as_ptr().cast()).unwrap_or(std::ptr::null()),
|
||||
name.unwrap_or("").len(),
|
||||
);
|
||||
let zone = if callstack_depth == 0 {
|
||||
sys::___tracy_emit_zone_begin_alloc(loc, 1)
|
||||
} else {
|
||||
let stack_depth = adjust_stack_depth(callstack_depth).into();
|
||||
sys::___tracy_emit_zone_begin_alloc_callstack(loc, stack_depth, 1)
|
||||
};
|
||||
Span {
|
||||
client: self,
|
||||
zone,
|
||||
_no_send_sync: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "enable"))]
|
||||
Span {
|
||||
_no_send_sync: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Span {
|
||||
/// Emit a numeric value associated with this span.
|
||||
pub fn emit_value(&self, value: u64) {
|
||||
#[cfg(feature = "enable")]
|
||||
unsafe {
|
||||
// SAFE: the only way to construct `Span` is by creating a valid tracy zone context.
|
||||
sys::___tracy_emit_zone_value(self.zone, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit some text associated with this span.
|
||||
pub fn emit_text(&self, text: &str) {
|
||||
#[cfg(feature = "enable")]
|
||||
unsafe {
|
||||
// SAFE: the only way to construct `Span` is by creating a valid tracy zone context.
|
||||
sys::___tracy_emit_zone_text(self.zone, text.as_ptr().cast(), text.len());
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit a color associated with this span.
|
||||
pub fn emit_color(&self, color: u32) {
|
||||
#[cfg(feature = "enable")]
|
||||
unsafe {
|
||||
// SAFE: the only way to construct `Span` is by creating a valid tracy zone context.
|
||||
// TODO: verify if we need to shift by 8 or not...?
|
||||
sys::___tracy_emit_zone_color(self.zone, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Span {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(feature = "enable")]
|
||||
unsafe {
|
||||
// SAFE: The only way to construct `Span` is by creating a valid tracy zone context. We
|
||||
// also still have an owned Client handle.
|
||||
sys::___tracy_emit_zone_end(self.zone);
|
||||
std::convert::identity(&self.client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a <code>&'static [SpanLocation]</code>.
|
||||
///
|
||||
/// The returned `SpanLocation` is allocated statically and is cached between invocations. This
|
||||
/// `SpanLocation` will refer to the file and line at which this macro has been invoked, as well as
|
||||
/// to the item containing this macro invocation.
|
||||
///
|
||||
/// The resulting value may be used as an argument for the [`Client::span`] method.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let location: &'static tracy_client::SpanLocation = tracy_client::span_location!("some name");
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! span_location {
|
||||
() => {{
|
||||
struct S;
|
||||
// String processing in `const` when, Oli?
|
||||
static LOC: $crate::internal::Lazy<$crate::internal::SpanLocation> =
|
||||
$crate::internal::Lazy::new(|| {
|
||||
$crate::internal::make_span_location(
|
||||
$crate::internal::type_name::<S>(),
|
||||
$crate::internal::null(),
|
||||
concat!(file!(), "\0").as_ptr(),
|
||||
line!(),
|
||||
)
|
||||
});
|
||||
&*LOC
|
||||
}};
|
||||
($name: expr) => {{
|
||||
struct S;
|
||||
// String processing in `const` when, Oli?
|
||||
static LOC: $crate::internal::Lazy<$crate::internal::SpanLocation> =
|
||||
$crate::internal::Lazy::new(|| {
|
||||
$crate::internal::make_span_location(
|
||||
$crate::internal::type_name::<S>(),
|
||||
concat!($name, "\0").as_ptr(),
|
||||
concat!(file!(), "\0").as_ptr(),
|
||||
line!(),
|
||||
)
|
||||
});
|
||||
&*LOC
|
||||
}};
|
||||
}
|
||||
|
||||
/// Start a new Tracy span with function, file, and line determined automatically.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// `span!` will panic if the Client isn't running at the time this macro is invoked.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Begin a span region, which will be terminated once `_span` goes out of scope:
|
||||
///
|
||||
/// ```
|
||||
/// use tracy_client::{Client, span};
|
||||
/// # let _client = tracy_client::Client::start();
|
||||
/// let _span = span!("some span");
|
||||
/// ```
|
||||
///
|
||||
/// It is also possible to enable collection of the callstack by specifying a limit of call stack
|
||||
/// frames to record:
|
||||
///
|
||||
/// ```
|
||||
/// use tracy_client::span;
|
||||
/// # let _client = tracy_client::Client::start();
|
||||
/// let _span = span!("some span", 32);
|
||||
/// ```
|
||||
///
|
||||
/// Note, however, that collecting callstack introduces a non-trivial overhead at the point of
|
||||
/// instrumentation.
|
||||
#[macro_export]
|
||||
macro_rules! span {
|
||||
() => {
|
||||
$crate::Client::running()
|
||||
.expect("span! without a running Client")
|
||||
.span($crate::span_location!(), 0)
|
||||
};
|
||||
($name: expr) => {
|
||||
$crate::span!($name, 0)
|
||||
};
|
||||
($name: expr, $callstack_depth: expr) => {{
|
||||
let location = $crate::span_location!($name);
|
||||
$crate::Client::running()
|
||||
.expect("span! without a running Client")
|
||||
.span(location, $callstack_depth)
|
||||
}};
|
||||
}
|
||||
167
third-party/vendor/tracy-client/src/state.rs
vendored
Normal file
167
third-party/vendor/tracy-client/src/state.rs
vendored
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
use crate::Client;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
/// Enabling `Tracy` when it is already enabled, or Disabling when it is already disabled will
|
||||
/// cause applications to crash. I personally think it would be better if this was a sort-of
|
||||
/// reference counted kind-of thing so you could enable as many times as you wish and disable
|
||||
/// just as many times without any reprecursions. At the very least this could significantly
|
||||
/// help tests.
|
||||
///
|
||||
/// We can also try to implement something like this ourselves. To do this we'd want to track 4
|
||||
/// states that construct a following finite state machine:
|
||||
///
|
||||
/// ```text
|
||||
/// 0 = disabled -> 1 = enabling
|
||||
/// ^ v
|
||||
/// 3 = disabling <- 2 = enabled
|
||||
/// ```
|
||||
///
|
||||
/// And also include a reference count somewhere in there. Something we can throw in a static
|
||||
/// would be ideal.
|
||||
///
|
||||
/// Alas, Tracy's extensive use of thread-local storage presents us with another problem – we must
|
||||
/// start up and shut down the client within the same thread. A most straightforward soution for
|
||||
/// that would be to run a separate thread that would be dedicated entirely to just starting up and
|
||||
/// shutting down the profiler.
|
||||
///
|
||||
/// All that seems like a major pain to implement, and so we’ll punt on disabling entirely until
|
||||
/// somebody comes with a good use-case warranting that sort of complexity.
|
||||
#[cfg(feature = "enable")]
|
||||
#[cfg(not(loom))]
|
||||
static CLIENT_STATE: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
|
||||
#[cfg(loom)]
|
||||
loom::lazy_static! {
|
||||
static ref CLIENT_STATE: loom::sync::atomic::AtomicUsize =
|
||||
loom::sync::atomic::AtomicUsize::new(0);
|
||||
}
|
||||
|
||||
#[cfg(feature = "enable")]
|
||||
const STATE_STEP: usize = 1; // Move forward by 1 step in the FSM
|
||||
#[cfg(feature = "enable")]
|
||||
const STATE_DISABLED: usize = 0;
|
||||
#[cfg(feature = "enable")]
|
||||
const STATE_ENABLING: usize = STATE_DISABLED + STATE_STEP;
|
||||
#[cfg(feature = "enable")]
|
||||
const STATE_ENABLED: usize = STATE_ENABLING + STATE_STEP;
|
||||
|
||||
#[cfg(feature = "enable")]
|
||||
#[inline(always)]
|
||||
fn spin_loop() {
|
||||
#[cfg(loom)]
|
||||
loom::thread::yield_now();
|
||||
#[cfg(not(loom))]
|
||||
std::hint::spin_loop();
|
||||
}
|
||||
|
||||
/// Client initialization and lifetime management.
|
||||
impl Client {
|
||||
/// Start the client.
|
||||
///
|
||||
/// The client must be started with this function before any instrumentation is invoked
|
||||
/// anywhere in the process. This function can be called multiple times to obtain multiple
|
||||
/// `Client` values.
|
||||
///
|
||||
/// The underying client implementation will be started up only if it wasn't already running
|
||||
/// yet.
|
||||
///
|
||||
/// Note that there currently isn't a mechanism to stop the client once it has been started.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// // fn main() {
|
||||
/// let _client = tracy_client::Client::start();
|
||||
/// // ...
|
||||
/// // }
|
||||
/// ```
|
||||
pub fn start() -> Self {
|
||||
#[cfg(feature = "enable")]
|
||||
{
|
||||
let mut old_state = CLIENT_STATE.load(Ordering::Relaxed);
|
||||
loop {
|
||||
match old_state {
|
||||
STATE_ENABLED => return Client(()),
|
||||
STATE_ENABLING => {
|
||||
while !Self::is_running() {
|
||||
spin_loop();
|
||||
}
|
||||
return Client(());
|
||||
}
|
||||
STATE_DISABLED => {
|
||||
let result = CLIENT_STATE.compare_exchange_weak(
|
||||
old_state,
|
||||
STATE_ENABLING,
|
||||
Ordering::Relaxed,
|
||||
Ordering::Relaxed,
|
||||
);
|
||||
if let Err(next_old_state) = result {
|
||||
old_state = next_old_state;
|
||||
continue;
|
||||
} else {
|
||||
unsafe {
|
||||
// SAFE: This function must not be called if the profiler has
|
||||
// already been enabled. While in practice calling this function
|
||||
// multiple times will only serve to trigger an assertion, we
|
||||
// cannot exactly rely on this, since it is an undocumented
|
||||
// behaviour and the upstream might very well just decide to invoke
|
||||
// UB instead. In the case there are multiple copies of
|
||||
// `tracy-client` this invariant is not actually maintained, but
|
||||
// otherwise this is sound due to the `ENABLE_STATE` that we
|
||||
// manage.
|
||||
//
|
||||
// TODO: we _could_ define `ENABLE_STATE` in the `-sys` crate...
|
||||
sys::___tracy_startup_profiler();
|
||||
CLIENT_STATE.store(STATE_ENABLED, Ordering::Release);
|
||||
return Client(());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "enable"))]
|
||||
Client(())
|
||||
}
|
||||
|
||||
/// Obtain a client handle, but only if the client is already running.
|
||||
#[inline(always)]
|
||||
pub fn running() -> Option<Self> {
|
||||
if Self::is_running() {
|
||||
Some(Client(()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the client already running?
|
||||
#[inline(always)]
|
||||
pub fn is_running() -> bool {
|
||||
#[cfg(feature = "enable")]
|
||||
return CLIENT_STATE.load(Ordering::Relaxed) == STATE_ENABLED;
|
||||
#[cfg(not(feature = "enable"))]
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Client {
|
||||
/// A cheaper alternative to [`Client::start`] or [`Client::running`] when there is already a
|
||||
/// handle handy.
|
||||
#[inline(always)]
|
||||
fn clone(&self) -> Self {
|
||||
// We already know that the state is `ENABLED`, no need to check.
|
||||
Client(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "enable"))]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn state_transitions() {
|
||||
assert_eq!(0, STATE_DISABLED);
|
||||
assert_eq!(STATE_DISABLED.wrapping_add(STATE_STEP), STATE_ENABLING);
|
||||
assert_eq!(STATE_ENABLING.wrapping_add(STATE_STEP), STATE_ENABLED);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue