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:
bors 2016-01-30 14:50:44 +00:00
commit 9bda7ea81d
30 changed files with 4 additions and 87874 deletions

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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");
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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");
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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));
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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!("");
}

View File

@ -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])
}

View File

@ -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);
}
}
}
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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());
}

View File

@ -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));
}
}

View File

@ -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");
}
}

View File

@ -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; }
}