/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ // PSP speed and unit tests. Activate in tests.h // You may also want to build without any engines. #include "backends/platform/psp/tests.h" #if defined(PSP_ENABLE_UNIT_TESTS) || defined(PSP_ENABLE_SPEED_TESTS) #include "common/scummsys.h" #include #include #include #include #include #include #include #include #include #include "backends/platform/psp/rtc.h" #include "backends/platform/psp/thread.h" #include "backends/platform/psp/memory.h" #include "common/stream.h" #include "common/file.h" #include "common/fs.h" #define UNCACHED(x) ((byte *)(((uint32)(x)) | 0x40000000)) /* make an uncached access */ #define CACHED(x) ((byte *)(((uint32)(x)) & 0xBFFFFFFF)) /* make an uncached access into a cached one */ //#define __PSP_DEBUG_FUNCS__ //#define __PSP_DEBUG_PRINT__ // Results: (333Mhz/222Mhz) // Getting a tick: 1-2 us // Getting a time structure: 9/14us // ie. using a tick and just dividing by 1000 saves us time. #include "backends/platform/psp/trace.h" class PspSpeedTests { public: void tickSpeed(); void getMicrosSpeed(); void seekSpeed(); void msReadSpeed(); void threadFunctionsSpeed(); void semaphoreSpeed(); static int threadFunc(SceSize args, void *argp); void semaphoreManyThreadSpeed(); void fastCopySpeed(); private: enum { MEMCPY_BUFFER_SIZE = 8192 }; static PspSemaphore _sem; // semaphore void readAndTime(uint32 bytes, char *buffer, FILE *file); void seekAndTime(int bytes, int origin, FILE *file); void fastCopySpecificSize(byte *dst, byte *src, uint32 bytes); void fastCopyDifferentSizes(byte *dst, byte *src); int getThreadIdSpeed(); void getPrioritySpeed(); void changePrioritySpeed(int id, int priority); }; PspSemaphore PspSpeedTests::_sem(0); void PspSpeedTests::tickSpeed() { uint32 ticksPerSecond = sceRtcGetTickResolution(); PSP_INFO_PRINT("ticksPerSecond[%d]\n", ticksPerSecond); uint32 currentTicks1[2]; uint32 currentTicks2[2]; sceRtcGetCurrentTick((u64 *)currentTicks1); sceRtcGetCurrentTick((u64 *)currentTicks2); PSP_INFO_PRINT("current tick[%x %x][%u %u]\n", currentTicks1[0], currentTicks1[1], currentTicks1[0], currentTicks1[1]); PSP_INFO_PRINT("current tick[%x %x][%u %u]\n", currentTicks2[0], currentTicks2[1], currentTicks2[0], currentTicks2[1]); pspTime time; sceRtcSetTick(&time, (u64 *)currentTicks2); 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); pspTime time1; pspTime time2; sceRtcGetCurrentClockLocalTime(&time1); sceRtcGetCurrentClockLocalTime(&time2); 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); 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); } void PspSpeedTests::getMicrosSpeed() { uint32 time1, time2, time3, time4; time1 = PspRtc::instance().getMicros(); time2 = PspRtc::instance().getMicros(); time3 = PspRtc::instance().getMicros(); time4 = PspRtc::instance().getMicros(); PSP_INFO_PRINT("getMicros() times: %d, %d, %d\n", time4-time3, time3-time2, time2-time1); } void PspSpeedTests::readAndTime(uint32 bytes, char *buffer, FILE *file) { uint32 time1 = PspRtc::instance().getMicros(); // test minimal read fread(buffer, bytes, 1, file); uint32 time2 = PspRtc::instance().getMicros(); PSP_INFO_PRINT("Reading %d byte takes %dus\n", bytes, time2-time1); } /* 333MHz/222MHz Reading 1 byte takes 2590us / 3167 Reading 10 byte takes 8us / 9 Reading 50 byte takes 8us / 11 Reading 100 byte takes 8us / 11 Reading 1000 byte takes 915us / 1131 Reading 2000 byte takes 1806us / 2,284 Reading 3000 byte takes 2697us / 3,374 Reading 5000 byte takes 4551us / 5,544 Reading 6000 byte takes 5356us / 6,676 Reading 7000 byte takes 6800us / 8,358 Reading 8000 byte takes 6794us / 8,454 Reading 9000 byte takes 6782us / 8,563 Reading 10000 byte takes 8497us / 10,631 Reading 30000 byte takes 25995us / 32,473 Reading 80000 byte takes 68457us / 85,291 Reading 100000 byte takes 85103us / 106,163 */ // Function to test the impact of MS reads // These tests can't be done from shell - the cache screws them up void PspSpeedTests::msReadSpeed() { FILE *file; file = fopen("ms0:/psp/music/track1.mp3", "r"); char *buffer = (char *)malloc(2 * 1024 * 1024); readAndTime(1, buffer, file); readAndTime(10, buffer, file); readAndTime(50, buffer, file); readAndTime(100, buffer, file); readAndTime(1000, buffer, file); readAndTime(2000, buffer, file); readAndTime(3000, buffer, file); readAndTime(5000, buffer, file); readAndTime(6000, buffer, file); readAndTime(7000, buffer, file); readAndTime(8000, buffer, file); readAndTime(9000, buffer, file); readAndTime(10000, buffer, file); readAndTime(30000, buffer, file); readAndTime(50000, buffer, file); readAndTime(80000, buffer, file); readAndTime(100000, buffer, file); fclose(file); free(buffer); } void PspSpeedTests::seekAndTime(int bytes, int origin, FILE *file) { char buffer[1000]; uint32 time1 = PspRtc::instance().getMicros(); // test minimal read fseek(file, bytes, origin); uint32 time2 = PspRtc::instance().getMicros(); PSP_INFO_PRINT("Seeking %d byte from %d took %dus\n", bytes, origin, time2-time1); time1 = PspRtc::instance().getMicros(); // test minimal read fread(buffer, 1000, 1, file); time2 = PspRtc::instance().getMicros(); PSP_INFO_PRINT("Reading 1000 bytes took %dus\n", time2-time1); } /* 333MHz Seeking 0 byte from 0 took 946us Reading 1000 bytes took 1781us Seeking 5 byte from 0 took 6us Reading 1000 bytes took 19us Seeking 1000 byte from 0 took 5us Reading 1000 bytes took 913us Seeking 100 byte from 0 took 955us Reading 1000 bytes took 906us Seeking 10000 byte from 0 took 963us Reading 1000 bytes took 905us Seeking -5 byte from 1 took 1022us Reading 1000 bytes took 949us Seeking -100 byte from 1 took 1040us Reading 1000 bytes took 907us Seeking 100 byte from 1 took 1044us Reading 1000 bytes took 930us Seeking 0 byte from 2 took 7211us Reading 1000 bytes took 80us Seeking 10000 byte from 2 took 3636us Reading 1000 bytes took 110us */ void PspSpeedTests::seekSpeed() { FILE *file; file = fopen("ms0:/psp/music/track1.mp3", "r"); seekAndTime(0, SEEK_SET, file); seekAndTime(5, SEEK_SET, file); seekAndTime(1000, SEEK_SET, file); seekAndTime(100, SEEK_SET, file); seekAndTime(10000, SEEK_SET, file); seekAndTime(-5, SEEK_CUR, file); seekAndTime(-100, SEEK_CUR, file); seekAndTime(100, SEEK_CUR, file); seekAndTime(0, SEEK_END, file); seekAndTime(-10000, SEEK_END, file); fclose(file); } // 222: 5-7us int PspSpeedTests::getThreadIdSpeed() { uint32 time1 = PspRtc::instance().getMicros(); int threadId = sceKernelGetThreadId(); uint32 time2 = PspRtc::instance().getMicros(); PSP_INFO_PRINT("Getting thread ID %d took %dus\n", threadId, time2-time1); return threadId; } // 222: 4-5us void PspSpeedTests::getPrioritySpeed() { uint32 time1 = PspRtc::instance().getMicros(); int priority = sceKernelGetThreadCurrentPriority(); uint32 time2 = PspRtc::instance().getMicros(); PSP_INFO_PRINT("Getting thread priority %d took %dus\n", priority, time2-time1); } // 222: 9-10us void PspSpeedTests::changePrioritySpeed(int id, int priority) { uint32 time1 = PspRtc::instance().getMicros(); sceKernelChangeThreadPriority(id, priority); uint32 time2 = PspRtc::instance().getMicros(); PSP_INFO_PRINT("Changing thread priority to %d for id %d took %dus\n", priority, id, time2-time1); } void PspSpeedTests::threadFunctionsSpeed() { // very unscientific -- just ballpark int id; id = getThreadIdSpeed(); getThreadIdSpeed(); getPrioritySpeed(); getPrioritySpeed(); changePrioritySpeed(id, 30); changePrioritySpeed(id, 35); changePrioritySpeed(id, 25); // test context switch time for (int i=0; i<10; i++) { uint time1 = PspRtc::instance().getMicros(); PspThread::delayMicros(0); uint time2 = PspRtc::instance().getMicros(); PSP_INFO_PRINT("poll %d. context switch Time = %dus\n", i, time2-time1); // 10-15us } } void PspSpeedTests::semaphoreSpeed() { PspSemaphore sem(1); uint32 time1 = PspRtc::instance().getMicros(); sem.take(); uint32 time2 = PspRtc::instance().getMicros(); PSP_INFO_PRINT("taking semaphore took %d us\n", time2-time1); // 10us uint32 time3 = PspRtc::instance().getMicros(); sem.give(); uint32 time4 = PspRtc::instance().getMicros(); PSP_INFO_PRINT("releasing semaphore took %d us\n", time4-time3); //10us-55us } int PspSpeedTests::threadFunc(SceSize args, void *argp) { PSP_INFO_PRINT("thread %x created.\n", sceKernelGetThreadId()); _sem.take(); PSP_INFO_PRINT("grabbed semaphore. Quitting thread\n"); return 0; } void PspSpeedTests::semaphoreManyThreadSpeed() { // create 4 threads for (int i=0; i<4; i++) { int thid = sceKernelCreateThread("my_thread", PspSpeedTests::threadFunc, 0x18, 0x10000, THREAD_ATTR_USER, NULL); sceKernelStartThread(thid, 0, 0); } PSP_INFO_PRINT("main thread. created threads\n"); uint32 threads = _sem.numOfWaitingThreads(); while (threads < 4) { threads = _sem.numOfWaitingThreads(); PSP_INFO_PRINT("main thread: waiting threads[%d]\n", threads); } PSP_INFO_PRINT("main: semaphore value[%d]\n", _sem.getValue()); PSP_INFO_PRINT("main thread: waiting threads[%d]\n", _sem.numOfWaitingThreads()); _sem.give(4); } void PspSpeedTests::fastCopySpecificSize(byte *dst, byte *src, uint32 bytes) { uint32 time1, time2; uint32 fastcopyTime, memcpyTime; const int iterations = 2000; int intc; intc = pspSdkDisableInterrupts(); time1 = PspRtc::instance().getMicros(); for (int i=0; i 0) { if ((int)wrStream->write(index, curLength) != curLength) { PSP_ERROR("couldn't write %d bytes\n", curLength); delete[] buffer; delete wrStream; return false; } totalLength -= curLength; index += curLength; //curLength *= 2; //PSP_INFO_PRINT("write\n"); } // write the rest if ((int)wrStream->write(index, totalLength) != totalLength) { PSP_ERROR("couldn't write %d bytes\n", curLength); delete[] buffer; delete wrStream; return false; } delete wrStream; PSP_INFO_PRINT("reading...\n"); rdStream = file.createReadStream(); if (!rdStream) { PSP_ERROR("%s couldn't be created.\n", path); delete[] buffer; return false; } // seek to beginning if (!rdStream->seek(0, SEEK_SET)) { PSP_ERROR("couldn't seek to the beginning after writing the file\n"); delete[] buffer; delete rdStream; return false; } // read the contents char *readBuffer = new char[BufSize + 4]; memset(readBuffer, 0, (BufSize + 4)); index = readBuffer; while (rdStream->read(index, 100) == 100) { index += 100; } if (!rdStream->eos()) { PSP_ERROR("didn't find EOS at end of stream\n"); delete[] buffer; delete rdStream; delete[] readBuffer; return false; } // compare for (i=0; i<(int)BufSize; i++) if (buffer[i] != readBuffer[i]) { PSP_ERROR("reading/writing mistake at %x. Got %x instead of %x\n", i, readBuffer[i], buffer[i]); delete[] buffer; delete rdStream; delete[] readBuffer; return false; } // Check for exceeding limit for (i=0; i<4; i++) { if (readBuffer[BufSize + i]) { PSP_ERROR("read exceeded limits. %d = %x\n", BufSize + i, readBuffer[BufSize + i]); } } delete[] buffer; delete rdStream; delete[] readBuffer; PSP_INFO_PRINT("writing...\n"); wrStream = file.createWriteStream(); if (!wrStream) { PSP_ERROR("%s couldn't be created.\n", path); return false; } const char *phrase = "Jello is really fabulous"; uint32 phraseLen = strlen(phrase); int ret; if ((ret = wrStream->write(phrase, phraseLen)) != (int)phraseLen) { PSP_ERROR("couldn't write phrase. Got %d instead of %d\n", ret, phraseLen); delete wrStream; return false; } PSP_INFO_PRINT("reading...\n"); delete wrStream; rdStream = file.createReadStream(); if (!rdStream) { PSP_ERROR("%s couldn't be created.\n", path); return false; } char *readPhrase = new char[phraseLen + 2]; memset(readPhrase, 0, phraseLen + 2); if ((ret = rdStream->read(readPhrase, phraseLen) != phraseLen)) { PSP_ERROR("read error on phrase. Got %d instead of %d\n", ret, phraseLen); delete rdStream; delete[] readPhrase; return false; } for (i=0; i<(int)phraseLen; i++) { if (readPhrase[i] != phrase[i]) { PSP_ERROR("bad read/write in phrase. At %d, %x != %x\n", i, readPhrase[i], phrase[i]); delete rdStream; delete[] readPhrase; return false; } } // check for exceeding if (readPhrase[i] != 0) { PSP_ERROR("found excessive copy in phrase. %c at %d\n", readPhrase[i], i); delete rdStream; delete[] readPhrase; return false; } PSP_INFO_PRINT("trying to read end...\n"); // seek to end if (!rdStream->seek(0, SEEK_END)) { PSP_ERROR("couldn't seek to end for append\n"); delete rdStream; delete[] readPhrase; return false; }; // try to read if (rdStream->read(readPhrase, 2) || !rdStream->eos()) { PSP_ERROR("was able to read at end of file\n"); delete rdStream; delete[] readPhrase; return false; } delete rdStream; delete[] readPhrase; PSP_INFO_PRINT("ok\n"); return true; } void psp_tests() { PSP_INFO_PRINT("in tests\n"); #ifdef PSP_ENABLE_SPEED_TESTS // Speed tests PspSpeedTests speedTests; speedTests.tickSpeed(); speedTests.getMicrosSpeed(); speedTests.msReadSpeed(); speedTests.seekSpeed(); speedTests.msReadSpeed(); speedTests.threadFunctionsSpeed(); speedTests.semaphoreSpeed(); speedTests.semaphoreManyThreadSpeed(); speedTests.fastCopySpeed(); #endif #ifdef PSP_ENABLE_UNIT_TESTS // Unit tests PspUnitTests unitTests; //unitTests.testFastCopy(); unitTests.testFileSystem(); #endif } #endif /* (PSP_ENABLE_UNIT_TESTS) || defined(PSP_ENABLE_SPEED_TESTS) */