summaryrefslogtreecommitdiffstats
path: root/Tools/NoiseSpeedTest/NoiseSpeedTest.cpp
blob: 6857b1a270bc61593e94cf125685f88126800f74 (plain) (blame)
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
// NoiseSpeedTest.cpp

// Implements the main app entrypoint

/*
This program compares the performance of the highly-optimized noise implementation in Cuberite, and the Simplex noise.
Since the Simplex noise is not yet implemented in Cuberite, an own implementation is provided.
Also, the performance difference between using a float and double as datatype is measured, by using a templatized Simplex noise.

The testing is done on a usage of the generator that is typical for the Cuberite's terrain generator: generate a 3D array of numbers with
not much variance in the coords. The exact sizes and coord ranges were adapted from the cNoise3DComposable generator.
*/

#include "Globals.h"
#include "Noise/Noise.h"
#include "Noise/InterpolNoise.h"
#include "SimplexNoise.h"





/// The sizes of the interpolated noise that are calculated:
static const int SIZE_X = 33;
static const int SIZE_Y = 5;
static const int SIZE_Z = 5;





static void measureClassicNoise(int a_NumIterations)
{
	cInterp5DegNoise noise(1);
	NOISE_DATATYPE total = 0;
	auto timeStart = std::chrono::high_resolution_clock::now();
	for (int i = 0; i < a_NumIterations; ++i)
	{
		NOISE_DATATYPE out[SIZE_X * SIZE_Y * SIZE_Z];
		int blockX = i * 16;
		int blockZ = i * 16;
		NOISE_DATATYPE startX = 0;
		NOISE_DATATYPE endX = 257 / 80.0f;
		NOISE_DATATYPE startY = blockX / 40.0f;
		NOISE_DATATYPE endY = (blockX + 16) / 40.0f;
		NOISE_DATATYPE startZ = blockZ / 40.0f;
		NOISE_DATATYPE endZ = (blockZ + 16) / 40.0f;
		noise.Generate3D(out, SIZE_X, SIZE_Y, SIZE_Z, startX, endX, startY, endY, startZ, endZ);
		total += out[0];  // Do not let the optimizer optimize the whole calculation away
	}
	auto timeEnd = std::chrono::high_resolution_clock::now();
	auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(timeEnd - timeStart);
	printf("Classic noise took %d milliseconds, returned total %f\n", static_cast<int>(msec.count()), total);
}





static void measureSimplexNoiseFloat(int a_NumIterations)
{
	typedef float DATATYPE;
	cSimplexNoise<DATATYPE> noise(1);
	DATATYPE total = 0;
	auto timeStart = std::chrono::high_resolution_clock::now();
	for (int i = 0; i < a_NumIterations; ++i)
	{
		DATATYPE out[SIZE_X * SIZE_Y * SIZE_Z];
		int blockX = i * 16;
		int blockZ = i * 16;
		DATATYPE startX = 0;
		DATATYPE endX = 257 / 80.0f;
		DATATYPE startY = blockX / 40.0f;
		DATATYPE endY = (blockX + 16) / 40.0f;
		DATATYPE startZ = blockZ / 40.0f;
		DATATYPE endZ = (blockZ + 16) / 40.0f;
		noise.Generate3D(out, SIZE_X, SIZE_Y, SIZE_Z, startX, endX, startY, endY, startZ, endZ);
		total += out[0];  // Do not let the optimizer optimize the whole calculation away
	}
	auto timeEnd = std::chrono::high_resolution_clock::now();
	auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(timeEnd - timeStart);
	printf("SimplexNoise<float> took %d milliseconds, returned total %f\n", static_cast<int>(msec.count()), total);
}





static void measureSimplexNoiseDouble(int a_NumIterations)
{
	typedef double DATATYPE;
	cSimplexNoise<DATATYPE> noise(1);
	DATATYPE total = 0;
	auto timeStart = std::chrono::high_resolution_clock::now();
	for (int i = 0; i < a_NumIterations; ++i)
	{
		DATATYPE out[SIZE_X * SIZE_Y * SIZE_Z];
		int blockX = i * 16;
		int blockZ = i * 16;
		DATATYPE startX = 0;
		DATATYPE endX = 257 / 80.0f;
		DATATYPE startY = blockX / 40.0f;
		DATATYPE endY = (blockX + 16) / 40.0f;
		DATATYPE startZ = blockZ / 40.0f;
		DATATYPE endZ = (blockZ + 16) / 40.0f;
		noise.Generate3D(out, SIZE_X, SIZE_Y, SIZE_Z, startX, endX, startY, endY, startZ, endZ);
		total += out[0];  // Do not let the optimizer optimize the whole calculation away
	}
	auto timeEnd = std::chrono::high_resolution_clock::now();
	auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(timeEnd - timeStart);
	printf("SimplexNoise<double> took %d milliseconds, returned total %f\n", static_cast<int>(msec.count()), total);
}





int main(int argc, char ** argv)
{
	int numIterations = 10000;
	if (argc > 1)
	{
		numIterations = std::atoi(argv[1]);
		if (numIterations < 10)
		{
			printf("Invalid number of iterations, using 1000 instead\n");
			numIterations = 1000;
		}
	}

	// Perform each test twice, to account for cache-warmup:
	measureClassicNoise(numIterations);
	measureClassicNoise(numIterations);
	measureSimplexNoiseFloat(numIterations);
	measureSimplexNoiseFloat(numIterations);
	measureSimplexNoiseDouble(numIterations);
	measureSimplexNoiseDouble(numIterations);

	// If build on Windows using MSVC, wait for a keypress before ending:
	#ifdef _MSC_VER
		getchar();
	#endif

	return 0;
}