Skip to content

Commit 8679959

Browse files
authored
Merge pull request #200 from rust-lang/analysis-in-analyzeme
Move profile data analysis into analyzeme from summarizeme
2 parents e2d7d6a + 5ee583b commit 8679959

File tree

8 files changed

+907
-921
lines changed

8 files changed

+907
-921
lines changed

analyzeme/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ decodeme = { path = "../decodeme" }
1010
memchr = "2"
1111
measureme = { path = "../measureme" }
1212
rustc-hash = "1.0.1"
13+
serde = { version = "1.0", features = ["derive"] }
1314

1415
# Depending on older versions of this crate allows us to keep supporting older
1516
# file formats.

analyzeme/src/analysis.rs

Lines changed: 658 additions & 0 deletions
Large diffs are not rendered by default.

analyzeme/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@
1010
//! To retrieve an `Iterator` of all of the events in the file,
1111
//! call the [`ProfilingData::iter()`] method.
1212
13+
mod analysis;
1314
mod file_formats;
1415
mod profiling_data;
1516
mod stack_collapse;
1617
pub mod testing_common;
1718

1819
pub use crate::profiling_data::{ProfilingData, ProfilingDataBuilder};
1920
pub use crate::stack_collapse::collapse_stacks;
21+
pub use analysis::{AnalysisResults, ArtifactSize, QueryData};
2022
pub use decodeme::event::Event;
2123
pub use decodeme::event_payload::{EventPayload, Timestamp};
2224
pub use decodeme::lightweight_event::LightweightEvent;

summarize/src/analysis.rs

Lines changed: 0 additions & 592 deletions
This file was deleted.

summarize/src/diff.rs

Lines changed: 241 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
use crate::query_data::{ArtifactSize, ArtifactSizeDiff, QueryData, QueryDataDiff, Results};
2-
use crate::signed_duration::SignedDuration;
1+
use analyzeme::{AnalysisResults, ArtifactSize, QueryData};
32
use rustc_hash::{FxHashMap, FxHashSet};
43
use serde::{Deserialize, Serialize};
4+
use std::cmp::Ordering;
55
use std::collections::HashSet;
6+
use std::fmt;
67
use std::time::Duration;
78

89
#[derive(Serialize, Deserialize)]
@@ -30,7 +31,7 @@ fn build_artifact_lookup(artifact_sizes: &[ArtifactSize]) -> FxHashMap<&str, usi
3031
lookup
3132
}
3233

33-
pub fn calculate_diff(base: Results, change: Results) -> DiffResults {
34+
pub fn calculate_diff(base: AnalysisResults, change: AnalysisResults) -> DiffResults {
3435
#[inline]
3536
fn sd(d: Duration) -> SignedDuration {
3637
d.into()
@@ -54,9 +55,9 @@ pub fn calculate_diff(base: Results, change: Results) -> DiffResults {
5455
let c = change_data.get(l).map(|i| &change.query_data[*i]);
5556

5657
match (b, c) {
57-
(Some(b), Some(c)) => c.clone() - b.clone(),
58-
(Some(b), None) => b.invert(),
59-
(None, Some(c)) => c.as_query_data_diff(),
58+
(Some(b), Some(c)) => QueryDataDiff::sub(c.clone(), b.clone()),
59+
(Some(b), None) => QueryDataDiff::invert_query_data(b),
60+
(None, Some(c)) => QueryDataDiff::query_data_as_diff(c),
6061
(None, None) => unreachable!(),
6162
}
6263
})
@@ -79,9 +80,9 @@ pub fn calculate_diff(base: Results, change: Results) -> DiffResults {
7980
let c = change_data.get(l).map(|i| &change.artifact_sizes[*i]);
8081

8182
match (b, c) {
82-
(Some(b), Some(c)) => c.clone() - b.clone(),
83-
(Some(b), None) => b.invert(),
84-
(None, Some(c)) => c.as_artifact_size_diff(),
83+
(Some(b), Some(c)) => ArtifactSizeDiff::sub(c.clone(), b.clone()),
84+
(Some(b), None) => ArtifactSizeDiff::invert_artifact_size(b),
85+
(None, Some(c)) => ArtifactSizeDiff::artifact_size_as_diff(c),
8586
(None, None) => unreachable!(),
8687
}
8788
})
@@ -94,3 +95,234 @@ pub fn calculate_diff(base: Results, change: Results) -> DiffResults {
9495
total_time: sd(change.total_time) - sd(base.total_time),
9596
}
9697
}
98+
99+
/// The diff between two `QueryData`
100+
#[derive(Serialize, Deserialize)]
101+
pub struct QueryDataDiff {
102+
pub label: String,
103+
pub time: SignedDuration,
104+
pub time_change: f64,
105+
pub self_time: SignedDuration,
106+
pub self_time_change: f64,
107+
pub number_of_cache_misses: i64,
108+
pub number_of_cache_hits: i64,
109+
pub invocation_count: i64,
110+
pub blocked_time: SignedDuration,
111+
pub incremental_load_time: SignedDuration,
112+
pub incremental_hashing_time: SignedDuration,
113+
}
114+
115+
impl QueryDataDiff {
116+
fn sub(lhs: QueryData, rhs: QueryData) -> QueryDataDiff {
117+
#[inline(always)]
118+
fn sd(d: Duration) -> SignedDuration {
119+
d.into()
120+
}
121+
122+
#[inline(always)]
123+
fn i(u: usize) -> i64 {
124+
u as i64
125+
}
126+
127+
fn percentage_change(base: Duration, change: Duration) -> f64 {
128+
let nanos = change.as_nanos() as i128 - base.as_nanos() as i128;
129+
nanos as f64 / base.as_nanos() as f64 * 100.0
130+
}
131+
132+
QueryDataDiff {
133+
label: lhs.label,
134+
time: sd(lhs.time) - sd(rhs.time),
135+
time_change: percentage_change(rhs.time, lhs.time),
136+
self_time: sd(lhs.self_time) - sd(rhs.self_time),
137+
self_time_change: percentage_change(rhs.self_time, lhs.self_time),
138+
number_of_cache_misses: i(lhs.number_of_cache_misses) - i(rhs.number_of_cache_misses),
139+
number_of_cache_hits: i(lhs.number_of_cache_hits) - i(rhs.number_of_cache_hits),
140+
invocation_count: i(lhs.invocation_count) - i(rhs.invocation_count),
141+
blocked_time: sd(lhs.blocked_time) - sd(rhs.blocked_time),
142+
incremental_load_time: sd(lhs.incremental_load_time) - sd(rhs.incremental_load_time),
143+
incremental_hashing_time: sd(lhs.incremental_hashing_time)
144+
- sd(rhs.incremental_hashing_time),
145+
}
146+
}
147+
148+
pub fn invert_query_data(data: &QueryData) -> QueryDataDiff {
149+
fn invert(d: Duration) -> SignedDuration {
150+
SignedDuration {
151+
duration: d,
152+
is_positive: false,
153+
}
154+
}
155+
156+
QueryDataDiff {
157+
label: data.label.clone(),
158+
time: invert(data.time),
159+
time_change: -100.0,
160+
self_time: invert(data.self_time),
161+
self_time_change: -100.0,
162+
number_of_cache_misses: -(data.number_of_cache_misses as i64),
163+
number_of_cache_hits: -(data.number_of_cache_hits as i64),
164+
invocation_count: -(data.invocation_count as i64),
165+
blocked_time: invert(data.blocked_time),
166+
incremental_load_time: invert(data.incremental_load_time),
167+
incremental_hashing_time: invert(data.incremental_hashing_time),
168+
}
169+
}
170+
171+
pub fn query_data_as_diff(data: &QueryData) -> QueryDataDiff {
172+
QueryDataDiff {
173+
label: data.label.clone(),
174+
time: data.time.into(),
175+
time_change: std::f64::INFINITY,
176+
self_time: data.self_time.into(),
177+
self_time_change: std::f64::INFINITY,
178+
number_of_cache_misses: data.number_of_cache_misses as i64,
179+
number_of_cache_hits: data.number_of_cache_hits as i64,
180+
invocation_count: data.invocation_count as i64,
181+
blocked_time: data.blocked_time.into(),
182+
incremental_load_time: data.incremental_load_time.into(),
183+
incremental_hashing_time: data.incremental_hashing_time.into(),
184+
}
185+
}
186+
}
187+
188+
#[derive(Serialize, Deserialize, Debug)]
189+
pub struct ArtifactSizeDiff {
190+
pub label: String,
191+
pub size_change: i64,
192+
}
193+
194+
impl ArtifactSizeDiff {
195+
pub fn invert_artifact_size(size: &ArtifactSize) -> ArtifactSizeDiff {
196+
ArtifactSizeDiff {
197+
label: size.label.clone(),
198+
size_change: -(size.value as i64),
199+
}
200+
}
201+
202+
pub fn artifact_size_as_diff(size: &ArtifactSize) -> ArtifactSizeDiff {
203+
ArtifactSizeDiff {
204+
label: size.label.clone(),
205+
size_change: size.value as i64,
206+
}
207+
}
208+
fn sub(lhs: ArtifactSize, rhs: ArtifactSize) -> ArtifactSizeDiff {
209+
ArtifactSizeDiff {
210+
label: lhs.label,
211+
size_change: lhs.value as i64 - rhs.value as i64,
212+
}
213+
}
214+
}
215+
216+
#[derive(Serialize, Deserialize, Clone, Copy, Eq, PartialEq)]
217+
pub struct SignedDuration {
218+
pub duration: Duration,
219+
pub is_positive: bool,
220+
}
221+
222+
impl SignedDuration {
223+
pub fn as_nanos(&self) -> i128 {
224+
let sign = if self.is_positive { 1 } else { -1 };
225+
226+
sign * (self.duration.as_nanos() as i128)
227+
}
228+
229+
pub fn from_nanos(nanos: i128) -> SignedDuration {
230+
let is_positive = nanos >= 0;
231+
232+
SignedDuration {
233+
duration: Duration::from_nanos(nanos.abs() as u64),
234+
is_positive,
235+
}
236+
}
237+
}
238+
239+
impl From<Duration> for SignedDuration {
240+
fn from(d: Duration) -> SignedDuration {
241+
SignedDuration {
242+
duration: d,
243+
is_positive: true,
244+
}
245+
}
246+
}
247+
248+
impl Ord for SignedDuration {
249+
fn cmp(&self, other: &SignedDuration) -> Ordering {
250+
self.as_nanos().cmp(&other.as_nanos())
251+
}
252+
}
253+
254+
impl PartialOrd for SignedDuration {
255+
fn partial_cmp(&self, other: &SignedDuration) -> Option<Ordering> {
256+
Some(self.cmp(other))
257+
}
258+
}
259+
260+
impl std::ops::Sub for SignedDuration {
261+
type Output = SignedDuration;
262+
263+
fn sub(self, rhs: SignedDuration) -> SignedDuration {
264+
SignedDuration::from_nanos(self.as_nanos() - rhs.as_nanos())
265+
}
266+
}
267+
268+
impl fmt::Debug for SignedDuration {
269+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270+
if self.is_positive {
271+
write!(f, "+")?;
272+
} else {
273+
write!(f, "-")?;
274+
}
275+
276+
write!(f, "{:?}", self.duration)
277+
}
278+
}
279+
280+
#[cfg(test)]
281+
mod test {
282+
use super::SignedDuration;
283+
use std::time::Duration;
284+
285+
#[test]
286+
fn op_subtract() {
287+
let zero_d = Duration::from_nanos(0);
288+
let one_d = Duration::from_nanos(1);
289+
let two_d = Duration::from_nanos(2);
290+
291+
let zero_sd = SignedDuration::from(zero_d);
292+
let one_sd = SignedDuration::from(one_d);
293+
let neg_one_sd = SignedDuration {
294+
duration: one_d,
295+
is_positive: false,
296+
};
297+
let two_sd = SignedDuration::from(two_d);
298+
let neg_two_sd = SignedDuration {
299+
duration: two_d,
300+
is_positive: false,
301+
};
302+
303+
assert_eq!(zero_d, zero_sd.duration);
304+
assert_eq!(true, zero_sd.is_positive);
305+
306+
assert_eq!(zero_sd, zero_sd - zero_sd);
307+
308+
assert_eq!(one_d, one_sd.duration);
309+
assert_eq!(true, one_sd.is_positive);
310+
311+
assert_eq!(one_sd, one_sd - zero_sd);
312+
313+
assert_eq!(one_d, neg_one_sd.duration);
314+
assert_eq!(false, neg_one_sd.is_positive);
315+
316+
assert_eq!(neg_one_sd, neg_one_sd - zero_sd);
317+
318+
assert_eq!(zero_sd, one_sd - one_sd);
319+
320+
assert_eq!(one_sd, two_sd - one_sd);
321+
322+
assert_eq!(neg_one_sd, one_sd - two_sd);
323+
324+
assert_eq!(neg_two_sd, neg_one_sd - one_sd);
325+
326+
assert_eq!(zero_sd, neg_one_sd - neg_one_sd);
327+
}
328+
}

summarize/src/main.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#[macro_use]
22
extern crate prettytable;
33

4+
use analyzeme::AnalysisResults;
45
use analyzeme::ProfilingData;
56
use std::error::Error;
67
use std::fs::File;
@@ -12,12 +13,7 @@ use serde::Serialize;
1213
use structopt::StructOpt;
1314

1415
mod aggregate;
15-
mod analysis;
1616
mod diff;
17-
mod query_data;
18-
mod signed_duration;
19-
20-
use query_data::Results;
2117

2218
#[derive(StructOpt, Debug)]
2319
struct AggregateOpt {
@@ -63,16 +59,16 @@ enum Opt {
6359
Summarize(SummarizeOpt),
6460
}
6561

66-
fn process_results(file: &PathBuf) -> Result<Results, Box<dyn Error + Send + Sync>> {
62+
fn process_results(file: &PathBuf) -> Result<AnalysisResults, Box<dyn Error + Send + Sync>> {
6763
if file.ends_with("json") {
6864
let reader = BufReader::new(File::open(&file)?);
6965

70-
let results: Results = serde_json::from_reader(reader)?;
66+
let results: AnalysisResults = serde_json::from_reader(reader)?;
7167
Ok(results)
7268
} else {
7369
let data = ProfilingData::new(&file)?;
7470

75-
Ok(analysis::perform_analysis(data))
71+
Ok(data.perform_analysis())
7672
}
7773
}
7874

@@ -172,7 +168,7 @@ fn diff(opt: DiffOpt) -> Result<(), Box<dyn Error + Send + Sync>> {
172168
fn summarize(opt: SummarizeOpt) -> Result<(), Box<dyn Error + Send + Sync>> {
173169
let data = ProfilingData::new(&opt.file_prefix)?;
174170

175-
let mut results = analysis::perform_analysis(data);
171+
let mut results = data.perform_analysis();
176172

177173
//just output the results into a json file
178174
if opt.json {

0 commit comments

Comments
 (0)