Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8371b95

Browse files
authoredSep 8, 2019
Merge pull request #146 from koute/master
Reduce the number of dependencies
2 parents af3cb2a + f9c119d commit 8371b95

File tree

5 files changed

+137
-17
lines changed

5 files changed

+137
-17
lines changed
 

‎Cargo.toml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,22 @@ cirrus-ci = { repository = "jonhoo/inferno" }
2121
codecov = { repository = "jonhoo/inferno", branch = "master", service = "github" }
2222

2323
[features]
24-
default = ["cli"]
24+
default = ["cli", "multithreaded"]
2525
cli = ["structopt", "env_logger"]
26+
multithreaded = ["chashmap", "crossbeam", "num_cpus"]
2627

2728
[dependencies]
28-
chashmap = "2.2"
29-
crossbeam = "0.7"
29+
chashmap = { version = "2.2", optional = true }
30+
crossbeam = { version = "0.7", optional = true }
3031
env_logger = { version = "0.6.0", optional = true }
3132
fnv = "1.0.3"
3233
indexmap = "1.0"
3334
itoa = "0.4.3"
3435
lazy_static = "1.3.0"
3536
log = "0.4"
36-
num_cpus = "1.10"
37+
num_cpus = { version = "1.10", optional = true }
3738
num-format = { version = "0.4", default-features = false }
38-
quick-xml = { version = "0.15", default-features = false }
39-
rand = "0.7"
39+
quick-xml = { version = "0.16", default-features = false }
4040
rgb = "0.8.13"
4141
str_stack = "0.1"
4242
structopt = { version = "0.2", optional = true }

‎src/collapse/common.rs

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ use std::io;
33
use std::mem;
44
use std::sync::Arc;
55

6+
#[cfg(feature = "multithreaded")]
67
use chashmap::CHashMap;
8+
#[cfg(feature = "multithreaded")]
79
use crossbeam::channel;
10+
811
use fnv::FnvHashMap;
912
use lazy_static::lazy_static;
1013

@@ -26,11 +29,18 @@ const NBYTES_PER_STACK_GUESS: usize = 1024;
2629

2730
const RUST_HASH_LENGTH: usize = 17;
2831

32+
#[cfg(feature = "multithreaded")]
2933
lazy_static! {
3034
#[doc(hidden)]
3135
pub static ref DEFAULT_NTHREADS: usize = num_cpus::get();
3236
}
3337

38+
#[cfg(not(feature = "multithreaded"))]
39+
lazy_static! {
40+
#[doc(hidden)]
41+
pub static ref DEFAULT_NTHREADS: usize = 1;
42+
}
43+
3444
/// Private trait for internal library authors.
3545
///
3646
/// If you implement this trait, your type will implement the public-facing
@@ -154,6 +164,15 @@ pub trait CollapsePrivate: Send + Sized {
154164
occurrences.write_and_clear(writer)
155165
}
156166

167+
#[cfg(not(feature = "multithreaded"))]
168+
fn collapse_multi_threaded<R>(&mut self, _: R, _: &mut Occurrences) -> io::Result<()>
169+
where
170+
R: io::BufRead,
171+
{
172+
unimplemented!();
173+
}
174+
175+
#[cfg(feature = "multithreaded")]
157176
fn collapse_multi_threaded<R>(
158177
&mut self,
159178
mut reader: R,
@@ -332,32 +351,48 @@ pub trait CollapsePrivate: Send + Sized {
332351
#[derive(Clone, Debug)]
333352
pub enum Occurrences {
334353
SingleThreaded(FnvHashMap<String, usize>),
354+
#[cfg(feature = "multithreaded")]
335355
MultiThreaded(Arc<CHashMap<String, usize>>),
336356
}
337357

338358
impl Occurrences {
359+
#[cfg(feature = "multithreaded")]
339360
pub(crate) fn new(nthreads: usize) -> Self {
340361
assert_ne!(nthreads, 0);
341362
if nthreads == 1 {
342-
let map = FnvHashMap::with_capacity_and_hasher(
343-
CAPACITY_HASHMAP,
344-
fnv::FnvBuildHasher::default(),
345-
);
346-
Occurrences::SingleThreaded(map)
363+
Self::new_single_threaded()
347364
} else {
348-
let map = CHashMap::with_capacity(CAPACITY_HASHMAP);
349-
let arc = Arc::new(map);
350-
Occurrences::MultiThreaded(arc)
365+
Self::new_multi_threaded()
351366
}
352367
}
353368

369+
#[cfg(not(feature = "multithreaded"))]
370+
pub(crate) fn new(nthreads: usize) -> Self {
371+
assert_ne!(nthreads, 0);
372+
Self::new_single_threaded()
373+
}
374+
375+
fn new_single_threaded() -> Self {
376+
let map =
377+
FnvHashMap::with_capacity_and_hasher(CAPACITY_HASHMAP, fnv::FnvBuildHasher::default());
378+
Occurrences::SingleThreaded(map)
379+
}
380+
381+
#[cfg(feature = "multithreaded")]
382+
fn new_multi_threaded() -> Self {
383+
let map = CHashMap::with_capacity(CAPACITY_HASHMAP);
384+
let arc = Arc::new(map);
385+
Occurrences::MultiThreaded(arc)
386+
}
387+
354388
/// Inserts a key-count pair into the map. If the map did not have this key
355389
/// present, `None` is returned. If the map did have this key present, the
356390
/// value is updated, and the old value is returned.
357391
pub(crate) fn insert(&mut self, key: String, count: usize) -> Option<usize> {
358392
use self::Occurrences::*;
359393
match self {
360394
SingleThreaded(map) => map.insert(key, count),
395+
#[cfg(feature = "multithreaded")]
361396
MultiThreaded(arc) => arc.insert(key, count),
362397
}
363398
}
@@ -369,6 +404,7 @@ impl Occurrences {
369404
use self::Occurrences::*;
370405
match self {
371406
SingleThreaded(map) => *map.entry(key).or_insert(0) += count,
407+
#[cfg(feature = "multithreaded")]
372408
MultiThreaded(arc) => arc.upsert(key, || count, |v| *v += count),
373409
}
374410
}
@@ -377,6 +413,7 @@ impl Occurrences {
377413
use self::Occurrences::*;
378414
match self {
379415
SingleThreaded(_) => false,
416+
#[cfg(feature = "multithreaded")]
380417
MultiThreaded(_) => true,
381418
}
382419
}
@@ -394,6 +431,7 @@ impl Occurrences {
394431
writeln!(writer, "{} {}", key, value)?;
395432
}
396433
}
434+
#[cfg(feature = "multithreaded")]
397435
MultiThreaded(ref mut arc) => {
398436
let map = match Arc::get_mut(arc) {
399437
Some(map) => map,

‎src/flamegraph/color/mod.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use std::borrow::Cow;
77
use std::fmt;
88
use std::str::FromStr;
99

10-
use rand::prelude::*;
1110
use rgb::RGB8;
1211

1312
pub use self::palette_map::PaletteMap;
@@ -328,14 +327,19 @@ fn rgb_components_for_palette(palette: Palette, name: &str, v1: f32, v2: f32, v3
328327
}
329328
}
330329

331-
pub(super) fn color(palette: Palette, hash: bool, name: &str, thread_rng: &mut ThreadRng) -> Color {
330+
pub(super) fn color(
331+
palette: Palette,
332+
hash: bool,
333+
name: &str,
334+
mut rng: impl FnMut() -> f32,
335+
) -> Color {
332336
let (v1, v2, v3) = if hash {
333337
let name_hash = namehash(name.bytes());
334338
let reverse_name_hash = namehash(name.bytes().rev());
335339

336340
(name_hash, reverse_name_hash, reverse_name_hash)
337341
} else {
338-
(thread_rng.gen(), thread_rng.gen(), thread_rng.gen())
342+
(rng(), rng(), rng())
339343
};
340344

341345
rgb_components_for_palette(palette, name, v1, v2, v3)

‎src/flamegraph/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ macro_rules! args {
77
mod attrs;
88
pub mod color;
99
mod merge;
10+
mod rand;
1011
mod svg;
1112

1213
use std::fs::File;

‎src/flamegraph/rand.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use std::cell::RefCell;
2+
3+
pub struct XorShift64 {
4+
a: u64,
5+
}
6+
7+
impl XorShift64 {
8+
pub fn new(seed: u64) -> XorShift64 {
9+
XorShift64 { a: seed }
10+
}
11+
12+
pub fn next(&mut self) -> u64 {
13+
let mut x = self.a;
14+
x ^= x << 13;
15+
x ^= x >> 7;
16+
x ^= x << 17;
17+
self.a = x;
18+
x
19+
}
20+
21+
pub fn next_f64(&mut self) -> f64 {
22+
sample(self.next())
23+
}
24+
}
25+
26+
thread_local! {
27+
pub static RNG: RefCell<XorShift64> = RefCell::new(XorShift64::new(1234));
28+
}
29+
30+
// Copied from `rand` with minor modifications.
31+
fn sample(value: u64) -> f64 {
32+
let fraction_bits = 52;
33+
34+
// Multiply-based method; 24/53 random bits; [0, 1) interval.
35+
// We use the most significant bits because for simple RNGs
36+
// those are usually more random.
37+
let float_size = std::mem::size_of::<f64>() as u32 * 8;
38+
let precision = fraction_bits + 1;
39+
let scale = 1.0 / ((1_u64 << precision) as f64);
40+
41+
let value = value >> (float_size - precision);
42+
scale * (value as f64)
43+
}
44+
45+
pub fn thread_rng() -> impl Fn() -> f32 {
46+
|| RNG.with(|rng| rng.borrow_mut().next_f64() as f32)
47+
}
48+
49+
#[test]
50+
fn test_rng() {
51+
const ITERATIONS: usize = 10000;
52+
53+
let mut rng = XorShift64::new(1234);
54+
let mut sum = rng.next_f64();
55+
let mut min = sum;
56+
let mut max = sum;
57+
for _ in 0..ITERATIONS - 1 {
58+
let value = rng.next_f64();
59+
sum += value;
60+
if value < min {
61+
min = value;
62+
}
63+
if value > max {
64+
max = value;
65+
}
66+
}
67+
68+
let avg = sum / ITERATIONS as f64;
69+
70+
// Make sure the RNG is uniform.
71+
assert!(min >= 0.000);
72+
assert!(min <= 0.001);
73+
assert!(max <= 1.000);
74+
assert!(max >= 0.999);
75+
assert!(avg >= 0.490);
76+
assert!(avg <= 0.510);
77+
}

0 commit comments

Comments
 (0)