diff options
Diffstat (limited to 'tests/sdcard/testcase.cpp')
-rw-r--r-- | tests/sdcard/testcase.cpp | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/tests/sdcard/testcase.cpp b/tests/sdcard/testcase.cpp new file mode 100644 index 00000000..0de436f7 --- /dev/null +++ b/tests/sdcard/testcase.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "testcase.h" +#include <hardware_legacy/power.h> // wake lock +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <linux/fadvise.h> + +namespace { +const bool kVerbose = false; +} + +namespace android_test { + +TestCase::TestCase(const char *appName) + : mTestBody(NULL), mAppName(appName), mDataSize(1000 * 1000), + mChunkSize(mDataSize), mIter(20), mNproc(1), + mType(UNKNOWN_TEST), mDump(false), mCpuScaling(false), + mSync(NO_SYNC), mFadvice(POSIX_FADV_NORMAL), mTruncateToSize(false), + mTestTimer(NULL) +{ + // Make sure the cpu and phone are fully awake. The + // FULL_WAKE_LOCK was used by java apps and don't do + // anything. Also the partial wake lock is a nop if the phone + // is plugged in via USB. + acquire_wake_lock(PARTIAL_WAKE_LOCK, mAppName); + mPid = getpid(); + setNewFairSleepers(true); + setNormalizedSleepers(true); + if (pipe(mIpc) < 0) + { + fprintf(stderr, "pipe failed\n"); + exit(1); + } + if (pipe(mIpc + 2) < 0) + { + fprintf(stderr, "pipe failed\n"); + exit(1); + } +} + +TestCase::~TestCase() +{ + release_wake_lock(mAppName); + for (int i = 0; i < 4; ++i) close(mIpc[i]); + delete mTestTimer; + delete mOpenTimer; +} + + +bool TestCase::runTest() +{ + if (UNKNOWN_TEST == mType) + { + fprintf(stderr, "No test set."); + return false; + } + for (size_t p = 0; p < mNproc; ++p) + { + pid_t childpid = android::forkOrExit(); + + if (0 == childpid) { // I am a child, run the test. + mPid = getpid(); + close(mIpc[READ_FROM_CHILD]); + close(mIpc[WRITE_TO_CHILD]); + + if (kVerbose) printf("Child pid: %d\n", mPid); + if (!mTestBody(this)) { + printf("Test failed\n"); + } + char buffer[32000] = {0,}; + char *str = buffer; + size_t size_left = sizeof(buffer); + + testTimer()->sprint(&str, &size_left); + if(openTimer()->used()) openTimer()->sprint(&str, &size_left); + if(readTimer()->used()) readTimer()->sprint(&str, &size_left); + if(writeTimer()->used()) writeTimer()->sprint(&str, &size_left); + if(syncTimer()->used()) syncTimer()->sprint(&str, &size_left); + if(truncateTimer()->used()) truncateTimer()->sprint(&str, &size_left); + + write(mIpc[TestCase::WRITE_TO_PARENT], buffer, str - buffer); + + + close(mIpc[WRITE_TO_PARENT]); + close(mIpc[READ_FROM_PARENT]); + exit(EXIT_SUCCESS); + } + } + // I am the parent process + close(mIpc[WRITE_TO_PARENT]); + close(mIpc[READ_FROM_PARENT]); + + // Block until all the children have reported for + // duty. Unblock them so they start the work. + if (!android::waitForChildrenAndSignal(mNproc, mIpc[READ_FROM_CHILD], mIpc[WRITE_TO_CHILD])) + { + exit(1); + } + + // Process the output of each child. + // TODO: handle EINTR + char buffer[32000] = {0,}; + while(read(mIpc[READ_FROM_CHILD], buffer, sizeof(buffer)) != 0) + { + printf("%s", buffer); + fflush(stdout); + memset(buffer, 0, sizeof(buffer)); + } + // Parent is waiting for children to exit. + android::waitForChildrenOrExit(mNproc); + return true; +} + +void TestCase::setIter(size_t iter) +{ + mIter = iter; +} + +void TestCase::createTimers() +{ + char total_time[80]; + + snprintf(total_time, sizeof(total_time), "%s_total", mName); + mTestTimer = new StopWatch(total_time, 1); + mTestTimer->setDataSize(dataSize()); + + mOpenTimer = new StopWatch("open", iter() * kReadWriteFactor); + + mReadTimer = new StopWatch("read", iter() * dataSize() / chunkSize() * kReadWriteFactor); + mReadTimer->setDataSize(dataSize()); + + mWriteTimer = new StopWatch("write", iter() * dataSize() / chunkSize()); + mWriteTimer->setDataSize(dataSize()); + + mSyncTimer = new StopWatch("sync", iter()); + + mTruncateTimer = new StopWatch("truncate", iter()); +} + +bool TestCase::setTypeFromName(const char *test_name) +{ + strcpy(mName, test_name); + if (strcmp(mName, "write") == 0) mType = WRITE; + if (strcmp(mName, "read") == 0) mType = READ; + if (strcmp(mName, "read_write") == 0) mType = READ_WRITE; + if (strcmp(mName, "open_create") == 0) mType = OPEN_CREATE; + + return UNKNOWN_TEST != mType; +} + +void TestCase::setSync(Sync s) +{ + mSync = s; +} + +const char *TestCase::syncAsStr() const +{ + return mSync == NO_SYNC ? "disabled" : (mSync == FSYNC ? "fsync" : "sync"); +} + +void TestCase::setFadvise(const char *advice) +{ + mFadvice = POSIX_FADV_NORMAL; + if (strcmp(advice, "sequential") == 0) + { + mFadvice = POSIX_FADV_SEQUENTIAL; + } + else if (strcmp(advice, "random") == 0) + { + mFadvice = POSIX_FADV_RANDOM; + } + else if (strcmp(advice, "noreuse") == 0) + { + mFadvice = POSIX_FADV_NOREUSE; + } + else if (strcmp(advice, "willneed") == 0) + { + mFadvice = POSIX_FADV_WILLNEED; + } + else if (strcmp(advice, "dontneed") == 0) + { + mFadvice = POSIX_FADV_DONTNEED; + } +} + +const char *TestCase::fadviseAsStr() const +{ + switch (mFadvice) { + case POSIX_FADV_NORMAL: return "fadv_normal"; + case POSIX_FADV_SEQUENTIAL: return "fadv_sequential"; + case POSIX_FADV_RANDOM: return "fadv_random"; + case POSIX_FADV_NOREUSE: return "fadv_noreuse"; + case POSIX_FADV_WILLNEED: return "fadv_willneed"; + case POSIX_FADV_DONTNEED: return "fadv_dontneed"; + default: return "fadvice_unknown"; + } +} + + +} // namespace android_test |