Factor wgpu-subscriber into its own repo

This commit is contained in:
Connor Fitzgerald 2020-08-17 16:14:18 -04:00
parent 096c57008f
commit 350637df40
8 changed files with 3 additions and 343 deletions

1
Cargo.lock generated
View File

@ -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",

View File

@ -3,6 +3,5 @@ members = [
"dummy",
"player",
"wgpu-core",
"wgpu-subscriber",
"wgpu-types",
]

View File

@ -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.

View File

@ -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]

View File

@ -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"

View File

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

View File

@ -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();
}
}

View File

@ -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();
}