1 // Copyright 2017 The Emscripten Authors.  All rights reserved.
2 // Emscripten is available under two separate licenses, the MIT license and the
3 // University of Illinois/NCSA Open Source License.  Both these licenses can be
4 // found in the LICENSE file.
5 
6 #include <string.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <vector>
10 #include <iostream>
11 #include <algorithm>
12 
13 #ifdef WIN32
14 #include <Windows.h>
15 #define aligned_alloc(align, size) _aligned_malloc((size), (align))
16 #endif
17 
18 #ifdef __EMSCRIPTEN__
19 #include <emscripten/emscripten.h>
20 #endif
21 
22 #include "tick.h"
23 
24 char dst[1024*1024*64+16] = {};
25 char src[1024*1024*64+16] = {};
26 
27 uint8_t resultCheckSum = 0;
28 
test_memcpy(int numTimes,int copySize)29 void __attribute__((noinline)) test_memcpy(int numTimes, int copySize)
30 {
31 	for(int i = 0; i < numTimes - 8; i += 8)
32 	{
33 		memcpy(dst, src, copySize); resultCheckSum += dst[copySize >> 1];
34 		memcpy(dst, src, copySize); resultCheckSum += dst[copySize >> 1];
35 		memcpy(dst, src, copySize); resultCheckSum += dst[copySize >> 1];
36 		memcpy(dst, src, copySize); resultCheckSum += dst[copySize >> 1];
37 		memcpy(dst, src, copySize); resultCheckSum += dst[copySize >> 1];
38 		memcpy(dst, src, copySize); resultCheckSum += dst[copySize >> 1];
39 		memcpy(dst, src, copySize); resultCheckSum += dst[copySize >> 1];
40 		memcpy(dst, src, copySize); resultCheckSum += dst[copySize >> 1];
41 	}
42 	numTimes &= 15;
43 	for(int i = 0; i < numTimes; ++i)
44 	{
45 		memcpy(dst, src, copySize); resultCheckSum += dst[copySize >> 1];
46 	}
47 }
48 
49 std::vector<int> copySizes;
50 std::vector<double> results;
51 
52 std::vector<int> testCases;
53 
54 double totalTimeSecs = 0.0;
55 
test_case(int copySize)56 void test_case(int copySize)
57 {
58 	const int minimumCopyBytes = 1024*1024*64;
59 
60 	int numTimes = (minimumCopyBytes + copySize-1) / copySize;
61 	if (numTimes < 8) numTimes = 8;
62 
63 	tick_t bestResult = 1e9;
64 
65 #ifndef NUM_TRIALS
66 #define NUM_TRIALS 5
67 #endif
68 
69 	for(int i = 0; i < NUM_TRIALS; ++i)
70 	{
71 		double t0 = tick();
72 		test_memcpy(numTimes, copySize);
73 		double t1 = tick();
74 		if (t1 - t0 < bestResult) bestResult = t1 - t0;
75 		totalTimeSecs += (double)(t1 - t0) / ticks_per_sec();
76 	}
77 	unsigned long long totalBytesTransferred = numTimes * copySize;
78 
79 	copySizes.push_back(copySize);
80 
81 	tick_t ticksElapsed = bestResult;
82 	if (ticksElapsed > 0)
83 	{
84 		double seconds = (double)ticksElapsed / ticks_per_sec();
85 		double bytesPerSecond = totalBytesTransferred / seconds;
86 		double mbytesPerSecond = bytesPerSecond / (1024.0*1024.0);
87 		results.push_back(mbytesPerSecond);
88 	}
89 	else
90 	{
91 		results.push_back(0.0);
92 	}
93 }
94 
print_results()95 void print_results()
96 {
97 	std::cout << "Test cases: " << std::endl;
98 	for(size_t i = 0; i < copySizes.size(); ++i)
99 	{
100 		std::cout << copySizes[i];
101 		if (i != copySizes.size()-1) std::cout << ", ";
102 		else std::cout << std::endl;
103 		if (i % 10 == 9) std::cout << std::endl;
104 	}
105 	std::cout << std::endl;
106 	std::cout << std::endl;
107 	std::cout << std::endl;
108 	std::cout << "Test results: " << std::endl;
109 	for(size_t i = 0; i < results.size(); ++i)
110 	{
111 		std::cout << results[i];
112 		if (i != results.size()-1) std::cout << ", ";
113 		else std::cout << std::endl;
114 		if (i % 10 == 9) std::cout << std::endl;
115 	}
116 
117 	std::cout << "Result checksum: " << (int)resultCheckSum << std::endl;
118 	std::cout << "Total time: " << totalTimeSecs << std::endl;
119 }
120 
121 int numDone = 0;
122 
run_one()123 void run_one()
124 {
125 	std::cout << (numDone+1) << "/" << (numDone+testCases.size()) << std::endl;
126 	++numDone;
127 
128 	int copySize = testCases.front();
129 	testCases.erase(testCases.begin());
130 	test_case(copySize);
131 }
132 
133 #ifdef __EMSCRIPTEN__
main_loop()134 void main_loop()
135 {
136 	if (!testCases.empty())
137 	{
138 		run_one();
139 	}
140 	else
141 	{
142 		emscripten_cancel_main_loop();
143 		print_results();
144 	}
145 }
146 #endif
147 
148 #ifndef MAX_COPY
149 #define MAX_COPY 32*1024*1024
150 #endif
151 
152 #ifndef MIN_COPY
153 #define MIN_COPY 1
154 #endif
155 
main()156 int main()
157 {
158 	for(int copySizeI = MIN_COPY; copySizeI < MAX_COPY; copySizeI <<= 1)
159 		for(int copySizeJ = 1; copySizeJ <= copySizeI; copySizeJ <<= 1)
160 		{
161 			testCases.push_back(copySizeI | copySizeJ);
162 		}
163 
164 	std::sort(testCases.begin(), testCases.end());
165 #if defined(__EMSCRIPTEN__) && !defined(BUILD_FOR_SHELL)
166 	emscripten_set_main_loop(main_loop, 0, 0);
167 #else
168 	while(!testCases.empty()) run_one();
169 	print_results();
170 #endif
171 }
172