mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-21 22:33:49 +00:00
Factor wgpu-subscriber into its own repo
This commit is contained in:
parent
096c57008f
commit
350637df40
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1648,6 +1648,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "wgpu-subscriber"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/gfx-rs/subscriber.git?rev=cdc9feb53f152f9c41905ed9efeff2c1ed214361#cdc9feb53f152f9c41905ed9efeff2c1ed214361"
|
||||
dependencies = [
|
||||
"parking_lot 0.11.0",
|
||||
"thread-id",
|
||||
|
@ -3,6 +3,5 @@ members = [
|
||||
"dummy",
|
||||
"player",
|
||||
"wgpu-core",
|
||||
"wgpu-subscriber",
|
||||
"wgpu-types",
|
||||
]
|
||||
|
@ -13,7 +13,6 @@ The implementation consists of the following parts:
|
||||
|
||||
- [![Crates.io](https://img.shields.io/crates/v/wgpu-core.svg?label=wgpu-core)](https://crates.io/crates/wgpu-core) [![docs.rs](https://docs.rs/wgpu-core/badge.svg)](https://docs.rs/wgpu-core/) - internal Rust API for WebGPU implementations to use
|
||||
- [![Crates.io](https://img.shields.io/crates/v/wgpu-types.svg?label=wgpu-types)](https://crates.io/crates/wgpu-types) [![docs.rs](https://docs.rs/wgpu-types/badge.svg)](https://docs.rs/wgpu-types/) - Rust types shared between `wgpu-core`, `wgpu-native`, and `wgpu-rs`
|
||||
- [![Crates.io](https://img.shields.io/crates/v/wgpu-subscriber.svg?label=wgpu-subsciber)](https://crates.io/crates/wgpu-subscriber) [![docs.rs](https://docs.rs/wgpu-subscriber/badge.svg)](https://docs.rs/wgpu-subscriber/) - tracing subscribers to use with `wgpu`
|
||||
- `player` - standalone application for replaying the API traces, uses `winit`
|
||||
|
||||
This repository contains the core of `wgpu`, and is not usable directly by applications.
|
||||
|
@ -35,7 +35,8 @@ version = "0.5"
|
||||
features = ["replay", "raw-window-handle"]
|
||||
|
||||
[dependencies.wgpu-subscriber]
|
||||
path = "../wgpu-subscriber"
|
||||
git = "https://github.com/gfx-rs/subscriber.git"
|
||||
rev = "cdc9feb53f152f9c41905ed9efeff2c1ed214361"
|
||||
version = "0.1"
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))'.dependencies]
|
||||
|
@ -1,21 +0,0 @@
|
||||
[package]
|
||||
name = "wgpu-subscriber"
|
||||
version = "0.1.0"
|
||||
authors = ["wgpu developers"]
|
||||
edition = "2018"
|
||||
description = "WebGPU tracing subscriber"
|
||||
homepage = "https://github.com/gfx-rs/wgpu"
|
||||
repository = "https://github.com/gfx-rs/wgpu"
|
||||
keywords = ["graphics"]
|
||||
license = "MPL-2.0"
|
||||
|
||||
[lib]
|
||||
|
||||
[features]
|
||||
|
||||
[dependencies]
|
||||
parking_lot = "0.11"
|
||||
thread-id = "3"
|
||||
tracing = { version = "0.1", default-features = false, features = ["std"] }
|
||||
tracing-log = "0.1"
|
||||
tracing-subscriber = "0.2"
|
@ -1,172 +0,0 @@
|
||||
use crate::CURRENT_THREAD_ID;
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fmt,
|
||||
io::{self, Write as _},
|
||||
path::Path,
|
||||
sync::Arc,
|
||||
time::Instant,
|
||||
};
|
||||
use tracing::{
|
||||
field::{Field, Visit},
|
||||
span, Event, Metadata, Subscriber,
|
||||
};
|
||||
use tracing_subscriber::{layer::Context, registry::LookupSpan, Layer};
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
enum EventType {
|
||||
Begin,
|
||||
Event,
|
||||
End,
|
||||
}
|
||||
|
||||
/// A layer to add to a [`tracing_subscriber::Registry`] to output to a chrome
|
||||
/// trace.
|
||||
///
|
||||
/// If you want an easy "set and forget" method of installing this and normal
|
||||
/// tracing logging, call [`initialize_default_subscriber`].
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ChromeTracingLayer {
|
||||
file: Arc<Mutex<std::fs::File>>,
|
||||
start_time: Instant,
|
||||
process_id: u32,
|
||||
}
|
||||
|
||||
impl ChromeTracingLayer {
|
||||
/// Create a trace which outputs to the given file. The file will be cleared if it exits.
|
||||
pub fn with_file(file: impl AsRef<Path>) -> io::Result<Self> {
|
||||
std::fs::File::create(file).map(|mut file| {
|
||||
writeln!(file, "[").unwrap();
|
||||
ChromeTracingLayer {
|
||||
file: Arc::new(Mutex::new(file)),
|
||||
start_time: Instant::now(),
|
||||
process_id: std::process::id(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn write_event(
|
||||
&self,
|
||||
mut fields: Option<EventVisitor>,
|
||||
metadata: &'static Metadata<'static>,
|
||||
event_type: EventType,
|
||||
) {
|
||||
if let Some(EventVisitor { trace: false, .. }) = fields {
|
||||
return;
|
||||
}
|
||||
|
||||
let current_time = Instant::now();
|
||||
|
||||
let diff = current_time - self.start_time;
|
||||
let diff_in_us = diff.as_micros();
|
||||
|
||||
let event_type_str = match event_type {
|
||||
EventType::Begin => "B",
|
||||
EventType::Event => "i",
|
||||
EventType::End => "E",
|
||||
};
|
||||
|
||||
let instant_scope = if event_type == EventType::Event {
|
||||
r#","s": "p""#
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
let name = match event_type {
|
||||
EventType::Event => fields
|
||||
.as_mut()
|
||||
.and_then(|fields| fields.message.take())
|
||||
.map_or_else(
|
||||
|| {
|
||||
let name = metadata.name();
|
||||
// The default name for events has a path in it, filter paths only on windows
|
||||
if cfg!(target_os = "windows") {
|
||||
Cow::Owned(name.replace("\\", "\\\\"))
|
||||
} else {
|
||||
Cow::Borrowed(name)
|
||||
}
|
||||
},
|
||||
Cow::from,
|
||||
),
|
||||
EventType::Begin | EventType::End => Cow::Borrowed(metadata.name()),
|
||||
};
|
||||
|
||||
let category = fields
|
||||
.as_mut()
|
||||
.and_then(|fields| fields.category.take())
|
||||
.map_or_else(|| Cow::Borrowed("trace"), Cow::from);
|
||||
|
||||
let mut file = self.file.lock();
|
||||
writeln!(
|
||||
file,
|
||||
r#"{{ "name": "{}", "cat": "{}", "ph": "{}", "ts": {}, "pid": {}, "tid": {} {} }},"#,
|
||||
name,
|
||||
category,
|
||||
event_type_str,
|
||||
diff_in_us,
|
||||
self.process_id,
|
||||
CURRENT_THREAD_ID.with(|v| *v),
|
||||
instant_scope,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ChromeTracingLayer {
|
||||
fn drop(&mut self) {
|
||||
let mut file = self.file.lock();
|
||||
writeln!(file, "]").unwrap();
|
||||
file.flush().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct EventVisitor {
|
||||
message: Option<String>,
|
||||
category: Option<String>,
|
||||
trace: bool,
|
||||
}
|
||||
|
||||
impl Visit for EventVisitor {
|
||||
fn record_bool(&mut self, field: &Field, value: bool) {
|
||||
match field.name() {
|
||||
"trace" => self.trace = value,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
|
||||
match field.name() {
|
||||
"message" => self.message = Some(format!("{:?}", value)),
|
||||
"category" => self.category = Some(format!("{:?}", value)),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Layer<S> for ChromeTracingLayer
|
||||
where
|
||||
S: Subscriber + for<'span> LookupSpan<'span>,
|
||||
{
|
||||
fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
|
||||
let mut event_visitor = EventVisitor::default();
|
||||
event.record(&mut event_visitor);
|
||||
|
||||
self.write_event(Some(event_visitor), event.metadata(), EventType::Event);
|
||||
}
|
||||
|
||||
fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
|
||||
let span = ctx.span(id).unwrap();
|
||||
self.write_event(None, span.metadata(), EventType::Begin);
|
||||
}
|
||||
|
||||
fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
|
||||
if std::thread::panicking() {
|
||||
return;
|
||||
}
|
||||
|
||||
let span = ctx.span(id).unwrap();
|
||||
self.write_event(None, span.metadata(), EventType::End);
|
||||
}
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
use std::{fmt, io, time::Instant};
|
||||
use tracing::{
|
||||
field::{Field, Visit},
|
||||
Event, Level, Subscriber,
|
||||
};
|
||||
use tracing_subscriber::{layer::Context, registry::LookupSpan, Layer};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct FmtEventVisitor {
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl Visit for FmtEventVisitor {
|
||||
fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
|
||||
match field.name() {
|
||||
"message" => self.message = format!("{:?}", value),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum StandardOutput {
|
||||
Out(io::Stdout),
|
||||
Err(io::Stderr),
|
||||
}
|
||||
|
||||
impl StandardOutput {
|
||||
fn new(level: &Level) -> Self {
|
||||
match *level {
|
||||
Level::ERROR | Level::WARN => Self::Err(io::stderr()),
|
||||
_ => Self::Out(io::stdout()),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_dyn_ref(&mut self) -> &mut dyn io::Write {
|
||||
match self {
|
||||
Self::Out(out) => out,
|
||||
Self::Err(err) => err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FmtLayer {
|
||||
start: Instant,
|
||||
}
|
||||
|
||||
impl FmtLayer {
|
||||
pub fn new() -> Self {
|
||||
FmtLayer {
|
||||
start: Instant::now(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Layer<S> for FmtLayer
|
||||
where
|
||||
S: Subscriber + for<'span> LookupSpan<'span>,
|
||||
{
|
||||
fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
|
||||
let now = Instant::now();
|
||||
let time = now - self.start;
|
||||
|
||||
let mut visitor = FmtEventVisitor::default();
|
||||
event.record(&mut visitor);
|
||||
|
||||
let mut span_string = String::new();
|
||||
for span in ctx.scope() {
|
||||
if !span_string.is_empty() {
|
||||
span_string.push_str(" | ");
|
||||
}
|
||||
span_string.push_str(span.name());
|
||||
}
|
||||
|
||||
let metadata = event.metadata();
|
||||
let level = match *metadata.level() {
|
||||
Level::ERROR => "ERROR",
|
||||
Level::WARN => "WARN",
|
||||
Level::INFO => "INFO",
|
||||
Level::DEBUG => "DEBUG",
|
||||
Level::TRACE => "TRACE",
|
||||
};
|
||||
|
||||
let module = metadata.module_path().unwrap_or("no module");
|
||||
|
||||
let mut output = StandardOutput::new(metadata.level());
|
||||
let output_ref = output.get_dyn_ref();
|
||||
|
||||
writeln!(
|
||||
output_ref,
|
||||
"[{:.6} {}]({})({}): {}",
|
||||
time.as_secs_f64(),
|
||||
level,
|
||||
span_string,
|
||||
module,
|
||||
visitor.message,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
pub use chrome::*;
|
||||
pub use fmt_layer::*;
|
||||
use std::path::Path;
|
||||
use tracing_subscriber::{layer::SubscriberExt as _, EnvFilter};
|
||||
|
||||
mod chrome;
|
||||
mod fmt_layer;
|
||||
|
||||
/// Set up the "standard" logger.
|
||||
///
|
||||
/// This is fairly inflexible, but a good default to start with. If you need more customization,
|
||||
/// take what this function does and implement it however you need.
|
||||
///
|
||||
/// If this function is called, you should **not** set up a log-based logger like env_logger
|
||||
/// or fern. This will result in duplicate messages.
|
||||
///
|
||||
/// # Args
|
||||
///
|
||||
/// - `chrome_tracing_path` if set to `Some`, will create a trace compatible with chrome://tracing
|
||||
/// at that location.
|
||||
pub fn initialize_default_subscriber(chrome_trace_path: Option<&Path>) {
|
||||
let chrome_tracing_layer_opt =
|
||||
chrome_trace_path.map(|path| ChromeTracingLayer::with_file(path).unwrap());
|
||||
|
||||
// Tracing currently doesn't support type erasure with layer composition
|
||||
if let Some(chrome_tracing_layer) = chrome_tracing_layer_opt {
|
||||
tracing::subscriber::set_global_default(
|
||||
tracing_subscriber::Registry::default()
|
||||
.with(chrome_tracing_layer)
|
||||
.with(FmtLayer::new())
|
||||
.with(EnvFilter::from_default_env()),
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
tracing::subscriber::set_global_default(
|
||||
tracing_subscriber::Registry::default()
|
||||
.with(FmtLayer::new())
|
||||
.with(EnvFilter::from_default_env()),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
tracing_log::LogTracer::init().unwrap();
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static CURRENT_THREAD_ID: usize = thread_id::get();
|
||||
}
|
Loading…
Reference in New Issue
Block a user