Target Instrumentation (styx-trace)¶
This library package implements a tracing facility for programattically eminating events during emulation. Like logging, but optimized on the qualities we care about:
Don’t slow down emulation
High volume / throughput (events per unit of time)
Low memory usage per event (eg low resource util)
Multi-process (event readers can be in a different process than the event writer)
Extensible event list
Easy to use API
styx-trace package contents¶
lib.rs has a trace interface using rust idioms (traits, structs, macros) and a set of Events.
ipc_impl.rs is an implementation of the interface leveraging ipmpsc::SharedRingBuffer.
strace.rs is a cli utility for reading the trace buffers. It also contains an option for generating events, for testing.
Design / Implementation Notes¶
The SharedRingBuffer
implementation uses a a memory-mapped file, memmap2, for inter-process communication (IPC), and:
A sender sends messages (writes to the buffer)
A receiver receives (opens file, reads) uses a memory mapped file with a ring buffer algo. the
Sender
can send (ie write to the buffer), theReceiver
Note: the receiver does not memcpy - it uses a zero copy context, ie just returns an interpreted pointer to the item.
Trace Abstraction¶
The macro strace!(event)
is used to write an event, where event
must be an impl of trait Traceable
. All events must provide impl Traceable
and be fixed-sized (size_of<BaseTestEvent>
). (Currently 24 bytes if numbered, 16 otherwise). Things won’t compile otherwise.
Adding new events is a 2-item process:
Define the event
Add the event to the dispatch list
For defining the event, there is a helper macro, styx_event
. All new events must be the same size (in bytes) as the BaseTraceEvent
. All new events should be aligned by 4-byte boundaries.
The macro takes care of implementing required traits, adding an event type (etype
) field, and adding an event number field event_num
if the numbered feature is enabled (enabled by default).
#[styx_event(etype=TraceEventType::MEM_READ)]
struct MemReadEvent {
pub size_bytes: u16,
pub pc: u32,
pub address: u32,
pub value: u32,
}
For adding to the dispatch list, the styx_event_dispatch
macro provides a mechanism that associates event types (enum TraceEventType
) with specific event types, and enables polymorphic method calling, powered by enum_dispatch.
To enable this mechanism, each new event is added to the TraceableItem
enum. The macro takes care of creating the enum_dispatch
variants.
#[styx_event_dispatch(BaseTraceEvent, Traceable)]
pub enum TraceableItem {
InsnExecEvent(TraceEventType::INST_EXEC),
InsnFetchEvent(TraceEventType::INST_FETCH),
MemReadEvent(TraceEventType::MEM_READ),
MemWriteEvent(TraceEventType::MEM_WRT),
RegReadEvent(TraceEventType::REG_READ),
RegWriteEvent(TraceEventType::REG_WRITE),
BranchEvent(TraceEventType::BRANCH),
ControlEvent(TraceEventType::CTRL),
...
}
Viewing Events¶
When using the strace!()
macro, events are viewable with the strace
tool.
# from the repo root
cargo run --bin strace -- -help
The tool has 2 modes: “generate” for generating sample events, and “read” for reading events from a trace buffer.
With the SharedRingBuffer
trace provider, events can be accessed via the memory mapped file in, for example:
KFILE=/tmp/strace_150847_9edd2997-eada-4bcd-924d-74068705ddbb.srb
# ^ ^ ^
# | | +- file ext
# | +- uuid4
# +- process id of emulator
strace -R -k $KEY_FILE -o text -v 3
Performance Benchmarks¶
The table below shows performance stats for cargo run --release -p benchmarks
.
For the Action column the row labeled PRODUCE is the stats for emitting events, sequentially, using strace!
.
The rows labeled CONSUME, CAST, JSON, and TEXT are variants of a client consuming events sequentially, where:
CONSUME: is just the time to read the event
CAST: is the time to read and interpret the event (ie transmute or cast to a specific event type)
JSON: is the time to read, interpret, and convert to
jsonl
usingserde::Serialize
TEXT: is the time to read, interpret, and convert to
text
using the derivedDebug
and rust’s standard debug formatting.
Stats for 100 million “numbered” events:
Action |
Time (rounded secs) |
Rate (events/sec) |
---|---|---|
PRODUCE |
10 |
9,454,832 |
CONSUME |
4 |
20,710,341 |
CAST |
5 |
18,100,958 |
JSON |
16 |
5,999,676 |
TEXT |
38 |
2,604,706 |