summaryrefslogtreecommitdiff
path: root/tests/src/JIT/Performance/CodeQuality/FractalPerf/FractalPerf.cs
blob: 9d9f36095e495a8bde56b48e3368a89c14218056 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

using Microsoft.Xunit.Performance;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Xunit;

[assembly: OptimizeForBenchmarks]
[assembly: MeasureInstructionsRetired]

namespace FractalPerf
{
    struct complex
    {
        public complex(double a, double b) { r = a; i = b; }
        public double r;
        public double i;

        public complex square() {
            return new complex(r * r - i * i, 2.0 * r * i);
        }

        public double sqabs() {
            return r * r + i * i;
        }

        public override string ToString() {
            return String.Format("[{0} + {1}i]", r, i);
        }

        public static complex operator +(complex a, complex b) {
            return new complex(a.r + b.r, a.i + b.i);
        }
    }

    public abstract class Fractal
    {
        protected double XB, YB, XE, YE, XS, YS;
        const double resolution = 375.0;

        public Fractal(double xbeg, double ybeg, double xend, double yend) {
            XB = Math.Min(xbeg, xend);
            YB = Math.Min(ybeg, yend);
            XE = Math.Max(xbeg, xend);
            YE = Math.Max(ybeg, yend);
            XS = (xend - xbeg) / resolution;
            YS = (yend - ybeg) / resolution;
        }

        public abstract double Render();

        public static double Clamp(double val, double lo, double hi) {
            return Math.Min(Math.Max(val, lo), hi);
        }
    }

    public class Mandelbrot : Fractal
    {
        public Mandelbrot() : base(-2.0, -1.5, 1.0, 1.5) { }

        public override double Render() {
            double limit = 4.0;
            double result = 0.0;

            for (double y = YB; y < YE; y += YS) {
                for (double x = YB; x < YE; x += XS) {
                    complex num = new complex(x, y);
                    complex accum = num;
                    int iters;
                    for (iters = 0; iters < 1000; iters++) {
                        accum = accum.square();
                        accum += num;
                        if (accum.sqabs() > limit)
                            break;
                    }
                    result += iters;
                }
            }
            return result;
        }
    }

    public class Julia : Fractal
    {
        private double Real;
        double Imaginary;
        public Julia(double real, double imaginary)
            : base(-2.0, -1.5, 1.0, 1.5) {
            Real = real;
            Imaginary = imaginary;
        }

        public override double Render() {
            double limit = 4.0;
            double result = 0.0;

            // set the Julia Set constant
            complex seed = new complex(Real, Imaginary);
            // run through every point on the screen, setting 
            // m and n to the coordinates
            for (double m = XB; m < XE; m += XS) {
                for (double n = YB; n < YE; n += YS) {
                    // the initial z value is the current pixel,  
                    // so x and y have to be set to m and n
                    complex accum = new complex(m, n);
                    // perform the iteration
                    int num;
                    for (num = 0; num < 1000; num++) {
                        // exit the loop if the number  becomes too big
                        if (accum.sqabs() > limit)
                            break;
                        // use the formula
                        accum = accum.square() + seed;
                    }
                    // determine the color using the number of
                    // iterations it took for the number to become too big 
                    // char color = num % number_of_colors; 
                    // plot the point
                    result += num;
                }
            }
            return result;
        }
    }

    public class Launch
    {

#if DEBUG
        public const int Iterations = 1;
#else
        public const int Iterations = 5;
#endif

        [MethodImpl(MethodImplOptions.NoInlining)]
        static bool Bench()
        {
            Mandelbrot m = new Mandelbrot();
            Julia j = new Julia(-0.62, 0.41);
            double mResult = m.Render();
            double jResult = j.Render();

            return true;
        }

        [Benchmark]
        public static void Test() {
            foreach (var iteration in Benchmark.Iterations) {
                using (iteration.StartMeasurement()) {
                    for (int i = 0; i < Iterations; i++) {
                        Bench();
                    }
                }
            }
        }

        static bool TestBase() {
            bool result = true;
            for (int i = 0; i < Iterations; i++) {
                result &= Bench();
            }
            return result;
        }
    
        public static int Main() {
            bool result = TestBase();
            return (result ? 100 : -1);
        }
    }
}