1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 // PSP speed and unit tests. Activate in tests.h
24 // You may also want to build without any engines.
25 
26 #include "backends/platform/psp/tests.h"
27 
28 #if defined(PSP_ENABLE_UNIT_TESTS) || defined(PSP_ENABLE_SPEED_TESTS)
29 
30 #include "common/scummsys.h"
31 #include <pspiofilemgr_fcntl.h>
32 #include <pspiofilemgr_stat.h>
33 #include <pspiofilemgr.h>
34 #include <pspthreadman.h>
35 #include <pspsdk.h>
36 #include <psprtc.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <psputils.h>
40 #include "backends/platform/psp/rtc.h"
41 #include "backends/platform/psp/thread.h"
42 #include "backends/platform/psp/memory.h"
43 #include "common/stream.h"
44 #include "common/file.h"
45 #include "common/fs.h"
46 
47 #define UNCACHED(x)		((byte *)(((uint32)(x)) | 0x40000000))	/* make an uncached access */
48 #define CACHED(x)		((byte *)(((uint32)(x)) & 0xBFFFFFFF))	/* make an uncached access into a cached one */
49 
50 //#define __PSP_DEBUG_FUNCS__
51 //#define __PSP_DEBUG_PRINT__
52 
53 // Results: (333Mhz/222Mhz)
54 // Getting a tick: 1-2 us
55 // Getting a time structure: 9/14us
56 // ie. using a tick and just dividing by 1000 saves us time.
57 
58 #include "backends/platform/psp/trace.h"
59 
60 class PspSpeedTests {
61 public:
62 	void tickSpeed();
63 	void getMicrosSpeed();
64 	void seekSpeed();
65 	void msReadSpeed();
66 	void threadFunctionsSpeed();
67 	void semaphoreSpeed();
68 	static int threadFunc(SceSize args, void *argp);
69 	void semaphoreManyThreadSpeed();
70 	void fastCopySpeed();
71 
72 private:
73 	enum {
74 		MEMCPY_BUFFER_SIZE = 8192
75 	};
76 	static PspSemaphore _sem;	// semaphore
77 
78 	void readAndTime(uint32 bytes, char *buffer, FILE *file);
79 	void seekAndTime(int bytes, int origin, FILE *file);
80 	void fastCopySpecificSize(byte *dst, byte *src, uint32 bytes);
81 	void fastCopyDifferentSizes(byte *dst, byte *src);
82 	int getThreadIdSpeed();
83 	void getPrioritySpeed();
84 	void changePrioritySpeed(int id, int priority);
85 };
86 
87 PspSemaphore PspSpeedTests::_sem(0);
88 
tickSpeed()89 void PspSpeedTests::tickSpeed() {
90 	uint32 ticksPerSecond = sceRtcGetTickResolution();
91 	PSP_INFO_PRINT("ticksPerSecond[%d]\n", ticksPerSecond);
92 
93 	uint32 currentTicks1[2];
94 	uint32 currentTicks2[2];
95 
96 	sceRtcGetCurrentTick((u64 *)currentTicks1);
97 	sceRtcGetCurrentTick((u64 *)currentTicks2);
98 	PSP_INFO_PRINT("current tick[%x %x][%u %u]\n", currentTicks1[0], currentTicks1[1], currentTicks1[0], currentTicks1[1]);
99 	PSP_INFO_PRINT("current tick[%x %x][%u %u]\n", currentTicks2[0], currentTicks2[1], currentTicks2[0], currentTicks2[1]);
100 
101 	pspTime time;
102 	sceRtcSetTick(&time, (u64 *)currentTicks2);
103 	PSP_INFO_PRINT("current tick in time, year[%d] month[%d] day[%d] hour[%d] minutes[%d] seconds[%d] us[%d]\n", time.year, time.month, time.day, time.hour, time.minutes, time.seconds, time.microseconds);
104 
105 	pspTime time1;
106 	pspTime time2;
107 	sceRtcGetCurrentClockLocalTime(&time1);
108 	sceRtcGetCurrentClockLocalTime(&time2);
109 	PSP_INFO_PRINT("time1, year[%d] month[%d] day[%d] hour[%d] minutes[%d] seconds[%d] us[%d]\n", time1.year, time1.month, time1.day, time1.hour, time1.minutes, time1.seconds, time1.microseconds);
110 	PSP_INFO_PRINT("time2, year[%d] month[%d] day[%d] hour[%d] minutes[%d] seconds[%d] us[%d]\n", time2.year, time2.month, time2.day, time2.hour, time2.minutes, time2.seconds, time2.microseconds);
111 }
112 
getMicrosSpeed()113 void PspSpeedTests::getMicrosSpeed() {
114 	uint32 time1, time2, time3, time4;
115 	time1 = PspRtc::instance().getMicros();
116 	time2 = PspRtc::instance().getMicros();
117 	time3 = PspRtc::instance().getMicros();
118 	time4 = PspRtc::instance().getMicros();
119 
120 	PSP_INFO_PRINT("getMicros() times: %d, %d, %d\n", time4-time3, time3-time2, time2-time1);
121 }
122 
readAndTime(uint32 bytes,char * buffer,FILE * file)123 void PspSpeedTests::readAndTime(uint32 bytes, char *buffer, FILE *file) {
124 	uint32 time1 = PspRtc::instance().getMicros();
125 	// test minimal read
126 	fread(buffer, bytes, 1, file);
127 	uint32 time2 = PspRtc::instance().getMicros();
128 
129 	PSP_INFO_PRINT("Reading %d byte takes %dus\n", bytes, time2-time1);
130 }
131 
132 /*
133 	333MHz/222MHz
134 	Reading 1 byte takes 2590us / 3167
135 	Reading 10 byte takes 8us / 9
136 	Reading 50 byte takes 8us / 11
137 	Reading 100 byte takes 8us / 11
138 	Reading 1000 byte takes 915us / 1131
139 	Reading 2000 byte takes 1806us / 2,284
140 	Reading 3000 byte takes 2697us / 3,374
141 	Reading 5000 byte takes 4551us / 5,544
142 	Reading 6000 byte takes 5356us / 6,676
143 	Reading 7000 byte takes 6800us / 8,358
144 	Reading 8000 byte takes 6794us / 8,454
145 	Reading 9000 byte takes 6782us / 8,563
146 	Reading 10000 byte takes 8497us / 10,631
147 	Reading 30000 byte takes 25995us / 32,473
148 	Reading 80000 byte takes 68457us / 85,291
149 	Reading 100000 byte takes 85103us / 106,163
150 */
151 // Function to test the impact of MS reads
152 // These tests can't be done from shell - the cache screws them up
msReadSpeed()153 void PspSpeedTests::msReadSpeed() {
154 	FILE *file;
155 	file = fopen("ms0:/psp/music/track1.mp3", "r");
156 
157 	char *buffer = (char *)malloc(2 * 1024 * 1024);
158 
159 	readAndTime(1, buffer, file);
160 	readAndTime(10, buffer, file);
161 	readAndTime(50, buffer, file);
162 	readAndTime(100, buffer, file);
163 	readAndTime(1000, buffer, file);
164 	readAndTime(2000, buffer, file);
165 	readAndTime(3000, buffer, file);
166 	readAndTime(5000, buffer, file);
167 	readAndTime(6000, buffer, file);
168 	readAndTime(7000, buffer, file);
169 	readAndTime(8000, buffer, file);
170 	readAndTime(9000, buffer, file);
171 	readAndTime(10000, buffer, file);
172 	readAndTime(30000, buffer, file);
173 	readAndTime(50000, buffer, file);
174 	readAndTime(80000, buffer, file);
175 	readAndTime(100000, buffer, file);
176 
177 	fclose(file);
178 	free(buffer);
179 }
180 
seekAndTime(int bytes,int origin,FILE * file)181 void PspSpeedTests::seekAndTime(int bytes, int origin, FILE *file) {
182 	char buffer[1000];
183 
184 	uint32 time1 = PspRtc::instance().getMicros();
185 	// test minimal read
186 	fseek(file, bytes, origin);
187 	uint32 time2 = PspRtc::instance().getMicros();
188 
189 	PSP_INFO_PRINT("Seeking %d byte from %d took %dus\n", bytes, origin, time2-time1);
190 
191 	time1 = PspRtc::instance().getMicros();
192 	// test minimal read
193 	fread(buffer, 1000, 1, file);
194 	time2 = PspRtc::instance().getMicros();
195 
196 	PSP_INFO_PRINT("Reading 1000 bytes took %dus\n", time2-time1);
197 }
198 
199 /*
200 333MHz
201 Seeking 0 byte from 0 took 946us
202 Reading 1000 bytes took 1781us
203 Seeking 5 byte from 0 took 6us
204 Reading 1000 bytes took 19us
205 Seeking 1000 byte from 0 took 5us
206 Reading 1000 bytes took 913us
207 Seeking 100 byte from 0 took 955us
208 Reading 1000 bytes took 906us
209 Seeking 10000 byte from 0 took 963us
210 Reading 1000 bytes took 905us
211 Seeking -5 byte from 1 took 1022us
212 Reading 1000 bytes took 949us
213 Seeking -100 byte from 1 took 1040us
214 Reading 1000 bytes took 907us
215 Seeking 100 byte from 1 took 1044us
216 Reading 1000 bytes took 930us
217 Seeking 0 byte from 2 took 7211us
218 Reading 1000 bytes took 80us
219 Seeking 10000 byte from 2 took 3636us
220 Reading 1000 bytes took 110us
221 */
222 
seekSpeed()223 void PspSpeedTests::seekSpeed() {
224 	FILE *file;
225 	file = fopen("ms0:/psp/music/track1.mp3", "r");
226 
227 	seekAndTime(0, SEEK_SET, file);
228 	seekAndTime(5, SEEK_SET, file);
229 	seekAndTime(1000, SEEK_SET, file);
230 	seekAndTime(100, SEEK_SET, file);
231 	seekAndTime(10000, SEEK_SET, file);
232 	seekAndTime(-5, SEEK_CUR, file);
233 	seekAndTime(-100, SEEK_CUR, file);
234 	seekAndTime(100, SEEK_CUR, file);
235 	seekAndTime(0, SEEK_END, file);
236 	seekAndTime(-10000, SEEK_END, file);
237 
238 	fclose(file);
239 }
240 
241 // 222: 5-7us
getThreadIdSpeed()242 int PspSpeedTests::getThreadIdSpeed() {
243 	uint32 time1 = PspRtc::instance().getMicros();
244 	int threadId = sceKernelGetThreadId();
245 	uint32 time2 = PspRtc::instance().getMicros();
246 
247 	PSP_INFO_PRINT("Getting thread ID %d took %dus\n", threadId, time2-time1);
248 
249 	return threadId;
250 }
251 
252 // 222: 4-5us
getPrioritySpeed()253 void PspSpeedTests::getPrioritySpeed() {
254 	uint32 time1 = PspRtc::instance().getMicros();
255 	int priority = sceKernelGetThreadCurrentPriority();
256 	uint32 time2 = PspRtc::instance().getMicros();
257 
258 	PSP_INFO_PRINT("Getting thread priority %d took %dus\n", priority, time2-time1);
259 }
260 
261 // 222: 9-10us
changePrioritySpeed(int id,int priority)262 void PspSpeedTests::changePrioritySpeed(int id, int priority) {
263 	uint32 time1 = PspRtc::instance().getMicros();
264 	sceKernelChangeThreadPriority(id, priority);
265 	uint32 time2 = PspRtc::instance().getMicros();
266 
267 	PSP_INFO_PRINT("Changing thread priority to %d for id %d took %dus\n", priority, id, time2-time1);
268 }
269 
threadFunctionsSpeed()270 void PspSpeedTests::threadFunctionsSpeed() {
271 	// very unscientific -- just ballpark
272 	int id;
273 	id = getThreadIdSpeed();
274 	getThreadIdSpeed();
275 	getPrioritySpeed();
276 	getPrioritySpeed();
277 	changePrioritySpeed(id, 30);
278 	changePrioritySpeed(id, 35);
279 	changePrioritySpeed(id, 25);
280 
281 	// test context switch time
282 	for (int i=0; i<10; i++) {
283 		uint time1 = PspRtc::instance().getMicros();
284 		PspThread::delayMicros(0);
285 		uint time2 = PspRtc::instance().getMicros();
286 		PSP_INFO_PRINT("poll %d. context switch Time = %dus\n", i, time2-time1);	// 10-15us
287 	}
288 }
289 
semaphoreSpeed()290 void PspSpeedTests::semaphoreSpeed() {
291 	PspSemaphore sem(1);
292 
293 	uint32 time1 = PspRtc::instance().getMicros();
294 
295 	sem.take();
296 
297 	uint32 time2 = PspRtc::instance().getMicros();
298 
299 	PSP_INFO_PRINT("taking semaphore took %d us\n", time2-time1);	// 10us
300 
301 	uint32 time3 = PspRtc::instance().getMicros();
302 
303 	sem.give();
304 
305 	uint32 time4 = PspRtc::instance().getMicros();
306 	PSP_INFO_PRINT("releasing semaphore took %d us\n", time4-time3);	//10us-55us
307 }
308 
threadFunc(SceSize args,void * argp)309 int PspSpeedTests::threadFunc(SceSize args, void *argp) {
310 	PSP_INFO_PRINT("thread %x created.\n", sceKernelGetThreadId());
311 
312 	_sem.take();
313 
314 	PSP_INFO_PRINT("grabbed semaphore. Quitting thread\n");
315 
316 	return 0;
317 }
318 
semaphoreManyThreadSpeed()319 void PspSpeedTests::semaphoreManyThreadSpeed() {
320 
321 	// create 4 threads
322 	for (int i=0; i<4; i++) {
323 		int thid = sceKernelCreateThread("my_thread", PspSpeedTests::threadFunc, 0x18, 0x10000, THREAD_ATTR_USER, NULL);
324 		sceKernelStartThread(thid, 0, 0);
325 	}
326 
327 	PSP_INFO_PRINT("main thread. created threads\n");
328 
329 	uint32 threads = _sem.numOfWaitingThreads();
330 	while (threads < 4) {
331 		threads = _sem.numOfWaitingThreads();
332 		PSP_INFO_PRINT("main thread: waiting threads[%d]\n", threads);
333 	}
334 
335 	PSP_INFO_PRINT("main: semaphore value[%d]\n", _sem.getValue());
336 	PSP_INFO_PRINT("main thread: waiting threads[%d]\n", _sem.numOfWaitingThreads());
337 
338 	_sem.give(4);
339 }
340 
fastCopySpecificSize(byte * dst,byte * src,uint32 bytes)341 void PspSpeedTests::fastCopySpecificSize(byte *dst, byte *src, uint32 bytes) {
342 	uint32 time1, time2;
343 	uint32 fastcopyTime, memcpyTime;
344 	const int iterations = 2000;
345 	int intc;
346 
347 	intc = pspSdkDisableInterrupts();
348 
349 	time1 = PspRtc::instance().getMicros();
350 	for (int i=0; i<iterations; i++) {
351 		PspMemory::fastCopy(dst, src, bytes);
352 	}
353 	time2 = PspRtc::instance().getMicros();
354 
355 	pspSdkEnableInterrupts(intc);
356 
357 	fastcopyTime = time2-time1;
358 
359 	intc = pspSdkDisableInterrupts();
360 
361 	time1 = PspRtc::instance().getMicros();
362 	for (int i=0; i<iterations; i++) {
363 		memcpy(dst, src, bytes);
364 	}
365 	time2 = PspRtc::instance().getMicros();
366 
367 	pspSdkEnableInterrupts(intc);
368 
369 	memcpyTime = time2-time1;
370 
371 	PSP_INFO_PRINT("%d bytes. memcpy[%d], fastcopy[%d]\n", bytes, memcpyTime, fastcopyTime);
372 }
373 
fastCopyDifferentSizes(byte * dst,byte * src)374 void PspSpeedTests::fastCopyDifferentSizes(byte *dst, byte *src) {
375 	PSP_INFO_PRINT("\nsrc[%p], dst[%p]\n", src, dst);
376 	fastCopySpecificSize(dst, src, 1);
377 	fastCopySpecificSize(dst, src, 2);
378 	fastCopySpecificSize(dst, src, 3);
379 	fastCopySpecificSize(dst, src, 4);
380 	fastCopySpecificSize(dst, src, 5);
381 	fastCopySpecificSize(dst, src, 8);
382 	fastCopySpecificSize(dst, src, 10);
383 	fastCopySpecificSize(dst, src, 16);
384 	fastCopySpecificSize(dst, src, 32);
385 	fastCopySpecificSize(dst, src, 50);
386 	fastCopySpecificSize(dst, src, 100);
387 	fastCopySpecificSize(dst, src, 500);
388 	fastCopySpecificSize(dst, src, 1024);
389 	fastCopySpecificSize(dst, src, 2048);
390 }
391 
fastCopySpeed()392 void PspSpeedTests::fastCopySpeed() {
393 	PSP_INFO_PRINT("running fastCopy speed test\n");
394 
395 	uint32 *bufferSrc32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE);
396 	uint32 *bufferDst32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE);
397 
398 	// fill buffer 1
399 	for (int i=0; i<MEMCPY_BUFFER_SIZE/4; i++)
400 		bufferSrc32[i] = i | (((MEMCPY_BUFFER_SIZE/4)-i)<<16);
401 
402 	// print buffer
403 	for (int i=0; i<50; i++)
404 		PSP_INFO_PRINT("%x ", bufferSrc32[i]);
405 	PSP_INFO_PRINT("\n");
406 
407 	byte *bufferSrc = ((byte *)bufferSrc32);
408 	byte *bufferDst = ((byte *)bufferDst32);
409 
410 	PSP_INFO_PRINT("\n\ndst and src cached: -----------------\n");
411 	fastCopyDifferentSizes(bufferDst, bufferSrc);
412 	fastCopyDifferentSizes(bufferDst+1, bufferSrc+1);
413 	fastCopyDifferentSizes(bufferDst, bufferSrc+1);
414 	fastCopyDifferentSizes(bufferDst+1, bufferSrc);
415 
416 	PSP_INFO_PRINT("\n\ndst cached, src uncached: -----------------\n");
417 	bufferSrc = UNCACHED(bufferSrc);
418 	fastCopyDifferentSizes(bufferDst, bufferSrc);
419 	fastCopyDifferentSizes(bufferDst+1, bufferSrc+1);
420 	fastCopyDifferentSizes(bufferDst, bufferSrc+1);
421 	fastCopyDifferentSizes(bufferDst+1, bufferSrc);
422 
423 	PSP_INFO_PRINT("\n\ndst uncached, src uncached: --------------\n");
424 	bufferDst = UNCACHED(bufferDst);
425 	fastCopyDifferentSizes(bufferDst, bufferSrc);
426 	fastCopyDifferentSizes(bufferDst+1, bufferSrc+1);
427 	fastCopyDifferentSizes(bufferDst, bufferSrc+1);
428 	fastCopyDifferentSizes(bufferDst+1, bufferSrc);
429 
430 	PSP_INFO_PRINT("\n\ndst uncached, src cached: -------------------\n");
431 	bufferSrc = CACHED(bufferSrc);
432 	fastCopyDifferentSizes(bufferDst, bufferSrc);
433 	fastCopyDifferentSizes(bufferDst+1, bufferSrc+1);
434 	fastCopyDifferentSizes(bufferDst, bufferSrc+1);
435 	fastCopyDifferentSizes(bufferDst+1, bufferSrc);
436 
437 
438 	free(bufferSrc32);
439 	free(bufferDst32);
440 }
441 
442 //-------Unit Tests -------------------------------
443 
444 class PspUnitTests {
445 public:
446 	void testFastCopy();
447 	bool testFileSystem();
448 
449 private:
450 	enum {
451 		MEMCPY_BUFFER_SIZE = 8192
452 	};
453 
454 	void fastCopySpecificSize(byte *dst, byte *src, uint32 bytes, bool swap = false);
455 	void fastCopyDifferentSizes(byte *dst, byte *src, bool swap = false);
456 
457 };
458 
testFastCopy()459 void PspUnitTests::testFastCopy() {
460 	PSP_INFO_PRINT("running fastcopy unit test ***********\n");
461 	PSP_INFO_PRINT("this test requires the test flag to be on in fastCopy\n\n");
462 
463 	uint32 *bufferSrc32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE);
464 	uint32 *bufferDst32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE);
465 
466 	// fill buffer 1
467 	for (int i=0; i<MEMCPY_BUFFER_SIZE/4; i++)
468 		bufferSrc32[i] = i | (((MEMCPY_BUFFER_SIZE/4)-i)<<16);
469 
470 	// print buffer
471 	for (int i=0; i<50; i++)
472 		PSP_INFO_PRINT("%x ", bufferSrc32[i]);
473 	PSP_INFO_PRINT("\n");
474 
475 	byte *bufferSrc = ((byte *)bufferSrc32);
476 	byte *bufferDst = ((byte *)bufferDst32);
477 
478 	fastCopyDifferentSizes(bufferDst, bufferSrc, true);
479 	fastCopyDifferentSizes(bufferDst+1, bufferSrc+1);
480 	fastCopyDifferentSizes(bufferDst+2, bufferSrc+2, true);
481 	fastCopyDifferentSizes(bufferDst+3, bufferSrc+3);
482 	fastCopyDifferentSizes(bufferDst, bufferSrc+1);
483 	fastCopyDifferentSizes(bufferDst, bufferSrc+2, true);
484 	fastCopyDifferentSizes(bufferDst+2, bufferSrc, true);
485 	fastCopyDifferentSizes(bufferDst, bufferSrc+3);
486 	fastCopyDifferentSizes(bufferDst+1, bufferSrc+2);
487 	fastCopyDifferentSizes(bufferDst+1, bufferSrc+3);
488 	fastCopyDifferentSizes(bufferDst+2, bufferSrc+1);
489 	fastCopyDifferentSizes(bufferDst+2, bufferSrc+3);
490 	fastCopyDifferentSizes(bufferDst+3, bufferSrc+1);
491 	fastCopyDifferentSizes(bufferDst+3, bufferSrc+2);
492 
493 	free(bufferSrc32);
494 	free(bufferDst32);
495 }
496 
fastCopyDifferentSizes(byte * dst,byte * src,bool swap)497 void PspUnitTests::fastCopyDifferentSizes(byte *dst, byte *src, bool swap) {
498 	fastCopySpecificSize(dst, src, 1);
499 	fastCopySpecificSize(dst, src, 2, swap);
500 	fastCopySpecificSize(dst, src, 4, swap);
501 	fastCopySpecificSize(dst, src, 6, swap);
502 	fastCopySpecificSize(dst, src, 8, swap);
503 	fastCopySpecificSize(dst, src, 9);
504 	fastCopySpecificSize(dst, src, 10, swap);
505 	fastCopySpecificSize(dst, src, 11);
506 	fastCopySpecificSize(dst, src, 12, swap);
507 	fastCopySpecificSize(dst, src, 13);
508 	fastCopySpecificSize(dst, src, 14, swap);
509 	fastCopySpecificSize(dst, src, 15);
510 	fastCopySpecificSize(dst, src, 16, swap);
511 	fastCopySpecificSize(dst, src, 17);
512 	fastCopySpecificSize(dst, src, 18, swap);
513 	fastCopySpecificSize(dst, src, 19);
514 	fastCopySpecificSize(dst, src, 20, swap);
515 	fastCopySpecificSize(dst, src, 32, swap);
516 	fastCopySpecificSize(dst, src, 33);
517 	fastCopySpecificSize(dst, src, 34, swap);
518 	fastCopySpecificSize(dst, src, 35);
519 	fastCopySpecificSize(dst, src, 36, swap);
520 	fastCopySpecificSize(dst, src, 50, swap);
521 	fastCopySpecificSize(dst, src, 100, swap);
522 	fastCopySpecificSize(dst, src, 500, swap);
523 	fastCopySpecificSize(dst, src, 1000, swap);
524 }
525 
fastCopySpecificSize(byte * dst,byte * src,uint32 bytes,bool swap)526 void PspUnitTests::fastCopySpecificSize(byte *dst, byte *src, uint32 bytes, bool swap) {
527 	memset(dst, 0, bytes);
528 	PspMemory::fastCopy(dst, src, bytes);
529 
530 	if (swap) {	// test swap also
531 		memset(dst, 0, bytes);
532 
533 		// pixelformat for swap
534 		PSPPixelFormat format;
535 		format.set(PSPPixelFormat::Type_4444, true);
536 
537 		PspMemory::fastSwap(dst, src, bytes, format);
538 	}
539 }
540 
541 // This function leaks. For now I don't care
testFileSystem()542 bool PspUnitTests::testFileSystem() {
543 	// create memory
544 	const uint32 BufSize = 32 * 1024;
545 	char* buffer = new char[BufSize];
546 	int i;
547 	Common::WriteStream *wrStream;
548 	Common::SeekableReadStream *rdStream;
549 
550 	PSP_INFO_PRINT("testing fileSystem...\n");
551 
552 	// fill buffer
553 	for (i=0; i<(int)BufSize; i += 4) {
554 		buffer[i] = 'A';
555 		buffer[i + 1] = 'B';
556 		buffer[i + 2] = 'C';
557 		buffer[i + 3] = 'D';
558 	}
559 
560 	// create a file
561 	const char *path = "./file.test";
562 	Common::FSNode file(path);
563 
564 	PSP_INFO_PRINT("creating write stream...\n");
565 
566 	wrStream = file.createWriteStream();
567 	if (!wrStream) {
568 		PSP_ERROR("%s couldn't be created.\n", path);
569 		delete[] buffer;
570 		return false;
571 	}
572 
573 	// write contents
574 	char* index = buffer;
575 	int32 totalLength = BufSize;
576 	int32 curLength = 50;
577 
578 	PSP_INFO_PRINT("writing...\n");
579 
580 	while(totalLength - curLength > 0) {
581 		if ((int)wrStream->write(index, curLength) != curLength) {
582 			PSP_ERROR("couldn't write %d bytes\n", curLength);
583 			delete[] buffer;
584 			delete wrStream;
585 			return false;
586 		}
587 		totalLength -= curLength;
588 		index += curLength;
589 		//curLength *= 2;
590 		//PSP_INFO_PRINT("write\n");
591 	}
592 
593 	// write the rest
594 	if ((int)wrStream->write(index, totalLength) != totalLength) {
595 		PSP_ERROR("couldn't write %d bytes\n", curLength);
596 		delete[] buffer;
597 		delete wrStream;
598 		return false;
599 	}
600 
601 	delete wrStream;
602 
603 	PSP_INFO_PRINT("reading...\n");
604 
605 	rdStream = file.createReadStream();
606 	if (!rdStream) {
607 		PSP_ERROR("%s couldn't be created.\n", path);
608 		delete[] buffer;
609 		return false;
610 	}
611 
612 	// seek to beginning
613 	if (!rdStream->seek(0, SEEK_SET)) {
614 		PSP_ERROR("couldn't seek to the beginning after writing the file\n");
615 		delete[] buffer;
616 		delete rdStream;
617 		return false;
618 	}
619 
620 	// read the contents
621 	char *readBuffer = new char[BufSize + 4];
622 	memset(readBuffer, 0, (BufSize + 4));
623 	index = readBuffer;
624 	while (rdStream->read(index, 100) == 100) {
625 		index += 100;
626 	}
627 
628 	if (!rdStream->eos()) {
629 		PSP_ERROR("didn't find EOS at end of stream\n");
630 		delete[] buffer;
631 		delete rdStream;
632 		delete[] readBuffer;
633 		return false;
634 	}
635 
636 	// compare
637 	for (i=0; i<(int)BufSize; i++)
638 		if (buffer[i] != readBuffer[i]) {
639 			PSP_ERROR("reading/writing mistake at %x. Got %x instead of %x\n", i, readBuffer[i], buffer[i]);
640 			delete[] buffer;
641 			delete rdStream;
642 			delete[] readBuffer;
643 			return false;
644 		}
645 
646 	// Check for exceeding limit
647 	for (i=0; i<4; i++) {
648 		if (readBuffer[BufSize + i]) {
649 			PSP_ERROR("read exceeded limits. %d = %x\n", BufSize + i, readBuffer[BufSize + i]);
650 		}
651 	}
652 
653 	delete[] buffer;
654 	delete rdStream;
655 	delete[] readBuffer;
656 
657 	PSP_INFO_PRINT("writing...\n");
658 
659 	wrStream = file.createWriteStream();
660 	if (!wrStream) {
661 		PSP_ERROR("%s couldn't be created.\n", path);
662 		return false;
663 	}
664 
665 	const char *phrase = "Jello is really fabulous";
666 	uint32 phraseLen = strlen(phrase);
667 
668 	int ret;
669 	if ((ret = wrStream->write(phrase, phraseLen)) != (int)phraseLen) {
670 		PSP_ERROR("couldn't write phrase. Got %d instead of %d\n", ret, phraseLen);
671 		delete wrStream;
672 		return false;
673 	}
674 
675 	PSP_INFO_PRINT("reading...\n");
676 
677 	delete wrStream;
678 
679 	rdStream = file.createReadStream();
680 	if (!rdStream) {
681 		PSP_ERROR("%s couldn't be created.\n", path);
682 		return false;
683 	}
684 
685 	char *readPhrase = new char[phraseLen + 2];
686 	memset(readPhrase, 0, phraseLen + 2);
687 
688 	if ((ret = rdStream->read(readPhrase, phraseLen) != phraseLen)) {
689 		PSP_ERROR("read error on phrase. Got %d instead of %d\n", ret, phraseLen);
690 		delete rdStream;
691 		delete[] readPhrase;
692 		return false;
693 	}
694 
695 	for (i=0; i<(int)phraseLen; i++) {
696 		if (readPhrase[i] != phrase[i]) {
697 			PSP_ERROR("bad read/write in phrase. At %d, %x != %x\n", i, readPhrase[i], phrase[i]);
698 			delete rdStream;
699 			delete[] readPhrase;
700 			return false;
701 		}
702 	}
703 
704 	// check for exceeding
705 	if (readPhrase[i] != 0) {
706 		PSP_ERROR("found excessive copy in phrase. %c at %d\n", readPhrase[i], i);
707 		delete rdStream;
708 		delete[] readPhrase;
709 		return false;
710 	}
711 
712 	PSP_INFO_PRINT("trying to read end...\n");
713 
714 	// seek to end
715 	if (!rdStream->seek(0, SEEK_END)) {
716 		PSP_ERROR("couldn't seek to end for append\n");
717 		delete rdStream;
718 		delete[] readPhrase;
719 		return false;
720 	};
721 
722 	// try to read
723 	if (rdStream->read(readPhrase, 2) || !rdStream->eos()) {
724 		PSP_ERROR("was able to read at end of file\n");
725 		delete rdStream;
726 		delete[] readPhrase;
727 		return false;
728 	}
729 
730 	delete rdStream;
731 	delete[] readPhrase;
732 
733 	PSP_INFO_PRINT("ok\n");
734 	return true;
735 }
736 
psp_tests()737 void psp_tests() {
738 	PSP_INFO_PRINT("in tests\n");
739 
740 #ifdef PSP_ENABLE_SPEED_TESTS
741 	// Speed tests
742 	PspSpeedTests speedTests;
743 	speedTests.tickSpeed();
744 	speedTests.getMicrosSpeed();
745 	speedTests.msReadSpeed();
746 	speedTests.seekSpeed();
747 	speedTests.msReadSpeed();
748 	speedTests.threadFunctionsSpeed();
749 	speedTests.semaphoreSpeed();
750 	speedTests.semaphoreManyThreadSpeed();
751 	speedTests.fastCopySpeed();
752 #endif
753 
754 #ifdef PSP_ENABLE_UNIT_TESTS
755 	// Unit tests
756 	PspUnitTests unitTests;
757 
758 	//unitTests.testFastCopy();
759 	unitTests.testFileSystem();
760 #endif
761 }
762 
763 #endif /* (PSP_ENABLE_UNIT_TESTS) || defined(PSP_ENABLE_SPEED_TESTS) */
764