- update README to reflect correct performance numbers
- add tasks to README - repair bug in events.rs that prevented most events in VCD file from being parsed - add some initial code for timeline scrubbing
This commit is contained in:
parent
3a4ed56532
commit
cbd8be1708
|
@ -12,5 +12,5 @@ debug = 1
|
||||||
num = "0.4"
|
num = "0.4"
|
||||||
clap = { version = "3.1.8", features = ["derive"] }
|
clap = { version = "3.1.8", features = ["derive"] }
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
itertools = "0.10.3"
|
# TODO : remove itertools once date parser is reworked.
|
||||||
backtrace = "0.3"
|
itertools = "0.10.3"
|
10
README.md
10
README.md
|
@ -37,7 +37,7 @@ slower.
|
||||||
|
|
||||||
| Software | Time(s) | Memory(MB) |
|
| Software | Time(s) | Memory(MB) |
|
||||||
|----------|---------|------------|
|
|----------|---------|------------|
|
||||||
| FastWave | ~15.09 | 267.3 |
|
| FastWave | ~27.30 | 1100+ |
|
||||||
| GtkWave | ~30 | 89.8 |
|
| GtkWave | ~30 | 89.8 |
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,7 +67,10 @@ Here's a command to test on a malformed VCD:
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
## Features
|
## Features and Other
|
||||||
|
- [ ] add timeline value scanner code
|
||||||
|
- [ ] test against large waveform directly within SpinalHDL
|
||||||
|
- [ ] (a bit of work) consolidate error messages in validation phase
|
||||||
- [ ] be explicit with imports, remove exports as possible
|
- [ ] be explicit with imports, remove exports as possible
|
||||||
once FastWave is known to be fairly stable.
|
once FastWave is known to be fairly stable.
|
||||||
- [ ] do a read through all the code
|
- [ ] do a read through all the code
|
||||||
|
@ -88,5 +91,8 @@ Here's a command to test on a malformed VCD:
|
||||||
- [ ] Handle TODOs
|
- [ ] Handle TODOs
|
||||||
- [ ] Remove debug code/comments.
|
- [ ] Remove debug code/comments.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
- [ ] Document indexing structure with diagram and possibly include the rational
|
||||||
|
|
||||||
## Marketing
|
## Marketing
|
||||||
- [ ] Send survey to community
|
- [ ] Send survey to community
|
|
@ -25,7 +25,7 @@ fn main() -> std::io::Result<()> {
|
||||||
let elapsed = now.elapsed();
|
let elapsed = now.elapsed();
|
||||||
println!("Elapsed: {:.2?}", elapsed);
|
println!("Elapsed: {:.2?}", elapsed);
|
||||||
|
|
||||||
std::thread::sleep(std::time::Duration::from_secs(10));
|
// std::thread::sleep(std::time::Duration::from_secs(10));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use num::BigInt;
|
use num::BigUint;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub(super) fn parse_events<'a>(
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
let (word, cursor) = next_word!(word_reader)?;
|
let (word, cursor) = next_word.unwrap();
|
||||||
let Cursor(Line(_), Word(word_in_line_idx)) = cursor;
|
let Cursor(Line(_), Word(word_in_line_idx)) = cursor;
|
||||||
// we only want to match on the first word in a line
|
// we only want to match on the first word in a line
|
||||||
if word_in_line_idx != 1 {
|
if word_in_line_idx != 1 {
|
||||||
|
@ -26,14 +26,14 @@ pub(super) fn parse_events<'a>(
|
||||||
"#" => {
|
"#" => {
|
||||||
let value = &word[1..];
|
let value = &word[1..];
|
||||||
let (f, l) = (file!(), line!());
|
let (f, l) = (file!(), line!());
|
||||||
let value = BigInt::parse_bytes(value.as_bytes(), 10)
|
let value = BigUint::parse_bytes(value.as_bytes(), 10)
|
||||||
.ok_or(())
|
.ok_or(())
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
format!(
|
format!(
|
||||||
"Error near {f}:{l}. Failed to parse {value} as BigInt at {cursor:?}"
|
"Error near {f}:{l}. Failed to parse {value} as BigInt at {cursor:?}"
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
let (_, mut value) = value.to_bytes_le();
|
let mut value = value.to_bytes_le();
|
||||||
// TODO : u32 helps with less memory, but should ideally likely be
|
// TODO : u32 helps with less memory, but should ideally likely be
|
||||||
// configurable.
|
// configurable.
|
||||||
let (f, l) = (file!(), line!());
|
let (f, l) = (file!(), line!());
|
||||||
|
|
|
@ -5,8 +5,6 @@ use std::io::prelude::*;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use backtrace::{Backtrace, BacktraceFrame, BacktraceSymbol};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(super) struct Line(pub(super) usize);
|
pub(super) struct Line(pub(super) usize);
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
use super::utilities::{ordered_binary_lookup_u8, LookupErrors};
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
|
use num::{BigUint, Zero};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct Version(pub String);
|
pub(super) struct Version(pub String);
|
||||||
|
@ -72,6 +74,26 @@ pub(super) enum Signal {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) enum TimelineQueryResults {
|
||||||
|
BigUint(BigUint),
|
||||||
|
String(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scope {
|
||||||
|
pub(super) fn query_value(&self, time: TimelineIdx) -> Result<TimelineQueryResults, String> {
|
||||||
|
// match
|
||||||
|
// assert
|
||||||
|
// ordered_binary_lookup_u8(
|
||||||
|
// &value_sequence_as_bytes_u8,
|
||||||
|
// 4,
|
||||||
|
// &timeline_cursors,
|
||||||
|
// TimelineIdx(scrubbing_cursor),
|
||||||
|
// );
|
||||||
|
Ok(TimelineQueryResults::String("".to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct Scope {
|
pub(super) struct Scope {
|
||||||
pub(super) name: String,
|
pub(super) name: String,
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) enum BinaryParserErrTypes {
|
pub(super) enum BinaryParserErrTypes {
|
||||||
XValue,
|
XValue,
|
||||||
|
@ -77,61 +75,105 @@ pub(super) fn binary_str_to_vec_u8(binary_str: &str) -> Result<Vec<u8>, BinaryPa
|
||||||
Ok(vec_u8)
|
Ok(vec_u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO : modify ordered_binary_lookup to support VCD timeline lookup
|
use num::{BigUint, Zero};
|
||||||
// and return time in signature
|
|
||||||
fn compare_strs(a: &str, b: &str) -> Ordering {
|
|
||||||
// choose the smaller of the two indices
|
|
||||||
let upper_bound = if a.len() > b.len() { b.len() } else { a.len() };
|
|
||||||
let a_as_bytes = a.as_bytes();
|
|
||||||
let b_as_bytes = b.as_bytes();
|
|
||||||
|
|
||||||
for i in 0..upper_bound {
|
#[derive(Debug)]
|
||||||
let a_byte = a_as_bytes[i];
|
pub(super) enum LookupErrors {
|
||||||
let b_byte = b_as_bytes[i];
|
PreTimeline {
|
||||||
if a_byte > b_byte {
|
desired_time: TimelineIdx,
|
||||||
return Ordering::Greater;
|
timeline_start_time: TimelineIdx,
|
||||||
}
|
},
|
||||||
if b_byte > a_byte {
|
EmptyTimeline,
|
||||||
return Ordering::Less;
|
TimelineNotMultiple,
|
||||||
}
|
OrderingFailure,
|
||||||
}
|
|
||||||
|
|
||||||
if a.len() > b.len() {
|
|
||||||
return Ordering::Greater;
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.len() < b.len() {
|
|
||||||
return Ordering::Less;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ordering::Equal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ordered_binary_lookup(map: &Vec<(String, SignalIdx)>, key: &str) -> Result<SignalIdx, String> {
|
pub(super) fn ordered_binary_lookup_u8(
|
||||||
let mut upper_idx = map.len() - 1;
|
value_sequence_as_bytes: &Vec<u8>,
|
||||||
let mut lower_idx = 0usize;
|
bytes_per_value: usize,
|
||||||
|
timeline_cursors: &Vec<TimelineIdx>,
|
||||||
|
desired_time: TimelineIdx,
|
||||||
|
) -> Result<BigUint, LookupErrors> {
|
||||||
|
// timeline must not be empty
|
||||||
|
if timeline_cursors.is_empty() {
|
||||||
|
return Err(LookupErrors::EmptyTimeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertion that value_sequence is a proper multiple of
|
||||||
|
// timeline_markers
|
||||||
|
if value_sequence_as_bytes.len() != (timeline_cursors.len() * bytes_per_value) {
|
||||||
|
return Err(LookupErrors::TimelineNotMultiple);
|
||||||
|
}
|
||||||
|
|
||||||
|
let TimelineIdx(desired_time) = desired_time;
|
||||||
|
|
||||||
|
// check if we're requesting a value that occurs before the recorded
|
||||||
|
// start of the timeline
|
||||||
|
let TimelineIdx(timeline_start_time) = timeline_cursors.first().unwrap();
|
||||||
|
if desired_time < *timeline_start_time {
|
||||||
|
return Err(LookupErrors::PreTimeline {
|
||||||
|
desired_time: TimelineIdx(desired_time),
|
||||||
|
timeline_start_time: TimelineIdx(*timeline_start_time),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut lower_idx = 0usize;
|
||||||
|
let mut upper_idx = timeline_cursors.len() - 1;
|
||||||
|
|
||||||
|
// check if we're requesting a value that occurs beyond the end of the timeline,
|
||||||
|
// if so, return the last value in this timeline
|
||||||
|
let TimelineIdx(timeline_end_time) = timeline_cursors.last().unwrap();
|
||||||
|
if desired_time > *timeline_end_time {
|
||||||
|
let range = (value_sequence_as_bytes.len() - bytes_per_value)..;
|
||||||
|
let value_by_bytes = &value_sequence_as_bytes[range];
|
||||||
|
let value = BigUint::from_bytes_le(value_by_bytes);
|
||||||
|
|
||||||
|
return Ok(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This while loop is the meat of the lookup. Performance is log2(n),
|
||||||
|
// where n is the number of events on the timeline.
|
||||||
|
// We can assume that by the time we get here, that the desired_time
|
||||||
|
// is an event that occurs on the timeline, given that we handle any events
|
||||||
|
// occuring after or before the recorded tiimeline in the code above.
|
||||||
while lower_idx <= upper_idx {
|
while lower_idx <= upper_idx {
|
||||||
let mid_idx = lower_idx + ((upper_idx - lower_idx) / 2);
|
let mid_idx = lower_idx + ((upper_idx - lower_idx) / 2);
|
||||||
let (str_val, signal_idx) = map.get(mid_idx).unwrap();
|
let TimelineIdx(curr_time) = timeline_cursors[mid_idx];
|
||||||
let ordering = compare_strs(key, str_val.as_str());
|
let ordering = curr_time.cmp(&desired_time);
|
||||||
|
|
||||||
match ordering {
|
match ordering {
|
||||||
Ordering::Less => {
|
std::cmp::Ordering::Less => {
|
||||||
upper_idx = mid_idx - 1;
|
|
||||||
}
|
|
||||||
Ordering::Equal => {
|
|
||||||
return Ok(*signal_idx);
|
|
||||||
}
|
|
||||||
Ordering::Greater => {
|
|
||||||
lower_idx = mid_idx + 1;
|
lower_idx = mid_idx + 1;
|
||||||
}
|
}
|
||||||
|
std::cmp::Ordering::Equal => {
|
||||||
|
let u8_timeline_start_idx = mid_idx * bytes_per_value;
|
||||||
|
let u8_timeline_end_idx = u8_timeline_start_idx + bytes_per_value;
|
||||||
|
let range = u8_timeline_start_idx..u8_timeline_end_idx;
|
||||||
|
let value_by_bytes = &value_sequence_as_bytes[range];
|
||||||
|
let value = BigUint::from_bytes_le(value_by_bytes);
|
||||||
|
return Ok(value);
|
||||||
|
}
|
||||||
|
std::cmp::Ordering::Greater => {
|
||||||
|
upper_idx = mid_idx - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(format!(
|
let idx = lower_idx - 1;
|
||||||
"Error near {}:{}. Unable to find key: `{key}` in the map.",
|
let TimelineIdx(left_time) = timeline_cursors[idx];
|
||||||
file!(),
|
let TimelineIdx(right_time) = timeline_cursors[idx + 1];
|
||||||
line!()
|
|
||||||
));
|
let ordered_left = left_time < desired_time;
|
||||||
|
let ordered_right = desired_time < right_time;
|
||||||
|
if !(ordered_left && ordered_right) {
|
||||||
|
return Err(LookupErrors::OrderingFailure);
|
||||||
|
}
|
||||||
|
|
||||||
|
let u8_timeline_start_idx = idx * bytes_per_value;
|
||||||
|
let u8_timeline_end_idx = u8_timeline_start_idx + bytes_per_value;
|
||||||
|
let range = u8_timeline_start_idx..u8_timeline_end_idx;
|
||||||
|
let value_by_bytes = &value_sequence_as_bytes[range];
|
||||||
|
let value = BigUint::from_bytes_le(value_by_bytes);
|
||||||
|
|
||||||
|
return Ok(value);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue