Print module name and priority

This commit is contained in:
Henrik Tjäder 2020-03-07 23:39:20 +01:00
parent 6eafcf10e9
commit d4439fe73b

View file

@ -1,13 +1,11 @@
use syn::parse; use syn::parse;
//use syn::Ident; use std::collections::HashMap;
//use proc_macro2::{Ident, Span};
use proc_macro2::Ident; use proc_macro2::Ident;
use rtfm_syntax::{ use rtfm_syntax::{
analyze::{Analysis, Ownership}, analyze::Analysis,
ast::App, ast::App,
}; };
use syn::Error; use syn::Error;
// ast::{App, CustomArg},
type Idents<'a> = Vec<&'a Ident>; type Idents<'a> = Vec<&'a Ident>;
@ -42,26 +40,31 @@ pub fn app(app: &App, _analysis: &Analysis) -> parse::Result<()> {
// collect all tasks into a vector // collect all tasks into a vector
type Task = String; type Task = String;
type Priority = u8;
let all_tasks: Vec<(Task, Idents)> = app let all_tasks: Vec<(Task, Idents, Priority)> = app
.idles .idles
.iter() .iter()
.map(|(core, ht)| { .map(|(core, ht)| {
( (
format!("Idle (core {})", core), format!("Idle (core {})", core),
ht.args.resources.iter().map(|(v, _)| v).collect::<Vec<_>>(), ht.args.resources.iter().map(|(v, _)| v).collect::<Vec<_>>(),
0
) )
}) })
.chain(app.software_tasks.iter().map(|(name, ht)| { .chain(app.software_tasks.iter().map(|(name, ht)| {
( (
name.to_string(), name.to_string(),
ht.args.resources.iter().map(|(v, _)| v).collect::<Vec<_>>(), ht.args.resources.iter().map(|(v, _)| v).collect::<Vec<_>>(),
ht.args.priority
) )
})) }))
.chain(app.hardware_tasks.iter().map(|(name, ht)| { .chain(app.hardware_tasks.iter().map(|(name, ht)| {
( (
name.to_string(), name.to_string(),
ht.args.resources.iter().map(|(v, _)| v).collect::<Vec<_>>(), ht.args.resources.iter().map(|(v, _)| v).collect::<Vec<_>>(),
ht.args.priority
) )
})) }))
.collect(); .collect();
@ -70,10 +73,10 @@ pub fn app(app: &App, _analysis: &Analysis) -> parse::Result<()> {
let mut error = vec![]; let mut error = vec![];
for task_local_id in task_local.iter() { for task_local_id in task_local.iter() {
let mut used = vec![]; let mut used = vec![];
for (task, tr) in all_tasks.iter() { for (task, tr, priority) in all_tasks.iter() {
for r in tr { for r in tr {
if task_local_id == r { if task_local_id == r {
used.push((task, r)); used.push((task, r, priority));
} }
} }
} }
@ -86,45 +89,70 @@ pub fn app(app: &App, _analysis: &Analysis) -> parse::Result<()> {
), ),
)); ));
used.iter().for_each(|(task, resource)| { used.iter().for_each(|(task, resource, priority)| {
error.push(Error::new( error.push(Error::new(
resource.span(), resource.span(),
format!( format!(
"task local resource {:?} is used by task {:?}", "task local resource {:?} is used by task {:?} with priority {:?}",
resource.to_string(), resource.to_string(),
task task,
priority
), ),
)) ))
}); });
} }
} }
// filter out contended resources let mut lf_res_with_error = vec![];
let contended: Vec<(&Ident, &Ownership)> = _analysis let mut lf_hash = HashMap::new();
.ownerships
.iter()
.filter(|(_id, own)| match own {
Ownership::Contended { .. } => true,
_ => false,
})
.collect();
// filter out lock_free contended resources for lf_res in lock_free.iter() {
let lock_free_violation: Vec<&(&Ident, &Ownership)> = contended for (task, tr, priority) in all_tasks.iter() {
.iter() for r in tr {
.filter(|(cont_id, _)| lock_free.iter().any(|lf_id| cont_id == lf_id)) // Get all uses of resources annotated lock_free
.collect(); if lf_res == r {
// HashMap returns the previous existing object if old.key == new.key
if let Some(lf_res) = lf_hash.insert(r.to_string(), (task, r, priority)) {
// Check if priority differ, if it does, append to
// list of resources which will be annotated with errors
if priority != lf_res.2 {
lf_res_with_error.push(lf_res.1);
lf_res_with_error.push(r);
}
// If the resource already violates lock free properties
if lf_res_with_error.contains(&r) {
lf_res_with_error.push(lf_res.1);
lf_res_with_error.push(r);
}
}
}
}
}
}
// report contention error // Add error message in the resource struct
lock_free_violation.iter().for_each(|(lf_err_id, _)| { for r in lock_free {
if lf_res_with_error.contains(&&r) {
error.push(Error::new( error.push(Error::new(
lf_err_id.span(), r.span(),
format!( format!(
"lock_free resource {:?} is contended by higher priority task", "Lock free resource {:?} is used by tasks at different priorities",
lf_err_id.to_string() r.to_string(),
), ),
)) ));
}); }
}
// Add error message for each use of the resource
for resource in lf_res_with_error.clone() {
error.push(Error::new(
resource.span(),
format!(
"Resource {:?} is declared lock free but used by tasks at different priorities",
resource.to_string(),
),
));
}
// collect errors // collect errors
if error.is_empty() { if error.is_empty() {
@ -134,45 +162,4 @@ pub fn app(app: &App, _analysis: &Analysis) -> parse::Result<()> {
error.iter().for_each(|e| err.combine(e.clone())); error.iter().for_each(|e| err.combine(e.clone()));
Err(err) Err(err)
} }
// for tl in task_local {
// println!("tl {:?}", tl);
// // let mut first_use = None;
// for i in _analysis.ownerships.iter() {
// println!("\nown: {:?}", i);
// }
// // println!("analysis {:?}", _analysis.locations);
// for i in _analysis.locations.iter() {
// println!("\nloc: {:?}", i);
// }
// ErrorMessage {
// // Span is implemented as an index into a thread-local interner to keep the
// // size small. It is not safe to access from a different thread. We want
// // errors to be Send and Sync to play nicely with the Failure crate, so pin
// // the span we're given to its original thread and assume it is
// // Span::call_site if accessed from any other thread.
// start_span: ThreadBound<Span>,
// end_span: ThreadBound<Span>,
// message: String,
// }
// (app.name, "here");
// let span = app.name.span();
// let start = span.start();
// Err(vec![ErrorMessage { start_span: app.name.}]);
// let mut task_locals = Vec::new();
// println!("-- app:late_resources");
// println!(
// "task_locals {:?}",
// app.late_resources.filter(|r| r.task_local)
// );
// println!("-- resources");
// for i in app.resources.iter() {
// println!("res: {:?}", i);
// }
} }