Skip to content

Commit

Permalink
Refactor to support ineraction modes
Browse files Browse the repository at this point in the history
  • Loading branch information
jonlamb-gh committed May 8, 2024
1 parent 4ea8274 commit 5f4fdfd
Show file tree
Hide file tree
Showing 13 changed files with 683 additions and 1,054 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,18 @@ Result 2:
║ timestamp = +2.684145s
```

### Interaction Modes

The plugins can be configured for different interaction modes via the `interaction-mode` field (or `--interaction-mode` at the CLI).

Available modes:
* `fully-linearized`: An interaction is produced on every context switch event from the preceding task/ISR context to the
active task/ISR context. This effectively linearizes the system execution where everything is causally connected.
* `ipc`: An interaction is produced for each task/ISR IPC.
Currently this supports the following object kinds:
- queue
- task notification

## Configuration

All of the plugins can be configured through a TOML configuration file (from either the `--config` option or the `MODALITY_REFLECTOR_CONFIG` environment variable).
Expand All @@ -141,6 +153,7 @@ These sections are the same for each of the plugins.
* `[metadata]` — Plugin configuration table.
- `run-id` — Use the provided UUID as the run ID instead of generating a random one.
- `time-domain` — Use the provided UUID as the time domain ID instead of generating a random one.
- `interaction-mode` — Interaction mode to use (`fully-linearized` or `ipc`). The default value is `fully-linearized`.
- `startup-task-name` — Use the provided initial startup task name instead of the default (`(startup)`).
- `single-task-timeline` — Use a single timeline for all tasks instead of a timeline per task. ISRs can still be represented with their own timelines or not.
- `disable-task-interactions` — Don't synthesize interactions between tasks and ISRs when a context switch occurs.
Expand Down Expand Up @@ -241,7 +254,7 @@ reflector configuration file, e.g. `[plugins.ingest.collectors.trace-recorder-it
These are used to start and stop tracing by writing control plane commands from the probe.
- `command-len-addr` — Use the provided memory address for the ITM streaming port variable `tz_host_command_bytes_to_read`.
These are used to start and stop tracing by writing control plane commands from the probe.
- `stimulus-port` — The ITM stimulus port used for trace recorder data.The default value is 1.
- `stimulus-port` — The ITM stimulus port used for trace recorder data. The default value is 1.
- `probe-selector` — Select a specific probe instead of opening the first available one.
- `chip` — The target chip to attach to (e.g. `STM32F407VE`).
- `protocol` — Protocol used to connect to chip. Possible options: [`swd`, `jtag`]. The default value is `swd`.
Expand Down
63 changes: 9 additions & 54 deletions src/attr.rs
Original file line number Diff line number Diff line change
@@ -1,57 +1,8 @@
use auxon_sdk::{
ingest_client::{BoundTimelineState, IngestClient, IngestError},
ingest_protocol::InternedAttrKey,
};
use auxon_sdk::ingest_protocol::InternedAttrKey;
use derive_more::Display;
use std::{collections::HashMap, fmt, hash::Hash};
use std::collections::HashMap;

pub trait AttrKeyIndex: Hash + Eq + Clone + fmt::Display {}

#[derive(Clone, Debug)]
pub struct AttrKeys<T: AttrKeyIndex>(HashMap<T, InternedAttrKey>);

impl<T: AttrKeyIndex> Default for AttrKeys<T> {
fn default() -> Self {
Self(HashMap::new())
}
}

impl<T: AttrKeyIndex> AttrKeys<T> {
pub async fn get(
&mut self,
client: &mut IngestClient<BoundTimelineState>,
key: T,
) -> Result<InternedAttrKey, IngestError> {
if let Some(k) = self.0.get(&key) {
Ok(*k)
} else {
let interned_key = client.declare_attr_key(key.to_string()).await?;
self.0.insert(key, interned_key);
Ok(interned_key)
}
}

pub(crate) fn remove_string_key_entry(&mut self, key: &str) -> Option<(T, InternedAttrKey)> {
self.0
.keys()
.find_map(|k| {
let k_str = k.to_string();
if k_str.as_str() == key {
Some(k.clone())
} else {
None
}
})
.and_then(|k| self.0.remove_entry(&k))
}

pub(crate) fn insert(&mut self, key: T, interned_key: InternedAttrKey) {
self.0.insert(key, interned_key);
}
}

impl AttrKeyIndex for TimelineAttrKey {}
impl AttrKeyIndex for EventAttrKey {}
pub type AttrKeys<T> = HashMap<T, InternedAttrKey>;

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display)]
pub enum TimelineAttrKey {
Expand Down Expand Up @@ -133,8 +84,12 @@ pub enum EventAttrKey {
Timestamp,
#[display(fmt = "event.interaction.remote_timeline_id")]
RemoteTimelineId,
#[display(fmt = "event.interaction.remote_timestamp")]
RemoteTimestamp,
#[display(fmt = "event.interaction.remote_nonce")]
RemoteNonce,
#[display(fmt = "event.internal.trace_recorder.nonce")]
InternalNonce,
#[display(fmt = "event.nonce")]
Nonce,
#[display(fmt = "event.mutator.id")]
MutatorId,
#[display(fmt = "event.internal.trace_recorder.mutator.id")]
Expand Down
80 changes: 46 additions & 34 deletions src/client.rs
Original file line number Diff line number Diff line change
@@ -1,55 +1,67 @@
use crate::attr::{AttrKeys, EventAttrKey, TimelineAttrKey};
use crate::{
attr::{AttrKeys, EventAttrKey, TimelineAttrKey},
error::Error,
};
use auxon_sdk::{
ingest_client::{BoundTimelineState, IngestClient, IngestError},
ingest_protocol::InternedAttrKey,
api::{AttrVal, TimelineId},
ingest_client::{dynamic::DynamicIngestClient, IngestClient, ReadyState},
};

pub struct Client {
timeline_keys: AttrKeys<TimelineAttrKey>,
event_keys: AttrKeys<EventAttrKey>,
inner: IngestClient<BoundTimelineState>,
pub(crate) inner: DynamicIngestClient,
}

impl Client {
pub fn new(client: IngestClient<BoundTimelineState>) -> Self {
pub fn new(client: IngestClient<ReadyState>) -> Self {
Self {
timeline_keys: AttrKeys::default(),
event_keys: AttrKeys::default(),
inner: client,
inner: client.into(),
}
}

pub async fn close(mut self) -> Result<(), IngestError> {
self.inner.flush().await?;
let _ = self.inner.close_timeline();
Ok(())
}

pub async fn timeline_key(
pub async fn switch_timeline(
&mut self,
key: TimelineAttrKey,
) -> Result<InternedAttrKey, IngestError> {
let k = self.timeline_keys.get(&mut self.inner, key).await?;
Ok(k)
}

pub async fn event_key(&mut self, key: EventAttrKey) -> Result<InternedAttrKey, IngestError> {
let k = self.event_keys.get(&mut self.inner, key).await?;
Ok(k)
}

pub fn inner(&mut self) -> &mut IngestClient<BoundTimelineState> {
&mut self.inner
id: TimelineId,
new_timeline_attrs: Option<impl IntoIterator<Item = (&TimelineAttrKey, &AttrVal)>>,
) -> Result<(), Error> {
self.inner.open_timeline(id).await?;
if let Some(attrs) = new_timeline_attrs {
let mut interned_attrs = Vec::new();
for (k, v) in attrs.into_iter() {
let int_key = if let Some(ik) = self.timeline_keys.get(k) {
*ik
} else {
let ik = self.inner.declare_attr_key(k.to_string()).await?;
self.timeline_keys.insert(k.clone(), ik);
ik
};
interned_attrs.push((int_key, v.clone()));
}
self.inner.timeline_metadata(interned_attrs).await?;
}
Ok(())
}

pub(crate) fn remove_timeline_string_key(
pub async fn send_event(
&mut self,
key: &str,
) -> Option<(TimelineAttrKey, InternedAttrKey)> {
self.timeline_keys.remove_string_key_entry(key)
}

pub(crate) fn add_timeline_key(&mut self, key: TimelineAttrKey, interned_key: InternedAttrKey) {
self.timeline_keys.insert(key, interned_key)
ordering: u128,
attrs: impl IntoIterator<Item = (&EventAttrKey, &AttrVal)>,
) -> Result<(), Error> {
let mut interned_attrs = Vec::new();
for (k, v) in attrs.into_iter() {
let int_key = if let Some(ik) = self.event_keys.get(k) {
*ik
} else {
let ik = self.inner.declare_attr_key(k.to_string()).await?;
self.event_keys.insert(k.clone(), ik);
ik
};
interned_attrs.push((int_key, v.clone()));
}
self.inner.event(ordering, interned_attrs).await?;
Ok(())
}
}
18 changes: 17 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
error::AuthTokenError,
opts::{
FormatArgAttributeKeysSet, IgnoredObjectClasses, ReflectorOpts, RenameMap,
FormatArgAttributeKeysSet, IgnoredObjectClasses, InteractionMode, ReflectorOpts, RenameMap,
TraceRecorderOpts,
},
};
Expand Down Expand Up @@ -50,6 +50,7 @@ pub struct PluginConfig {
pub user_event_channel_rename_map: RenameMap,
pub user_event_formatted_string_rename_map: RenameMap,
pub user_event_fmt_arg_attr_keys: FormatArgAttributeKeysSet,
pub interaction_mode: InteractionMode,

pub import: ImportConfig,
pub tcp_collector: TcpCollectorConfig,
Expand Down Expand Up @@ -309,6 +310,11 @@ impl TraceRecorderConfig {
} else {
cfg_plugin.user_event_fmt_arg_attr_keys
},
interaction_mode: if let Some(m) = tr_opts.interaction_mode {
m
} else {
cfg_plugin.interaction_mode
},
import: cfg_plugin.import,
tcp_collector: cfg_plugin.tcp_collector,
itm_collector: cfg_plugin.itm_collector,
Expand Down Expand Up @@ -365,6 +371,7 @@ mod internal {
#[serde(rename = "user-event-formatted-string-name")]
pub user_event_formatted_string_rename_map: RenameMap,
pub user_event_fmt_arg_attr_keys: FormatArgAttributeKeysSet,
pub interaction_mode: InteractionMode,
}

impl From<CommonPluginConfig> for PluginConfig {
Expand All @@ -385,6 +392,7 @@ mod internal {
user_event_channel_rename_map: c.user_event_channel_rename_map,
user_event_formatted_string_rename_map: c.user_event_formatted_string_rename_map,
user_event_fmt_arg_attr_keys: c.user_event_fmt_arg_attr_keys,
interaction_mode: c.interaction_mode,
import: Default::default(),
tcp_collector: Default::default(),
itm_collector: Default::default(),
Expand Down Expand Up @@ -532,6 +540,7 @@ time-domain = 'a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d1'
startup-task-name = 'm3'
user-event-channel = true
user-event-format-string = true
interaction-mode = "ipc"
single-task-timeline = true
flatten-isr-timelines = true
disable-task-interactions = true
Expand Down Expand Up @@ -569,6 +578,7 @@ user-event-channel = true
user-event-format-string = true
single-task-timeline = true
flatten-isr-timelines = true
interaction-mode = "ipc"
include-unknown-events = true
disable-task-interactions = true
disable-control-plane = true
Expand Down Expand Up @@ -609,6 +619,7 @@ single-task-timeline = true
flatten-isr-timelines = true
disable-control-plane = true
use-timeline-id-channel = true
interaction-mode = "fully-linearized"
include-unknown-events = true
disable-task-interactions = true
ignored-object-classes = ['queue', 'Semaphore']
Expand Down Expand Up @@ -663,6 +674,7 @@ flatten-isr-timelines = true
disable-control-plane = true
use-timeline-id-channel = true
disable-task-interactions = true
interaction-mode = "ipc"
ignored-object-classes = ['queue', 'Semaphore']
attach-timeout = "100ms"
restart = true
Expand Down Expand Up @@ -790,6 +802,7 @@ metrics = true
}]
.into_iter()
.collect(),
interaction_mode: InteractionMode::Ipc,
import: ImportConfig {
protocol: None,
file: PathBuf::from("/path/to/memdump.bin").into(),
Expand Down Expand Up @@ -886,6 +899,7 @@ metrics = true
}]
.into_iter()
.collect(),
interaction_mode: InteractionMode::Ipc,
import: Default::default(),
tcp_collector: TcpCollectorConfig {
disable_control_plane: true,
Expand Down Expand Up @@ -986,6 +1000,7 @@ metrics = true
}]
.into_iter()
.collect(),
interaction_mode: InteractionMode::FullyLinearized,
import: Default::default(),
tcp_collector: Default::default(),
itm_collector: ItmCollectorConfig {
Expand Down Expand Up @@ -1097,6 +1112,7 @@ metrics = true
}]
.into_iter()
.collect(),
interaction_mode: InteractionMode::Ipc,
import: Default::default(),
tcp_collector: Default::default(),
itm_collector: Default::default(),
Expand Down
Loading

0 comments on commit 5f4fdfd

Please sign in to comment.