Skip to content

Commit fc3b638

Browse files
committed
Update fannkuchredux benchmark
From the discussion on reddit: http://www.reddit.com/r/rust/comments/2fenlg/benchmark_improvement_fannkuchredux/ This adds two variants: the primary, that uses an unsafe block, and a secondary that is completely safe. The one with the unsafe block matches clang's performance and beats gcc's.
1 parent e024017 commit fc3b638

File tree

3 files changed

+326
-48
lines changed

3 files changed

+326
-48
lines changed

src/etc/licenseck.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"libsync/mpsc_intrusive.rs", # BSD
4545
"test/bench/shootout-binarytrees.rs", # BSD
4646
"test/bench/shootout-fannkuch-redux.rs", # BSD
47+
"test/bench/shootout-fannkuch-redux-safe.rs", # BSD
4748
"test/bench/shootout-k-nucleotide.rs", # BSD
4849
"test/bench/shootout-mandelbrot.rs", # BSD
4950
"test/bench/shootout-meteor.rs", # BSD
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
// The Computer Language Benchmarks Game
2+
// http://benchmarksgame.alioth.debian.org/
3+
//
4+
// contributed by the Rust Project Developers
5+
6+
// Copyright (c) 2014 The Rust Project Developers
7+
//
8+
// All rights reserved.
9+
//
10+
// Redistribution and use in source and binary forms, with or without
11+
// modification, are permitted provided that the following conditions
12+
// are met:
13+
//
14+
// - Redistributions of source code must retain the above copyright
15+
// notice, this list of conditions and the following disclaimer.
16+
//
17+
// - Redistributions in binary form must reproduce the above copyright
18+
// notice, this list of conditions and the following disclaimer in
19+
// the documentation and/or other materials provided with the
20+
// distribution.
21+
//
22+
// - Neither the name of "The Computer Language Benchmarks Game" nor
23+
// the name of "The Computer Language Shootout Benchmarks" nor the
24+
// names of its contributors may be used to endorse or promote
25+
// products derived from this software without specific prior
26+
// written permission.
27+
//
28+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31+
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32+
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33+
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34+
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35+
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36+
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37+
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39+
// OF THE POSSIBILITY OF SUCH DAMAGE.
40+
41+
use std::{cmp, iter, mem};
42+
use std::sync::Future;
43+
44+
fn rotate(x: &mut [i32]) {
45+
let mut prev = x[0];
46+
for place in x.mut_iter().rev() {
47+
prev = mem::replace(place, prev)
48+
}
49+
}
50+
51+
fn next_permutation(perm: &mut [i32], count: &mut [i32]) {
52+
for i in range(1, perm.len()) {
53+
rotate(perm.mut_slice_to(i + 1));
54+
let count_i = &mut count[i];
55+
if *count_i >= i as i32 {
56+
*count_i = 0;
57+
} else {
58+
*count_i += 1;
59+
break
60+
}
61+
}
62+
}
63+
64+
struct P {
65+
p: [i32, .. 16],
66+
}
67+
68+
struct Perm {
69+
cnt: [i32, .. 16],
70+
fact: [u32, .. 16],
71+
n: u32,
72+
permcount: u32,
73+
perm: P,
74+
}
75+
76+
impl Perm {
77+
fn new(n: u32) -> Perm {
78+
let mut fact = [1, .. 16];
79+
for i in range(1, n as uint + 1) {
80+
fact[i] = fact[i - 1] * i as u32;
81+
}
82+
Perm {
83+
cnt: [0, .. 16],
84+
fact: fact,
85+
n: n,
86+
permcount: 0,
87+
perm: P { p: [0, .. 16 ] }
88+
}
89+
}
90+
91+
fn get(&mut self, mut idx: i32) -> P {
92+
let mut pp = [0u8, .. 16];
93+
self.permcount = idx as u32;
94+
for (i, place) in self.perm.p.mut_iter().enumerate() {
95+
*place = i as i32 + 1;
96+
}
97+
98+
for i in range(1, self.n as uint).rev() {
99+
let d = idx / self.fact[i] as i32;
100+
self.cnt[i] = d;
101+
idx %= self.fact[i] as i32;
102+
for (place, val) in pp.mut_iter().zip(self.perm.p.slice_to(i + 1).iter()) {
103+
*place = (*val) as u8
104+
}
105+
106+
let d = d as uint;
107+
for j in range(0, i + 1) {
108+
self.perm.p[j] = if j + d <= i {pp[j + d]} else {pp[j+d-i-1]} as i32;
109+
}
110+
}
111+
112+
self.perm
113+
}
114+
115+
fn count(&self) -> u32 { self.permcount }
116+
fn max(&self) -> u32 { self.fact[self.n as uint] }
117+
118+
fn next(&mut self) -> P {
119+
next_permutation(self.perm.p, self.cnt);
120+
self.permcount += 1;
121+
122+
self.perm
123+
}
124+
}
125+
126+
127+
fn reverse(tperm: &mut [i32], mut k: uint) {
128+
tperm.mut_slice_to(k).reverse()
129+
}
130+
131+
fn work(mut perm: Perm, n: uint, max: uint) -> (i32, i32) {
132+
let mut checksum = 0;
133+
let mut maxflips = 0;
134+
135+
let mut p = perm.get(n as i32);
136+
137+
while perm.count() < max as u32 {
138+
let mut flips = 0;
139+
140+
while p.p[0] != 1 {
141+
let k = p.p[0] as uint;
142+
reverse(p.p, k);
143+
flips += 1;
144+
}
145+
146+
checksum += if perm.count() % 2 == 0 {flips} else {-flips};
147+
maxflips = cmp::max(maxflips, flips);
148+
149+
p = perm.next();
150+
}
151+
152+
(checksum, maxflips)
153+
}
154+
155+
fn fannkuch(n: i32) -> (i32, i32) {
156+
let perm = Perm::new(n as u32);
157+
158+
let N = 4;
159+
let mut futures = vec![];
160+
let k = perm.max() / N;
161+
162+
for (i, j) in range(0, N).zip(iter::count(0, k)) {
163+
let max = cmp::min(j+k, perm.max());
164+
165+
futures.push(Future::spawn(proc() {
166+
work(perm, j as uint, max as uint)
167+
}))
168+
}
169+
170+
let mut checksum = 0;
171+
let mut maxflips = 0;
172+
for fut in futures.mut_iter() {
173+
let (cs, mf) = fut.get();
174+
checksum += cs;
175+
maxflips = cmp::max(maxflips, mf);
176+
}
177+
(checksum, maxflips)
178+
}
179+
180+
fn main() {
181+
let n = std::os::args().as_slice()
182+
.get(1)
183+
.and_then(|arg| from_str(arg.as_slice()))
184+
.unwrap_or(2i32);
185+
186+
let (checksum, maxflips) = fannkuch(n);
187+
println!("{}\nPfannkuchen({}) = {}", checksum, n, maxflips);
188+
}

0 commit comments

Comments
 (0)