Skip to content

Commit

Permalink
dummy: plot worst-case enter/exits of tasks
Browse files Browse the repository at this point in the history
This is a quick-and-dirty demo for plotting the states of traced RTIC
tasks over time. The used timestamp is the worst-case timestamp.
Timestamp quality and the time required to context switch between
tasks (that is, the time between a task exit and a HW task returned
action) are not rendered.
  • Loading branch information
tmplt committed Feb 1, 2022
1 parent ecd67a1 commit 0a8490c
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 0 deletions.
97 changes: 97 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions rtic-scope-frontend-dummy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ rtic-scope-api = { version = "0.3", path = "../rtic-scope-api" }
anyhow = "1"
tempfile = "3"
serde_json = "1"

[dependencies.pyo3]
version = "0.15.1"
features = ["macros"]
58 changes: 58 additions & 0 deletions rtic-scope-frontend-dummy/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
#![doc = include_str!("../../docs/profile/README.md")]

use anyhow::{Context, Result};
use pyo3::prelude::*;
use pyo3::types::{PyDict, PyString};
use rtic_scope_api as api;
use serde_json::Deserializer;
use std::string::String;

fn main() -> Result<()> {
// Create frontend socket in a temporary directory, print it for the parent backend.
Expand All @@ -15,6 +18,9 @@ fn main() -> Result<()> {
.context("Failed to bind frontend socket")?;
println!("{}", socket_path.display());

let mut task_enters = std::collections::HashMap::new();
let mut csv = String::new();

// Deserialize api::EventChunks from socket and print events to
// stderr along with nanoseconds timestamp.
let (socket, _addr) = listener.accept().context("Failed to accept()")?;
Expand All @@ -32,7 +38,59 @@ fn main() -> Result<()> {
let diff = nanos - prev_nanos;
eprintln!("@{nanos} µs (+{diff} ns) [{quality}]: {events:?}");
prev_nanos = nanos;

for e in events {
match e {
api::EventType::Task { name, action } if action == api::TaskAction::Entered => {
task_enters.insert(name, nanos);
}
api::EventType::Task { name, action } if action == api::TaskAction::Exited => {
let start = task_enters.get(&name).unwrap_or(&0);
let end = nanos;
let entry = format!("{name},{start},{end}\n");
eprintln!("CSV: {entry}");
csv.push_str(entry.as_str());
}
_ => (),
}
}
}

pyo3::prepare_freethreaded_python();
Python::with_gil(|py| {
let locals = PyDict::new(py);
let csv = PyString::new(py, &csv);
locals.set_item("csv", csv).unwrap();
py.run(
r#"
import pandas as pd
import io
import matplotlib.pyplot as plt
df = pd.read_csv(io.StringIO(csv), header=None, names=['Task', 'Start', 'End'])
df['Diff'] = df.End - df.Start
fig, ax = plt.subplots(figsize=(6,3))
labels = []
for i, task in enumerate(df.groupby('Task')):
labels.append(task[0])
data = task[1][["Start", "Diff"]]
ax.broken_barh(data.values, (i - 0.4, 0.8))
ax.set_yticks(range(len(labels)))
ax.set_yticklabels(labels)
ax.set_xlabel('time [ns]')
ax.set_ylabel('RTIC task')
plt.tight_layout()
plt.grid(visible=True, which='both', axis='x')
plt.show()
"#,
None,
Some(locals),
)
.unwrap();
});

Ok(())
}

0 comments on commit 0a8490c

Please sign in to comment.