]> git.lizzy.rs Git - rust.git/commitdiff
shootout-mandlebrot: calculate two bits of the result per inner loop, +10-15%
authorKevin Butler <haqkrs@gmail.com>
Tue, 13 May 2014 20:15:11 +0000 (21:15 +0100)
committerAlex Crichton <alex@alexcrichton.com>
Thu, 15 May 2014 20:50:39 +0000 (13:50 -0700)
src/test/bench/shootout-mandelbrot.rs

index e17324ee596491dfb58a87439bd880ce37e70060..5302bd1dd6312b98c22c56347d1f69f0ae7b3bf8 100644 (file)
@@ -7,6 +7,7 @@
 // <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(macro_rules)]
 
 // ignore-pretty very bad with line comments
 
 static ITER: int = 50;
 static LIMIT: f64 = 2.0;
 
+macro_rules! core_loop(
+    ($pow:expr ~ $mask:expr: $ctx:ident, $b:ident) => (
+        {
+            let r = $ctx.r;
+            let i = $ctx.i;
+
+            $ctx.r = r * r - i * i + $ctx.init_r;
+            $ctx.i = 2.0 * r * i + $ctx.init_i;
+
+            if r * r + i * i > LIMIT * LIMIT {
+                $b |= $pow;
+                if $b == $mask { break; }
+            }
+        }
+    );
+)
+
+#[inline(always)]
 fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec<u8>) {
+    struct Context { r: f64, i: f64, init_i: f64, init_r: f64 }
+    impl Context {
+        #[inline(always)]
+        fn new(i: f64, r: f64) -> Context {
+            Context { r: r, i: i, init_r: r, init_i: i }
+        }
+    }
+
+    let mut cur_byte;
+    let mut i;
+    let mut bit_1;
+    let mut bit_2;
+    let mut b;
     for chunk_init_r in vec_init_r.chunks(8) {
-        let mut cur_byte = 0xff;
-        let mut cur_bitmask = 0x80;
-        for &init_r in chunk_init_r.iter() {
-            let mut cur_r = init_r;
-            let mut cur_i = init_i;
+        cur_byte = 0xff;
+        i = 0;
+
+        while i < 8 {
+            bit_1 = Context::new(init_i, chunk_init_r[i]);
+            bit_2 = Context::new(init_i, chunk_init_r[i + 1]);
+
+            b = 0;
             for _ in range(0, ITER) {
-                let r = cur_r;
-                let i = cur_i;
-                cur_r = r * r - i * i + init_r;
-                cur_i = 2.0 * r * i + init_i;
-
-                if r * r + i * i > LIMIT * LIMIT {
-                    cur_byte &= !cur_bitmask;
-                    break;
-                }
+                core_loop!(2 ~ 3: bit_1, b);
+                core_loop!(1 ~ 3: bit_2, b);
             }
-            cur_bitmask >>= 1;
+
+            cur_byte = (cur_byte << 2) + b;
+            i += 2;
         }
-        res.push(cur_byte);
+        res.push(cur_byte^-1);
     }
 }
 
@@ -46,13 +76,15 @@ fn mandelbrot<W: io::Writer>(w: uint, mut out: W) -> io::IoResult<()> {
     // Ensure w and h are multiples of 8.
     let w = (w + 7) / 8 * 8;
     let h = w;
-    let chunk_size = h / 8;
+    let inverse_w_doubled = 2.0 / w as f64;
+    let inverse_h_doubled = 2.0 / h as f64;
+    let chunk_size = h / 16;
 
-    let data: Vec<Future<Vec<u8>>> = range(0u, 8).map(|i| Future::spawn(proc () {
-        let vec_init_r = Vec::from_fn(w, |x| 2.0 * (x as f64) / (w as f64) - 1.5);
+    let data: Vec<Future<Vec<u8>>> = range(0u, 16).map(|i| Future::spawn(proc () {
+        let vec_init_r = Vec::from_fn(w, |x| (x as f64) * inverse_w_doubled - 1.5);
         let mut res: Vec<u8> = Vec::with_capacity((chunk_size * w) / 8);
         for y in range(i * chunk_size, (i + 1) * chunk_size) {
-            let init_i = 2.0 * (y as f64) / (h as f64) - 1.0;
+            let init_i = (y as f64) * inverse_h_doubled - 1.0;
             write_line(init_i, vec_init_r.as_slice(), &mut res);
         }
         res