Commit f24ea4d3 authored by Marco Perronet's avatar Marco Perronet
Browse files

Add proper I/O in the match-model tool

parent 7b75d479
use structopt::StructOpt;
use serde_yaml;
use std::fs;
use std::fs::{
OpenOptions,
remove_file,
read_to_string,
};
use std::collections::HashMap;
use std::path::PathBuf;
use std::io::Write;
use rbf_trace::util::helpers::*;
use rbf_trace::event_generation::evg::{
......@@ -14,6 +20,8 @@ use rbf_trace::real_time::model_matching::mm::{
ScalarMM,
CurveMM,
};
use rbf_trace::real_time::model_matching::models::*;
use rbf_trace::real_time::rbf_curve::*;
fn main() {
let args = Opt::from_args();
......@@ -23,6 +31,10 @@ fn main() {
let mut trace_cycles: HashMap<Pid, InvocationCycle> = HashMap::new();
/* Processed events ("Arrival") */
let mut new_arrivals: HashMap<Pid, ArrivalSequence> = HashMap::new();
/* Output */
let mut scalar_models: &HashMap<Pid, Model> = &HashMap::new();
let mut curve_models: &HashMap<Pid, RbfCurve> = &HashMap::new();
let mut output = dd::Output::new();
let mut last_update_time = 0;
/* Model matcher instances */
......@@ -52,17 +64,49 @@ fn main() {
let last_update_elapsed = ns_to_s(event.instant - last_update_time);
if last_update_elapsed > args.update_interval {
let scalar_models = scalar_mm.update_and_match(&new_arrivals);
let curve_models = curve_mm.update_rbfs(&new_arrivals);
scalar_models = scalar_mm.update_and_match(&new_arrivals);
curve_models = curve_mm.update_rbfs(&new_arrivals);
/* Append to output */
// TODO
/* Print current model */
if args.print {
for (pid, model) in scalar_models {
eprintln!("PID {}:", pid);
model.pretty_print();
}
}
/* Reset */
last_update_time = event.instant;
new_arrivals.clear();
}
}
/* Convert to output format */
output.scalar_models = scalar_models.clone();
for (pid, rbf) in curve_models {
output.curve_models.insert(*pid, dd::OutputRbf::from(rbf));
}
if let Some(ref path) = args.output_path {
/* Write in output file */
if path.exists() {
remove_file(path).unwrap();
}
let mut outputfile = OpenOptions::new()
.create_new(true)
.write(true)
.open(path)
.expect("Can't initialize file.");
let serialized = serde_yaml::to_string(&output).expect("Can't serialize.");
write!(outputfile, "{}", serialized).expect("I/O error.");
} else {
/* Only print human readable information */
for (pid, model) in scalar_models {
eprintln!("PID {}:", pid);
model.pretty_print();
}
}
}
#[derive(Debug)]
......@@ -72,6 +116,8 @@ struct YamlSource {
path: String,
}
/* Event Generator */
impl YamlSource {
pub fn new(path: &String) -> Self {
let mut ret = YamlSource {
......@@ -88,7 +134,8 @@ impl YamlSource {
impl EventsGenerator for YamlSource {
fn setup(&mut self) {
self.trace = serde_yaml::from_str(&fs::read_to_string(&self.path).unwrap()).unwrap();
let s = &read_to_string(&self.path).unwrap();
self.trace = serde_yaml::from_str(s).unwrap();
}
fn shutdown(&mut self) {
......@@ -97,8 +144,14 @@ impl EventsGenerator for YamlSource {
fn next_event(&mut self) -> Option<TraceEvent> {
if self.curr_event_idx < self.trace.len() {
let ret: Option<TraceEvent>;
ret = Some(self.trace[self.curr_event_idx]);
// Check monotonicity
// TODO Can fail in non-uniprocessor configurations (clocks in different CPUs are not synchronized)
if self.curr_event_idx > 0 && self.trace[self.curr_event_idx-1].instant > self.trace[self.curr_event_idx].instant {
eprintln!("{} > {} !", self.trace[self.curr_event_idx-1].instant, self.trace[self.curr_event_idx].instant);
panic!();
}
let ret = Some(self.trace[self.curr_event_idx]);
self.curr_event_idx += 1;
return ret;
} else {
......@@ -107,27 +160,33 @@ impl EventsGenerator for YamlSource {
}
}
/* Args */
#[derive(Debug, StructOpt)]
pub struct Opt {
/// Specify the event source (YAML file).
#[structopt(short = "s", long)]
pub source_path: String,
/// Specify the output (YAML file).
#[structopt(short = "o", long)]
pub output_path: String,
/// Specify the output (YAML file). If not specified, will only print human-readable output.
#[structopt(short = "o", long, parse(from_os_str))]
pub output_path: Option<PathBuf>,
/// Update interval
/// Perform model matching every "interval" seconds
#[structopt(short = "i", long="interval", default_value="5.")]
pub update_interval: f32,
/// Print currently extracted scalar models every "interval" seconds
#[structopt(short = "p", long)]
pub print: bool,
// TUNABLES
/// Jitter bound
#[structopt(short = "J", long, default_value="1_500_000")]
#[structopt(short = "J", long, default_value="1500000")]
pub jitter_bound: Jitter,
/// Complexity threshold
#[structopt(short = "C", long, default_value="1_000_000")]
#[structopt(short = "C", long, default_value="1000000")]
pub complexity: u128,
/// Sparsify factor
......@@ -135,10 +194,65 @@ pub struct Opt {
pub sparsify: u64,
/// Arrivals buffer size
#[structopt(short = "B", long, default_value="1_000")]
#[structopt(short = "B", long, default_value="1000")]
pub bufsize: usize,
/// Maximal busy window for all curves
#[structopt(short = "w", long, default_value="1_000")]
#[structopt(short = "w", long, default_value="1000")]
pub window_size: usize,
}
/* I/O formats and conversions */
mod dd {
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use rbf_trace::util::helpers::*;
use rbf_trace::real_time::model_matching::models::*;
use rbf_trace::real_time::sparse_map::Point;
/* Note: we do not include the priority of the thread in the output.
That information can be inferred from the system configuration. */
#[derive(Serialize, Deserialize, Debug)]
pub struct Output {
// Human-readable
pub scalar_models: HashMap<Pid, Model>,
// Not human-readable
pub curve_models: HashMap<Pid, OutputRbf>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct OutputRbf {
pub rbf: Vec<Point>,
}
/* Only converting output */
mod conversion {
use super::*;
use std::convert::From;
use rbf_trace::real_time::rbf_curve::*;
use crate::dd;
impl From<&RbfCurve> for dd::OutputRbf {
fn from(rbf_curve: &RbfCurve) -> Self {
let mut points: Vec<Point> = Vec::new();
for p in rbf_curve.curve.into_iter() {
points.push(p);
}
dd::OutputRbf {
rbf: points,
}
}
}
}
impl Output {
pub fn new() -> Self {
Output {
scalar_models: HashMap::new(),
curve_models: HashMap::new(),
}
}
}
}
......@@ -12,6 +12,7 @@ use rbf_trace::event_generation::evg::{
EventsGenerator,
};
use rbf_trace::event_generation::ftrace::FTraceEVG;
use rbf_trace::event_generation::evg::TraceEvent;
use rbf_trace::config_detection::system::get_pids_with_policy;
use rbf_trace::config_detection::features::SchedPolicy;
......@@ -19,6 +20,7 @@ fn main() {
let args = Opt::from_args();
let traced_pids: Vec<Pid>;
let target_pids: Vec<Pid>;
let mut output: Vec<TraceEvent> = Vec::new();
/* Parsing */
if let Some(pids) = args.pids {
......@@ -57,14 +59,18 @@ fn main() {
}
while let Some(event) = evg.next_event() {
let serialized = serde_yaml::to_string(&event).expect("Can't serialize.");
if let Some(ref mut file) = outputfile {
write!(file, "{}", serialized).expect("I/O error.");
} else {
if outputfile.is_none() {
let serialized = serde_yaml::to_string(&event).expect("Can't serialize.");
print!("{}", serialized);
} else {
output.push(event);
}
}
if let Some(ref mut file) = outputfile {
let serialized = serde_yaml::to_string(&output).expect("Can't serialize.");
write!(file, "{}", serialized).expect("I/O error.");
}
}
#[derive(Debug, StructOpt)]
......@@ -73,7 +79,7 @@ pub struct Opt {
#[structopt(short = "p", long)]
pub pids: Option<Vec<Pid>>,
/// Trace until the specified pids are dead.
/// Trace until the specified pids are dead. By default, tracing is done until all traced pids are dead, unless -l is specified.
#[structopt(short = "t", long)]
pub target_pids: Option<Vec<Pid>>,
......
......@@ -114,6 +114,7 @@ pub struct ArrivalSequenceSubset {
pub pid: Pid,
pub buf_size: usize,
pub wcet: Cost,
pub tot_observations: u64,
// Current feasible periods range
pub t_interval: PeriodRange,
......@@ -123,6 +124,8 @@ impl ArrivalSequenceSubset {
/* Returns false if there are no feasible periods */
pub fn add_arrival(&mut self, mut new_arrival: Arrival) -> Option<PeriodRange> {
new_arrival.idx = self.tot_observations;
self.tot_observations += 1;
// Update wcet
self.wcet = self.wcet.max(new_arrival.cost);
......@@ -199,6 +202,7 @@ impl ArrivalSequenceSubset {
pid: pid,
buf_size: buf_size,
wcet: 0,
tot_observations: 0,
t_interval: PeriodRange::default(),
}
}
......
use crate::util::helpers::*;
use serde::{Serialize, Deserialize};
/* Only scalar models */
#[derive(Debug, Copy, Clone, PartialEq)]
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub enum Model {
PJitterOffset(Period, Jitter, Cost, Offset),
PJitter(Period, Jitter, Cost),
......
#!/bin/bash
SCRIPT_DIR="$(dirname "$0")"
LD_LIBRARY_PATH="$SCRIPT_DIR"/../event_generation/binary_parser/lib/build_output/usr/lib64 "$SCRIPT_DIR"/../../target/debug/match-model "$@"
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment