Vendor things

This commit is contained in:
John Doty 2024-03-08 11:03:01 -08:00
parent 5deceec006
commit 977e3c17e5
19434 changed files with 10682014 additions and 0 deletions

View file

@ -0,0 +1 @@
{"files":{"Cargo.toml":"8f0517ddbb0c8bd2f3f641fb07c06f31317dbee536f11dbb5ed86421fc4d9370","FEATURES.mkd":"69d3909888fa40cb568254983f8901d1f13e1b0af0a8af5b44ae899612e9c8fe","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.mkd":"d06643cfb277a6b84c32a614ba36429c11f61b5b0ddcf756e931ed80352c59e8","benches/client.rs":"993b8818c1c8d2ac0d8e14ed4f66faa855f24ec75dbf006ad82cadba8929d465","src/frame.rs":"4bcdf7a95793bffaf50aa8ec2e497163516c15164fdcfb725510fd910ad064be","src/lib.rs":"487e3268ba40aa456cebc4a9ade3879e852960507e47a539cd5ee1f781440d98","src/plot.rs":"9fe5d4215c8d10d3cd8306e44fa15b36e413e383fac5b55909e5bd4254041730","src/span.rs":"0f86a078bcbc172af9243fb886506c8e836233945f33a0028ba9c185b15512da","src/state.rs":"178843ae073c17b18d14d62f6cacf778a431e9d3341c7aef9a7a65d95d392d13","tests/loom.rs":"8d89230354c88ef046ae9ac338b7c94320cd4fac64a32603c82b47910b3ad39d","tests/tests.rs":"28a01f919930c6159e8ee0d54bf727077e1374a5f6dbccf6b0f65a11e3551472"},"package":"434ecabbda9f67eeea1eab44d52f4a20538afa3e2c2770f2efc161142b25b608"}

View file

@ -0,0 +1,84 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "tracy-client"
version = "0.15.2"
authors = ["Simonas Kazlauskas <tracy-client@kazlauskas.me>"]
description = """
High level bindings to the client libraries for the Tracy profiler
"""
homepage = "https://github.com/nagisa/rust_tracy_client"
documentation = "https://docs.rs/tracy-client"
readme = "README.mkd"
license = "MIT/Apache-2.0"
repository = "https://github.com/nagisa/rust_tracy_client"
[package.metadata.docs.rs]
rustdoc-args = [
"--cfg",
"tracy_client_docs",
]
[[test]]
name = "tests"
path = "tests/tests.rs"
harness = false
[[test]]
name = "loom"
path = "tests/loom.rs"
harness = false
[[bench]]
name = "client"
path = "benches/client.rs"
harness = false
[dependencies.once_cell]
version = "1.10"
[dependencies.sys]
version = ">=0.17.0, <0.22.0"
features = [
"manual-lifetime",
"delayed-init",
]
default-features = false
package = "tracy-client-sys"
[dev-dependencies.criterion]
version = "0.3"
[features]
broadcast = ["sys/broadcast"]
code-transfer = ["sys/code-transfer"]
context-switch-tracing = ["sys/context-switch-tracing"]
default = [
"enable",
"system-tracing",
"context-switch-tracing",
"sampling",
"code-transfer",
"broadcast",
]
enable = ["sys/enable"]
fibers = ["sys/fibers"]
ondemand = ["sys/ondemand"]
only-ipv4 = ["sys/only-ipv4"]
only-localhost = ["sys/only-localhost"]
sampling = ["sys/sampling"]
system-tracing = ["sys/system-tracing"]
timer-fallback = ["sys/timer-fallback"]
[target."cfg(loom)".dependencies.loom]
version = "0.5"

View file

@ -0,0 +1,24 @@
* `enable` enables the Tracy client. Corresponds to the `TRACY_ENABLE` define.
* `system-tracing` enable capture of system level details. Corresponds to the
`TRACY_NO_SYSTEM_TRACING` define.
* `context-switch-tracing` enable capture of the context switch data. Corresponds to the
`TRACY_NO_CONTEXT_SWITCH` define.
* `sampling` enable periodic sampling of the call stack. Corresponds to the
`TRACY_NO_SAMPLING` define.
* `code-transfer` enable transfer of the machine code to the profiler. Corresponds to the
`TRACY_NO_CODE_TRANSFER` define.
* `broadcast` announce presence of the client to the profilers on the local network.
Corresponds to the `TRACY_NO_BROADCAST` define.
* `only-localhost` listen for profilers on the localhost interface only. Corresponds to the
`TRACY_ONLY_LOCALHOST` define.
* `only-ipv4` listen for profilers on IPv4 interfaces only. Corresponds to the
`TRACY_ONLY_IPV4` define.
* `timer-fallback` allow running on devices without a high resolution timer support.
Corresponds to the `TRACY_TIMER_FALLBACK` define.
* `ondemand` start collecting traces only when a server connects to the client. Corresponds
to the `TRACY_ON_DEMAND` define.
* `fibers` enable support for instrumenting fibers, coroutines and similar such asynchrony
primitives. Corresponds to the `TRACY_FIBERS` define.
Refer to this package's `Cargo.toml` for the list of the features enabled by default. Refer to
the `Tracy` manual for more information on the implications of each feature.

View file

@ -0,0 +1,176 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View file

@ -0,0 +1,23 @@
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,54 @@
# Tracy profiler clients in Rust
This project contains Rust crates for producing [Tracy profiler](https://github.com/wolfpld/tracy)
traces. Tracy features nanosecond precision, ability to profile remotely and a full-featured
graphical interface for finding hot spots in profiled programs.
While Tracy's support for Rust is not first-class, it is still a very potent tool. If you have an
application instrumented with the `tracing` crate, Tracy can be used with your program in minutes
via the `tracing-tracy` crate. It can work well as both a profiling and, to a lesser extent,
an observability tool.
## 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 `tracing-tracy`, `tracy-client` and
`tracy-client-sys` crates conditionally, via the `enable` feature flag provided by the crates.
## Version support table
This project, unlike Tracy itself, follows semantic versioning. We will publish a breaking version
bump for `tracy-client-sys` whenever there is a potentially breaking protocol change, even if the
`Tracy` project itself does not. An older version of `Tracy` being unable to communicate with the
client of a more recent version is an example of such a breaking change.
`tracy-client`, `tracing-tracy` and other crates also follow semantic versioning, but do not
consider protocol breaks a breaking change for their purposes. For that reason each future version
of `tracy-client` may be able to support depending on a large number of incompatible
`tracy-client-sys` versions. Users are expected to select the version of `Tracy` profiler they
target and use precise version bounds in `Cargo.toml` or `Cargo.lock` to specify the version of
`tracy-client-sys` that they want to use.
The following table lists the version correspondence between the libraries.
| Tracy | tracy-client-sys | tracy-client | tracing-tracy |
| ----- | ---------------- | ------------ | ------------- |
| 0.7.1 | 0.9.0 | 0.8.0 | 0.2.0 |
| 0.7.3 | 0.10.0 | 0.9.0 | 0.3.0 |
| 0.7.4 | 0.11.0 | 0.10.0 | 0.4.0 |
| 0.7.5 | 0.12.0 | 0.11.0 | 0.5.0 |
| 0.7.6 | 0.13.0, 0.14.0 | 0.12.* | 0.6.* |
| v0.7.7 | 0.15.0 | 0.12.* | 0.6.* |
| v0.7.8 | 0.16.0 | 0.12.* | 0.6.* |
| v0.7.8 | 0.16.0 | 0.12.* | 0.7.* |
| v0.7.8 | 0.16.0 | 0.12.* | 0.8.* |
| v0.8.1 | 0.17.* | 0.13.* | 0.9.* |
| v0.8.1 | 0.17.* | 0.14.* | 0.10.* |
| v0.8.2 | 0.18.0 | 0.14.* | 0.10.* |
| v0.9 | 0.19.0 | 0.14.2 | 0.10.0 |
| v0.9 | 0.19.0 | 0.15.0 | 0.10.1 |
| v0.9.1 | 0.21.0 | 0.14.2 | 0.10.2 |
<!-- AUTO-UPDATE -->

View file

@ -0,0 +1,60 @@
use criterion::{criterion_group, criterion_main, Criterion};
use tracy_client::Client;
fn client_start(c: &mut Criterion) {
let mut clients = Vec::<Client>::with_capacity(1_000_000_000);
c.bench_function("start", |b| b.iter(|| clients.push(Client::start())));
}
fn client_clone(c: &mut Criterion) {
let mut clients = Vec::<Client>::with_capacity(1_000_000_000);
let client = Client::start();
c.bench_function("clone", |b| b.iter(|| clients.push(client.clone())));
}
fn client_running(c: &mut Criterion) {
let _client = Client::start();
c.bench_function("running", |b| b.iter(|| Client::running()));
}
fn ops_alloc(c: &mut Criterion) {
let client = tracy_client::Client::start();
c.bench_function("span_alloc_callstack/0", |bencher| {
bencher.iter(|| {
client
.clone()
.span_alloc("hello", "function", "file", 42, 0);
});
});
c.bench_function("span_alloc_callstack/100", |bencher| {
bencher.iter(|| {
client
.clone()
.span_alloc("hello", "function", "file", 42, 100);
});
});
}
fn ops_static(c: &mut Criterion) {
let _client = tracy_client::Client::start();
c.bench_function("span_callstack/0", |bencher| {
bencher.iter(|| {
tracy_client::span!("some_name", 0);
});
});
c.bench_function("span_callstack/100", |bencher| {
bencher.iter(|| {
tracy_client::span!("some_name", 100);
});
});
}
criterion_group!(
benches,
client_start,
client_clone,
client_running,
ops_alloc,
ops_static
);
criterion_main!(benches);

View 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))
}};
}

View 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
}
}

View 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)
}};
}

View 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)
}};
}

View 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 well 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);
}
}

View file

@ -0,0 +1,76 @@
#[cfg(loom)]
mod loom {
use loom::thread;
use tracy_client::Client;
fn model<F>(f: F)
where
F: Fn() + Sync + Send + 'static,
{
#[cfg(not(loom))]
{
f()
}
#[cfg(loom)]
{
let mut builder = loom::model::Builder::new();
builder.preemption_bound = Some(3);
builder.check(f)
}
}
fn main() {
model(|| {
let client = Client::start();
assert!(Client::is_running());
drop(client);
unsafe {
___tracy_shutdown_profiler();
}
});
model(|| {
let t1 = thread::spawn(|| {
let client = Client::start();
assert!(Client::is_running());
drop(client);
});
let client = Client::start();
assert!(Client::is_running());
drop(client);
t1.join().unwrap();
unsafe {
___tracy_shutdown_profiler();
}
});
model(|| {
let t1 = thread::spawn(move || {
let client = Client::start();
assert!(Client::is_running());
let client2 = client.clone();
assert!(Client::is_running());
drop(client);
assert!(Client::is_running());
drop(client2);
});
let client = Client::start();
assert!(Client::is_running());
let client2 = client.clone();
assert!(Client::is_running());
drop(client2);
assert!(Client::is_running());
drop(client);
t1.join().unwrap();
unsafe {
___tracy_shutdown_profiler();
}
});
}
}
fn main() {
#[cfg(loom)]
loom::main();
}

View file

@ -0,0 +1,124 @@
use tracy_client::*;
#[global_allocator]
static GLOBAL: ProfiledAllocator<std::alloc::System> =
ProfiledAllocator::new(std::alloc::System, 100);
fn basic_zone() {
let client = Client::start();
let span = client.span(span_location!("basic_zone"), 100);
span.emit_value(42);
span.emit_text("some text");
for i in 322..420 {
span.emit_value(i);
}
}
fn alloc_zone() {
let client = Client::start();
let span = client.span_alloc(Some("alloc_zone"), "alloc_zone", file!(), line!(), 100);
span.emit_value(42);
span.emit_color(0x00FF0000);
span.emit_text("some text");
}
fn finish_frameset() {
let client = Client::start();
for _ in 0..10 {
client.frame_mark();
}
frame_mark();
}
fn finish_secondary_frameset() {
let client = Client::start();
for _ in 0..5 {
client.secondary_frame_mark(frame_name!("secondary frame"));
}
secondary_frame_mark!("secondary frame macro");
}
fn non_continuous_frameset() {
const NON_CONTINUOUS: FrameName = frame_name!("non continuous");
let client = Client::start();
client.non_continuous_frame(NON_CONTINUOUS);
non_continuous_frame!("non continuous macro");
}
fn plot_something() {
static TEMPERATURE: PlotName = plot_name!("temperature");
let client = Client::start();
for i in 0..10 {
client.plot(TEMPERATURE, i as f64);
}
plot!("temperature", 42.0);
}
fn allocations() {
let mut strings = Vec::new();
for i in 0..100 {
strings.push(format!("{:?}", i));
}
}
fn fib(i: u16) -> u64 {
let span = span!();
span.emit_text(&format!("fib({})", i));
let result = match i {
0 => 0,
1 => 1,
_ => fib(i - 1) + fib(i - 2),
};
span.emit_value(result);
result
}
fn message() {
let client = Client::start();
client.message("test message", 100);
client.message("test message without stack", 0);
}
fn tls_confusion() {
let client = Client::start();
let t1 = std::thread::spawn(move || {
drop(client);
});
let _ = t1.join();
let _ = Client::start();
}
fn set_thread_name() {
let _client = Client::start();
set_thread_name!("test thread");
}
fn nameless_span() {
let client = Client::start();
span!();
client.span_alloc(None, "nameless_span", file!(), line!(), 0);
set_thread_name!("test thread");
}
fn main() {
#[cfg(not(loom))]
{
basic_zone();
alloc_zone();
finish_frameset();
finish_secondary_frameset();
non_continuous_frameset();
plot_something();
message();
allocations();
tls_confusion();
nameless_span();
let thread = std::thread::spawn(|| {
let _client = Client::start();
fib(25);
});
thread.join().unwrap();
set_thread_name();
}
}