1
- #![ feature( portable_simd) ]
1
+ #![ cfg_attr ( feature = "std" , feature ( portable_simd) ) ]
2
2
3
3
/// Benchmarks game nbody code
4
4
/// Taken from the `packed_simd` crate
5
5
/// Run this benchmark with `cargo test --example nbody`
6
- use core_simd:: * ;
6
+ #[ cfg( feature = "std" ) ]
7
+ mod nbody {
8
+ use core_simd:: * ;
7
9
8
- use std:: f64:: consts:: PI ;
9
- const SOLAR_MASS : f64 = 4.0 * PI * PI ;
10
- const DAYS_PER_YEAR : f64 = 365.24 ;
10
+ use std:: f64:: consts:: PI ;
11
+ const SOLAR_MASS : f64 = 4.0 * PI * PI ;
12
+ const DAYS_PER_YEAR : f64 = 365.24 ;
11
13
12
- #[ derive( Debug , Clone , Copy ) ]
13
- pub struct Body {
14
- pub x : f64x4 ,
15
- pub v : f64x4 ,
16
- pub mass : f64 ,
17
- }
14
+ #[ derive( Debug , Clone , Copy ) ]
15
+ struct Body {
16
+ pub x : f64x4 ,
17
+ pub v : f64x4 ,
18
+ pub mass : f64 ,
19
+ }
18
20
19
- const N_BODIES : usize = 5 ;
20
- const BODIES : [ Body ; N_BODIES ] = [
21
- // sun:
22
- Body {
23
- x : f64x4:: from_array ( [ 0. , 0. , 0. , 0. ] ) ,
24
- v : f64x4:: from_array ( [ 0. , 0. , 0. , 0. ] ) ,
25
- mass : SOLAR_MASS ,
26
- } ,
27
- // jupiter:
28
- Body {
29
- x : f64x4:: from_array ( [
30
- 4.84143144246472090e+00 ,
31
- -1.16032004402742839e+00 ,
32
- -1.03622044471123109e-01 ,
33
- 0. ,
34
- ] ) ,
35
- v : f64x4:: from_array ( [
36
- 1.66007664274403694e-03 * DAYS_PER_YEAR ,
37
- 7.69901118419740425e-03 * DAYS_PER_YEAR ,
38
- -6.90460016972063023e-05 * DAYS_PER_YEAR ,
39
- 0. ,
40
- ] ) ,
41
- mass : 9.54791938424326609e-04 * SOLAR_MASS ,
42
- } ,
43
- // saturn:
44
- Body {
45
- x : f64x4:: from_array ( [
46
- 8.34336671824457987e+00 ,
47
- 4.12479856412430479e+00 ,
48
- -4.03523417114321381e-01 ,
49
- 0. ,
50
- ] ) ,
51
- v : f64x4:: from_array ( [
52
- -2.76742510726862411e-03 * DAYS_PER_YEAR ,
53
- 4.99852801234917238e-03 * DAYS_PER_YEAR ,
54
- 2.30417297573763929e-05 * DAYS_PER_YEAR ,
55
- 0. ,
56
- ] ) ,
57
- mass : 2.85885980666130812e-04 * SOLAR_MASS ,
58
- } ,
59
- // uranus:
60
- Body {
61
- x : f64x4:: from_array ( [
62
- 1.28943695621391310e+01 ,
63
- -1.51111514016986312e+01 ,
64
- -2.23307578892655734e-01 ,
65
- 0. ,
66
- ] ) ,
67
- v : f64x4:: from_array ( [
68
- 2.96460137564761618e-03 * DAYS_PER_YEAR ,
69
- 2.37847173959480950e-03 * DAYS_PER_YEAR ,
70
- -2.96589568540237556e-05 * DAYS_PER_YEAR ,
71
- 0. ,
72
- ] ) ,
73
- mass : 4.36624404335156298e-05 * SOLAR_MASS ,
74
- } ,
75
- // neptune:
76
- Body {
77
- x : f64x4:: from_array ( [
78
- 1.53796971148509165e+01 ,
79
- -2.59193146099879641e+01 ,
80
- 1.79258772950371181e-01 ,
81
- 0. ,
82
- ] ) ,
83
- v : f64x4:: from_array ( [
84
- 2.68067772490389322e-03 * DAYS_PER_YEAR ,
85
- 1.62824170038242295e-03 * DAYS_PER_YEAR ,
86
- -9.51592254519715870e-05 * DAYS_PER_YEAR ,
87
- 0. ,
88
- ] ) ,
89
- mass : 5.15138902046611451e-05 * SOLAR_MASS ,
90
- } ,
91
- ] ;
21
+ const N_BODIES : usize = 5 ;
22
+ const BODIES : [ Body ; N_BODIES ] = [
23
+ // sun:
24
+ Body {
25
+ x : f64x4:: from_array ( [ 0. , 0. , 0. , 0. ] ) ,
26
+ v : f64x4:: from_array ( [ 0. , 0. , 0. , 0. ] ) ,
27
+ mass : SOLAR_MASS ,
28
+ } ,
29
+ // jupiter:
30
+ Body {
31
+ x : f64x4:: from_array ( [
32
+ 4.84143144246472090e+00 ,
33
+ -1.16032004402742839e+00 ,
34
+ -1.03622044471123109e-01 ,
35
+ 0. ,
36
+ ] ) ,
37
+ v : f64x4:: from_array ( [
38
+ 1.66007664274403694e-03 * DAYS_PER_YEAR ,
39
+ 7.69901118419740425e-03 * DAYS_PER_YEAR ,
40
+ -6.90460016972063023e-05 * DAYS_PER_YEAR ,
41
+ 0. ,
42
+ ] ) ,
43
+ mass : 9.54791938424326609e-04 * SOLAR_MASS ,
44
+ } ,
45
+ // saturn:
46
+ Body {
47
+ x : f64x4:: from_array ( [
48
+ 8.34336671824457987e+00 ,
49
+ 4.12479856412430479e+00 ,
50
+ -4.03523417114321381e-01 ,
51
+ 0. ,
52
+ ] ) ,
53
+ v : f64x4:: from_array ( [
54
+ -2.76742510726862411e-03 * DAYS_PER_YEAR ,
55
+ 4.99852801234917238e-03 * DAYS_PER_YEAR ,
56
+ 2.30417297573763929e-05 * DAYS_PER_YEAR ,
57
+ 0. ,
58
+ ] ) ,
59
+ mass : 2.85885980666130812e-04 * SOLAR_MASS ,
60
+ } ,
61
+ // uranus:
62
+ Body {
63
+ x : f64x4:: from_array ( [
64
+ 1.28943695621391310e+01 ,
65
+ -1.51111514016986312e+01 ,
66
+ -2.23307578892655734e-01 ,
67
+ 0. ,
68
+ ] ) ,
69
+ v : f64x4:: from_array ( [
70
+ 2.96460137564761618e-03 * DAYS_PER_YEAR ,
71
+ 2.37847173959480950e-03 * DAYS_PER_YEAR ,
72
+ -2.96589568540237556e-05 * DAYS_PER_YEAR ,
73
+ 0. ,
74
+ ] ) ,
75
+ mass : 4.36624404335156298e-05 * SOLAR_MASS ,
76
+ } ,
77
+ // neptune:
78
+ Body {
79
+ x : f64x4:: from_array ( [
80
+ 1.53796971148509165e+01 ,
81
+ -2.59193146099879641e+01 ,
82
+ 1.79258772950371181e-01 ,
83
+ 0. ,
84
+ ] ) ,
85
+ v : f64x4:: from_array ( [
86
+ 2.68067772490389322e-03 * DAYS_PER_YEAR ,
87
+ 1.62824170038242295e-03 * DAYS_PER_YEAR ,
88
+ -9.51592254519715870e-05 * DAYS_PER_YEAR ,
89
+ 0. ,
90
+ ] ) ,
91
+ mass : 5.15138902046611451e-05 * SOLAR_MASS ,
92
+ } ,
93
+ ] ;
92
94
93
- pub fn offset_momentum ( bodies : & mut [ Body ; N_BODIES ] ) {
94
- let ( sun, rest) = bodies. split_at_mut ( 1 ) ;
95
- let sun = & mut sun[ 0 ] ;
96
- for body in rest {
97
- let m_ratio = body. mass / SOLAR_MASS ;
98
- sun. v -= body. v * m_ratio;
95
+ fn offset_momentum ( bodies : & mut [ Body ; N_BODIES ] ) {
96
+ let ( sun, rest) = bodies. split_at_mut ( 1 ) ;
97
+ let sun = & mut sun[ 0 ] ;
98
+ for body in rest {
99
+ let m_ratio = body. mass / SOLAR_MASS ;
100
+ sun. v -= body. v * m_ratio;
101
+ }
99
102
}
100
- }
101
103
102
- pub fn energy ( bodies : & [ Body ; N_BODIES ] ) -> f64 {
103
- let mut e = 0. ;
104
- for i in 0 ..N_BODIES {
105
- let bi = & bodies[ i] ;
106
- e += bi. mass * ( bi. v * bi. v ) . horizontal_sum ( ) * 0.5 ;
107
- for bj in bodies. iter ( ) . take ( N_BODIES ) . skip ( i + 1 ) {
108
- let dx = bi. x - bj. x ;
109
- e -= bi. mass * bj. mass / ( dx * dx) . horizontal_sum ( ) . sqrt ( )
104
+ fn energy ( bodies : & [ Body ; N_BODIES ] ) -> f64 {
105
+ let mut e = 0. ;
106
+ for i in 0 ..N_BODIES {
107
+ let bi = & bodies[ i] ;
108
+ e += bi. mass * ( bi. v * bi. v ) . horizontal_sum ( ) * 0.5 ;
109
+ for bj in bodies. iter ( ) . take ( N_BODIES ) . skip ( i + 1 ) {
110
+ let dx = bi. x - bj. x ;
111
+ e -= bi. mass * bj. mass / ( dx * dx) . horizontal_sum ( ) . sqrt ( )
112
+ }
110
113
}
114
+ e
111
115
}
112
- e
113
- }
114
116
115
- pub fn advance ( bodies : & mut [ Body ; N_BODIES ] , dt : f64 ) {
116
- const N : usize = N_BODIES * ( N_BODIES - 1 ) / 2 ;
117
+ fn advance ( bodies : & mut [ Body ; N_BODIES ] , dt : f64 ) {
118
+ const N : usize = N_BODIES * ( N_BODIES - 1 ) / 2 ;
119
+
120
+ // compute distance between bodies:
121
+ let mut r = [ f64x4:: splat ( 0. ) ; N ] ;
122
+ {
123
+ let mut i = 0 ;
124
+ for j in 0 ..N_BODIES {
125
+ for k in j + 1 ..N_BODIES {
126
+ r[ i] = bodies[ j] . x - bodies[ k] . x ;
127
+ i += 1 ;
128
+ }
129
+ }
130
+ }
131
+
132
+ let mut mag = [ 0.0 ; N ] ;
133
+ for i in ( 0 ..N ) . step_by ( 2 ) {
134
+ let d2s = f64x2:: from_array ( [
135
+ ( r[ i] * r[ i] ) . horizontal_sum ( ) ,
136
+ ( r[ i + 1 ] * r[ i + 1 ] ) . horizontal_sum ( ) ,
137
+ ] ) ;
138
+ let dmags = f64x2:: splat ( dt) / ( d2s * d2s. sqrt ( ) ) ;
139
+ mag[ i] = dmags[ 0 ] ;
140
+ mag[ i + 1 ] = dmags[ 1 ] ;
141
+ }
117
142
118
- // compute distance between bodies:
119
- let mut r = [ f64x4:: splat ( 0. ) ; N ] ;
120
- {
121
143
let mut i = 0 ;
122
144
for j in 0 ..N_BODIES {
123
145
for k in j + 1 ..N_BODIES {
124
- r[ i] = bodies[ j] . x - bodies[ k] . x ;
125
- i += 1 ;
146
+ let f = r[ i] * mag[ i] ;
147
+ bodies[ j] . v -= f * bodies[ k] . mass ;
148
+ bodies[ k] . v += f * bodies[ j] . mass ;
149
+ i += 1
126
150
}
127
151
}
152
+ for body in bodies {
153
+ body. x += dt * body. v
154
+ }
128
155
}
129
156
130
- let mut mag = [ 0.0 ; N ] ;
131
- for i in ( 0 ..N ) . step_by ( 2 ) {
132
- let d2s = f64x2:: from_array ( [
133
- ( r[ i] * r[ i] ) . horizontal_sum ( ) ,
134
- ( r[ i + 1 ] * r[ i + 1 ] ) . horizontal_sum ( ) ,
135
- ] ) ;
136
- let dmags = f64x2:: splat ( dt) / ( d2s * d2s. sqrt ( ) ) ;
137
- mag[ i] = dmags[ 0 ] ;
138
- mag[ i + 1 ] = dmags[ 1 ] ;
139
- }
140
-
141
- let mut i = 0 ;
142
- for j in 0 ..N_BODIES {
143
- for k in j + 1 ..N_BODIES {
144
- let f = r[ i] * mag[ i] ;
145
- bodies[ j] . v -= f * bodies[ k] . mass ;
146
- bodies[ k] . v += f * bodies[ j] . mass ;
147
- i += 1
157
+ pub fn run ( n : usize ) -> ( f64 , f64 ) {
158
+ let mut bodies = BODIES ;
159
+ offset_momentum ( & mut bodies) ;
160
+ let energy_before = energy ( & bodies) ;
161
+ for _ in 0 ..n {
162
+ advance ( & mut bodies, 0.01 ) ;
148
163
}
149
- }
150
- for body in bodies {
151
- body. x += dt * body. v
152
- }
153
- }
164
+ let energy_after = energy ( & bodies) ;
154
165
155
- pub fn run ( n : usize ) -> ( f64 , f64 ) {
156
- let mut bodies = BODIES ;
157
- offset_momentum ( & mut bodies) ;
158
- let energy_before = energy ( & bodies) ;
159
- for _ in 0 ..n {
160
- advance ( & mut bodies, 0.01 ) ;
166
+ ( energy_before, energy_after)
161
167
}
162
- let energy_after = energy ( & bodies) ;
163
-
164
- ( energy_before, energy_after)
165
168
}
166
169
170
+ #[ cfg( feature = "std" ) ]
167
171
#[ cfg( test) ]
168
172
mod tests {
169
173
// Good enough for demonstration purposes, not going for strictness here.
@@ -173,12 +177,17 @@ mod tests {
173
177
#[ test]
174
178
fn test ( ) {
175
179
const OUTPUT : [ f64 ; 2 ] = [ -0.169075164 , -0.169087605 ] ;
176
- let ( energy_before, energy_after) = super :: run ( 1000 ) ;
180
+ let ( energy_before, energy_after) = super :: nbody :: run ( 1000 ) ;
177
181
assert ! ( approx_eq_f64( energy_before, OUTPUT [ 0 ] ) ) ;
178
182
assert ! ( approx_eq_f64( energy_after, OUTPUT [ 1 ] ) ) ;
179
183
}
180
184
}
181
185
182
186
fn main ( ) {
183
- // empty main to pass CI
187
+ #[ cfg( feature = "std" ) ]
188
+ {
189
+ let ( energy_before, energy_after) = nbody:: run ( 1000 ) ;
190
+ println ! ( "Energy before: {}" , energy_before) ;
191
+ println ! ( "Energy after: {}" , energy_after) ;
192
+ }
184
193
}
0 commit comments