summaryrefslogtreecommitdiffstats
path: root/third_party/rust/tracy-rs/src/profiler.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/tracy-rs/src/profiler.rs')
-rw-r--r--third_party/rust/tracy-rs/src/profiler.rs189
1 files changed, 189 insertions, 0 deletions
diff --git a/third_party/rust/tracy-rs/src/profiler.rs b/third_party/rust/tracy-rs/src/profiler.rs
new file mode 100644
index 0000000000..220aa955e8
--- /dev/null
+++ b/third_party/rust/tracy-rs/src/profiler.rs
@@ -0,0 +1,189 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use minidl::Library;
+
+// Must match `___tracy_source_location_data` struct in TracyC.h
+#[repr(C)]
+pub struct SourceLocation {
+ pub name: *const u8,
+ pub function: *const u8,
+ pub file: *const u8,
+ pub line: u32,
+ pub color: u32,
+}
+
+// Must match `___tracy_c_zone_context` in TracyC.h
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct ZoneContext {
+ id: u32,
+ active: i32,
+}
+
+// Define a set of no-op implementation functions that are called if the tracy
+// shared library is not loaded.
+extern "C" fn unimpl_mark_frame(_: *const u8) {}
+extern "C" fn unimpl_mark_frame_start(_: *const u8) {}
+extern "C" fn unimpl_mark_frame_end(_: *const u8) {}
+extern "C" fn unimpl_zone_begin(_: *const SourceLocation, _: i32) -> ZoneContext {
+ ZoneContext {
+ id: 0,
+ active: 0,
+ }
+}
+extern "C" fn unimpl_zone_end(_: ZoneContext) {}
+extern "C" fn unimpl_zone_text(_: ZoneContext, _: *const u8, _: usize) {}
+
+extern "C" fn unimpl_plot(_: *const u8, _: f64) {}
+
+// Function pointers to the tracy API functions (if loaded), or the no-op functions above.
+pub static mut MARK_FRAME: extern "C" fn(name: *const u8) = unimpl_mark_frame;
+pub static mut MARK_FRAME_START: extern "C" fn(name: *const u8) = unimpl_mark_frame_start;
+pub static mut MARK_FRAME_END: extern "C" fn(name: *const u8) = unimpl_mark_frame_end;
+pub static mut EMIT_ZONE_BEGIN: extern "C" fn(srcloc: *const SourceLocation, active: i32) -> ZoneContext = unimpl_zone_begin;
+pub static mut EMIT_ZONE_END: extern "C" fn(ctx: ZoneContext) = unimpl_zone_end;
+pub static mut EMIT_ZONE_TEXT: extern "C" fn(ctx: ZoneContext, txt: *const u8, size: usize) = unimpl_zone_text;
+pub static mut EMIT_PLOT: extern "C" fn(name: *const u8, val: f64) = unimpl_plot;
+
+// Load the tracy library, and get function pointers. This is unsafe since:
+// - It must not be called while other threads are calling the functions.
+// - It doesn't ensure that the library is not unloaded during use.
+pub unsafe fn load(path: &str) -> bool {
+ match Library::load(path) {
+ Ok(lib) => {
+ // If lib loading succeeds, assume we can find all the symbols required.
+ MARK_FRAME = lib.sym("___tracy_emit_frame_mark\0").unwrap();
+ MARK_FRAME_START = lib.sym("___tracy_emit_frame_mark_start\0").unwrap();
+ MARK_FRAME_END = lib.sym("___tracy_emit_frame_mark_end\0").unwrap();
+ EMIT_ZONE_BEGIN = lib.sym("___tracy_emit_zone_begin\0").unwrap();
+ EMIT_ZONE_END = lib.sym("___tracy_emit_zone_end\0").unwrap();
+ EMIT_ZONE_TEXT = lib.sym("___tracy_emit_zone_text\0").unwrap();
+ EMIT_PLOT = lib.sym("___tracy_emit_plot\0").unwrap();
+
+ true
+ }
+ Err(..) => {
+ println!("Failed to load the tracy profiling library!");
+
+ false
+ }
+ }
+}
+
+/// A simple stack scope for tracing function execution time
+pub struct ProfileScope {
+ ctx: ZoneContext,
+}
+
+impl ProfileScope {
+ pub fn new(callsite: &'static SourceLocation) -> Self {
+ let ctx = unsafe { EMIT_ZONE_BEGIN(callsite, 1) };
+
+ ProfileScope {
+ ctx,
+ }
+ }
+
+ pub fn text(&self, text: &[u8]) {
+ unsafe { EMIT_ZONE_TEXT(self.ctx, text.as_ptr(), text.len()) };
+ }
+}
+
+impl Drop for ProfileScope {
+ fn drop(&mut self) {
+ unsafe {
+ EMIT_ZONE_END(self.ctx)
+ }
+ }
+}
+
+/// Define a profiling scope.
+///
+/// This macro records a Tracy 'zone' starting at the point at which the macro
+/// occurs, and extending to the end of the block. More precisely, the zone ends
+/// when a variable declared by this macro would be dropped, so early returns
+/// exit the zone.
+///
+/// For example:
+///
+/// fn an_operation_that_may_well_take_a_long_time() {
+/// profile_scope!("an_operation_that_may_well_take_a_long_time");
+/// ...
+/// }
+///
+/// The first argument to `profile_scope!` is the name of the zone, and must be
+/// a string literal.
+///
+/// Tracy zones can also have associated 'text' values that vary from one
+/// execution to the next - for example, a zone's text might record the name of
+/// the file being processed. The text must be a `CStr` value. You can provide
+/// zone text like this:
+///
+/// fn run_reftest(test_name: &str) {
+/// profile_scope!("run_reftest", text: test_name);
+/// ...
+/// }
+#[macro_export]
+macro_rules! profile_scope {
+ ($string:literal $(, text: $text:expr )? ) => {
+ const CALLSITE: $crate::profiler::SourceLocation = $crate::profiler::SourceLocation {
+ name: concat!($string, "\0").as_ptr(),
+ function: concat!(module_path!(), "\0").as_ptr(),
+ file: concat!(file!(), "\0").as_ptr(),
+ line: line!(),
+ color: 0xff0000ff,
+ };
+
+ let _profile_scope = $crate::profiler::ProfileScope::new(&CALLSITE);
+
+ $(
+ _profile_scope.text(str::as_bytes($text));
+ )?
+ }
+}
+
+/// Define the main frame marker, typically placed after swap_buffers or similar.
+#[macro_export]
+macro_rules! tracy_frame_marker {
+ () => {
+ unsafe {
+ $crate::profiler::MARK_FRAME(std::ptr::null())
+ }
+ }
+}
+
+/// Define start of an explicit frame marker, typically used for sub-frames.
+#[macro_export]
+macro_rules! tracy_begin_frame {
+ ($name:expr) => {
+ unsafe {
+ $crate::profiler::MARK_FRAME_START(concat!($name, "\0").as_ptr())
+ }
+ }
+}
+
+/// Define end of an explicit frame marker, typically used for sub-frames.
+#[macro_export]
+macro_rules! tracy_end_frame {
+ ($name:expr) => {
+ unsafe {
+ $crate::profiler::MARK_FRAME_END(concat!($name, "\0").as_ptr())
+ }
+ }
+}
+
+#[macro_export]
+macro_rules! tracy_plot {
+ ($name:expr, $value:expr) => {
+ unsafe {
+ $crate::profiler::EMIT_PLOT(concat!($name, "\0").as_ptr(), $value)
+ }
+ }
+}
+
+// Provide a name for this thread to the profiler
+pub fn register_thread_with_profiler(_: String) {
+ // TODO(gw): Add support for passing this to the tracy api
+}