Auto merge of #31274 - brson:nobench, r=nikomatsakis
I don't believe these test cases have served any purpose in years. The shootout benchmarks are now upstreamed. A new benchmark suite should rather be maintained out of tree. r? @nikomatsakis
This commit is contained in:
commit
9bda7ea81d
22
mk/tests.mk
22
mk/tests.mk
@ -45,7 +45,7 @@ ifdef CHECK_IGNORED
|
||||
TESTARGS += --ignored
|
||||
endif
|
||||
|
||||
# Arguments to the cfail/rfail/rpass/bench tests
|
||||
# Arguments to the cfail/rfail/rpass tests
|
||||
ifdef CFG_VALGRIND
|
||||
CTEST_RUNTOOL = --runtool "$(CFG_VALGRIND)"
|
||||
endif
|
||||
@ -306,7 +306,6 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-rustdocck-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-crates-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-crates-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-bench-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-debuginfo-gdb-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-debuginfo-lldb-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-codegen-exec \
|
||||
@ -344,7 +343,6 @@ check-stage$(1)-T-$(2)-H-$(3)-pretty-exec: \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-full-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-full-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-pretty-bench-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-pretty-pretty-exec
|
||||
|
||||
endef
|
||||
@ -468,7 +466,6 @@ CFAIL_FULL_RS := $(wildcard $(S)src/test/compile-fail-fulldeps/*.rs)
|
||||
RFAIL_RS := $(wildcard $(S)src/test/run-fail/*.rs)
|
||||
CFAIL_RS := $(wildcard $(S)src/test/compile-fail/*.rs)
|
||||
PFAIL_RS := $(wildcard $(S)src/test/parse-fail/*.rs)
|
||||
BENCH_RS := $(wildcard $(S)src/test/bench/*.rs)
|
||||
PRETTY_RS := $(wildcard $(S)src/test/pretty/*.rs)
|
||||
DEBUGINFO_GDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
|
||||
DEBUGINFO_LLDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
|
||||
@ -485,7 +482,6 @@ CFAIL_FULL_TESTS := $(CFAIL_FULL_RS)
|
||||
RFAIL_TESTS := $(RFAIL_RS)
|
||||
CFAIL_TESTS := $(CFAIL_RS)
|
||||
PFAIL_TESTS := $(PFAIL_RS)
|
||||
BENCH_TESTS := $(BENCH_RS)
|
||||
PRETTY_TESTS := $(PRETTY_RS)
|
||||
DEBUGINFO_GDB_TESTS := $(DEBUGINFO_GDB_RS)
|
||||
DEBUGINFO_LLDB_TESTS := $(DEBUGINFO_LLDB_RS)
|
||||
@ -533,11 +529,6 @@ CTEST_BUILD_BASE_pfail = parse-fail
|
||||
CTEST_MODE_pfail = parse-fail
|
||||
CTEST_RUNTOOL_pfail = $(CTEST_RUNTOOL)
|
||||
|
||||
CTEST_SRC_BASE_bench = bench
|
||||
CTEST_BUILD_BASE_bench = bench
|
||||
CTEST_MODE_bench = run-pass
|
||||
CTEST_RUNTOOL_bench = $(CTEST_RUNTOOL)
|
||||
|
||||
CTEST_SRC_BASE_debuginfo-gdb = debuginfo
|
||||
CTEST_BUILD_BASE_debuginfo-gdb = debuginfo-gdb
|
||||
CTEST_MODE_debuginfo-gdb = debuginfo-gdb
|
||||
@ -612,7 +603,7 @@ TEST_SREQ$(1)_T_$(2)_H_$(3) = \
|
||||
$$(HBIN$(1)_H_$(3))/compiletest$$(X_$(3)) \
|
||||
$$(SREQ$(1)_T_$(2)_H_$(3))
|
||||
|
||||
# Rules for the cfail/rfail/rpass/bench test runner
|
||||
# Rules for the cfail/rfail/rpass test runner
|
||||
|
||||
# The tests select when to use debug configuration on their own;
|
||||
# remove directive, if present, from CFG_RUSTC_FLAGS (issue #7898).
|
||||
@ -675,7 +666,6 @@ CTEST_DEPS_cfail-full_$(1)-T-$(2)-H-$(3) = $$(CFAIL_FULL_TESTS) $$(CSREQ$(1)_T_$
|
||||
CTEST_DEPS_rfail_$(1)-T-$(2)-H-$(3) = $$(RFAIL_TESTS)
|
||||
CTEST_DEPS_cfail_$(1)-T-$(2)-H-$(3) = $$(CFAIL_TESTS)
|
||||
CTEST_DEPS_pfail_$(1)-T-$(2)-H-$(3) = $$(PFAIL_TESTS)
|
||||
CTEST_DEPS_bench_$(1)-T-$(2)-H-$(3) = $$(BENCH_TESTS)
|
||||
CTEST_DEPS_debuginfo-gdb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_GDB_TESTS)
|
||||
CTEST_DEPS_debuginfo-lldb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_LLDB_TESTS) \
|
||||
$(S)src/etc/lldb_batchmode.py \
|
||||
@ -748,7 +738,7 @@ endif
|
||||
endef
|
||||
|
||||
CTEST_NAMES = rpass rpass-valgrind rpass-full rfail-full cfail-full rfail cfail pfail \
|
||||
bench debuginfo-gdb debuginfo-lldb codegen codegen-units rustdocck
|
||||
debuginfo-gdb debuginfo-lldb codegen codegen-units rustdocck
|
||||
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
$(eval $(foreach target,$(CFG_TARGET), \
|
||||
@ -757,20 +747,18 @@ $(foreach host,$(CFG_HOST), \
|
||||
$(eval $(call DEF_RUN_COMPILETEST,$(stage),$(target),$(host),$(name))))))))))
|
||||
|
||||
PRETTY_NAMES = pretty-rpass pretty-rpass-valgrind pretty-rpass-full pretty-rfail-full pretty-rfail \
|
||||
pretty-bench pretty-pretty
|
||||
pretty-pretty
|
||||
PRETTY_DEPS_pretty-rpass = $(RPASS_TESTS)
|
||||
PRETTY_DEPS_pretty-rpass-valgrind = $(RPASS_VALGRIND_TESTS)
|
||||
PRETTY_DEPS_pretty-rpass-full = $(RPASS_FULL_TESTS)
|
||||
PRETTY_DEPS_pretty-rfail-full = $(RFAIL_FULL_TESTS)
|
||||
PRETTY_DEPS_pretty-rfail = $(RFAIL_TESTS)
|
||||
PRETTY_DEPS_pretty-bench = $(BENCH_TESTS)
|
||||
PRETTY_DEPS_pretty-pretty = $(PRETTY_TESTS)
|
||||
PRETTY_DIRNAME_pretty-rpass = run-pass
|
||||
PRETTY_DIRNAME_pretty-rpass-valgrind = run-pass-valgrind
|
||||
PRETTY_DIRNAME_pretty-rpass-full = run-pass-fulldeps
|
||||
PRETTY_DIRNAME_pretty-rfail-full = run-fail-fulldeps
|
||||
PRETTY_DIRNAME_pretty-rfail = run-fail
|
||||
PRETTY_DIRNAME_pretty-bench = bench
|
||||
PRETTY_DIRNAME_pretty-pretty = pretty
|
||||
|
||||
define DEF_PRETTY_FULLDEPS
|
||||
@ -920,7 +908,6 @@ TEST_GROUPS = \
|
||||
rfail \
|
||||
cfail \
|
||||
pfail \
|
||||
bench \
|
||||
rmake \
|
||||
rustdocck \
|
||||
debuginfo-gdb \
|
||||
@ -935,7 +922,6 @@ TEST_GROUPS = \
|
||||
pretty-rpass-full \
|
||||
pretty-rfail-full \
|
||||
pretty-rfail \
|
||||
pretty-bench \
|
||||
pretty-pretty \
|
||||
$(NULL)
|
||||
|
||||
|
@ -1,164 +0,0 @@
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(std_misc, rand, duration, duration_span)]
|
||||
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use std::env;
|
||||
use std::__rand::{Rng, thread_rng};
|
||||
use std::time::Duration;
|
||||
|
||||
fn timed<F>(label: &str, f: F) where F: FnMut() {
|
||||
println!(" {}: {:?}", label, Duration::span(f));
|
||||
}
|
||||
|
||||
trait MutableMap {
|
||||
fn insert(&mut self, k: usize, v: usize);
|
||||
fn remove(&mut self, k: &usize) -> bool;
|
||||
fn find(&self, k: &usize) -> Option<&usize>;
|
||||
}
|
||||
|
||||
impl MutableMap for BTreeMap<usize, usize> {
|
||||
fn insert(&mut self, k: usize, v: usize) { self.insert(k, v); }
|
||||
fn remove(&mut self, k: &usize) -> bool { self.remove(k).is_some() }
|
||||
fn find(&self, k: &usize) -> Option<&usize> { self.get(k) }
|
||||
}
|
||||
impl MutableMap for HashMap<usize, usize> {
|
||||
fn insert(&mut self, k: usize, v: usize) { self.insert(k, v); }
|
||||
fn remove(&mut self, k: &usize) -> bool { self.remove(k).is_some() }
|
||||
fn find(&self, k: &usize) -> Option<&usize> { self.get(k) }
|
||||
}
|
||||
|
||||
fn ascending<M: MutableMap>(map: &mut M, n_keys: usize) {
|
||||
println!(" Ascending integers:");
|
||||
|
||||
timed("insert", || {
|
||||
for i in 0..n_keys {
|
||||
map.insert(i, i + 1);
|
||||
}
|
||||
});
|
||||
|
||||
timed("search", || {
|
||||
for i in 0..n_keys {
|
||||
assert_eq!(map.find(&i).unwrap(), &(i + 1));
|
||||
}
|
||||
});
|
||||
|
||||
timed("remove", || {
|
||||
for i in 0..n_keys {
|
||||
assert!(map.remove(&i));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn descending<M: MutableMap>(map: &mut M, n_keys: usize) {
|
||||
println!(" Descending integers:");
|
||||
|
||||
timed("insert", || {
|
||||
for i in (0..n_keys).rev() {
|
||||
map.insert(i, i + 1);
|
||||
}
|
||||
});
|
||||
|
||||
timed("search", || {
|
||||
for i in (0..n_keys).rev() {
|
||||
assert_eq!(map.find(&i).unwrap(), &(i + 1));
|
||||
}
|
||||
});
|
||||
|
||||
timed("remove", || {
|
||||
for i in 0..n_keys {
|
||||
assert!(map.remove(&i));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn vector<M: MutableMap>(map: &mut M, n_keys: usize, dist: &[usize]) {
|
||||
timed("insert", || {
|
||||
for i in 0..n_keys {
|
||||
map.insert(dist[i], i + 1);
|
||||
}
|
||||
});
|
||||
|
||||
timed("search", || {
|
||||
for i in 0..n_keys {
|
||||
assert_eq!(map.find(&dist[i]).unwrap(), &(i + 1));
|
||||
}
|
||||
});
|
||||
|
||||
timed("remove", || {
|
||||
for i in 0..n_keys {
|
||||
assert!(map.remove(&dist[i]));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args();
|
||||
let n_keys = {
|
||||
if args.len() == 2 {
|
||||
args.nth(1).unwrap().parse::<usize>().unwrap()
|
||||
} else {
|
||||
1000000
|
||||
}
|
||||
};
|
||||
|
||||
let mut rand = Vec::with_capacity(n_keys);
|
||||
|
||||
{
|
||||
let seed: &[_] = &[1, 1, 1, 1, 1, 1, 1];
|
||||
let mut rng = thread_rng();
|
||||
let mut set = HashSet::new();
|
||||
while set.len() != n_keys {
|
||||
let next = rng.gen();
|
||||
if set.insert(next) {
|
||||
rand.push(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("{} keys", n_keys);
|
||||
|
||||
println!("\nBTreeMap:");
|
||||
|
||||
{
|
||||
let mut map: BTreeMap<usize,usize> = BTreeMap::new();
|
||||
ascending(&mut map, n_keys);
|
||||
}
|
||||
|
||||
{
|
||||
let mut map: BTreeMap<usize,usize> = BTreeMap::new();
|
||||
descending(&mut map, n_keys);
|
||||
}
|
||||
|
||||
{
|
||||
println!(" Random integers:");
|
||||
let mut map: BTreeMap<usize,usize> = BTreeMap::new();
|
||||
vector(&mut map, n_keys, &rand);
|
||||
}
|
||||
|
||||
println!("\nHashMap:");
|
||||
|
||||
{
|
||||
let mut map: HashMap<usize,usize> = HashMap::new();
|
||||
ascending(&mut map, n_keys);
|
||||
}
|
||||
|
||||
{
|
||||
let mut map: HashMap<usize,usize> = HashMap::new();
|
||||
descending(&mut map, n_keys);
|
||||
}
|
||||
|
||||
{
|
||||
println!(" Random integers:");
|
||||
let mut map: HashMap<usize,usize> = HashMap::new();
|
||||
vector(&mut map, n_keys, &rand);
|
||||
}
|
||||
}
|
@ -1,215 +0,0 @@
|
||||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty very bad with line comments
|
||||
|
||||
#![feature(unboxed_closures, rand, std_misc, collections, duration, duration_span)]
|
||||
#![feature(bitset)]
|
||||
|
||||
extern crate collections;
|
||||
extern crate rand;
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::HashSet;
|
||||
use std::hash::Hash;
|
||||
use std::env;
|
||||
use std::time::Duration;
|
||||
|
||||
struct Results {
|
||||
sequential_ints: Duration,
|
||||
random_ints: Duration,
|
||||
delete_ints: Duration,
|
||||
|
||||
sequential_strings: Duration,
|
||||
random_strings: Duration,
|
||||
delete_strings: Duration,
|
||||
}
|
||||
|
||||
fn timed<F>(result: &mut Duration, op: F) where F: FnOnce() {
|
||||
*result = Duration::span(op);
|
||||
}
|
||||
|
||||
trait MutableSet<T> {
|
||||
fn insert(&mut self, k: T);
|
||||
fn remove(&mut self, k: &T) -> bool;
|
||||
fn contains(&self, k: &T) -> bool;
|
||||
}
|
||||
|
||||
impl<T: Hash + Eq> MutableSet<T> for HashSet<T> {
|
||||
fn insert(&mut self, k: T) { self.insert(k); }
|
||||
fn remove(&mut self, k: &T) -> bool { self.remove(k) }
|
||||
fn contains(&self, k: &T) -> bool { self.contains(k) }
|
||||
}
|
||||
impl<T: Ord> MutableSet<T> for BTreeSet<T> {
|
||||
fn insert(&mut self, k: T) { self.insert(k); }
|
||||
fn remove(&mut self, k: &T) -> bool { self.remove(k) }
|
||||
fn contains(&self, k: &T) -> bool { self.contains(k) }
|
||||
}
|
||||
|
||||
impl Results {
|
||||
pub fn bench_int<T:MutableSet<usize>,
|
||||
R:rand::Rng,
|
||||
F:FnMut() -> T>(
|
||||
&mut self,
|
||||
rng: &mut R,
|
||||
num_keys: usize,
|
||||
rand_cap: usize,
|
||||
mut f: F) {
|
||||
{
|
||||
let mut set = f();
|
||||
timed(&mut self.sequential_ints, || {
|
||||
for i in 0..num_keys {
|
||||
set.insert(i);
|
||||
}
|
||||
|
||||
for i in 0..num_keys {
|
||||
assert!(set.contains(&i));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
let mut set = f();
|
||||
timed(&mut self.random_ints, || {
|
||||
for _ in 0..num_keys {
|
||||
set.insert(rng.gen::<usize>() % rand_cap);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
let mut set = f();
|
||||
for i in 0..num_keys {
|
||||
set.insert(i);
|
||||
}
|
||||
|
||||
timed(&mut self.delete_ints, || {
|
||||
for i in 0..num_keys {
|
||||
assert!(set.remove(&i));
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bench_str<T:MutableSet<String>,
|
||||
R:rand::Rng,
|
||||
F:FnMut() -> T>(
|
||||
&mut self,
|
||||
rng: &mut R,
|
||||
num_keys: usize,
|
||||
mut f: F) {
|
||||
{
|
||||
let mut set = f();
|
||||
timed(&mut self.sequential_strings, || {
|
||||
for i in 0..num_keys {
|
||||
set.insert(i.to_string());
|
||||
}
|
||||
|
||||
for i in 0..num_keys {
|
||||
assert!(set.contains(&i.to_string()));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
let mut set = f();
|
||||
timed(&mut self.random_strings, || {
|
||||
for _ in 0..num_keys {
|
||||
let s = rng.gen::<usize>().to_string();
|
||||
set.insert(s);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
let mut set = f();
|
||||
for i in 0..num_keys {
|
||||
set.insert(i.to_string());
|
||||
}
|
||||
timed(&mut self.delete_strings, || {
|
||||
for i in 0..num_keys {
|
||||
assert!(set.remove(&i.to_string()));
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_header(header: &str) {
|
||||
println!("{}", header);
|
||||
}
|
||||
|
||||
fn write_row(label: &str, value: Duration) {
|
||||
println!("{:30} {:?} s\n", label, value);
|
||||
}
|
||||
|
||||
fn write_results(label: &str, results: &Results) {
|
||||
write_header(label);
|
||||
write_row("sequential_ints", results.sequential_ints);
|
||||
write_row("random_ints", results.random_ints);
|
||||
write_row("delete_ints", results.delete_ints);
|
||||
write_row("sequential_strings", results.sequential_strings);
|
||||
write_row("random_strings", results.random_strings);
|
||||
write_row("delete_strings", results.delete_strings);
|
||||
}
|
||||
|
||||
fn empty_results() -> Results {
|
||||
Results {
|
||||
sequential_ints: Duration::new(0, 0),
|
||||
random_ints: Duration::new(0, 0),
|
||||
delete_ints: Duration::new(0, 0),
|
||||
|
||||
sequential_strings: Duration::new(0, 0),
|
||||
random_strings: Duration::new(0, 0),
|
||||
delete_strings: Duration::new(0, 0),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args();
|
||||
let num_keys = {
|
||||
if args.len() == 2 {
|
||||
args.nth(1).unwrap().parse::<usize>().unwrap()
|
||||
} else {
|
||||
100 // woefully inadequate for any real measurement
|
||||
}
|
||||
};
|
||||
|
||||
let seed: &[_] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
let max = 200000;
|
||||
|
||||
{
|
||||
let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(seed);
|
||||
let mut results = empty_results();
|
||||
results.bench_int(&mut rng, num_keys, max, || {
|
||||
let s: HashSet<usize> = HashSet::new();
|
||||
s
|
||||
});
|
||||
results.bench_str(&mut rng, num_keys, || {
|
||||
let s: HashSet<String> = HashSet::new();
|
||||
s
|
||||
});
|
||||
write_results("collections::HashSet", &results);
|
||||
}
|
||||
|
||||
{
|
||||
let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(seed);
|
||||
let mut results = empty_results();
|
||||
results.bench_int(&mut rng, num_keys, max, || {
|
||||
let s: BTreeSet<usize> = BTreeSet::new();
|
||||
s
|
||||
});
|
||||
results.bench_str(&mut rng, num_keys, || {
|
||||
let s: BTreeSet<String> = BTreeSet::new();
|
||||
s
|
||||
});
|
||||
write_results("collections::BTreeSet", &results);
|
||||
}
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Microbenchmarks for various functions in std and extra
|
||||
|
||||
#![feature(rand, vec_push_all, duration, duration_span)]
|
||||
|
||||
use std::mem::swap;
|
||||
use std::env;
|
||||
use std::__rand::{thread_rng, Rng};
|
||||
use std::str;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
let argv: Vec<String> = env::args().collect();
|
||||
|
||||
macro_rules! bench {
|
||||
($id:ident) =>
|
||||
(maybe_run_test(&argv,
|
||||
stringify!($id).to_string(),
|
||||
$id))
|
||||
}
|
||||
|
||||
bench!(shift_push);
|
||||
bench!(vec_plus);
|
||||
bench!(vec_append);
|
||||
bench!(vec_push_all);
|
||||
bench!(is_utf8_ascii);
|
||||
bench!(is_utf8_multibyte);
|
||||
}
|
||||
|
||||
fn maybe_run_test<F>(argv: &[String], name: String, test: F) where F: FnOnce() {
|
||||
let mut run_test = false;
|
||||
|
||||
if env::var_os("RUST_BENCH").is_some() {
|
||||
run_test = true
|
||||
} else if !argv.is_empty() {
|
||||
run_test = argv.iter().any(|x| x == &"all".to_string()) || argv.iter().any(|x| x == &name)
|
||||
}
|
||||
|
||||
if !run_test {
|
||||
return
|
||||
}
|
||||
|
||||
let dur = Duration::span(test);
|
||||
|
||||
println!("{}:\t\t{:?}", name, dur);
|
||||
}
|
||||
|
||||
fn shift_push() {
|
||||
let mut v1 = vec![1; 30000];
|
||||
let mut v2 = Vec::new();
|
||||
|
||||
while !v1.is_empty() {
|
||||
v2.push(v1.remove(0));
|
||||
}
|
||||
}
|
||||
|
||||
fn vec_plus() {
|
||||
let mut r = thread_rng();
|
||||
|
||||
let mut v = Vec::new();
|
||||
let mut i = 0;
|
||||
while i < 1500 {
|
||||
let rv = vec![i; r.gen_range(0, i + 1)];
|
||||
if r.gen() {
|
||||
v.extend(rv);
|
||||
} else {
|
||||
let mut rv = rv.clone();
|
||||
rv.push_all(&v);
|
||||
v = rv;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn vec_append() {
|
||||
let mut r = thread_rng();
|
||||
|
||||
let mut v = Vec::new();
|
||||
let mut i = 0;
|
||||
while i < 1500 {
|
||||
let rv = vec![i; r.gen_range(0, i + 1)];
|
||||
if r.gen() {
|
||||
let mut t = v.clone();
|
||||
t.push_all(&rv);
|
||||
v = t;
|
||||
}
|
||||
else {
|
||||
let mut t = rv.clone();
|
||||
t.push_all(&v);
|
||||
v = t;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn vec_push_all() {
|
||||
let mut r = thread_rng();
|
||||
|
||||
let mut v = Vec::new();
|
||||
for i in 0..1500 {
|
||||
let mut rv = vec![i; r.gen_range(0, i + 1)];
|
||||
if r.gen() {
|
||||
v.push_all(&rv);
|
||||
}
|
||||
else {
|
||||
swap(&mut v, &mut rv);
|
||||
v.push_all(&rv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_utf8_ascii() {
|
||||
let mut v : Vec<u8> = Vec::new();
|
||||
for _ in 0..20000 {
|
||||
v.push('b' as u8);
|
||||
if str::from_utf8(&v).is_err() {
|
||||
panic!("from_utf8 panicked");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_utf8_multibyte() {
|
||||
let s = "b¢€𤭢";
|
||||
let mut v : Vec<u8> = Vec::new();
|
||||
for _ in 0..5000 {
|
||||
v.push_all(s.as_bytes());
|
||||
if str::from_utf8(&v).is_err() {
|
||||
panic!("from_utf8 panicked");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
let args = if env::var_os("RUST_BENCH").is_some() {
|
||||
vec!("".to_string(), "10000000".to_string())
|
||||
} else if args.len() <= 1 {
|
||||
vec!("".to_string(), "100000".to_string())
|
||||
} else {
|
||||
args.collect()
|
||||
};
|
||||
|
||||
let n = args[1].parse().unwrap();
|
||||
|
||||
for i in 0..n {
|
||||
let x = i.to_string();
|
||||
println!("{}", x);
|
||||
}
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// A port of the simplistic benchmark from
|
||||
//
|
||||
// http://github.com/PaulKeeble/ScalaVErlangAgents
|
||||
//
|
||||
// I *think* it's the same, more or less.
|
||||
|
||||
// This version uses pipes with a shared send endpoint. It should have
|
||||
// different scalability characteristics compared to the select
|
||||
// version.
|
||||
|
||||
#![feature(duration, duration_span)]
|
||||
|
||||
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||
use std::env;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
fn move_out<T>(_x: T) {}
|
||||
|
||||
enum request {
|
||||
get_count,
|
||||
bytes(usize),
|
||||
stop
|
||||
}
|
||||
|
||||
fn server(requests: &Receiver<request>, responses: &Sender<usize>) {
|
||||
let mut count = 0;
|
||||
let mut done = false;
|
||||
while !done {
|
||||
match requests.recv() {
|
||||
Ok(request::get_count) => { responses.send(count.clone()).unwrap(); }
|
||||
Ok(request::bytes(b)) => {
|
||||
//println!("server: received {} bytes", b);
|
||||
count += b;
|
||||
}
|
||||
Err(..) => { done = true; }
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
responses.send(count).unwrap();
|
||||
//println!("server exiting");
|
||||
}
|
||||
|
||||
fn run(args: &[String]) {
|
||||
let (to_parent, from_child) = channel();
|
||||
let (to_child, from_parent) = channel();
|
||||
|
||||
let size = args[1].parse::<usize>().unwrap();
|
||||
let workers = args[2].parse::<usize>().unwrap();
|
||||
let num_bytes = 100;
|
||||
let mut result = None;
|
||||
let mut p = Some((to_child, to_parent, from_parent));
|
||||
let dur = Duration::span(|| {
|
||||
let (to_child, to_parent, from_parent) = p.take().unwrap();
|
||||
let mut worker_results = Vec::new();
|
||||
for _ in 0..workers {
|
||||
let to_child = to_child.clone();
|
||||
worker_results.push(thread::spawn(move|| {
|
||||
for _ in 0..size / workers {
|
||||
//println!("worker {}: sending {} bytes", i, num_bytes);
|
||||
to_child.send(request::bytes(num_bytes)).unwrap();
|
||||
}
|
||||
//println!("worker {} exiting", i);
|
||||
}));
|
||||
}
|
||||
thread::spawn(move|| {
|
||||
server(&from_parent, &to_parent);
|
||||
});
|
||||
|
||||
for r in worker_results {
|
||||
let _ = r.join();
|
||||
}
|
||||
|
||||
//println!("sending stop message");
|
||||
to_child.send(request::stop).unwrap();
|
||||
move_out(to_child);
|
||||
result = Some(from_child.recv().unwrap());
|
||||
});
|
||||
let result = result.unwrap();
|
||||
print!("Count is {}\n", result);
|
||||
print!("Test took {:?}\n", dur);
|
||||
let thruput = ((size / workers * workers) as f64) / (dur.as_secs() as f64);
|
||||
print!("Throughput={} per sec\n", thruput);
|
||||
assert_eq!(result, num_bytes * size);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
let args = if env::var_os("RUST_BENCH").is_some() {
|
||||
vec!("".to_string(), "1000000".to_string(), "10000".to_string())
|
||||
} else if args.len() <= 1 {
|
||||
vec!("".to_string(), "10000".to_string(), "4".to_string())
|
||||
} else {
|
||||
args.map(|x| x.to_string()).collect()
|
||||
};
|
||||
|
||||
println!("{:?}", args);
|
||||
run(&args);
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// A port of the simplistic benchmark from
|
||||
//
|
||||
// http://github.com/PaulKeeble/ScalaVErlangAgents
|
||||
//
|
||||
// I *think* it's the same, more or less.
|
||||
|
||||
#![feature(duration, duration_span)]
|
||||
|
||||
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||
use std::env;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
enum request {
|
||||
get_count,
|
||||
bytes(usize),
|
||||
stop
|
||||
}
|
||||
|
||||
fn server(requests: &Receiver<request>, responses: &Sender<usize>) {
|
||||
let mut count: usize = 0;
|
||||
let mut done = false;
|
||||
while !done {
|
||||
match requests.recv() {
|
||||
Ok(request::get_count) => { responses.send(count.clone()); }
|
||||
Ok(request::bytes(b)) => {
|
||||
//println!("server: received {} bytes", b);
|
||||
count += b;
|
||||
}
|
||||
Err(..) => { done = true; }
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
responses.send(count).unwrap();
|
||||
//println!("server exiting");
|
||||
}
|
||||
|
||||
fn run(args: &[String]) {
|
||||
let (to_parent, from_child) = channel();
|
||||
|
||||
let size = args[1].parse::<usize>().unwrap();
|
||||
let workers = args[2].parse::<usize>().unwrap();
|
||||
let num_bytes = 100;
|
||||
let mut result = None;
|
||||
let mut to_parent = Some(to_parent);
|
||||
let dur = Duration::span(|| {
|
||||
let to_parent = to_parent.take().unwrap();
|
||||
let mut worker_results = Vec::new();
|
||||
let from_parent = if workers == 1 {
|
||||
let (to_child, from_parent) = channel();
|
||||
worker_results.push(thread::spawn(move|| {
|
||||
for _ in 0..size / workers {
|
||||
//println!("worker {}: sending {} bytes", i, num_bytes);
|
||||
to_child.send(request::bytes(num_bytes));
|
||||
}
|
||||
//println!("worker {} exiting", i);
|
||||
}));
|
||||
from_parent
|
||||
} else {
|
||||
let (to_child, from_parent) = channel();
|
||||
for _ in 0..workers {
|
||||
let to_child = to_child.clone();
|
||||
worker_results.push(thread::spawn(move|| {
|
||||
for _ in 0..size / workers {
|
||||
//println!("worker {}: sending {} bytes", i, num_bytes);
|
||||
to_child.send(request::bytes(num_bytes));
|
||||
}
|
||||
//println!("worker {} exiting", i);
|
||||
}));
|
||||
}
|
||||
from_parent
|
||||
};
|
||||
thread::spawn(move|| {
|
||||
server(&from_parent, &to_parent);
|
||||
});
|
||||
|
||||
for r in worker_results {
|
||||
let _ = r.join();
|
||||
}
|
||||
|
||||
//println!("sending stop message");
|
||||
//to_child.send(stop);
|
||||
//move_out(to_child);
|
||||
result = Some(from_child.recv().unwrap());
|
||||
});
|
||||
let result = result.unwrap();
|
||||
print!("Count is {}\n", result);
|
||||
print!("Test took {:?}\n", dur);
|
||||
let thruput = ((size / workers * workers) as f64) / (dur.as_secs() as f64);
|
||||
print!("Throughput={} per sec\n", thruput);
|
||||
assert_eq!(result, num_bytes * size);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
let args = if env::var_os("RUST_BENCH").is_some() {
|
||||
vec!("".to_string(), "1000000".to_string(), "8".to_string())
|
||||
} else if args.len() <= 1 {
|
||||
vec!("".to_string(), "10000".to_string(), "4".to_string())
|
||||
} else {
|
||||
args.map(|x| x.to_string()).collect()
|
||||
};
|
||||
|
||||
println!("{:?}", args);
|
||||
run(&args);
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// This test creates a bunch of threads that simultaneously send to each
|
||||
// other in a ring. The messages should all be basically
|
||||
// independent.
|
||||
// This is like msgsend-ring-pipes but adapted to use Arcs.
|
||||
|
||||
// This also serves as a pipes test, because Arcs are implemented with pipes.
|
||||
|
||||
// no-pretty-expanded FIXME #15189
|
||||
|
||||
#![feature(duration_span)]
|
||||
|
||||
use std::env;
|
||||
use std::sync::{Arc, Mutex, Condvar};
|
||||
use std::time::Duration;
|
||||
use std::thread;
|
||||
|
||||
// A poor man's pipe.
|
||||
type pipe = Arc<(Mutex<Vec<usize>>, Condvar)>;
|
||||
|
||||
fn send(p: &pipe, msg: usize) {
|
||||
let &(ref lock, ref cond) = &**p;
|
||||
let mut arr = lock.lock().unwrap();
|
||||
arr.push(msg);
|
||||
cond.notify_one();
|
||||
}
|
||||
fn recv(p: &pipe) -> usize {
|
||||
let &(ref lock, ref cond) = &**p;
|
||||
let mut arr = lock.lock().unwrap();
|
||||
while arr.is_empty() {
|
||||
arr = cond.wait(arr).unwrap();
|
||||
}
|
||||
arr.pop().unwrap()
|
||||
}
|
||||
|
||||
fn init() -> (pipe,pipe) {
|
||||
let m = Arc::new((Mutex::new(Vec::new()), Condvar::new()));
|
||||
((&m).clone(), m)
|
||||
}
|
||||
|
||||
|
||||
fn thread_ring(i: usize, count: usize, num_chan: pipe, num_port: pipe) {
|
||||
let mut num_chan = Some(num_chan);
|
||||
let mut num_port = Some(num_port);
|
||||
// Send/Receive lots of messages.
|
||||
for j in 0..count {
|
||||
//println!("thread %?, iter %?", i, j);
|
||||
let num_chan2 = num_chan.take().unwrap();
|
||||
let num_port2 = num_port.take().unwrap();
|
||||
send(&num_chan2, i * j);
|
||||
num_chan = Some(num_chan2);
|
||||
let _n = recv(&num_port2);
|
||||
//log(error, _n);
|
||||
num_port = Some(num_port2);
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
let args = if env::var_os("RUST_BENCH").is_some() {
|
||||
vec!("".to_string(), "100".to_string(), "10000".to_string())
|
||||
} else if args.len() <= 1 {
|
||||
vec!("".to_string(), "10".to_string(), "100".to_string())
|
||||
} else {
|
||||
args.collect()
|
||||
};
|
||||
|
||||
let num_tasks = args[1].parse::<usize>().unwrap();
|
||||
let msg_per_task = args[2].parse::<usize>().unwrap();
|
||||
|
||||
let (num_chan, num_port) = init();
|
||||
|
||||
let mut p = Some((num_chan, num_port));
|
||||
let dur = Duration::span(|| {
|
||||
let (mut num_chan, num_port) = p.take().unwrap();
|
||||
|
||||
// create the ring
|
||||
let mut futures = Vec::new();
|
||||
|
||||
for i in 1..num_tasks {
|
||||
//println!("spawning %?", i);
|
||||
let (new_chan, num_port) = init();
|
||||
let num_chan_2 = num_chan.clone();
|
||||
let new_future = thread::spawn(move|| {
|
||||
thread_ring(i, msg_per_task, num_chan_2, num_port)
|
||||
});
|
||||
futures.push(new_future);
|
||||
num_chan = new_chan;
|
||||
};
|
||||
|
||||
// do our iteration
|
||||
thread_ring(0, msg_per_task, num_chan, num_port);
|
||||
|
||||
// synchronize
|
||||
for f in futures {
|
||||
f.join().unwrap()
|
||||
}
|
||||
});
|
||||
|
||||
// all done, report stats.
|
||||
let num_msgs = num_tasks * msg_per_task;
|
||||
let rate = (num_msgs as f64) / (dur.as_secs() as f64);
|
||||
|
||||
println!("Sent {} messages in {:?}", num_msgs, dur);
|
||||
println!(" {} messages / second", rate);
|
||||
println!(" {} μs / message", 1000000. / rate);
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Multi-language Perlin noise benchmark.
|
||||
// See https://github.com/nsf/pnoise for timings and alternative implementations.
|
||||
|
||||
#![feature(rand, core)]
|
||||
|
||||
use std::f32::consts::PI;
|
||||
use std::__rand::{Rng, thread_rng};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Vec2 {
|
||||
x: f32,
|
||||
y: f32,
|
||||
}
|
||||
|
||||
fn lerp(a: f32, b: f32, v: f32) -> f32 { a * (1.0 - v) + b * v }
|
||||
|
||||
fn smooth(v: f32) -> f32 { v * v * (3.0 - 2.0 * v) }
|
||||
|
||||
fn random_gradient<R: Rng>(r: &mut R) -> Vec2 {
|
||||
let v = PI * 2.0 * r.gen::<f32>();
|
||||
Vec2 { x: v.cos(), y: v.sin() }
|
||||
}
|
||||
|
||||
fn gradient(orig: Vec2, grad: Vec2, p: Vec2) -> f32 {
|
||||
(p.x - orig.x) * grad.x + (p.y - orig.y) * grad.y
|
||||
}
|
||||
|
||||
struct Noise2DContext {
|
||||
rgradients: [Vec2; 256],
|
||||
permutations: [i32; 256],
|
||||
}
|
||||
|
||||
impl Noise2DContext {
|
||||
fn new() -> Noise2DContext {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let mut rgradients = [Vec2 { x: 0.0, y: 0.0 }; 256];
|
||||
for x in &mut rgradients[..] {
|
||||
*x = random_gradient(&mut rng);
|
||||
}
|
||||
|
||||
let mut permutations = [0; 256];
|
||||
for (i, x) in permutations.iter_mut().enumerate() {
|
||||
*x = i as i32;
|
||||
}
|
||||
rng.shuffle(&mut permutations);
|
||||
|
||||
Noise2DContext { rgradients: rgradients, permutations: permutations }
|
||||
}
|
||||
|
||||
fn get_gradient(&self, x: i32, y: i32) -> Vec2 {
|
||||
let idx = self.permutations[(x & 255) as usize] +
|
||||
self.permutations[(y & 255) as usize];
|
||||
self.rgradients[(idx & 255) as usize]
|
||||
}
|
||||
|
||||
fn get_gradients(&self, x: f32, y: f32) -> ([Vec2; 4], [Vec2; 4]) {
|
||||
let x0f = x.floor();
|
||||
let y0f = y.floor();
|
||||
let x1f = x0f + 1.0;
|
||||
let y1f = y0f + 1.0;
|
||||
|
||||
let x0 = x0f as i32;
|
||||
let y0 = y0f as i32;
|
||||
let x1 = x0 + 1;
|
||||
let y1 = y0 + 1;
|
||||
|
||||
([self.get_gradient(x0, y0), self.get_gradient(x1, y0),
|
||||
self.get_gradient(x0, y1), self.get_gradient(x1, y1)],
|
||||
[Vec2 { x: x0f, y: y0f }, Vec2 { x: x1f, y: y0f },
|
||||
Vec2 { x: x0f, y: y1f }, Vec2 { x: x1f, y: y1f }])
|
||||
}
|
||||
|
||||
fn get(&self, x: f32, y: f32) -> f32 {
|
||||
let p = Vec2 {x: x, y: y};
|
||||
let (gradients, origins) = self.get_gradients(x, y);
|
||||
|
||||
let v0 = gradient(origins[0], gradients[0], p);
|
||||
let v1 = gradient(origins[1], gradients[1], p);
|
||||
let v2 = gradient(origins[2], gradients[2], p);
|
||||
let v3 = gradient(origins[3], gradients[3], p);
|
||||
|
||||
let fx = smooth(x - origins[0].x);
|
||||
let vx0 = lerp(v0, v1, fx);
|
||||
let vx1 = lerp(v2, v3, fx);
|
||||
let fy = smooth(y - origins[0].y);
|
||||
|
||||
lerp(vx0, vx1, fy)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let symbols = [' ', '░', '▒', '▓', '█', '█'];
|
||||
let mut pixels = Box::new([0f32; 256*256]);
|
||||
let n2d = Box::new(Noise2DContext::new());
|
||||
|
||||
for _ in 0..100 {
|
||||
for y in 0..256 {
|
||||
for x in 0..256 {
|
||||
let v = n2d.get(x as f32 * 0.1, y as f32 * 0.1);
|
||||
pixels[y*256+x] = v * 0.5 + 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for y in 0..256 {
|
||||
for x in 0..256 {
|
||||
let idx = (pixels[y*256+x] / 0.2) as usize;
|
||||
print!("{}", symbols[idx]);
|
||||
}
|
||||
print!("\n");
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::sync::mpsc::channel;
|
||||
use std::env;
|
||||
use std::thread;
|
||||
|
||||
// This is a simple bench that creates M pairs of threads. These
|
||||
// threads ping-pong back and forth over a pair of streams. This is a
|
||||
// canonical message-passing benchmark as it heavily strains message
|
||||
// passing and almost nothing else.
|
||||
|
||||
fn ping_pong_bench(n: usize, m: usize) {
|
||||
|
||||
// Create pairs of threads that pingpong back and forth.
|
||||
fn run_pair(n: usize) {
|
||||
// Create a channel: A->B
|
||||
let (atx, arx) = channel();
|
||||
// Create a channel: B->A
|
||||
let (btx, brx) = channel();
|
||||
|
||||
let guard_a = thread::spawn(move|| {
|
||||
let (tx, rx) = (atx, brx);
|
||||
for _ in 0..n {
|
||||
tx.send(()).unwrap();
|
||||
rx.recv().unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
let guard_b = thread::spawn(move|| {
|
||||
let (tx, rx) = (btx, arx);
|
||||
for _ in 0..n {
|
||||
rx.recv().unwrap();
|
||||
tx.send(()).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
guard_a.join().ok();
|
||||
guard_b.join().ok();
|
||||
}
|
||||
|
||||
for _ in 0..m {
|
||||
run_pair(n)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args();
|
||||
let (n, m) = if args.len() == 3 {
|
||||
let n = args.nth(1).unwrap().parse::<usize>().unwrap();
|
||||
let m = args.next().unwrap().parse::<usize>().unwrap();
|
||||
(n, m)
|
||||
} else {
|
||||
(10000, 4)
|
||||
};
|
||||
|
||||
ping_pong_bench(n, m);
|
||||
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::sync::mpsc::channel;
|
||||
use std::env;
|
||||
use std::thread;
|
||||
|
||||
// A simple implementation of parfib. One subtree is found in a new
|
||||
// thread and communicated over a oneshot pipe, the other is found
|
||||
// locally. There is no sequential-mode threshold.
|
||||
|
||||
fn parfib(n: u64) -> u64 {
|
||||
if n == 0 || n == 1 {
|
||||
return 1;
|
||||
}
|
||||
|
||||
let (tx, rx) = channel();
|
||||
thread::spawn(move|| {
|
||||
tx.send(parfib(n-1)).unwrap();
|
||||
});
|
||||
let m2 = parfib(n-2);
|
||||
return rx.recv().unwrap() + m2;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args();
|
||||
let n = if args.len() == 2 {
|
||||
args.nth(1).unwrap().parse::<u64>().unwrap()
|
||||
} else {
|
||||
10
|
||||
};
|
||||
|
||||
parfib(n);
|
||||
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::env;
|
||||
|
||||
fn ack(m: i64, n: i64) -> i64 {
|
||||
if m == 0 {
|
||||
return n + 1
|
||||
} else {
|
||||
if n == 0 {
|
||||
return ack(m - 1, 1);
|
||||
} else {
|
||||
return ack(m - 1, ack(m, n - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args();
|
||||
let args = if env::var_os("RUST_BENCH").is_some() {
|
||||
vec!("".to_string(), "12".to_string())
|
||||
} else if args.len() <= 1 {
|
||||
vec!("".to_string(), "8".to_string())
|
||||
} else {
|
||||
args.collect()
|
||||
};
|
||||
let n = args[1].parse().unwrap();
|
||||
println!("Ack(3,{}): {}\n", n, ack(3, n));
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// contributed by the Rust Project Developers
|
||||
|
||||
// Copyright (c) 2012-2014 The Rust Project Developers
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// - Neither the name of "The Computer Language Benchmarks Game" nor
|
||||
// the name of "The Computer Language Shootout Benchmarks" nor the
|
||||
// names of its contributors may be used to endorse or promote
|
||||
// products derived from this software without specific prior
|
||||
// written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#![feature(rustc_private, core, step_by)]
|
||||
|
||||
extern crate arena;
|
||||
|
||||
use std::thread;
|
||||
use arena::TypedArena;
|
||||
|
||||
struct Tree<'a> {
|
||||
l: Option<&'a Tree<'a>>,
|
||||
r: Option<&'a Tree<'a>>,
|
||||
i: i32
|
||||
}
|
||||
|
||||
fn item_check(t: &Option<&Tree>) -> i32 {
|
||||
match *t {
|
||||
None => 0,
|
||||
Some(&Tree { ref l, ref r, i }) => i + item_check(l) - item_check(r)
|
||||
}
|
||||
}
|
||||
|
||||
fn bottom_up_tree<'r>(arena: &'r TypedArena<Tree<'r>>, item: i32, depth: i32)
|
||||
-> Option<&'r Tree<'r>> {
|
||||
if depth > 0 {
|
||||
let t: &Tree<'r> = arena.alloc(Tree {
|
||||
l: bottom_up_tree(arena, 2 * item - 1, depth - 1),
|
||||
r: bottom_up_tree(arena, 2 * item, depth - 1),
|
||||
i: item
|
||||
});
|
||||
Some(t)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn inner(depth: i32, iterations: i32) -> String {
|
||||
let mut chk = 0;
|
||||
for i in 1 .. iterations + 1 {
|
||||
let arena = TypedArena::new();
|
||||
let a = bottom_up_tree(&arena, i, depth);
|
||||
let b = bottom_up_tree(&arena, -i, depth);
|
||||
chk += item_check(&a) + item_check(&b);
|
||||
}
|
||||
format!("{}\t trees of depth {}\t check: {}",
|
||||
iterations * 2, depth, chk)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args = std::env::args();
|
||||
let n = if std::env::var_os("RUST_BENCH").is_some() {
|
||||
17
|
||||
} else if args.len() <= 1 {
|
||||
8
|
||||
} else {
|
||||
args.nth(1).unwrap().parse().unwrap()
|
||||
};
|
||||
let min_depth = 4;
|
||||
let max_depth = if min_depth + 2 > n {min_depth + 2} else {n};
|
||||
|
||||
{
|
||||
let arena = TypedArena::new();
|
||||
let depth = max_depth + 1;
|
||||
let tree = bottom_up_tree(&arena, 0, depth);
|
||||
|
||||
println!("stretch tree of depth {}\t check: {}",
|
||||
depth, item_check(&tree));
|
||||
}
|
||||
|
||||
let long_lived_arena = TypedArena::new();
|
||||
let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth);
|
||||
|
||||
let messages = (min_depth..max_depth + 1).step_by(2).map(|depth| {
|
||||
let iterations = 2i32.pow((max_depth - depth + min_depth) as u32);
|
||||
thread::spawn(move || inner(depth, iterations))
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
for message in messages {
|
||||
println!("{}", message.join().unwrap());
|
||||
}
|
||||
|
||||
println!("long lived tree of depth {}\t check: {}",
|
||||
max_depth, item_check(&long_lived_tree));
|
||||
}
|
@ -1,246 +0,0 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// contributed by the Rust Project Developers
|
||||
|
||||
// Copyright (c) 2012-2014 The Rust Project Developers
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// - Neither the name of "The Computer Language Benchmarks Game" nor
|
||||
// the name of "The Computer Language Shootout Benchmarks" nor the
|
||||
// names of its contributors may be used to endorse or promote
|
||||
// products derived from this software without specific prior
|
||||
// written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// no-pretty-expanded
|
||||
|
||||
use self::Color::{Red, Yellow, Blue};
|
||||
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||
use std::fmt;
|
||||
use std::thread;
|
||||
|
||||
fn print_complements() {
|
||||
let all = [Blue, Red, Yellow];
|
||||
for aa in &all {
|
||||
for bb in &all {
|
||||
println!("{:?} + {:?} -> {:?}", *aa, *bb, transform(*aa, *bb));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Color {
|
||||
Red,
|
||||
Yellow,
|
||||
Blue,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Color {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let str = match *self {
|
||||
Red => "red",
|
||||
Yellow => "yellow",
|
||||
Blue => "blue",
|
||||
};
|
||||
write!(f, "{}", str)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct CreatureInfo {
|
||||
name: usize,
|
||||
color: Color
|
||||
}
|
||||
|
||||
fn show_color_list(set: Vec<Color>) -> String {
|
||||
let mut out = String::new();
|
||||
for col in &set {
|
||||
out.push(' ');
|
||||
out.push_str(&format!("{:?}", col));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn show_digit(nn: usize) -> &'static str {
|
||||
match nn {
|
||||
0 => {" zero"}
|
||||
1 => {" one"}
|
||||
2 => {" two"}
|
||||
3 => {" three"}
|
||||
4 => {" four"}
|
||||
5 => {" five"}
|
||||
6 => {" six"}
|
||||
7 => {" seven"}
|
||||
8 => {" eight"}
|
||||
9 => {" nine"}
|
||||
_ => {panic!("expected digits from 0 to 9...")}
|
||||
}
|
||||
}
|
||||
|
||||
struct Number(usize);
|
||||
impl fmt::Debug for Number {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut out = vec![];
|
||||
let Number(mut num) = *self;
|
||||
if num == 0 { out.push(show_digit(0)) };
|
||||
|
||||
while num != 0 {
|
||||
let dig = num % 10;
|
||||
num = num / 10;
|
||||
let s = show_digit(dig);
|
||||
out.push(s);
|
||||
}
|
||||
|
||||
for s in out.iter().rev() {
|
||||
try!(write!(f, "{}", s))
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn transform(aa: Color, bb: Color) -> Color {
|
||||
match (aa, bb) {
|
||||
(Red, Red ) => { Red }
|
||||
(Red, Yellow) => { Blue }
|
||||
(Red, Blue ) => { Yellow }
|
||||
(Yellow, Red ) => { Blue }
|
||||
(Yellow, Yellow) => { Yellow }
|
||||
(Yellow, Blue ) => { Red }
|
||||
(Blue, Red ) => { Yellow }
|
||||
(Blue, Yellow) => { Red }
|
||||
(Blue, Blue ) => { Blue }
|
||||
}
|
||||
}
|
||||
|
||||
fn creature(
|
||||
name: usize,
|
||||
mut color: Color,
|
||||
from_rendezvous: Receiver<CreatureInfo>,
|
||||
to_rendezvous: Sender<CreatureInfo>,
|
||||
to_rendezvous_log: Sender<String>
|
||||
) {
|
||||
let mut creatures_met = 0;
|
||||
let mut evil_clones_met = 0;
|
||||
let mut rendezvous = from_rendezvous.iter();
|
||||
|
||||
loop {
|
||||
// ask for a pairing
|
||||
to_rendezvous.send(CreatureInfo {name: name, color: color}).unwrap();
|
||||
|
||||
// log and change, or quit
|
||||
match rendezvous.next() {
|
||||
Some(other_creature) => {
|
||||
color = transform(color, other_creature.color);
|
||||
|
||||
// track some statistics
|
||||
creatures_met += 1;
|
||||
if other_creature.name == name {
|
||||
evil_clones_met += 1;
|
||||
}
|
||||
}
|
||||
None => break
|
||||
}
|
||||
}
|
||||
// log creatures met and evil clones of self
|
||||
let report = format!("{}{:?}", creatures_met, Number(evil_clones_met));
|
||||
to_rendezvous_log.send(report).unwrap();
|
||||
}
|
||||
|
||||
fn rendezvous(nn: usize, set: Vec<Color>) {
|
||||
// these ports will allow us to hear from the creatures
|
||||
let (to_rendezvous, from_creatures) = channel::<CreatureInfo>();
|
||||
|
||||
// these channels will be passed to the creatures so they can talk to us
|
||||
let (to_rendezvous_log, from_creatures_log) = channel::<String>();
|
||||
|
||||
// these channels will allow us to talk to each creature by 'name'/index
|
||||
let to_creature: Vec<Sender<CreatureInfo>> =
|
||||
set.iter().enumerate().map(|(ii, &col)| {
|
||||
// create each creature as a listener with a port, and
|
||||
// give us a channel to talk to each
|
||||
let to_rendezvous = to_rendezvous.clone();
|
||||
let to_rendezvous_log = to_rendezvous_log.clone();
|
||||
let (to_creature, from_rendezvous) = channel();
|
||||
thread::spawn(move|| {
|
||||
creature(ii,
|
||||
col,
|
||||
from_rendezvous,
|
||||
to_rendezvous,
|
||||
to_rendezvous_log);
|
||||
});
|
||||
to_creature
|
||||
}).collect();
|
||||
|
||||
let mut creatures_met = 0;
|
||||
|
||||
// set up meetings...
|
||||
for _ in 0..nn {
|
||||
let fst_creature = from_creatures.recv().unwrap();
|
||||
let snd_creature = from_creatures.recv().unwrap();
|
||||
|
||||
creatures_met += 2;
|
||||
|
||||
to_creature[fst_creature.name].send(snd_creature).unwrap();
|
||||
to_creature[snd_creature.name].send(fst_creature).unwrap();
|
||||
}
|
||||
|
||||
// tell each creature to stop
|
||||
drop(to_creature);
|
||||
|
||||
// print each color in the set
|
||||
println!("{}", show_color_list(set));
|
||||
|
||||
// print each creature's stats
|
||||
drop(to_rendezvous_log);
|
||||
for rep in from_creatures_log.iter() {
|
||||
println!("{}", rep);
|
||||
}
|
||||
|
||||
// print the total number of creatures met
|
||||
println!("{:?}\n", Number(creatures_met));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let nn = if std::env::var_os("RUST_BENCH").is_some() {
|
||||
200000
|
||||
} else {
|
||||
std::env::args()
|
||||
.nth(1)
|
||||
.and_then(|arg| arg.parse().ok())
|
||||
.unwrap_or(600)
|
||||
};
|
||||
|
||||
print_complements();
|
||||
println!("");
|
||||
|
||||
rendezvous(nn, vec!(Blue, Red, Yellow));
|
||||
|
||||
rendezvous(nn,
|
||||
vec!(Blue, Red, Yellow, Red, Yellow, Blue, Red, Yellow, Red, Blue));
|
||||
}
|
@ -1,192 +0,0 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// contributed by the Rust Project Developers
|
||||
|
||||
// Copyright (c) 2014 The Rust Project Developers
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// - Neither the name of "The Computer Language Benchmarks Game" nor
|
||||
// the name of "The Computer Language Shootout Benchmarks" nor the
|
||||
// names of its contributors may be used to endorse or promote
|
||||
// products derived from this software without specific prior
|
||||
// written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#![feature(step_by)]
|
||||
|
||||
use std::{cmp, mem};
|
||||
use std::thread;
|
||||
|
||||
fn rotate(x: &mut [i32]) {
|
||||
let mut prev = x[0];
|
||||
for place in x.iter_mut().rev() {
|
||||
prev = mem::replace(place, prev)
|
||||
}
|
||||
}
|
||||
|
||||
fn next_permutation(perm: &mut [i32], count: &mut [i32]) {
|
||||
for i in 1..perm.len() {
|
||||
rotate(&mut perm[..i + 1]);
|
||||
let count_i = &mut count[i];
|
||||
if *count_i >= i as i32 {
|
||||
*count_i = 0;
|
||||
} else {
|
||||
*count_i += 1;
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct P {
|
||||
p: [i32; 16],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Perm {
|
||||
cnt: [i32; 16],
|
||||
fact: [u32; 16],
|
||||
n: u32,
|
||||
permcount: u32,
|
||||
perm: P,
|
||||
}
|
||||
|
||||
impl Perm {
|
||||
fn new(n: u32) -> Perm {
|
||||
let mut fact = [1; 16];
|
||||
for i in 1..n as usize + 1 {
|
||||
fact[i] = fact[i - 1] * i as u32;
|
||||
}
|
||||
Perm {
|
||||
cnt: [0; 16],
|
||||
fact: fact,
|
||||
n: n,
|
||||
permcount: 0,
|
||||
perm: P { p: [0; 16 ] }
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&mut self, mut idx: i32) -> P {
|
||||
let mut pp = [0; 16];
|
||||
self.permcount = idx as u32;
|
||||
for (i, place) in self.perm.p.iter_mut().enumerate() {
|
||||
*place = i as i32 + 1;
|
||||
}
|
||||
|
||||
for i in (1..self.n as usize).rev() {
|
||||
let d = idx / self.fact[i] as i32;
|
||||
self.cnt[i] = d;
|
||||
idx %= self.fact[i] as i32;
|
||||
for (place, val) in pp.iter_mut().zip(&self.perm.p[..i+1]) {
|
||||
*place = (*val) as u8
|
||||
}
|
||||
|
||||
let d = d as usize;
|
||||
for j in 0..i + 1 {
|
||||
self.perm.p[j] = if j + d <= i {pp[j + d]} else {pp[j+d-i-1]} as i32;
|
||||
}
|
||||
}
|
||||
|
||||
self.perm
|
||||
}
|
||||
|
||||
fn count(&self) -> u32 { self.permcount }
|
||||
fn max(&self) -> u32 { self.fact[self.n as usize] }
|
||||
|
||||
fn next(&mut self) -> P {
|
||||
next_permutation(&mut self.perm.p, &mut self.cnt);
|
||||
self.permcount += 1;
|
||||
|
||||
self.perm
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn reverse(tperm: &mut [i32], k: usize) {
|
||||
tperm[..k].reverse()
|
||||
}
|
||||
|
||||
fn work(mut perm: Perm, n: usize, max: usize) -> (i32, i32) {
|
||||
let mut checksum = 0;
|
||||
let mut maxflips = 0;
|
||||
|
||||
let mut p = perm.get(n as i32);
|
||||
|
||||
while perm.count() < max as u32 {
|
||||
let mut flips = 0;
|
||||
|
||||
while p.p[0] != 1 {
|
||||
let k = p.p[0] as usize;
|
||||
reverse(&mut p.p, k);
|
||||
flips += 1;
|
||||
}
|
||||
|
||||
checksum += if perm.count() % 2 == 0 {flips} else {-flips};
|
||||
maxflips = cmp::max(maxflips, flips);
|
||||
|
||||
p = perm.next();
|
||||
}
|
||||
|
||||
(checksum, maxflips)
|
||||
}
|
||||
|
||||
fn fannkuch(n: i32) -> (i32, i32) {
|
||||
let perm = Perm::new(n as u32);
|
||||
|
||||
let N = 4;
|
||||
let mut futures = vec![];
|
||||
let k = perm.max() / N;
|
||||
|
||||
for (_, j) in (0..N).zip((0..).step_by(k)) {
|
||||
let max = cmp::min(j+k, perm.max());
|
||||
|
||||
futures.push(thread::spawn(move|| {
|
||||
work(perm, j as usize, max as usize)
|
||||
}))
|
||||
}
|
||||
|
||||
let mut checksum = 0;
|
||||
let mut maxflips = 0;
|
||||
for fut in futures {
|
||||
let (cs, mf) = fut.join().unwrap();
|
||||
checksum += cs;
|
||||
maxflips = cmp::max(maxflips, mf);
|
||||
}
|
||||
(checksum, maxflips)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let n = std::env::args()
|
||||
.nth(1)
|
||||
.and_then(|arg| arg.parse().ok())
|
||||
.unwrap_or(2);
|
||||
|
||||
let (checksum, maxflips) = fannkuch(n);
|
||||
println!("{}\nPfannkuchen({}) = {}", checksum, n, maxflips);
|
||||
}
|
@ -1,376 +0,0 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// contributed by the Rust Project Developers
|
||||
|
||||
// Copyright (c) 2013-2014 The Rust Project Developers
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// - Neither the name of "The Computer Language Benchmarks Game" nor
|
||||
// the name of "The Computer Language Shootout Benchmarks" nor the
|
||||
// names of its contributors may be used to endorse or promote
|
||||
// products derived from this software without specific prior
|
||||
// written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
use std::cmp::min;
|
||||
use std::io::{self, Write};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
|
||||
|
||||
const LINE_LEN: usize = 60;
|
||||
|
||||
const BLOCK_LINES: usize = 512;
|
||||
const BLOCK_THOROUGHPUT: usize = LINE_LEN * BLOCK_LINES;
|
||||
const BLOCK_LEN: usize = BLOCK_THOROUGHPUT + BLOCK_LINES;
|
||||
|
||||
const STDIN_BUF: usize = (LINE_LEN + 1) * 1024;
|
||||
const LOOKUP_SIZE: usize = 4 * 1024;
|
||||
const LOOKUP_SCALE: f32 = (LOOKUP_SIZE - 1) as f32;
|
||||
|
||||
const ALU: &'static [u8] =
|
||||
b"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG\
|
||||
GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA\
|
||||
CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT\
|
||||
ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA\
|
||||
GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG\
|
||||
AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC\
|
||||
AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
|
||||
|
||||
const IUB: &'static [(u8, f32)] =
|
||||
&[(b'a', 0.27), (b'c', 0.12), (b'g', 0.12),
|
||||
(b't', 0.27), (b'B', 0.02), (b'D', 0.02),
|
||||
(b'H', 0.02), (b'K', 0.02), (b'M', 0.02),
|
||||
(b'N', 0.02), (b'R', 0.02), (b'S', 0.02),
|
||||
(b'V', 0.02), (b'W', 0.02), (b'Y', 0.02)];
|
||||
|
||||
const HOMOSAPIENS: &'static [(u8, f32)] =
|
||||
&[(b'a', 0.3029549426680),
|
||||
(b'c', 0.1979883004921),
|
||||
(b'g', 0.1975473066391),
|
||||
(b't', 0.3015094502008)];
|
||||
|
||||
// We need a specific Rng,
|
||||
// so implement this manually
|
||||
|
||||
const MODULUS: u32 = 139968;
|
||||
const MULTIPLIER: u32 = 3877;
|
||||
const ADDITIVE: u32 = 29573;
|
||||
|
||||
// Why doesn't rust already have this?
|
||||
// Algorithm directly taken from Wikipedia
|
||||
fn powmod(mut base: u64, mut exponent: u32, modulus: u64) -> u64 {
|
||||
let mut ret = 1;
|
||||
base %= modulus;
|
||||
|
||||
while exponent > 0 {
|
||||
if exponent & 1 == 1 {
|
||||
ret *= base;
|
||||
ret %= modulus;
|
||||
}
|
||||
exponent >>= 1;
|
||||
base *= base;
|
||||
base %= modulus;
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
// Just a typical LCRNG
|
||||
pub struct Rng {
|
||||
last: u32
|
||||
}
|
||||
|
||||
impl Rng {
|
||||
pub fn new() -> Rng {
|
||||
Rng { last: 42 }
|
||||
}
|
||||
|
||||
pub fn max_value() -> u32 {
|
||||
MODULUS - 1
|
||||
}
|
||||
|
||||
pub fn normalize(p: f32) -> u32 {
|
||||
(p * MODULUS as f32).floor() as u32
|
||||
}
|
||||
|
||||
pub fn gen(&mut self) -> u32 {
|
||||
self.last = (self.last * MULTIPLIER + ADDITIVE) % MODULUS;
|
||||
self.last
|
||||
}
|
||||
|
||||
// This allows us to fast-forward the RNG,
|
||||
// allowing us to run it in parallel.
|
||||
pub fn future(&self, n: u32) -> Rng {
|
||||
let a = MULTIPLIER as u64;
|
||||
let b = ADDITIVE as u64;
|
||||
let m = MODULUS as u64;
|
||||
|
||||
// (a^n - 1) mod (a-1) m
|
||||
// x_k = ((a^n x_0 mod m) + --------------------- b) mod m
|
||||
// a - 1
|
||||
//
|
||||
// Since (a - 1) divides (a^n - 1) mod (a-1) m,
|
||||
// the subtraction does not overflow and thus can be non-modular.
|
||||
//
|
||||
let new_seed =
|
||||
(powmod(a, n, m) * self.last as u64) % m +
|
||||
(powmod(a, n, (a-1) * m) - 1) / (a-1) * b;
|
||||
|
||||
Rng { last: (new_seed % m) as u32 }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This will end up keeping track of threads, like
|
||||
// in the other multithreaded Rust version, in
|
||||
// order to keep writes in order.
|
||||
//
|
||||
// This is stolen from another multithreaded Rust
|
||||
// implementation, although that implementation
|
||||
// was not able to parallelize the RNG itself.
|
||||
struct BlockSubmitter<W: io::Write> {
|
||||
writer: W,
|
||||
pub waiting_on: usize,
|
||||
}
|
||||
|
||||
impl<W: io::Write> BlockSubmitter<W> {
|
||||
fn submit(&mut self, data: &[u8], block_num: usize) -> Option<io::Result<()>> {
|
||||
if block_num == self.waiting_on {
|
||||
self.waiting_on += 1;
|
||||
Some(self.submit_async(data))
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn submit_async(&mut self, data: &[u8]) -> io::Result<()> {
|
||||
self.writer.write_all(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// For repeating strings as output
|
||||
fn fasta_static<W: io::Write>(
|
||||
writer: &mut W,
|
||||
header: &[u8],
|
||||
data: &[u8],
|
||||
mut n: usize
|
||||
) -> io::Result<()>
|
||||
{
|
||||
// The aim here is to print a short(ish) string cyclically
|
||||
// with line breaks as appropriate.
|
||||
//
|
||||
// The secret technique is to repeat the string such that
|
||||
// any wanted line is a single offset in the string.
|
||||
//
|
||||
// This technique is stolen from the Haskell version.
|
||||
|
||||
try!(writer.write_all(header));
|
||||
|
||||
// Maximum offset is data.len(),
|
||||
// Maximum read len is LINE_LEN
|
||||
let stream = data.iter().cloned().cycle();
|
||||
let mut extended: Vec<u8> = stream.take(data.len() + LINE_LEN + 1).collect();
|
||||
|
||||
let mut offset = 0;
|
||||
while n > 0 {
|
||||
let write_len = min(LINE_LEN, n);
|
||||
let end = offset + write_len;
|
||||
n -= write_len;
|
||||
|
||||
let tmp = extended[end];
|
||||
extended[end] = b'\n';
|
||||
try!(writer.write_all(&extended[offset..end + 1]));
|
||||
extended[end] = tmp;
|
||||
|
||||
offset = end;
|
||||
offset %= data.len();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
// For RNG streams as output
|
||||
fn fasta<W: io::Write + Send + 'static>(
|
||||
submitter: &Arc<Mutex<BlockSubmitter<W>>>,
|
||||
header: &[u8],
|
||||
table: &'static [(u8, f32)],
|
||||
rng: &mut Rng,
|
||||
n: usize
|
||||
) -> io::Result<()>
|
||||
{
|
||||
// Here the lookup table is part of the algorithm and needs the
|
||||
// original probabilities (scaled with the LOOKUP_SCALE), because
|
||||
// Isaac says so :-)
|
||||
fn sum_and_scale(a: &'static [(u8, f32)]) -> Vec<(u8, f32)> {
|
||||
let mut p = 0f32;
|
||||
let mut result: Vec<(u8, f32)> = a.iter().map(|e| {
|
||||
p += e.1;
|
||||
(e.0, p * LOOKUP_SCALE)
|
||||
}).collect();
|
||||
let result_len = result.len();
|
||||
result[result_len - 1].1 = LOOKUP_SCALE;
|
||||
result
|
||||
}
|
||||
|
||||
fn make_lookup(a: &[(u8, f32)]) -> [(u8, f32); LOOKUP_SIZE] {
|
||||
let mut lookup = [(0, 0f32); LOOKUP_SIZE];
|
||||
let mut j = 0;
|
||||
for (i, slot) in lookup.iter_mut().enumerate() {
|
||||
while a[j].1 < (i as f32) {
|
||||
j += 1;
|
||||
}
|
||||
*slot = a[j];
|
||||
}
|
||||
lookup
|
||||
}
|
||||
|
||||
{
|
||||
try!(submitter.lock().unwrap().submit_async(header));
|
||||
}
|
||||
|
||||
let lookup_table = Arc::new(make_lookup(&sum_and_scale(table)));
|
||||
|
||||
let thread_count = 4;
|
||||
let mut threads = Vec::new();
|
||||
for block_num in (0..thread_count) {
|
||||
let offset = BLOCK_THOROUGHPUT * block_num;
|
||||
|
||||
let local_submitter = submitter.clone();
|
||||
let local_lookup_table = lookup_table.clone();
|
||||
let local_rng = rng.future(offset as u32);
|
||||
|
||||
threads.push(thread::spawn(move || {
|
||||
gen_block(
|
||||
local_submitter,
|
||||
local_lookup_table,
|
||||
local_rng,
|
||||
n.saturating_sub(offset),
|
||||
block_num,
|
||||
thread_count
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
for thread in threads {
|
||||
try!(thread.join().unwrap());
|
||||
}
|
||||
|
||||
*rng = rng.future(n as u32);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// A very optimized writer.
|
||||
// I have a feeling a simpler version wouldn't slow
|
||||
// things down too much, though, since the RNG
|
||||
// is the really heavy hitter.
|
||||
fn gen_block<W: io::Write>(
|
||||
submitter: Arc<Mutex<BlockSubmitter<W>>>,
|
||||
lookup_table: Arc<[(u8, f32)]>,
|
||||
mut rng: Rng,
|
||||
mut length: usize,
|
||||
mut block_num: usize,
|
||||
block_stride: usize,
|
||||
) -> io::Result<()>
|
||||
{
|
||||
// Include newlines in block
|
||||
length += length / LINE_LEN;
|
||||
let block: &mut [u8] = &mut [b'\n'; BLOCK_LEN];
|
||||
|
||||
while length > 0 {
|
||||
{
|
||||
let gen_into = &mut block[..min(length, BLOCK_LEN)];
|
||||
|
||||
// Write random numbers, skipping newlines
|
||||
for (i, byte) in gen_into.iter_mut().enumerate() {
|
||||
if (i + 1) % (LINE_LEN + 1) != 0 {
|
||||
let p = rng.gen() as f32 * (LOOKUP_SCALE / MODULUS as f32);
|
||||
*byte = lookup_table[p as usize..LOOKUP_SIZE].iter().find(
|
||||
|le| le.1 >= p).unwrap().0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let write_out = {
|
||||
if length >= BLOCK_LEN { &mut *block }
|
||||
else if length % (LINE_LEN + 1) == 0 { &mut block[..length] }
|
||||
else { &mut block[..length + 1] }
|
||||
};
|
||||
|
||||
*write_out.last_mut().unwrap() = b'\n';
|
||||
loop {
|
||||
// Make sure to release lock before calling `yield_now`
|
||||
let res = { submitter.lock().unwrap().submit(write_out, block_num) };
|
||||
|
||||
match res {
|
||||
Some(result) => { try!(result); break; }
|
||||
None => std::thread::yield_now()
|
||||
}
|
||||
}
|
||||
block_num += block_stride;
|
||||
rng = rng.future((BLOCK_THOROUGHPUT * (block_stride - 1)) as u32);
|
||||
length = length.saturating_sub(BLOCK_LEN * (block_stride - 1));
|
||||
|
||||
length = length.saturating_sub(BLOCK_LEN);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run<W: io::Write + Send + 'static>(writer: W) -> io::Result<()> {
|
||||
let n = std::env::args_os().nth(1)
|
||||
.and_then(|s| s.into_string().ok())
|
||||
.and_then(|n| n.parse().ok())
|
||||
.unwrap_or(1000);
|
||||
|
||||
let rng = &mut Rng::new();
|
||||
|
||||
// Use automatic buffering for the static version...
|
||||
let mut writer = io::BufWriter::with_capacity(STDIN_BUF, writer);
|
||||
try!(fasta_static(&mut writer, b">ONE Homo sapiens alu\n", ALU, n * 2));
|
||||
|
||||
// ...but the dynamic version does its own buffering already
|
||||
let writer = try!(writer.into_inner());
|
||||
let submitter = Arc::new(Mutex::new(BlockSubmitter { writer: writer, waiting_on: 0 }));
|
||||
|
||||
{ submitter.lock().unwrap().waiting_on = 0; }
|
||||
try!(fasta(&submitter, b">TWO IUB ambiguity codes\n", &IUB, rng, n * 3));
|
||||
{ submitter.lock().unwrap().waiting_on = 0; }
|
||||
try!(fasta(&submitter, b">THREE Homo sapiens frequency\n", &HOMOSAPIENS, rng, n * 5));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
run(io::stdout()).unwrap()
|
||||
}
|
@ -1,370 +0,0 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// contributed by the Rust Project Developers
|
||||
|
||||
// Copyright (c) 2012-2014 The Rust Project Developers
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// - Neither the name of "The Computer Language Benchmarks Game" nor
|
||||
// the name of "The Computer Language Shootout Benchmarks" nor the
|
||||
// names of its contributors may be used to endorse or promote
|
||||
// products derived from this software without specific prior
|
||||
// written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
use std::cmp::min;
|
||||
use std::io::{self, Write};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
|
||||
|
||||
const LINE_LEN: usize = 60;
|
||||
|
||||
const BLOCK_LINES: usize = 512;
|
||||
const BLOCK_THOROUGHPUT: usize = LINE_LEN * BLOCK_LINES;
|
||||
const BLOCK_LEN: usize = BLOCK_THOROUGHPUT + BLOCK_LINES;
|
||||
|
||||
const STDIN_BUF: usize = (LINE_LEN + 1) * 1024;
|
||||
|
||||
|
||||
const ALU: &'static [u8] =
|
||||
b"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG\
|
||||
GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA\
|
||||
CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT\
|
||||
ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA\
|
||||
GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG\
|
||||
AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC\
|
||||
AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
|
||||
|
||||
const IUB: &'static [(u8, f32)] =
|
||||
&[(b'a', 0.27), (b'c', 0.12), (b'g', 0.12),
|
||||
(b't', 0.27), (b'B', 0.02), (b'D', 0.02),
|
||||
(b'H', 0.02), (b'K', 0.02), (b'M', 0.02),
|
||||
(b'N', 0.02), (b'R', 0.02), (b'S', 0.02),
|
||||
(b'V', 0.02), (b'W', 0.02), (b'Y', 0.02)];
|
||||
|
||||
const HOMOSAPIENS: &'static [(u8, f32)] =
|
||||
&[(b'a', 0.3029549426680),
|
||||
(b'c', 0.1979883004921),
|
||||
(b'g', 0.1975473066391),
|
||||
(b't', 0.3015094502008)];
|
||||
|
||||
|
||||
// We need a specific Rng,
|
||||
// so implement this manually
|
||||
const MODULUS: u32 = 139968;
|
||||
const MULTIPLIER: u32 = 3877;
|
||||
const ADDITIVE: u32 = 29573;
|
||||
|
||||
// Why doesn't rust already have this?
|
||||
// Algorithm directly taken from Wikipedia
|
||||
fn powmod(mut base: u64, mut exponent: u32, modulus: u64) -> u64 {
|
||||
let mut ret = 1;
|
||||
base %= modulus;
|
||||
|
||||
while exponent > 0 {
|
||||
if exponent & 1 == 1 {
|
||||
ret *= base;
|
||||
ret %= modulus;
|
||||
}
|
||||
exponent >>= 1;
|
||||
base *= base;
|
||||
base %= modulus;
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
// Just a typical LCRNG
|
||||
pub struct Rng {
|
||||
last: u32
|
||||
}
|
||||
|
||||
impl Rng {
|
||||
pub fn new() -> Rng {
|
||||
Rng { last: 42 }
|
||||
}
|
||||
|
||||
pub fn max_value() -> u32 {
|
||||
MODULUS - 1
|
||||
}
|
||||
|
||||
pub fn normalize(p: f32) -> u32 {
|
||||
(p * MODULUS as f32).floor() as u32
|
||||
}
|
||||
|
||||
pub fn gen(&mut self) -> u32 {
|
||||
self.last = (self.last * MULTIPLIER + ADDITIVE) % MODULUS;
|
||||
self.last
|
||||
}
|
||||
|
||||
// This allows us to fast-forward the RNG,
|
||||
// allowing us to run it in parallel.
|
||||
pub fn future(&self, n: u32) -> Rng {
|
||||
let a = MULTIPLIER as u64;
|
||||
let b = ADDITIVE as u64;
|
||||
let m = MODULUS as u64;
|
||||
|
||||
// (a^n - 1) mod (a-1) m
|
||||
// x_k = ((a^n x_0 mod m) + --------------------- b) mod m
|
||||
// a - 1
|
||||
//
|
||||
// Since (a - 1) divides (a^n - 1) mod (a-1) m,
|
||||
// the subtraction does not overflow and thus can be non-modular.
|
||||
//
|
||||
let new_seed =
|
||||
(powmod(a, n, m) * self.last as u64) % m +
|
||||
(powmod(a, n, (a-1) * m) - 1) / (a-1) * b;
|
||||
|
||||
Rng { last: (new_seed % m) as u32 }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This will end up keeping track of threads, like
|
||||
// in the other multithreaded Rust version, in
|
||||
// order to keep writes in order.
|
||||
//
|
||||
// This is stolen from another multithreaded Rust
|
||||
// implementation, although that implementation
|
||||
// was not able to parallelize the RNG itself.
|
||||
struct BlockSubmitter<W: io::Write> {
|
||||
writer: W,
|
||||
pub waiting_on: usize,
|
||||
}
|
||||
|
||||
impl<W: io::Write> BlockSubmitter<W> {
|
||||
fn submit(&mut self, data: &[u8], block_num: usize) -> Option<io::Result<()>> {
|
||||
if block_num == self.waiting_on {
|
||||
self.waiting_on += 1;
|
||||
Some(self.submit_async(data))
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn submit_async(&mut self, data: &[u8]) -> io::Result<()> {
|
||||
self.writer.write_all(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// For repeating strings as output
|
||||
fn fasta_static<W: io::Write>(
|
||||
writer: &mut W,
|
||||
header: &[u8],
|
||||
data: &[u8],
|
||||
mut n: usize
|
||||
) -> io::Result<()>
|
||||
{
|
||||
// The aim here is to print a short(ish) string cyclically
|
||||
// with line breaks as appropriate.
|
||||
//
|
||||
// The secret technique is to repeat the string such that
|
||||
// any wanted line is a single offset in the string.
|
||||
//
|
||||
// This technique is stolen from the Haskell version.
|
||||
|
||||
try!(writer.write_all(header));
|
||||
|
||||
// Maximum offset is data.len(),
|
||||
// Maximum read len is LINE_LEN
|
||||
let stream = data.iter().cloned().cycle();
|
||||
let mut extended: Vec<u8> = stream.take(data.len() + LINE_LEN + 1).collect();
|
||||
|
||||
let mut offset = 0;
|
||||
while n > 0 {
|
||||
let write_len = min(LINE_LEN, n);
|
||||
let end = offset + write_len;
|
||||
n -= write_len;
|
||||
|
||||
let tmp = extended[end];
|
||||
extended[end] = b'\n';
|
||||
try!(writer.write_all(&extended[offset..end + 1]));
|
||||
extended[end] = tmp;
|
||||
|
||||
offset = end;
|
||||
offset %= data.len();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
// For RNG streams as output
|
||||
fn fasta<W: io::Write + Send + 'static>(
|
||||
submitter: &Arc<Mutex<BlockSubmitter<W>>>,
|
||||
header: &[u8],
|
||||
table: &[(u8, f32)],
|
||||
rng: &mut Rng,
|
||||
n: usize
|
||||
) -> io::Result<()>
|
||||
{
|
||||
// There's another secret technique in use here:
|
||||
// we generate a lookup table to cache search of the
|
||||
// aa buffer.
|
||||
//
|
||||
// The secret technique used is stolen from Haskell's
|
||||
// implementation, and is the main secret to the Haskell
|
||||
// implementation's speed.
|
||||
fn gen_lookup_table(aa: &[(u8, f32)]) -> Vec<u8> {
|
||||
let mut table = Vec::with_capacity(Rng::max_value() as usize + 1);
|
||||
|
||||
let mut cumulative_prob = 0.0;
|
||||
let mut cumulative_norm = 0;
|
||||
|
||||
for &(byte, prob) in aa {
|
||||
let last_norm = cumulative_norm;
|
||||
cumulative_prob += prob;
|
||||
cumulative_norm = min(Rng::max_value(), Rng::normalize(cumulative_prob)) + 1;
|
||||
|
||||
table.extend((0..cumulative_norm - last_norm).map(|_| byte));
|
||||
}
|
||||
|
||||
table
|
||||
}
|
||||
|
||||
{
|
||||
try!(submitter.lock().unwrap().submit_async(header));
|
||||
}
|
||||
|
||||
let lookup_table = Arc::new(gen_lookup_table(table));
|
||||
|
||||
let thread_count = 4; // avoid external dependency
|
||||
let mut threads = Vec::new();
|
||||
for block_num in (0..thread_count) {
|
||||
let offset = BLOCK_THOROUGHPUT * block_num;
|
||||
|
||||
let local_submitter = submitter.clone();
|
||||
let local_lookup_table = lookup_table.clone();
|
||||
let local_rng = rng.future(offset as u32);
|
||||
|
||||
threads.push(thread::spawn(move || {
|
||||
gen_block(
|
||||
local_submitter,
|
||||
local_lookup_table,
|
||||
local_rng,
|
||||
n.saturating_sub(offset),
|
||||
block_num,
|
||||
thread_count
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
for thread in threads {
|
||||
try!(thread.join().unwrap());
|
||||
}
|
||||
|
||||
*rng = rng.future(n as u32);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// A very optimized writer.
|
||||
// I have a feeling a simpler version wouldn't slow
|
||||
// things down too much, though, since the RNG
|
||||
// is the really heavy hitter.
|
||||
fn gen_block<W: io::Write>(
|
||||
submitter: Arc<Mutex<BlockSubmitter<W>>>,
|
||||
lookup_table: Arc<Vec<u8>>,
|
||||
mut rng: Rng,
|
||||
mut length: usize,
|
||||
mut block_num: usize,
|
||||
block_stride: usize,
|
||||
) -> io::Result<()>
|
||||
{
|
||||
// Include newlines in block
|
||||
length += length / LINE_LEN;
|
||||
let block: &mut [u8] = &mut [b'\n'; BLOCK_LEN];
|
||||
|
||||
while length > 0 {
|
||||
{
|
||||
let gen_into = &mut block[..min(length, BLOCK_LEN)];
|
||||
|
||||
// Write random numbers, skipping newlines
|
||||
for (i, byte) in gen_into.iter_mut().enumerate() {
|
||||
if (i + 1) % (LINE_LEN + 1) != 0 {
|
||||
*byte = lookup_table[rng.gen() as usize];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let write_out = {
|
||||
if length >= BLOCK_LEN { &mut *block }
|
||||
else if length % (LINE_LEN + 1) == 0 { &mut block[..length] }
|
||||
else { &mut block[..length + 1] }
|
||||
};
|
||||
|
||||
*write_out.last_mut().unwrap() = b'\n';
|
||||
loop {
|
||||
match submitter.lock().unwrap().submit(write_out, block_num) {
|
||||
Some(result) => { try!(result); break; }
|
||||
None => std::thread::yield_now()
|
||||
}
|
||||
}
|
||||
block_num += block_stride;
|
||||
rng = rng.future((BLOCK_THOROUGHPUT * (block_stride - 1)) as u32);
|
||||
length = length.saturating_sub(BLOCK_LEN * (block_stride - 1));
|
||||
|
||||
length = length.saturating_sub(BLOCK_LEN);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn run<W: io::Write + Send + 'static>(writer: W) -> io::Result<()> {
|
||||
let n = std::env::args_os().nth(1)
|
||||
.and_then(|s| s.into_string().ok())
|
||||
.and_then(|n| n.parse().ok())
|
||||
.unwrap_or(1000);
|
||||
|
||||
let rng = &mut Rng::new();
|
||||
|
||||
// Use automatic buffering for the static version...
|
||||
let mut writer = io::BufWriter::with_capacity(STDIN_BUF, writer);
|
||||
try!(fasta_static(&mut writer, b">ONE Homo sapiens alu\n", ALU, n * 2));
|
||||
|
||||
// ...but the dynamic version does its own buffering already
|
||||
let writer = try!(writer.into_inner());
|
||||
let submitter = Arc::new(Mutex::new(BlockSubmitter { writer: writer, waiting_on: 0 }));
|
||||
|
||||
{ submitter.lock().unwrap().waiting_on = 0; }
|
||||
try!(fasta(&submitter, b">TWO IUB ambiguity codes\n", &IUB, rng, n * 3));
|
||||
{ submitter.lock().unwrap().waiting_on = 0; }
|
||||
try!(fasta(&submitter, b">THREE Homo sapiens frequency\n", &HOMOSAPIENS, rng, n * 5));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
run(io::stdout()).unwrap()
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::env;
|
||||
|
||||
fn fib(n: i64) -> i64 {
|
||||
if n < 2 {
|
||||
return 1;
|
||||
} else {
|
||||
return fib(n - 1) + fib(n - 2);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
let args = if env::var_os("RUST_BENCH").is_some() {
|
||||
vec!("".to_string(), "40".to_string())
|
||||
} else if args.len() <= 1 {
|
||||
vec!("".to_string(), "30".to_string())
|
||||
} else {
|
||||
args.collect()
|
||||
};
|
||||
let n = args[1].parse().unwrap();
|
||||
println!("{}\n", fib(n));
|
||||
}
|
@ -1,224 +0,0 @@
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-android: FIXME(#10393) hangs without output
|
||||
// ignore-pretty very bad with line comments
|
||||
|
||||
// multi threading k-nucleotide
|
||||
|
||||
use std::ascii::AsciiExt;
|
||||
use std::cmp::Ordering::{self, Less, Greater, Equal};
|
||||
use std::collections::HashMap;
|
||||
use std::mem::replace;
|
||||
use std::env;
|
||||
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||
use std::thread;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
|
||||
fn f64_cmp(x: f64, y: f64) -> Ordering {
|
||||
// arbitrarily decide that NaNs are larger than everything.
|
||||
if y.is_nan() {
|
||||
Less
|
||||
} else if x.is_nan() {
|
||||
Greater
|
||||
} else if x < y {
|
||||
Less
|
||||
} else if x == y {
|
||||
Equal
|
||||
} else {
|
||||
Greater
|
||||
}
|
||||
}
|
||||
|
||||
// given a map, print a sorted version of it
|
||||
fn sort_and_fmt(mm: &HashMap<Vec<u8> , usize>, total: usize) -> String {
|
||||
fn pct(xx: usize, yy: usize) -> f64 {
|
||||
return (xx as f64) * 100.0 / (yy as f64);
|
||||
}
|
||||
|
||||
// sort by key, then by value
|
||||
fn sort_kv(mut orig: Vec<(Vec<u8> ,f64)> ) -> Vec<(Vec<u8> ,f64)> {
|
||||
orig.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b));
|
||||
orig.sort_by(|&(_, a), &(_, b)| f64_cmp(b, a));
|
||||
orig
|
||||
}
|
||||
|
||||
let mut pairs = Vec::new();
|
||||
|
||||
// map -> [(k,%)]
|
||||
for (key, &val) in mm {
|
||||
pairs.push(((*key).clone(), pct(val, total)));
|
||||
}
|
||||
|
||||
let pairs_sorted = sort_kv(pairs);
|
||||
|
||||
let mut buffer = String::new();
|
||||
for &(ref k, v) in &pairs_sorted {
|
||||
buffer.push_str(&format!("{:?} {:0.3}\n",
|
||||
k.to_ascii_uppercase(),
|
||||
v));
|
||||
}
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
// given a map, search for the frequency of a pattern
|
||||
fn find(mm: &HashMap<Vec<u8> , usize>, key: String) -> usize {
|
||||
let key = key.to_ascii_lowercase();
|
||||
match mm.get(key.as_bytes()) {
|
||||
None => 0,
|
||||
Some(&num) => num,
|
||||
}
|
||||
}
|
||||
|
||||
// given a map, increment the counter for a key
|
||||
fn update_freq(mm: &mut HashMap<Vec<u8> , usize>, key: &[u8]) {
|
||||
let key = key.to_vec();
|
||||
let newval = match mm.remove(&key) {
|
||||
Some(v) => v + 1,
|
||||
None => 1
|
||||
};
|
||||
mm.insert(key, newval);
|
||||
}
|
||||
|
||||
// given a Vec<u8>, for each window call a function
|
||||
// i.e., for "hello" and windows of size four,
|
||||
// run it("hell") and it("ello"), then return "llo"
|
||||
fn windows_with_carry<F>(bb: &[u8], nn: usize, mut it: F) -> Vec<u8> where
|
||||
F: FnMut(&[u8]),
|
||||
{
|
||||
let mut ii = 0;
|
||||
|
||||
let len = bb.len();
|
||||
while ii < len - (nn - 1) {
|
||||
it(&bb[ii..ii+nn]);
|
||||
ii += 1;
|
||||
}
|
||||
|
||||
return bb[len - (nn - 1)..len].to_vec();
|
||||
}
|
||||
|
||||
fn make_sequence_processor(sz: usize,
|
||||
from_parent: &Receiver<Vec<u8>>,
|
||||
to_parent: &Sender<String>) {
|
||||
let mut freqs: HashMap<Vec<u8>, usize> = HashMap::new();
|
||||
let mut carry = Vec::new();
|
||||
let mut total: usize = 0;
|
||||
|
||||
let mut line: Vec<u8>;
|
||||
|
||||
loop {
|
||||
|
||||
line = from_parent.recv().unwrap();
|
||||
if line == Vec::new() { break; }
|
||||
|
||||
carry.extend(line);
|
||||
carry = windows_with_carry(&carry, sz, |window| {
|
||||
update_freq(&mut freqs, window);
|
||||
total += 1;
|
||||
});
|
||||
}
|
||||
|
||||
let buffer = match sz {
|
||||
1 => { sort_and_fmt(&freqs, total) }
|
||||
2 => { sort_and_fmt(&freqs, total) }
|
||||
3 => { format!("{}\t{}", find(&freqs, "GGT".to_string()), "GGT") }
|
||||
4 => { format!("{}\t{}", find(&freqs, "GGTA".to_string()), "GGTA") }
|
||||
6 => { format!("{}\t{}", find(&freqs, "GGTATT".to_string()), "GGTATT") }
|
||||
12 => { format!("{}\t{}", find(&freqs, "GGTATTTTAATT".to_string()), "GGTATTTTAATT") }
|
||||
18 => { format!("{}\t{}", find(&freqs, "GGTATTTTAATTTATAGT".to_string()),
|
||||
"GGTATTTTAATTTATAGT") }
|
||||
_ => { "".to_string() }
|
||||
};
|
||||
|
||||
to_parent.send(buffer).unwrap();
|
||||
}
|
||||
|
||||
// given a FASTA file on stdin, process sequence THREE
|
||||
fn main() {
|
||||
let input = io::stdin();
|
||||
let rdr = if env::var_os("RUST_BENCH").is_some() {
|
||||
let foo: &[u8] = include_bytes!("shootout-k-nucleotide.data");
|
||||
Box::new(foo) as Box<BufRead>
|
||||
} else {
|
||||
Box::new(input.lock()) as Box<BufRead>
|
||||
};
|
||||
|
||||
// initialize each sequence sorter
|
||||
let sizes: Vec<usize> = vec!(1,2,3,4,6,12,18);
|
||||
let mut streams = (0..sizes.len()).map(|_| {
|
||||
Some(channel::<String>())
|
||||
}).collect::<Vec<_>>();
|
||||
let mut from_child = Vec::new();
|
||||
let to_child = sizes.iter().zip(&mut streams).map(|(sz, stream_ref)| {
|
||||
let sz = *sz;
|
||||
let stream = replace(stream_ref, None);
|
||||
let (to_parent_, from_child_) = stream.unwrap();
|
||||
|
||||
from_child.push(from_child_);
|
||||
|
||||
let (to_child, from_parent) = channel();
|
||||
|
||||
thread::spawn(move|| {
|
||||
make_sequence_processor(sz, &from_parent, &to_parent_);
|
||||
});
|
||||
|
||||
to_child
|
||||
}).collect::<Vec<Sender<Vec<u8>>>>();
|
||||
|
||||
|
||||
// latch stores true after we've started
|
||||
// reading the sequence of interest
|
||||
let mut proc_mode = false;
|
||||
|
||||
for line in rdr.lines() {
|
||||
let line = line.unwrap().trim().to_string();
|
||||
|
||||
if line.is_empty() { continue; }
|
||||
|
||||
match (line.as_bytes()[0] as char, proc_mode) {
|
||||
|
||||
// start processing if this is the one
|
||||
('>', false) => {
|
||||
match line[1..].find("THREE") {
|
||||
Some(_) => { proc_mode = true; }
|
||||
None => { }
|
||||
}
|
||||
}
|
||||
|
||||
// break our processing
|
||||
('>', true) => { break; }
|
||||
|
||||
// process the sequence for k-mers
|
||||
(_, true) => {
|
||||
let line_bytes = line.as_bytes();
|
||||
|
||||
for (ii, _sz) in sizes.iter().enumerate() {
|
||||
let lb = line_bytes.to_vec();
|
||||
to_child[ii].send(lb).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// whatever
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
||||
// finish...
|
||||
for (ii, _sz) in sizes.iter().enumerate() {
|
||||
to_child[ii].send(Vec::new()).unwrap();
|
||||
}
|
||||
|
||||
// now fetch and print result messages
|
||||
for (ii, _sz) in sizes.iter().enumerate() {
|
||||
println!("{:?}", from_child[ii].recv().unwrap());
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,324 +0,0 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// contributed by the Rust Project Developers
|
||||
|
||||
// Copyright (c) 2014 The Rust Project Developers
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// - Neither the name of "The Computer Language Benchmarks Game" nor
|
||||
// the name of "The Computer Language Shootout Benchmarks" nor the
|
||||
// names of its contributors may be used to endorse or promote
|
||||
// products derived from this software without specific prior
|
||||
// written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ignore-android: FIXME(#10393) hangs without output
|
||||
|
||||
use std::ascii::AsciiExt;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::slice;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
static TABLE: [u8;4] = [ 'A' as u8, 'C' as u8, 'G' as u8, 'T' as u8 ];
|
||||
static TABLE_SIZE: usize = 2 << 16;
|
||||
|
||||
static OCCURRENCES: [&'static str;5] = [
|
||||
"GGT",
|
||||
"GGTA",
|
||||
"GGTATT",
|
||||
"GGTATTTTAATT",
|
||||
"GGTATTTTAATTTATAGT",
|
||||
];
|
||||
|
||||
// Code implementation
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
|
||||
struct Code(u64);
|
||||
|
||||
impl Code {
|
||||
fn hash(&self) -> u64 {
|
||||
let Code(ret) = *self;
|
||||
return ret;
|
||||
}
|
||||
|
||||
fn push_char(&self, c: u8) -> Code {
|
||||
Code((self.hash() << 2) + (pack_symbol(c) as u64))
|
||||
}
|
||||
|
||||
fn rotate(&self, c: u8, frame: usize) -> Code {
|
||||
Code(self.push_char(c).hash() & ((1 << (2 * frame)) - 1))
|
||||
}
|
||||
|
||||
fn pack(string: &str) -> Code {
|
||||
string.bytes().fold(Code(0), |a, b| a.push_char(b))
|
||||
}
|
||||
|
||||
fn unpack(&self, frame: usize) -> String {
|
||||
let mut key = self.hash();
|
||||
let mut result = Vec::new();
|
||||
for _ in 0..frame {
|
||||
result.push(unpack_symbol((key as u8) & 3));
|
||||
key >>= 2;
|
||||
}
|
||||
|
||||
result.reverse();
|
||||
String::from_utf8(result).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
// Hash table implementation
|
||||
|
||||
trait TableCallback {
|
||||
fn f(&self, entry: &mut Entry);
|
||||
}
|
||||
|
||||
struct BumpCallback;
|
||||
|
||||
impl TableCallback for BumpCallback {
|
||||
fn f(&self, entry: &mut Entry) {
|
||||
entry.count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct PrintCallback(&'static str);
|
||||
|
||||
impl TableCallback for PrintCallback {
|
||||
fn f(&self, entry: &mut Entry) {
|
||||
let PrintCallback(s) = *self;
|
||||
println!("{}\t{}", entry.count, s);
|
||||
}
|
||||
}
|
||||
|
||||
struct Entry {
|
||||
code: Code,
|
||||
count: usize,
|
||||
next: Option<Box<Entry>>,
|
||||
}
|
||||
|
||||
struct Table {
|
||||
items: Vec<Option<Box<Entry>>>
|
||||
}
|
||||
|
||||
struct Items<'a> {
|
||||
cur: Option<&'a Entry>,
|
||||
items: slice::Iter<'a, Option<Box<Entry>>>,
|
||||
}
|
||||
|
||||
impl Table {
|
||||
fn new() -> Table {
|
||||
Table {
|
||||
items: (0..TABLE_SIZE).map(|_| None).collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn search_remainder<C:TableCallback>(item: &mut Entry, key: Code, c: C) {
|
||||
match item.next {
|
||||
None => {
|
||||
let mut entry = Box::new(Entry {
|
||||
code: key,
|
||||
count: 0,
|
||||
next: None,
|
||||
});
|
||||
c.f(&mut *entry);
|
||||
item.next = Some(entry);
|
||||
}
|
||||
Some(ref mut entry) => {
|
||||
if entry.code == key {
|
||||
c.f(&mut **entry);
|
||||
return;
|
||||
}
|
||||
|
||||
Table::search_remainder(&mut **entry, key, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup<C:TableCallback>(&mut self, key: Code, c: C) {
|
||||
let index = key.hash() % (TABLE_SIZE as u64);
|
||||
|
||||
{
|
||||
if self.items[index as usize].is_none() {
|
||||
let mut entry = Box::new(Entry {
|
||||
code: key,
|
||||
count: 0,
|
||||
next: None,
|
||||
});
|
||||
c.f(&mut *entry);
|
||||
self.items[index as usize] = Some(entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let entry = self.items[index as usize].as_mut().unwrap();
|
||||
if entry.code == key {
|
||||
c.f(&mut **entry);
|
||||
return;
|
||||
}
|
||||
|
||||
Table::search_remainder(&mut **entry, key, c)
|
||||
}
|
||||
}
|
||||
|
||||
fn iter(&self) -> Items {
|
||||
Items { cur: None, items: self.items.iter() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Items<'a> {
|
||||
type Item = &'a Entry;
|
||||
|
||||
fn next(&mut self) -> Option<&'a Entry> {
|
||||
let ret = match self.cur {
|
||||
None => {
|
||||
let i;
|
||||
loop {
|
||||
match self.items.next() {
|
||||
None => return None,
|
||||
Some(&None) => {}
|
||||
Some(&Some(ref a)) => { i = &**a; break }
|
||||
}
|
||||
}
|
||||
self.cur = Some(&*i);
|
||||
&*i
|
||||
}
|
||||
Some(c) => c
|
||||
};
|
||||
match ret.next {
|
||||
None => { self.cur = None; }
|
||||
Some(ref next) => { self.cur = Some(&**next); }
|
||||
}
|
||||
return Some(ret);
|
||||
}
|
||||
}
|
||||
|
||||
// Main program
|
||||
|
||||
fn pack_symbol(c: u8) -> u8 {
|
||||
match c as char {
|
||||
'A' => 0,
|
||||
'C' => 1,
|
||||
'G' => 2,
|
||||
'T' => 3,
|
||||
_ => panic!("{}", c as char),
|
||||
}
|
||||
}
|
||||
|
||||
fn unpack_symbol(c: u8) -> u8 {
|
||||
TABLE[c as usize]
|
||||
}
|
||||
|
||||
fn generate_frequencies(mut input: &[u8], frame: usize) -> Table {
|
||||
let mut frequencies = Table::new();
|
||||
if input.len() < frame { return frequencies; }
|
||||
let mut code = Code(0);
|
||||
|
||||
// Pull first frame.
|
||||
for _ in 0..frame {
|
||||
code = code.push_char(input[0]);
|
||||
input = &input[1..];
|
||||
}
|
||||
frequencies.lookup(code, BumpCallback);
|
||||
|
||||
while !input.is_empty() && input[0] != ('>' as u8) {
|
||||
code = code.rotate(input[0], frame);
|
||||
frequencies.lookup(code, BumpCallback);
|
||||
input = &input[1..];
|
||||
}
|
||||
frequencies
|
||||
}
|
||||
|
||||
fn print_frequencies(frequencies: &Table, frame: usize) {
|
||||
let mut vector = Vec::new();
|
||||
for entry in frequencies.iter() {
|
||||
vector.push((entry.count, entry.code));
|
||||
}
|
||||
vector.sort();
|
||||
|
||||
let mut total_count = 0;
|
||||
for &(count, _) in &vector {
|
||||
total_count += count;
|
||||
}
|
||||
|
||||
for &(count, key) in vector.iter().rev() {
|
||||
println!("{} {:.3}",
|
||||
key.unpack(frame),
|
||||
(count as f32 * 100.0) / (total_count as f32));
|
||||
}
|
||||
println!("");
|
||||
}
|
||||
|
||||
fn print_occurrences(frequencies: &mut Table, occurrence: &'static str) {
|
||||
frequencies.lookup(Code::pack(occurrence), PrintCallback(occurrence))
|
||||
}
|
||||
|
||||
fn get_sequence<R: BufRead>(r: &mut R, key: &str) -> Vec<u8> {
|
||||
let mut res = Vec::<u8>::new();
|
||||
for l in r.lines().map(|l| l.unwrap())
|
||||
.skip_while(|l| key != &l[..key.len()]).skip(1)
|
||||
{
|
||||
res.extend(l.trim().as_bytes());
|
||||
}
|
||||
for s in &mut res {
|
||||
*s = s.to_ascii_uppercase();
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let input = if env::var_os("RUST_BENCH").is_some() {
|
||||
let f = File::open("shootout-k-nucleotide.data").unwrap();
|
||||
get_sequence(&mut io::BufReader::new(f), ">THREE")
|
||||
} else {
|
||||
let stdin = io::stdin();
|
||||
let mut stdin = stdin.lock();
|
||||
get_sequence(&mut stdin, ">THREE")
|
||||
};
|
||||
let input = Arc::new(input);
|
||||
|
||||
let nb_freqs: Vec<_> = (1..3).map(|i| {
|
||||
let input = input.clone();
|
||||
(i, thread::spawn(move|| generate_frequencies(&input, i)))
|
||||
}).collect();
|
||||
let occ_freqs: Vec<_> = OCCURRENCES.iter().map(|&occ| {
|
||||
let input = input.clone();
|
||||
thread::spawn(move|| generate_frequencies(&input, occ.len()))
|
||||
}).collect();
|
||||
|
||||
for (i, freq) in nb_freqs {
|
||||
print_frequencies(&freq.join().unwrap(), i);
|
||||
}
|
||||
for (&occ, freq) in OCCURRENCES.iter().zip(occ_freqs) {
|
||||
print_occurrences(&mut freq.join().unwrap(), occ);
|
||||
}
|
||||
}
|
@ -1,343 +0,0 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// contributed by the Rust Project Developers
|
||||
|
||||
// Copyright (c) 2013-2014 The Rust Project Developers
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// - Neither the name of "The Computer Language Benchmarks Game" nor
|
||||
// the name of "The Computer Language Shootout Benchmarks" nor the
|
||||
// names of its contributors may be used to endorse or promote
|
||||
// products derived from this software without specific prior
|
||||
// written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// no-pretty-expanded FIXME #15189
|
||||
|
||||
#![feature(iter_cmp)]
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::thread;
|
||||
|
||||
//
|
||||
// Utilities.
|
||||
//
|
||||
|
||||
// returns an infinite iterator of repeated applications of f to x,
|
||||
// i.e. [x, f(x), f(f(x)), ...], as haskell iterate function.
|
||||
fn iterate<T, F>(x: T, f: F) -> Iterate<T, F> where F: FnMut(&T) -> T {
|
||||
Iterate {f: f, next: x}
|
||||
}
|
||||
struct Iterate<T, F> where F: FnMut(&T) -> T {
|
||||
f: F,
|
||||
next: T
|
||||
}
|
||||
impl<T, F> Iterator for Iterate<T, F> where F: FnMut(&T) -> T {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
let mut res = (self.f)(&self.next);
|
||||
std::mem::swap(&mut res, &mut self.next);
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
|
||||
// a linked list using borrowed next.
|
||||
enum List<'a, T:'a> {
|
||||
Nil,
|
||||
Cons(T, &'a List<'a, T>)
|
||||
}
|
||||
struct ListIterator<'a, T:'a> {
|
||||
cur: &'a List<'a, T>
|
||||
}
|
||||
impl<'a, T> List<'a, T> {
|
||||
fn iter(&'a self) -> ListIterator<'a, T> {
|
||||
ListIterator{cur: self}
|
||||
}
|
||||
}
|
||||
impl<'a, T> Iterator for ListIterator<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
match *self.cur {
|
||||
List::Nil => None,
|
||||
List::Cons(ref elt, next) => {
|
||||
self.cur = next;
|
||||
Some(elt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// preprocess
|
||||
//
|
||||
|
||||
// Takes a pieces p on the form [(y1, x1), (y2, x2), ...] and returns
|
||||
// every possible transformations (the 6 rotations with their
|
||||
// corresponding mirrored piece), with, as minimum coordinates, (0,
|
||||
// 0). If all is false, only generate half of the possibilities (used
|
||||
// to break the symmetry of the board).
|
||||
fn transform(piece: Vec<(i32, i32)> , all: bool) -> Vec<Vec<(i32, i32)>> {
|
||||
let mut res: Vec<Vec<(i32, i32)>> =
|
||||
// rotations
|
||||
iterate(piece, |rot| rot.iter().map(|&(y, x)| (x + y, -y)).collect())
|
||||
.take(if all {6} else {3})
|
||||
// mirror
|
||||
.flat_map(|cur_piece| {
|
||||
iterate(cur_piece, |mir| mir.iter().map(|&(y, x)| (x, y)).collect())
|
||||
.take(2)
|
||||
}).collect();
|
||||
|
||||
// translating to (0, 0) as minimum coordinates.
|
||||
for cur_piece in &mut res {
|
||||
let (dy, dx) = *cur_piece.iter().min_by(|e| *e).unwrap();
|
||||
for &mut (ref mut y, ref mut x) in cur_piece {
|
||||
*y -= dy; *x -= dx;
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
// A mask is a piece somewhere on the board. It is represented as a
|
||||
// u64: for i in the first 50 bits, m[i] = 1 if the cell at (i/5, i%5)
|
||||
// is occupied. m[50 + id] = 1 if the identifier of the piece is id.
|
||||
|
||||
// Takes a piece with minimum coordinate (0, 0) (as generated by
|
||||
// transform). Returns the corresponding mask if p translated by (dy,
|
||||
// dx) is on the board.
|
||||
fn mask(dy: i32, dx: i32, id: usize, p: &Vec<(i32, i32)>) -> Option<u64> {
|
||||
let mut m = 1 << (50 + id);
|
||||
for &(y, x) in p {
|
||||
let x = x + dx + (y + (dy % 2)) / 2;
|
||||
if x < 0 || x > 4 {return None;}
|
||||
let y = y + dy;
|
||||
if y < 0 || y > 9 {return None;}
|
||||
m |= 1 << (y * 5 + x) as usize;
|
||||
}
|
||||
Some(m)
|
||||
}
|
||||
|
||||
// Makes every possible masks. masks[i][id] correspond to every
|
||||
// possible masks for piece with identifier id with minimum coordinate
|
||||
// (i/5, i%5).
|
||||
fn make_masks() -> Vec<Vec<Vec<u64> > > {
|
||||
let pieces = vec!(
|
||||
vec!((0,0),(0,1),(0,2),(0,3),(1,3)),
|
||||
vec!((0,0),(0,2),(0,3),(1,0),(1,1)),
|
||||
vec!((0,0),(0,1),(0,2),(1,2),(2,1)),
|
||||
vec!((0,0),(0,1),(0,2),(1,1),(2,1)),
|
||||
vec!((0,0),(0,2),(1,0),(1,1),(2,1)),
|
||||
vec!((0,0),(0,1),(0,2),(1,1),(1,2)),
|
||||
vec!((0,0),(0,1),(1,1),(1,2),(2,1)),
|
||||
vec!((0,0),(0,1),(0,2),(1,0),(1,2)),
|
||||
vec!((0,0),(0,1),(0,2),(1,2),(1,3)),
|
||||
vec!((0,0),(0,1),(0,2),(0,3),(1,2)));
|
||||
|
||||
// To break the central symmetry of the problem, every
|
||||
// transformation must be taken except for one piece (piece 3
|
||||
// here).
|
||||
let transforms: Vec<Vec<Vec<(i32, i32)>>> =
|
||||
pieces.into_iter().enumerate()
|
||||
.map(|(id, p)| transform(p, id != 3))
|
||||
.collect();
|
||||
|
||||
(0..50).map(|yx| {
|
||||
transforms.iter().enumerate().map(|(id, t)| {
|
||||
t.iter().filter_map(|p| mask(yx / 5, yx % 5, id, p)).collect()
|
||||
}).collect()
|
||||
}).collect()
|
||||
}
|
||||
|
||||
// Check if all coordinates can be covered by an unused piece and that
|
||||
// all unused piece can be placed on the board.
|
||||
fn is_board_unfeasible(board: u64, masks: &Vec<Vec<Vec<u64>>>) -> bool {
|
||||
let mut coverable = board;
|
||||
for (i, masks_at) in masks.iter().enumerate() {
|
||||
if board & 1 << i != 0 { continue; }
|
||||
for (cur_id, pos_masks) in masks_at.iter().enumerate() {
|
||||
if board & 1 << (50 + cur_id) != 0 { continue; }
|
||||
for &cur_m in pos_masks {
|
||||
if cur_m & board != 0 { continue; }
|
||||
coverable |= cur_m;
|
||||
// if every coordinates can be covered and every
|
||||
// piece can be used.
|
||||
if coverable == (1 << 60) - 1 { return false; }
|
||||
}
|
||||
}
|
||||
if coverable & 1 << i == 0 { return true; }
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
// Filter the masks that we can prove to result to unfeasible board.
|
||||
fn filter_masks(masks: &mut Vec<Vec<Vec<u64>>>) {
|
||||
for i in 0..masks.len() {
|
||||
for j in 0..(*masks)[i].len() {
|
||||
masks[i][j] =
|
||||
(*masks)[i][j].iter().cloned()
|
||||
.filter(|&m| !is_board_unfeasible(m, masks))
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the identifier of a mask.
|
||||
fn get_id(m: u64) -> u8 {
|
||||
for id in 0..10 {
|
||||
if m & (1 << (id + 50) as usize) != 0 {return id;}
|
||||
}
|
||||
panic!("{:016x} does not have a valid identifier", m);
|
||||
}
|
||||
|
||||
// Converts a list of mask to a Vec<u8>.
|
||||
fn to_vec(raw_sol: &List<u64>) -> Vec<u8> {
|
||||
let mut sol = vec![b'.'; 50];
|
||||
for &m in raw_sol.iter() {
|
||||
let id = '0' as u8 + get_id(m);
|
||||
for i in 0..50 {
|
||||
if m & 1 << i != 0 {
|
||||
sol[i] = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
sol
|
||||
}
|
||||
|
||||
// Prints a solution in Vec<u8> form.
|
||||
fn print_sol(sol: &Vec<u8>) {
|
||||
for (i, c) in sol.iter().enumerate() {
|
||||
if (i) % 5 == 0 { println!(""); }
|
||||
if (i + 5) % 10 == 0 { print!(" "); }
|
||||
print!("{} ", *c as char);
|
||||
}
|
||||
println!("");
|
||||
}
|
||||
|
||||
// The data managed during the search
|
||||
struct Data {
|
||||
// Number of solution found.
|
||||
nb: isize,
|
||||
// Lexicographically minimal solution found.
|
||||
min: Vec<u8>,
|
||||
// Lexicographically maximal solution found.
|
||||
max: Vec<u8>
|
||||
}
|
||||
impl Data {
|
||||
fn new() -> Data {
|
||||
Data {nb: 0, min: vec!(), max: vec!()}
|
||||
}
|
||||
fn reduce_from(&mut self, other: Data) {
|
||||
self.nb += other.nb;
|
||||
let Data { min: min, max: max, ..} = other;
|
||||
if min < self.min { self.min = min; }
|
||||
if max > self.max { self.max = max; }
|
||||
}
|
||||
}
|
||||
|
||||
// Records a new found solution. Returns false if the search must be
|
||||
// stopped.
|
||||
fn handle_sol(raw_sol: &List<u64>, data: &mut Data) {
|
||||
// because we break the symmetry, 2 solutions correspond to a call
|
||||
// to this method: the normal solution, and the same solution in
|
||||
// reverse order, i.e. the board rotated by half a turn.
|
||||
data.nb += 2;
|
||||
let sol1 = to_vec(raw_sol);
|
||||
let sol2: Vec<u8> = sol1.iter().rev().cloned().collect();
|
||||
|
||||
if data.nb == 2 {
|
||||
data.min = sol1.clone();
|
||||
data.max = sol1.clone();
|
||||
}
|
||||
|
||||
if sol1 < data.min {data.min = sol1;}
|
||||
else if sol1 > data.max {data.max = sol1;}
|
||||
if sol2 < data.min {data.min = sol2;}
|
||||
else if sol2 > data.max {data.max = sol2;}
|
||||
}
|
||||
|
||||
fn search(
|
||||
masks: &Vec<Vec<Vec<u64>>>,
|
||||
board: u64,
|
||||
mut i: usize,
|
||||
cur: List<u64>,
|
||||
data: &mut Data)
|
||||
{
|
||||
// Search for the lesser empty coordinate.
|
||||
while board & (1 << i) != 0 && i < 50 {i += 1;}
|
||||
// the board is full: a solution is found.
|
||||
if i >= 50 {return handle_sol(&cur, data);}
|
||||
let masks_at = &masks[i];
|
||||
|
||||
// for every unused piece
|
||||
for id in (0..10).filter(|&id| board & (1 << (id + 50)) == 0) {
|
||||
// for each mask that fits on the board
|
||||
for m in masks_at[id].iter().filter(|&m| board & *m == 0) {
|
||||
// This check is too costly.
|
||||
//if is_board_unfeasible(board | m, masks) {continue;}
|
||||
search(masks, board | *m, i + 1, List::Cons(*m, &cur), data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn par_search(masks: Vec<Vec<Vec<u64>>>) -> Data {
|
||||
let masks = Arc::new(masks);
|
||||
let (tx, rx) = channel();
|
||||
|
||||
// launching the search in parallel on every masks at minimum
|
||||
// coordinate (0,0)
|
||||
for m in (*masks)[0].iter().flat_map(|masks_pos| masks_pos) {
|
||||
let masks = masks.clone();
|
||||
let tx = tx.clone();
|
||||
let m = *m;
|
||||
thread::spawn(move|| {
|
||||
let mut data = Data::new();
|
||||
search(&*masks, m, 1, List::Cons(m, &List::Nil), &mut data);
|
||||
tx.send(data).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
// collecting the results
|
||||
drop(tx);
|
||||
let mut data = rx.recv().unwrap();
|
||||
for d in rx.iter() { data.reduce_from(d); }
|
||||
data
|
||||
}
|
||||
|
||||
fn main () {
|
||||
let mut masks = make_masks();
|
||||
filter_masks(&mut masks);
|
||||
let data = par_search(masks);
|
||||
println!("{} solutions found", data.nb);
|
||||
print_sol(&data.min);
|
||||
print_sol(&data.max);
|
||||
println!("");
|
||||
}
|
@ -1,244 +0,0 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// contributed by the Rust Project Developers
|
||||
|
||||
// Copyright (c) 2011-2014 The Rust Project Developers
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// - Neither the name of "The Computer Language Benchmarks Game" nor
|
||||
// the name of "The Computer Language Shootout Benchmarks" nor the
|
||||
// names of its contributors may be used to endorse or promote
|
||||
// products derived from this software without specific prior
|
||||
// written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
use std::mem;
|
||||
use std::ops::{Add, Sub, Mul};
|
||||
|
||||
const PI: f64 = 3.141592653589793;
|
||||
const SOLAR_MASS: f64 = 4.0 * PI * PI;
|
||||
const YEAR: f64 = 365.24;
|
||||
const N_BODIES: usize = 5;
|
||||
const N_PAIRS: usize = N_BODIES * (N_BODIES - 1) / 2;
|
||||
|
||||
const BODIES: [Planet; N_BODIES] = [
|
||||
// Sun
|
||||
Planet {
|
||||
pos: Vec3(0.0, 0.0, 0.0),
|
||||
vel: Vec3(0.0, 0.0, 0.0),
|
||||
mass: SOLAR_MASS,
|
||||
},
|
||||
// Jupiter
|
||||
Planet {
|
||||
pos: Vec3(4.84143144246472090e+00,
|
||||
-1.16032004402742839e+00,
|
||||
-1.03622044471123109e-01),
|
||||
vel: Vec3(1.66007664274403694e-03 * YEAR,
|
||||
7.69901118419740425e-03 * YEAR,
|
||||
-6.90460016972063023e-05 * YEAR),
|
||||
mass: 9.54791938424326609e-04 * SOLAR_MASS,
|
||||
},
|
||||
// Saturn
|
||||
Planet {
|
||||
pos: Vec3(8.34336671824457987e+00,
|
||||
4.12479856412430479e+00,
|
||||
-4.03523417114321381e-01),
|
||||
vel: Vec3(-2.76742510726862411e-03 * YEAR,
|
||||
4.99852801234917238e-03 * YEAR,
|
||||
2.30417297573763929e-05 * YEAR),
|
||||
mass: 2.85885980666130812e-04 * SOLAR_MASS,
|
||||
},
|
||||
// Uranus
|
||||
Planet {
|
||||
pos: Vec3(1.28943695621391310e+01,
|
||||
-1.51111514016986312e+01,
|
||||
-2.23307578892655734e-01),
|
||||
vel: Vec3(2.96460137564761618e-03 * YEAR,
|
||||
2.37847173959480950e-03 * YEAR,
|
||||
-2.96589568540237556e-05 * YEAR),
|
||||
mass: 4.36624404335156298e-05 * SOLAR_MASS,
|
||||
},
|
||||
// Neptune
|
||||
Planet {
|
||||
pos: Vec3(1.53796971148509165e+01,
|
||||
-2.59193146099879641e+01,
|
||||
1.79258772950371181e-01),
|
||||
vel: Vec3(2.68067772490389322e-03 * YEAR,
|
||||
1.62824170038242295e-03 * YEAR,
|
||||
-9.51592254519715870e-05 * YEAR),
|
||||
mass: 5.15138902046611451e-05 * SOLAR_MASS,
|
||||
},
|
||||
];
|
||||
|
||||
/// A 3d Vector type with oveloaded operators to improve readability.
|
||||
#[derive(Clone, Copy)]
|
||||
struct Vec3(pub f64, pub f64, pub f64);
|
||||
|
||||
impl Vec3 {
|
||||
fn zero() -> Self { Vec3(0.0, 0.0, 0.0) }
|
||||
|
||||
fn norm(&self) -> f64 { self.squared_norm().sqrt() }
|
||||
|
||||
fn squared_norm(&self) -> f64 {
|
||||
self.0 * self.0 + self.1 * self.1 + self.2 * self.2
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Vec3 {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self {
|
||||
Vec3(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Vec3 {
|
||||
type Output = Self;
|
||||
fn sub(self, rhs: Self) -> Self {
|
||||
Vec3(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<f64> for Vec3 {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: f64) -> Self {
|
||||
Vec3(self.0 * rhs, self.1 * rhs, self.2 * rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct Planet {
|
||||
pos: Vec3,
|
||||
vel: Vec3,
|
||||
mass: f64,
|
||||
}
|
||||
|
||||
/// Computes all pairwise position differences between the planets.
|
||||
fn pairwise_diffs(bodies: &[Planet; N_BODIES], diff: &mut [Vec3; N_PAIRS]) {
|
||||
let mut bodies = bodies.iter();
|
||||
let mut diff = diff.iter_mut();
|
||||
while let Some(bi) = bodies.next() {
|
||||
for bj in bodies.clone() {
|
||||
*diff.next().unwrap() = bi.pos - bj.pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the magnitude of the force between each pair of planets.
|
||||
fn magnitudes(diff: &[Vec3; N_PAIRS], dt: f64, mag: &mut [f64; N_PAIRS]) {
|
||||
for (mag, diff) in mag.iter_mut().zip(diff.iter()) {
|
||||
let d2 = diff.squared_norm();
|
||||
*mag = dt / (d2 * d2.sqrt());
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the velocities of the planets by computing their gravitational
|
||||
/// accelerations and performing one step of Euler integration.
|
||||
fn update_velocities(bodies: &mut [Planet; N_BODIES], dt: f64,
|
||||
diff: &mut [Vec3; N_PAIRS], mag: &mut [f64; N_PAIRS]) {
|
||||
pairwise_diffs(bodies, diff);
|
||||
magnitudes(&diff, dt, mag);
|
||||
|
||||
let mut bodies = &mut bodies[..];
|
||||
let mut mag = mag.iter();
|
||||
let mut diff = diff.iter();
|
||||
while let Some(bi) = shift_mut_ref(&mut bodies) {
|
||||
for bj in bodies.iter_mut() {
|
||||
let diff = *diff.next().unwrap();
|
||||
let mag = *mag.next().unwrap();
|
||||
bi.vel = bi.vel - diff * (bj.mass * mag);
|
||||
bj.vel = bj.vel + diff * (bi.mass * mag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Advances the solar system by one timestep by first updating the
|
||||
/// velocities and then integrating the positions using the updated velocities.
|
||||
///
|
||||
/// Note: the `diff` & `mag` arrays are effectively scratch space. They're
|
||||
/// provided as arguments to avoid re-zeroing them every time `advance` is
|
||||
/// called.
|
||||
fn advance(mut bodies: &mut [Planet; N_BODIES], dt: f64,
|
||||
diff: &mut [Vec3; N_PAIRS], mag: &mut [f64; N_PAIRS]) {
|
||||
update_velocities(bodies, dt, diff, mag);
|
||||
for body in bodies.iter_mut() {
|
||||
body.pos = body.pos + body.vel * dt;
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the total energy of the solar system.
|
||||
fn energy(bodies: &[Planet; N_BODIES]) -> f64 {
|
||||
let mut e = 0.0;
|
||||
let mut bodies = bodies.iter();
|
||||
while let Some(bi) = bodies.next() {
|
||||
e += bi.vel.squared_norm() * bi.mass / 2.0
|
||||
- bi.mass * bodies.clone()
|
||||
.map(|bj| bj.mass / (bi.pos - bj.pos).norm())
|
||||
.fold(0.0, |a, b| a + b);
|
||||
}
|
||||
e
|
||||
}
|
||||
|
||||
/// Offsets the sun's velocity to make the overall momentum of the system zero.
|
||||
fn offset_momentum(bodies: &mut [Planet; N_BODIES]) {
|
||||
let p = bodies.iter().fold(Vec3::zero(), |v, b| v + b.vel * b.mass);
|
||||
bodies[0].vel = p * (-1.0 / bodies[0].mass);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let n = if std::env::var_os("RUST_BENCH").is_some() {
|
||||
5000000
|
||||
} else {
|
||||
std::env::args().nth(1)
|
||||
.and_then(|arg| arg.parse().ok())
|
||||
.unwrap_or(1000)
|
||||
};
|
||||
let mut bodies = BODIES;
|
||||
let mut diff = [Vec3::zero(); N_PAIRS];
|
||||
let mut mag = [0.0f64; N_PAIRS];
|
||||
|
||||
offset_momentum(&mut bodies);
|
||||
println!("{:.9}", energy(&bodies));
|
||||
|
||||
for _ in 0..n {
|
||||
advance(&mut bodies, 0.01, &mut diff, &mut mag);
|
||||
}
|
||||
|
||||
println!("{:.9}", energy(&bodies));
|
||||
}
|
||||
|
||||
/// Pop a mutable reference off the head of a slice, mutating the slice to no
|
||||
/// longer contain the mutable reference. This is a safe operation because the
|
||||
/// two mutable borrows are entirely disjoint.
|
||||
fn shift_mut_ref<'a, T>(r: &mut &'a mut [T]) -> Option<&'a mut T> {
|
||||
let res = mem::replace(r, &mut []);
|
||||
if res.is_empty() { return None }
|
||||
let (a, b) = res.split_at_mut(1);
|
||||
*r = b;
|
||||
Some(&mut a[0])
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
/*
|
||||
A parallel version of fibonacci numbers.
|
||||
|
||||
This version is meant mostly as a way of stressing and benchmarking
|
||||
the task system. It supports a lot of old command-line arguments to
|
||||
control how it runs.
|
||||
|
||||
*/
|
||||
|
||||
#![feature(duration, duration_span, rustc_private)]
|
||||
|
||||
extern crate getopts;
|
||||
|
||||
use std::sync::mpsc::{channel, Sender};
|
||||
use std::env;
|
||||
use std::result::Result::{Ok, Err};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
fn fib(n: isize) -> isize {
|
||||
fn pfib(tx: &Sender<isize>, n: isize) {
|
||||
if n == 0 {
|
||||
tx.send(0).unwrap();
|
||||
} else if n <= 2 {
|
||||
tx.send(1).unwrap();
|
||||
} else {
|
||||
let (tx1, rx) = channel();
|
||||
let tx2 = tx1.clone();
|
||||
thread::spawn(move|| pfib(&tx2, n - 1));
|
||||
let tx2 = tx1.clone();
|
||||
thread::spawn(move|| pfib(&tx2, n - 2));
|
||||
tx.send(rx.recv().unwrap() + rx.recv().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
let (tx, rx) = channel();
|
||||
thread::spawn(move|| pfib(&tx, n) );
|
||||
rx.recv().unwrap()
|
||||
}
|
||||
|
||||
struct Config {
|
||||
stress: bool
|
||||
}
|
||||
|
||||
fn parse_opts(argv: Vec<String> ) -> Config {
|
||||
let opts = vec!(getopts::optflag("", "stress", ""));
|
||||
|
||||
let argv = argv.iter().map(|x| x.to_string()).collect::<Vec<_>>();
|
||||
let opt_args = &argv[1..argv.len()];
|
||||
|
||||
match getopts::getopts(opt_args, &opts) {
|
||||
Ok(ref m) => {
|
||||
return Config {stress: m.opt_present("stress")}
|
||||
}
|
||||
Err(_) => { panic!(); }
|
||||
}
|
||||
}
|
||||
|
||||
fn stress_task(id: isize) {
|
||||
let mut i = 0;
|
||||
loop {
|
||||
let n = 15;
|
||||
assert_eq!(fib(n), fib(n));
|
||||
i += 1;
|
||||
println!("{}: Completed {} iterations", id, i);
|
||||
}
|
||||
}
|
||||
|
||||
fn stress(num_tasks: isize) {
|
||||
let mut results = Vec::new();
|
||||
for i in 0..num_tasks {
|
||||
results.push(thread::spawn(move|| {
|
||||
stress_task(i);
|
||||
}));
|
||||
}
|
||||
for r in results {
|
||||
let _ = r.join();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
let args = if env::var_os("RUST_BENCH").is_some() {
|
||||
vec!("".to_string(), "20".to_string())
|
||||
} else if args.len() <= 1 {
|
||||
vec!("".to_string(), "8".to_string())
|
||||
} else {
|
||||
args.map(|x| x.to_string()).collect()
|
||||
};
|
||||
|
||||
let opts = parse_opts(args.clone());
|
||||
|
||||
if opts.stress {
|
||||
stress(2);
|
||||
} else {
|
||||
let max = args[1].parse::<isize>().unwrap();
|
||||
|
||||
let num_trials = 10;
|
||||
|
||||
for n in 1..max + 1 {
|
||||
for _ in 0..num_trials {
|
||||
let mut fibn = None;
|
||||
let dur = Duration::span(|| fibn = Some(fib(n)));
|
||||
let fibn = fibn.unwrap();
|
||||
|
||||
println!("{}\t{}\t{:?}", n, fibn, dur);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,213 +0,0 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// contributed by the Rust Project Developers
|
||||
|
||||
// Copyright (c) 2013-2014 The Rust Project Developers
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// - Neither the name of "The Computer Language Benchmarks Game" nor
|
||||
// the name of "The Computer Language Shootout Benchmarks" nor the
|
||||
// names of its contributors may be used to endorse or promote
|
||||
// products derived from this software without specific prior
|
||||
// written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ignore-android: FIXME(#10393) hangs without output
|
||||
|
||||
#![feature(libc)]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::ptr::copy;
|
||||
use std::thread;
|
||||
|
||||
struct Tables {
|
||||
table8: Box<[u8; 1 << 8]>,
|
||||
table16: Box<[u16; 1 << 16]>,
|
||||
}
|
||||
|
||||
impl Tables {
|
||||
fn new() -> Tables {
|
||||
let mut table8 = Box::new([0;1 << 8]);
|
||||
for (i, v) in table8.iter_mut().enumerate() {
|
||||
*v = Tables::computed_cpl8(i as u8);
|
||||
}
|
||||
let mut table16 = Box::new([0;1 << 16]);
|
||||
for (i, v) in table16.iter_mut().enumerate() {
|
||||
*v = (table8[i & 255] as u16) << 8 |
|
||||
table8[i >> 8] as u16;
|
||||
}
|
||||
Tables { table8: table8, table16: table16 }
|
||||
}
|
||||
|
||||
fn computed_cpl8(c: u8) -> u8 {
|
||||
match c {
|
||||
b'A' | b'a' => b'T',
|
||||
b'C' | b'c' => b'G',
|
||||
b'G' | b'g' => b'C',
|
||||
b'T' | b't' => b'A',
|
||||
b'U' | b'u' => b'A',
|
||||
b'M' | b'm' => b'K',
|
||||
b'R' | b'r' => b'Y',
|
||||
b'W' | b'w' => b'W',
|
||||
b'S' | b's' => b'S',
|
||||
b'Y' | b'y' => b'R',
|
||||
b'K' | b'k' => b'M',
|
||||
b'V' | b'v' => b'B',
|
||||
b'H' | b'h' => b'D',
|
||||
b'D' | b'd' => b'H',
|
||||
b'B' | b'b' => b'V',
|
||||
b'N' | b'n' => b'N',
|
||||
i => i,
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves the complement for `i`.
|
||||
fn cpl8(&self, i: u8) -> u8 {
|
||||
self.table8[i as usize]
|
||||
}
|
||||
|
||||
/// Retrieves the complement for `i`.
|
||||
fn cpl16(&self, i: u16) -> u16 {
|
||||
self.table16[i as usize]
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds the first position at which `b` occurs in `s`.
|
||||
fn memchr(h: &[u8], n: u8) -> Option<usize> {
|
||||
use libc::{c_void, c_int, size_t};
|
||||
let res = unsafe {
|
||||
libc::memchr(h.as_ptr() as *const c_void, n as c_int, h.len() as size_t)
|
||||
};
|
||||
if res.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(res as usize - h.as_ptr() as usize)
|
||||
}
|
||||
}
|
||||
|
||||
/// A mutable iterator over DNA sequences
|
||||
struct MutDnaSeqs<'a> { s: &'a mut [u8] }
|
||||
fn mut_dna_seqs<'a>(s: &'a mut [u8]) -> MutDnaSeqs<'a> {
|
||||
MutDnaSeqs { s: s }
|
||||
}
|
||||
impl<'a> Iterator for MutDnaSeqs<'a> {
|
||||
type Item = &'a mut [u8];
|
||||
|
||||
fn next(&mut self) -> Option<&'a mut [u8]> {
|
||||
let tmp = std::mem::replace(&mut self.s, &mut []);
|
||||
let tmp = match memchr(tmp, b'\n') {
|
||||
Some(i) => &mut tmp[i + 1..],
|
||||
None => return None,
|
||||
};
|
||||
let (seq, tmp) = match memchr(tmp, b'>') {
|
||||
Some(i) => tmp.split_at_mut(i),
|
||||
None => {
|
||||
let len = tmp.len();
|
||||
tmp.split_at_mut(len)
|
||||
}
|
||||
};
|
||||
self.s = tmp;
|
||||
Some(seq)
|
||||
}
|
||||
}
|
||||
|
||||
/// Length of a normal line without the terminating \n.
|
||||
const LINE_LEN: usize = 60;
|
||||
|
||||
/// Compute the reverse complement.
|
||||
fn reverse_complement(seq: &mut [u8], tables: &Tables) {
|
||||
let len = seq.len();
|
||||
let seq = &mut seq[..len - 1]; // Drop the last newline
|
||||
let len = seq.len();
|
||||
let off = LINE_LEN - len % (LINE_LEN + 1);
|
||||
let mut i = LINE_LEN;
|
||||
while i < len {
|
||||
unsafe {
|
||||
copy(seq.as_ptr().offset((i - off) as isize),
|
||||
seq.as_mut_ptr().offset((i - off + 1) as isize), off);
|
||||
*seq.get_unchecked_mut(i - off) = b'\n';
|
||||
}
|
||||
i += LINE_LEN + 1;
|
||||
}
|
||||
|
||||
let div = len / 4;
|
||||
let rem = len % 4;
|
||||
unsafe {
|
||||
let mut left = seq.as_mut_ptr() as *mut u16;
|
||||
// This is slow if len % 2 != 0 but still faster than bytewise operations.
|
||||
let mut right = seq.as_mut_ptr().offset(len as isize - 2) as *mut u16;
|
||||
let end = left.offset(div as isize);
|
||||
while left != end {
|
||||
let tmp = tables.cpl16(*left);
|
||||
*left = tables.cpl16(*right);
|
||||
*right = tmp;
|
||||
left = left.offset(1);
|
||||
right = right.offset(-1);
|
||||
}
|
||||
|
||||
let end = end as *mut u8;
|
||||
match rem {
|
||||
1 => *end = tables.cpl8(*end),
|
||||
2 => {
|
||||
let tmp = tables.cpl8(*end);
|
||||
*end = tables.cpl8(*end.offset(1));
|
||||
*end.offset(1) = tmp;
|
||||
},
|
||||
3 => {
|
||||
*end.offset(1) = tables.cpl8(*end.offset(1));
|
||||
let tmp = tables.cpl8(*end);
|
||||
*end = tables.cpl8(*end.offset(2));
|
||||
*end.offset(2) = tmp;
|
||||
},
|
||||
_ => { },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Executes a closure in parallel over the given iterator over mutable slice.
|
||||
/// The closure `f` is run in parallel with an element of `iter`.
|
||||
// FIXME: replace with thread::scoped when it exists again
|
||||
fn parallel<I: Iterator, F>(iter: I, ref f: F)
|
||||
where I::Item: Send,
|
||||
F: Fn(I::Item) + Sync, {
|
||||
iter.map(|x| {
|
||||
f(x)
|
||||
}).collect::<Vec<_>>();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut data = Vec::with_capacity(1024 * 1024);
|
||||
io::stdin().read_to_end(&mut data).unwrap();
|
||||
let tables = &Tables::new();
|
||||
parallel(mut_dna_seqs(&mut data), |seq| reverse_complement(seq, tables));
|
||||
io::stdout().write_all(&data).unwrap();
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// contributed by the Rust Project Developers
|
||||
|
||||
// Copyright (c) 2012-2014 The Rust Project Developers
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// - Neither the name of "The Computer Language Benchmarks Game" nor
|
||||
// the name of "The Computer Language Shootout Benchmarks" nor the
|
||||
// names of its contributors may be used to endorse or promote
|
||||
// products derived from this software without specific prior
|
||||
// written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||
use std::thread;
|
||||
|
||||
fn start(n_tasks: i32, token: i32) {
|
||||
let (tx, mut rx) = channel();
|
||||
tx.send(token).unwrap();
|
||||
let mut guards = Vec::with_capacity(n_tasks as usize);
|
||||
for i in 2 .. n_tasks + 1 {
|
||||
let (tx, next_rx) = channel();
|
||||
let cur_rx = std::mem::replace(&mut rx, next_rx);
|
||||
guards.push(thread::spawn(move|| roundtrip(i, tx, cur_rx)));
|
||||
}
|
||||
let guard = thread::spawn(move|| roundtrip(1, tx, rx));
|
||||
}
|
||||
|
||||
fn roundtrip(id: i32, tx: Sender<i32>, rx: Receiver<i32>) {
|
||||
for token in rx.iter() {
|
||||
if token == 1 {
|
||||
println!("{}", id);
|
||||
break;
|
||||
}
|
||||
tx.send(token - 1).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args = std::env::args();
|
||||
let token = if std::env::var_os("RUST_BENCH").is_some() {
|
||||
2000000
|
||||
} else {
|
||||
args.nth(1).and_then(|arg| arg.parse().ok()).unwrap_or(1000)
|
||||
};
|
||||
let n_tasks = args.next()
|
||||
.and_then(|arg| arg.parse().ok())
|
||||
.unwrap_or(503);
|
||||
|
||||
start(n_tasks, token);
|
||||
}
|
@ -1,282 +0,0 @@
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty very bad with line comments
|
||||
|
||||
#![feature(box_syntax, core)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::env;
|
||||
|
||||
// Computes a single solution to a given 9x9 sudoku
|
||||
//
|
||||
// Call with "-" to read input sudoku from stdin
|
||||
//
|
||||
// The expected line-based format is:
|
||||
//
|
||||
// 9,9
|
||||
// <row>,<column>,<color>
|
||||
// ...
|
||||
//
|
||||
// Row and column are 0-based (i.e. <= 8) and color is 1-based (>=1,<=9).
|
||||
// A color of 0 indicates an empty field.
|
||||
//
|
||||
// If called without arguments, sudoku solves a built-in example sudoku
|
||||
//
|
||||
|
||||
// internal type of sudoku grids
|
||||
type grid = Vec<Vec<u8>>;
|
||||
|
||||
struct Sudoku {
|
||||
grid: grid
|
||||
}
|
||||
|
||||
impl Sudoku {
|
||||
pub fn new(g: grid) -> Sudoku {
|
||||
return Sudoku { grid: g }
|
||||
}
|
||||
|
||||
pub fn from_vec(vec: &[[u8;9];9]) -> Sudoku {
|
||||
let g = (0..9).map(|i| {
|
||||
(0..9).map(|j| { vec[i][j] }).collect()
|
||||
}).collect();
|
||||
return Sudoku::new(g)
|
||||
}
|
||||
|
||||
pub fn read(reader: &mut BufRead) -> Sudoku {
|
||||
/* assert first line is exactly "9,9" */
|
||||
let mut s = String::new();
|
||||
reader.read_line(&mut s).unwrap();
|
||||
assert_eq!(s, "9,9\n");
|
||||
|
||||
let mut g = vec![vec![0, 0, 0, 0, 0, 0, 0, 0, 0]; 10];
|
||||
for line in reader.lines() {
|
||||
let line = line.unwrap();
|
||||
let comps: Vec<&str> = line
|
||||
.trim()
|
||||
.split(',')
|
||||
.collect();
|
||||
|
||||
if comps.len() == 3 {
|
||||
let row = comps[0].parse::<u8>().unwrap();
|
||||
let col = comps[1].parse::<u8>().unwrap();
|
||||
g[row as usize][col as usize] = comps[2].parse().unwrap();
|
||||
}
|
||||
else {
|
||||
panic!("Invalid sudoku file");
|
||||
}
|
||||
}
|
||||
return Sudoku::new(g)
|
||||
}
|
||||
|
||||
pub fn write(&self, writer: &mut Write) {
|
||||
for row in 0u8..9u8 {
|
||||
write!(writer, "{}", self.grid[row as usize][0]);
|
||||
for col in 1u8..9u8 {
|
||||
write!(writer, " {}", self.grid[row as usize][col as usize]);
|
||||
}
|
||||
write!(writer, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
// solve sudoku grid
|
||||
pub fn solve(&mut self) {
|
||||
let mut work: Vec<(u8, u8)> = Vec::new(); /* queue of uncolored fields */
|
||||
for row in 0..9 {
|
||||
for col in 0..9 {
|
||||
let color = self.grid[row as usize][col as usize];
|
||||
if color == 0 {
|
||||
work.push((row, col));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut ptr = 0;
|
||||
let end = work.len();
|
||||
while ptr < end {
|
||||
let (row, col) = work[ptr];
|
||||
// is there another color to try?
|
||||
let the_color = self.grid[row as usize][col as usize] +
|
||||
(1 as u8);
|
||||
if self.next_color(row, col, the_color) {
|
||||
// yes: advance work list
|
||||
ptr = ptr + 1;
|
||||
} else {
|
||||
// no: redo this field aft recoloring pred; unless there is none
|
||||
if ptr == 0 { panic!("No solution found for this sudoku"); }
|
||||
ptr = ptr - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn next_color(&mut self, row: u8, col: u8, start_color: u8) -> bool {
|
||||
if start_color < 10 {
|
||||
// colors not yet used
|
||||
let mut avail: Box<_> = box Colors::new(start_color);
|
||||
|
||||
// drop colors already in use in neighbourhood
|
||||
self.drop_colors(&mut *avail, row, col);
|
||||
|
||||
// find first remaining color that is available
|
||||
let next = avail.next();
|
||||
self.grid[row as usize][col as usize] = next;
|
||||
return 0 != next;
|
||||
}
|
||||
self.grid[row as usize][col as usize] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// find colors available in neighbourhood of (row, col)
|
||||
fn drop_colors(&mut self, avail: &mut Colors, row: u8, col: u8) {
|
||||
for idx in 0..9 {
|
||||
/* check same column fields */
|
||||
avail.remove(self.grid[idx as usize][col as usize]);
|
||||
/* check same row fields */
|
||||
avail.remove(self.grid[row as usize][idx as usize]);
|
||||
}
|
||||
|
||||
// check same block fields
|
||||
let row0 = (row / 3) * 3;
|
||||
let col0 = (col / 3) * 3;
|
||||
for alt_row in row0..row0 + 3 {
|
||||
for alt_col in col0..col0 + 3 {
|
||||
avail.remove(self.grid[alt_row as usize][alt_col as usize]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stores available colors as simple bitfield, bit 0 is always unset
|
||||
struct Colors(u16);
|
||||
|
||||
static HEADS: u16 = (1 << 10) - 1; /* bits 9..0 */
|
||||
|
||||
impl Colors {
|
||||
fn new(start_color: u8) -> Colors {
|
||||
// Sets bits 9..start_color
|
||||
let tails = !0 << start_color as usize;
|
||||
return Colors(HEADS & tails);
|
||||
}
|
||||
|
||||
fn next(&self) -> u8 {
|
||||
let Colors(c) = *self;
|
||||
let val = c & HEADS;
|
||||
if 0 == val {
|
||||
return 0;
|
||||
} else {
|
||||
return val.trailing_zeros() as u8
|
||||
}
|
||||
}
|
||||
|
||||
fn remove(&mut self, color: u8) {
|
||||
if color != 0 {
|
||||
let Colors(val) = *self;
|
||||
let mask = !(1 << color as usize);
|
||||
*self = Colors(val & mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static DEFAULT_SUDOKU: [[u8;9];9] = [
|
||||
/* 0 1 2 3 4 5 6 7 8 */
|
||||
/* 0 */ [0, 4, 0, 6, 0, 0, 0, 3, 2],
|
||||
/* 1 */ [0, 0, 8, 0, 2, 0, 0, 0, 0],
|
||||
/* 2 */ [7, 0, 0, 8, 0, 0, 0, 0, 0],
|
||||
/* 3 */ [0, 0, 0, 5, 0, 0, 0, 0, 0],
|
||||
/* 4 */ [0, 5, 0, 0, 0, 3, 6, 0, 0],
|
||||
/* 5 */ [6, 8, 0, 0, 0, 0, 0, 9, 0],
|
||||
/* 6 */ [0, 9, 5, 0, 0, 6, 0, 7, 0],
|
||||
/* 7 */ [0, 0, 0, 0, 4, 0, 0, 6, 0],
|
||||
/* 8 */ [4, 0, 0, 0, 0, 7, 2, 0, 3]
|
||||
];
|
||||
|
||||
#[cfg(test)]
|
||||
static DEFAULT_SOLUTION: [[u8;9];9] = [
|
||||
/* 0 1 2 3 4 5 6 7 8 */
|
||||
/* 0 */ [1, 4, 9, 6, 7, 5, 8, 3, 2],
|
||||
/* 1 */ [5, 3, 8, 1, 2, 9, 7, 4, 6],
|
||||
/* 2 */ [7, 2, 6, 8, 3, 4, 1, 5, 9],
|
||||
/* 3 */ [9, 1, 4, 5, 6, 8, 3, 2, 7],
|
||||
/* 4 */ [2, 5, 7, 4, 9, 3, 6, 1, 8],
|
||||
/* 5 */ [6, 8, 3, 7, 1, 2, 5, 9, 4],
|
||||
/* 6 */ [3, 9, 5, 2, 8, 6, 4, 7, 1],
|
||||
/* 7 */ [8, 7, 2, 3, 4, 1, 9, 6, 5],
|
||||
/* 8 */ [4, 6, 1, 9, 5, 7, 2, 8, 3]
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn colors_new_works() {
|
||||
assert_eq!(*Colors::new(1), 1022);
|
||||
assert_eq!(*Colors::new(2), 1020);
|
||||
assert_eq!(*Colors::new(3), 1016);
|
||||
assert_eq!(*Colors::new(4), 1008);
|
||||
assert_eq!(*Colors::new(5), 992);
|
||||
assert_eq!(*Colors::new(6), 960);
|
||||
assert_eq!(*Colors::new(7), 896);
|
||||
assert_eq!(*Colors::new(8), 768);
|
||||
assert_eq!(*Colors::new(9), 512);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn colors_next_works() {
|
||||
assert_eq!(Colors(0).next(), 0);
|
||||
assert_eq!(Colors(2).next(), 1);
|
||||
assert_eq!(Colors(4).next(), 2);
|
||||
assert_eq!(Colors(8).next(), 3);
|
||||
assert_eq!(Colors(16).next(), 4);
|
||||
assert_eq!(Colors(32).next(), 5);
|
||||
assert_eq!(Colors(64).next(), 6);
|
||||
assert_eq!(Colors(128).next(), 7);
|
||||
assert_eq!(Colors(256).next(), 8);
|
||||
assert_eq!(Colors(512).next(), 9);
|
||||
assert_eq!(Colors(1024).next(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn colors_remove_works() {
|
||||
// GIVEN
|
||||
let mut colors = Colors::new(1);
|
||||
|
||||
// WHEN
|
||||
colors.remove(1);
|
||||
|
||||
// THEN
|
||||
assert_eq!(colors.next(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_DEFAULT_SUDOKU_solution() {
|
||||
// GIVEN
|
||||
let mut sudoku = Sudoku::from_vec(&DEFAULT_SUDOKU);
|
||||
let solution = Sudoku::from_vec(&DEFAULT_SOLUTION);
|
||||
|
||||
// WHEN
|
||||
sudoku.solve();
|
||||
|
||||
// THEN
|
||||
assert!(sudoku.equal(&solution));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
let use_default = args.len() == 1;
|
||||
let mut sudoku = if use_default {
|
||||
Sudoku::from_vec(&DEFAULT_SUDOKU)
|
||||
} else {
|
||||
let stdin = io::stdin();
|
||||
let mut locked = stdin.lock();
|
||||
Sudoku::read(&mut locked)
|
||||
};
|
||||
sudoku.solve();
|
||||
let out = io::stdout();
|
||||
sudoku.write(&mut out.lock());
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(box_syntax, duration, duration_span, vec_push_all)]
|
||||
|
||||
use std::env;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Clone)]
|
||||
enum List<T> {
|
||||
Nil, Cons(T, Box<List<T>>)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let (repeat, depth) = if env::var_os("RUST_BENCH").is_some() {
|
||||
(50, 1000)
|
||||
} else {
|
||||
(10, 10)
|
||||
};
|
||||
|
||||
run(repeat, depth);
|
||||
}
|
||||
|
||||
fn run(repeat: isize, depth: isize) {
|
||||
for _ in 0..repeat {
|
||||
let dur = Duration::span(|| {
|
||||
let _ = thread::spawn(move|| {
|
||||
recurse_or_panic(depth, None)
|
||||
}).join();
|
||||
});
|
||||
println!("iter: {:?}", dur);
|
||||
}
|
||||
}
|
||||
|
||||
type nillist = List<()>;
|
||||
|
||||
// Filled with things that have to be unwound
|
||||
|
||||
struct State {
|
||||
unique: Box<nillist>,
|
||||
vec: Vec<Box<nillist>>,
|
||||
res: r
|
||||
}
|
||||
|
||||
struct r {
|
||||
_l: Box<nillist>,
|
||||
}
|
||||
|
||||
impl Drop for r {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
fn r(l: Box<nillist>) -> r {
|
||||
r {
|
||||
_l: l
|
||||
}
|
||||
}
|
||||
|
||||
fn recurse_or_panic(depth: isize, st: Option<State>) {
|
||||
if depth == 0 {
|
||||
panic!();
|
||||
} else {
|
||||
let depth = depth - 1;
|
||||
|
||||
let st = match st {
|
||||
None => {
|
||||
State {
|
||||
unique: box List::Nil,
|
||||
vec: vec!(box List::Nil),
|
||||
res: r(box List::Nil)
|
||||
}
|
||||
}
|
||||
Some(st) => {
|
||||
let mut v = st.vec.clone();
|
||||
v.push_all(&[box List::Cons((), st.vec.last().unwrap().clone())]);
|
||||
State {
|
||||
unique: box List::Cons((), box *st.unique),
|
||||
vec: v,
|
||||
res: r(box List::Cons((), st.res._l.clone())),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
recurse_or_panic(depth, Some(st));
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test performance of a thread "spawn ladder", in which children thread have
|
||||
// many ancestor threadgroups, but with only a few such groups alive at a time.
|
||||
// Each child thread has to enlist as a descendant in each of its ancestor
|
||||
// groups, but that shouldn't have to happen for already-dead groups.
|
||||
//
|
||||
// The filename is a song reference; google it in quotes.
|
||||
|
||||
// ignore-pretty very bad with line comments
|
||||
|
||||
use std::sync::mpsc::{channel, Sender};
|
||||
use std::env;
|
||||
use std::thread;
|
||||
|
||||
fn child_generation(gens_left: usize, tx: Sender<()>) {
|
||||
// This used to be O(n^2) in the number of generations that ever existed.
|
||||
// With this code, only as many generations are alive at a time as threads
|
||||
// alive at a time,
|
||||
thread::spawn(move|| {
|
||||
if gens_left & 1 == 1 {
|
||||
thread::yield_now(); // shake things up a bit
|
||||
}
|
||||
if gens_left > 0 {
|
||||
child_generation(gens_left - 1, tx); // recurse
|
||||
} else {
|
||||
tx.send(()).unwrap()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
let args = if env::var_os("RUST_BENCH").is_some() {
|
||||
vec!("".to_string(), "100000".to_string())
|
||||
} else if args.len() <= 1 {
|
||||
vec!("".to_string(), "100".to_string())
|
||||
} else {
|
||||
args.collect()
|
||||
};
|
||||
|
||||
let (tx, rx) = channel();
|
||||
child_generation(args[1].parse().unwrap(), tx);
|
||||
if rx.recv().is_err() {
|
||||
panic!("it happened when we slumbered");
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::env;
|
||||
use std::thread;
|
||||
|
||||
fn f(n: usize) {
|
||||
let mut i = 0;
|
||||
while i < n {
|
||||
let _ = thread::spawn(move|| g()).join();
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn g() { }
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
let args = if env::var_os("RUST_BENCH").is_some() {
|
||||
vec!("".to_string(), "400".to_string())
|
||||
} else if args.len() <= 1 {
|
||||
vec!("".to_string(), "10".to_string())
|
||||
} else {
|
||||
args.collect()
|
||||
};
|
||||
let n = args[1].parse().unwrap();
|
||||
let mut i = 0;
|
||||
while i < n { thread::spawn(move|| f(n) ); i += 1; }
|
||||
}
|
Loading…
Reference in New Issue
Block a user