-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Interval log support #70
Changes from 1 commit
b7990f7
4d20592
e32c13a
b5bd78f
471be3a
a6eb1ab
5553e18
00a5ee1
686e350
ed8cda6
94574f3
15c14aa
a5997fe
046b595
4d35a9e
2e24769
bba8970
cf9ec24
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -94,21 +94,22 @@ | |
//! ``` | ||
//! use hdrsample::serialization::interval_log; | ||
//! | ||
//! let mut log = Vec::new(); | ||
//! log.extend_from_slice(b"#I'm a comment\n"); | ||
//! log.extend_from_slice(b"Tag=a,0.123,1.007,2.769,base64EncodedHisto\n"); | ||
//! log.extend_from_slice(b"1.456,1.007,2.769,base64EncodedHisto\n"); | ||
//! log.extend_from_slice(b"3.789,1.007,2.769,base64EncodedHisto\n"); | ||
//! log.extend_from_slice(b"Tag=b,4.123,1.007,2.769,base64EncodedHisto\n"); | ||
//! log.extend_from_slice(b"5.456,1.007,2.769,base64EncodedHisto\n"); | ||
//! log.extend_from_slice(b"#Another comment\n"); | ||
//! let mut log = "\ | ||
//! #I'm a comment\n\ | ||
//! Tag=a,0.123,1.007,2.769,base64EncodedHisto\n\ | ||
//! 1.456,1.007,2.769,base64EncodedHisto\n\ | ||
//! 3.789,1.007,2.769,base64EncodedHisto\n\ | ||
//! Tag=b,4.123,1.007,2.769,base64EncodedHisto\n\ | ||
//! 5.456,1.007,2.769,base64EncodedHisto\n\ | ||
//! #Another comment\n" | ||
//! .as_bytes(); | ||
//! | ||
//! let iter = interval_log::IntervalLogIterator::new(&log); | ||
//! | ||
//! let count = iter.map(|r| r.unwrap()) | ||
//! let count = iter | ||
//! // only look at intervals (which are the only non-comment lines in this log) | ||
//! .filter_map(|e| match e { | ||
//! interval_log::LogEntry::Interval(ilh) => Some(ilh), | ||
//! Ok(interval_log::LogEntry::Interval(ilh)) => Some(ilh), | ||
//! _ => None | ||
//! }) | ||
//! // do any filtering you want | ||
|
@@ -121,7 +122,7 @@ | |
//! Write a log. | ||
//! | ||
//! ``` | ||
//! use std::str; | ||
//! use std::{str, time}; | ||
//! use hdrsample; | ||
//! use hdrsample::serialization; | ||
//! use hdrsample::serialization::interval_log; | ||
|
@@ -149,7 +150,7 @@ | |
//! .write_histogram( | ||
//! &h, | ||
//! 1.234, | ||
//! 5.678, | ||
//! time::Duration::new(12, 345_678_901), | ||
//! interval_log::Tag::new("im-a-tag"), | ||
//! 1.0) | ||
//! .unwrap(); | ||
|
@@ -161,7 +162,7 @@ | |
|
||
extern crate base64; | ||
|
||
use std::{fmt, io, ops, str}; | ||
use std::{fmt, io, ops, str, time}; | ||
use std::fmt::Write; | ||
|
||
use nom::{double, line_ending, not_line_ending, IResult}; | ||
|
@@ -260,7 +261,7 @@ impl<'a, 'b, W: 'a + io::Write, S: 'b + Serializer> IntervalLogWriter<'a, 'b, W, | |
&mut self, | ||
h: &Histogram<T>, | ||
start_timestamp: f64, | ||
duration: f64, | ||
duration: time::Duration, | ||
tag: Option<Tag>, | ||
max_value_divisor: f64, | ||
) -> Result<(), IntervalLogWriterError<S::SerializeError>> { | ||
|
@@ -305,7 +306,7 @@ impl<'a, 'b, W: 'a + io::Write, S: 'b + Serializer> InternalLogWriter<'a, 'b, W, | |
&mut self, | ||
h: &Histogram<T>, | ||
start_timestamp: f64, | ||
duration: f64, | ||
duration: time::Duration, | ||
tag: Option<Tag>, | ||
max_value_divisor: f64, | ||
) -> Result<(), IntervalLogWriterError<S::SerializeError>> { | ||
|
@@ -321,7 +322,7 @@ impl<'a, 'b, W: 'a + io::Write, S: 'b + Serializer> InternalLogWriter<'a, 'b, W, | |
"{}{:.3},{:.3},{:.3},", | ||
self.text_buf, | ||
start_timestamp, | ||
duration, | ||
duration_as_fp_seconds(duration), | ||
h.max() as f64 / max_value_divisor // because the Java impl does it this way | ||
)?; | ||
|
||
|
@@ -345,7 +346,7 @@ impl<'a, 'b, W: 'a + io::Write, S: 'b + Serializer> InternalLogWriter<'a, 'b, W, | |
/// To get the wrapped `str` back out, use `as_str()` or the `Deref<str>` implementation | ||
/// (`&some_tag`). | ||
#[derive(Debug, PartialEq, Clone, Copy)] | ||
pub struct Tag<'a>(pub &'a str); | ||
pub struct Tag<'a>(&'a str); | ||
|
||
impl<'a> Tag<'a> { | ||
/// Create a new Tag. | ||
|
@@ -380,6 +381,7 @@ impl<'a> ops::Deref for Tag<'a> { | |
pub struct IntervalLogHistogram<'a> { | ||
tag: Option<Tag<'a>>, | ||
start_timestamp: f64, | ||
// lazily map to Duration to save parsing time and a few bytes of space on ILH | ||
duration: f64, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still think this should be exposed as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll make |
||
max: f64, | ||
encoded_histogram: &'a str, | ||
|
@@ -401,8 +403,11 @@ impl<'a> IntervalLogHistogram<'a> { | |
} | ||
|
||
/// Duration of the interval in seconds. | ||
pub fn duration(&self) -> f64 { | ||
self.duration | ||
pub fn duration(&self) -> time::Duration { | ||
let secs = self.duration as u64; | ||
// can't overflow because this can be at most 1 billion which is approx 2^30 | ||
let nsecs = (self.duration.fract() * 1_000_000_000_f64) as u32; | ||
time::Duration::new(secs, nsecs) | ||
} | ||
|
||
/// Max value in the encoded histogram | ||
|
@@ -525,6 +530,10 @@ impl<'a> Iterator for IntervalLogIterator<'a> { | |
} | ||
} | ||
|
||
fn duration_as_fp_seconds(d: time::Duration) -> f64 { | ||
d.as_secs() as f64 + d.subsec_nanos() as f64 / 1_000_000_000_f64 | ||
} | ||
|
||
named!(start_time<&[u8], LogEntry>, | ||
do_parse!( | ||
tag!("#[StartTime: ") >> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
//! This is used in tests (both unit tests and integration tests) to provide useful distributions | ||
//! of random numbers. | ||
|
||
extern crate rand; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This module is only used in tests, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's correct. I'll give it a comment to make it less confusing. |
||
use self::rand::Rng; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,7 @@ mod tests { | |
IntervalLogHistogram, IntervalLogIterator, | ||
LogEntry, LogIteratorError, Tag}; | ||
|
||
use std::{io, str}; | ||
use std::{io, str, time}; | ||
use std::io::{BufRead, Read}; | ||
use std::fs::File; | ||
use std::path::Path; | ||
|
@@ -97,7 +97,13 @@ mod tests { | |
intervals | ||
.iter() | ||
.filter(|ilh| ilh.tag().is_none()) | ||
.map(|ilh| { (ilh.start_timestamp(), ilh.duration(), ilh.max()) }) | ||
.map(|ilh| { | ||
( | ||
ilh.start_timestamp(), | ||
round(duration_as_fp_seconds(ilh.duration())), | ||
ilh.max(), | ||
) | ||
}) | ||
.collect::<Vec<(f64, f64, f64)>>() | ||
); | ||
|
||
|
@@ -106,7 +112,13 @@ mod tests { | |
intervals | ||
.iter() | ||
.filter(|ilh| !ilh.tag().is_none()) | ||
.map(|ilh| { (ilh.start_timestamp(), ilh.duration(), ilh.max()) }) | ||
.map(|ilh| { | ||
( | ||
ilh.start_timestamp(), | ||
round(duration_as_fp_seconds(ilh.duration())), | ||
ilh.max(), | ||
) | ||
}) | ||
.collect::<Vec<(f64, f64, f64)>>() | ||
); | ||
|
||
|
@@ -241,7 +253,13 @@ mod tests { | |
.map(|s| Tag::new(s.as_str()).unwrap()); | ||
|
||
writer | ||
.write_histogram(&h, i as f64, (i as f64) + 10000.0, tag, max_scaling_factor) | ||
.write_histogram( | ||
&h, | ||
i as f64, | ||
time::Duration::new(10_000 + i as u64, 0), | ||
tag, | ||
max_scaling_factor, | ||
) | ||
.unwrap(); | ||
|
||
writer.write_comment(&format!("line {}", i)).unwrap(); | ||
|
@@ -250,10 +268,11 @@ mod tests { | |
} | ||
} | ||
|
||
println!("{}", ::std::str::from_utf8(&log_buf).unwrap()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume this is just leftover from debugging? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doh! |
||
|
||
let parsed = IntervalLogIterator::new(&log_buf) | ||
.map(|r| r.unwrap()) | ||
.filter_map(|e| match e { | ||
LogEntry::Interval(ilh) => Some(ilh), | ||
Ok(LogEntry::Interval(ilh)) => Some(ilh), | ||
_ => None, | ||
}) | ||
.collect::<Vec<IntervalLogHistogram>>(); | ||
|
@@ -272,7 +291,10 @@ mod tests { | |
assert_eq!(original_hist, &decoded_hist); | ||
|
||
assert_eq!(index as f64, ilh.start_timestamp()); | ||
assert_eq!((index as f64) + 10000.0, ilh.duration()); | ||
assert_eq!( | ||
time::Duration::new(10_000 + index as u64, 0), | ||
ilh.duration() | ||
); | ||
assert_eq!( | ||
round(original_hist.max() as f64 / max_scaling_factor), | ||
ilh.max() | ||
|
@@ -287,6 +309,10 @@ mod tests { | |
format!("{:.3}", f).parse::<f64>().unwrap() | ||
} | ||
|
||
fn duration_as_fp_seconds(d: time::Duration) -> f64 { | ||
d.as_secs() as f64 + d.subsec_nanos() as f64 / 1_000_000_000_f64 | ||
} | ||
|
||
fn load_iterator_from_file<'a>(path: &Path) -> IntervalLogBufHolder { | ||
let mut buf = Vec::new(); | ||
let _ = File::open(path).unwrap().read_to_end(&mut buf).unwrap(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this should maybe be a
Duration
as well? 🤔 Conceivably, that's how it would be used: aDuration
since eitherUNIX_EPOCH
or whatever the chosenStartTime
/BaseTime
was.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, yeah, that's a good idea!