Implement debug output to be better (#33)
This commit is contained in:
parent
00ea6cf6a1
commit
8287e520b9
90
src/lib.rs
90
src/lib.rs
|
@ -20,12 +20,13 @@
|
||||||
|
|
||||||
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
|
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::panic::{RefUnwindSafe, UnwindSafe};
|
use std::panic::{RefUnwindSafe, UnwindSafe};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock, TryLockError};
|
||||||
use std::task::{Poll, Waker};
|
use std::task::{Poll, Waker};
|
||||||
|
|
||||||
use async_lock::OnceCell;
|
use async_lock::OnceCell;
|
||||||
|
@ -61,7 +62,6 @@ pub use async_task::Task;
|
||||||
/// drop(signal);
|
/// drop(signal);
|
||||||
/// }));
|
/// }));
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Executor<'a> {
|
pub struct Executor<'a> {
|
||||||
/// The executor state.
|
/// The executor state.
|
||||||
state: OnceCell<Arc<State>>,
|
state: OnceCell<Arc<State>>,
|
||||||
|
@ -76,6 +76,12 @@ unsafe impl Sync for Executor<'_> {}
|
||||||
impl UnwindSafe for Executor<'_> {}
|
impl UnwindSafe for Executor<'_> {}
|
||||||
impl RefUnwindSafe for Executor<'_> {}
|
impl RefUnwindSafe for Executor<'_> {}
|
||||||
|
|
||||||
|
impl fmt::Debug for Executor<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
debug_executor(self, "Executor", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Executor<'a> {
|
impl<'a> Executor<'a> {
|
||||||
/// Creates a new executor.
|
/// Creates a new executor.
|
||||||
///
|
///
|
||||||
|
@ -290,7 +296,6 @@ impl<'a> Default for Executor<'a> {
|
||||||
/// println!("Hello world!");
|
/// println!("Hello world!");
|
||||||
/// }));
|
/// }));
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct LocalExecutor<'a> {
|
pub struct LocalExecutor<'a> {
|
||||||
/// The inner executor.
|
/// The inner executor.
|
||||||
inner: Executor<'a>,
|
inner: Executor<'a>,
|
||||||
|
@ -302,6 +307,12 @@ pub struct LocalExecutor<'a> {
|
||||||
impl UnwindSafe for LocalExecutor<'_> {}
|
impl UnwindSafe for LocalExecutor<'_> {}
|
||||||
impl RefUnwindSafe for LocalExecutor<'_> {}
|
impl RefUnwindSafe for LocalExecutor<'_> {}
|
||||||
|
|
||||||
|
impl fmt::Debug for LocalExecutor<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
debug_executor(&self.inner, "LocalExecutor", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> LocalExecutor<'a> {
|
impl<'a> LocalExecutor<'a> {
|
||||||
/// Creates a single-threaded executor.
|
/// Creates a single-threaded executor.
|
||||||
///
|
///
|
||||||
|
@ -459,7 +470,6 @@ impl<'a> Default for LocalExecutor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The state of a executor.
|
/// The state of a executor.
|
||||||
#[derive(Debug)]
|
|
||||||
struct State {
|
struct State {
|
||||||
/// The global queue.
|
/// The global queue.
|
||||||
queue: ConcurrentQueue<Runnable>,
|
queue: ConcurrentQueue<Runnable>,
|
||||||
|
@ -510,7 +520,6 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A list of sleeping tickers.
|
/// A list of sleeping tickers.
|
||||||
#[derive(Debug)]
|
|
||||||
struct Sleepers {
|
struct Sleepers {
|
||||||
/// Number of sleeping tickers (both notified and unnotified).
|
/// Number of sleeping tickers (both notified and unnotified).
|
||||||
count: usize,
|
count: usize,
|
||||||
|
@ -587,7 +596,6 @@ impl Sleepers {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs task one by one.
|
/// Runs task one by one.
|
||||||
#[derive(Debug)]
|
|
||||||
struct Ticker<'a> {
|
struct Ticker<'a> {
|
||||||
/// The executor state.
|
/// The executor state.
|
||||||
state: &'a State,
|
state: &'a State,
|
||||||
|
@ -708,7 +716,6 @@ impl Drop for Ticker<'_> {
|
||||||
/// A worker in a work-stealing executor.
|
/// A worker in a work-stealing executor.
|
||||||
///
|
///
|
||||||
/// This is just a ticker that also has an associated local queue for improved cache locality.
|
/// This is just a ticker that also has an associated local queue for improved cache locality.
|
||||||
#[derive(Debug)]
|
|
||||||
struct Runner<'a> {
|
struct Runner<'a> {
|
||||||
/// The executor state.
|
/// The executor state.
|
||||||
state: &'a State,
|
state: &'a State,
|
||||||
|
@ -833,6 +840,75 @@ fn steal<T>(src: &ConcurrentQueue<T>, dest: &ConcurrentQueue<T>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Debug implementation for `Executor` and `LocalExecutor`.
|
||||||
|
fn debug_executor(executor: &Executor<'_>, name: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
// Get a reference to the state.
|
||||||
|
let state = match executor.state.get() {
|
||||||
|
Some(state) => state,
|
||||||
|
None => {
|
||||||
|
// The executor has not been initialized.
|
||||||
|
struct Uninitialized;
|
||||||
|
|
||||||
|
impl fmt::Debug for Uninitialized {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str("<uninitialized>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.debug_tuple(name).field(&Uninitialized).finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Debug wrapper for the number of active tasks.
|
||||||
|
struct ActiveTasks<'a>(&'a Mutex<Slab<Waker>>);
|
||||||
|
|
||||||
|
impl fmt::Debug for ActiveTasks<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self.0.try_lock() {
|
||||||
|
Ok(lock) => fmt::Debug::fmt(&lock.len(), f),
|
||||||
|
Err(TryLockError::WouldBlock) => f.write_str("<locked>"),
|
||||||
|
Err(TryLockError::Poisoned(_)) => f.write_str("<poisoned>"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Debug wrapper for the local runners.
|
||||||
|
struct LocalRunners<'a>(&'a RwLock<Vec<Arc<ConcurrentQueue<Runnable>>>>);
|
||||||
|
|
||||||
|
impl fmt::Debug for LocalRunners<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self.0.try_read() {
|
||||||
|
Ok(lock) => f
|
||||||
|
.debug_list()
|
||||||
|
.entries(lock.iter().map(|queue| queue.len()))
|
||||||
|
.finish(),
|
||||||
|
Err(TryLockError::WouldBlock) => f.write_str("<locked>"),
|
||||||
|
Err(TryLockError::Poisoned(_)) => f.write_str("<poisoned>"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Debug wrapper for the sleepers.
|
||||||
|
struct SleepCount<'a>(&'a Mutex<Sleepers>);
|
||||||
|
|
||||||
|
impl fmt::Debug for SleepCount<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self.0.try_lock() {
|
||||||
|
Ok(lock) => fmt::Debug::fmt(&lock.count, f),
|
||||||
|
Err(TryLockError::WouldBlock) => f.write_str("<locked>"),
|
||||||
|
Err(TryLockError::Poisoned(_)) => f.write_str("<poisoned>"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.debug_struct(name)
|
||||||
|
.field("active", &ActiveTasks(&state.active))
|
||||||
|
.field("global_tasks", &state.queue.len())
|
||||||
|
.field("local_runners", &LocalRunners(&state.local_queues))
|
||||||
|
.field("sleepers", &SleepCount(&state.sleepers))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
|
||||||
/// Runs a closure when dropped.
|
/// Runs a closure when dropped.
|
||||||
struct CallOnDrop<F: Fn()>(F);
|
struct CallOnDrop<F: Fn()>(F);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue