1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include "testcase.h" 30 #include <hardware_legacy/power.h> // wake lock 31 #include <sys/types.h> 32 #include <sys/wait.h> 33 #include <unistd.h> 34 #include <linux/fadvise.h> 35 36 namespace { 37 const bool kVerbose = false; 38 } 39 40 namespace android_test { 41 42 TestCase::TestCase(const char *appName) 43 : mTestBody(NULL), mAppName(appName), mDataSize(1000 * 1000), 44 mChunkSize(mDataSize), mTreeDepth(8), mIter(20), mNproc(1), 45 mType(UNKNOWN_TEST), mDump(false), mCpuScaling(false), 46 mSync(NO_SYNC), mFadvice(POSIX_FADV_NORMAL), mTruncateToSize(false), 47 mTestTimer(NULL) 48 { 49 // Make sure the cpu and phone are fully awake. The 50 // FULL_WAKE_LOCK was used by java apps and don't do 51 // anything. Also the partial wake lock is a nop if the phone 52 // is plugged in via USB. 53 acquire_wake_lock(PARTIAL_WAKE_LOCK, mAppName); 54 mPid = getpid(); 55 setNewFairSleepers(true); 56 setNormalizedSleepers(true); 57 if (pipe(mIpc) < 0) 58 { 59 fprintf(stderr, "pipe failed\n"); 60 exit(1); 61 } 62 if (pipe(mIpc + 2) < 0) 63 { 64 fprintf(stderr, "pipe failed\n"); 65 exit(1); 66 } 67 } 68 69 TestCase::~TestCase() 70 { 71 release_wake_lock(mAppName); 72 for (int i = 0; i < 4; ++i) close(mIpc[i]); 73 delete mTestTimer; 74 delete mOpenTimer; 75 } 76 77 78 bool TestCase::runTest() 79 { 80 if (UNKNOWN_TEST == mType) 81 { 82 fprintf(stderr, "No test set."); 83 return false; 84 } 85 for (size_t p = 0; p < mNproc; ++p) 86 { 87 pid_t childpid = android::forkOrExit(); 88 89 if (0 == childpid) { // I am a child, run the test. 90 mPid = getpid(); 91 close(mIpc[READ_FROM_CHILD]); 92 close(mIpc[WRITE_TO_CHILD]); 93 94 if (kVerbose) printf("Child pid: %d\n", mPid); 95 if (!mTestBody(this)) { 96 printf("Test failed\n"); 97 } 98 char buffer[32000] = {0,}; 99 char *str = buffer; 100 size_t size_left = sizeof(buffer); 101 102 testTimer()->sprint(&str, &size_left); 103 if(openTimer()->used()) openTimer()->sprint(&str, &size_left); 104 if(readTimer()->used()) readTimer()->sprint(&str, &size_left); 105 if(writeTimer()->used()) writeTimer()->sprint(&str, &size_left); 106 if(syncTimer()->used()) syncTimer()->sprint(&str, &size_left); 107 if(truncateTimer()->used()) truncateTimer()->sprint(&str, &size_left); 108 if(traverseTimer()->used()) traverseTimer()->sprint(&str, &size_left); 109 110 write(mIpc[TestCase::WRITE_TO_PARENT], buffer, str - buffer); 111 112 113 close(mIpc[WRITE_TO_PARENT]); 114 close(mIpc[READ_FROM_PARENT]); 115 exit(EXIT_SUCCESS); 116 } 117 } 118 // I am the parent process 119 close(mIpc[WRITE_TO_PARENT]); 120 close(mIpc[READ_FROM_PARENT]); 121 122 // Block until all the children have reported for 123 // duty. Unblock them so they start the work. 124 if (!android::waitForChildrenAndSignal(mNproc, mIpc[READ_FROM_CHILD], mIpc[WRITE_TO_CHILD])) 125 { 126 exit(1); 127 } 128 129 // Process the output of each child. 130 // TODO: handle EINTR 131 char buffer[32000] = {0,}; 132 while(read(mIpc[READ_FROM_CHILD], buffer, sizeof(buffer)) != 0) 133 { 134 printf("%s", buffer); 135 fflush(stdout); 136 memset(buffer, 0, sizeof(buffer)); 137 } 138 // Parent is waiting for children to exit. 139 android::waitForChildrenOrExit(mNproc); 140 return true; 141 } 142 143 void TestCase::setIter(size_t iter) 144 { 145 mIter = iter; 146 } 147 148 void TestCase::createTimers() 149 { 150 char total_time[80]; 151 152 snprintf(total_time, sizeof(total_time), "%s_total", mName); 153 mTestTimer = new StopWatch(total_time, 1); 154 mTestTimer->setDataSize(dataSize()); 155 156 mOpenTimer = new StopWatch("open", iter() * kReadWriteFactor); 157 158 mReadTimer = new StopWatch("read", iter() * dataSize() / chunkSize() * kReadWriteFactor); 159 mReadTimer->setDataSize(dataSize()); 160 161 mWriteTimer = new StopWatch("write", iter() * dataSize() / chunkSize()); 162 mWriteTimer->setDataSize(dataSize()); 163 164 mSyncTimer = new StopWatch("sync", iter()); 165 166 mTruncateTimer = new StopWatch("truncate", iter()); 167 168 mTraverseTimer = new StopWatch("traversal", iter()); 169 } 170 171 bool TestCase::setTypeFromName(const char *test_name) 172 { 173 strcpy(mName, test_name); 174 if (strcmp(mName, "write") == 0) mType = WRITE; 175 if (strcmp(mName, "read") == 0) mType = READ; 176 if (strcmp(mName, "read_write") == 0) mType = READ_WRITE; 177 if (strcmp(mName, "open_create") == 0) mType = OPEN_CREATE; 178 if (strcmp(mName, "traverse") == 0) mType = TRAVERSE; 179 180 return UNKNOWN_TEST != mType; 181 } 182 183 void TestCase::setSync(Sync s) 184 { 185 mSync = s; 186 } 187 188 const char *TestCase::syncAsStr() const 189 { 190 return mSync == NO_SYNC ? "disabled" : (mSync == FSYNC ? "fsync" : "sync"); 191 } 192 193 void TestCase::setFadvise(const char *advice) 194 { 195 mFadvice = POSIX_FADV_NORMAL; 196 if (strcmp(advice, "sequential") == 0) 197 { 198 mFadvice = POSIX_FADV_SEQUENTIAL; 199 } 200 else if (strcmp(advice, "random") == 0) 201 { 202 mFadvice = POSIX_FADV_RANDOM; 203 } 204 else if (strcmp(advice, "noreuse") == 0) 205 { 206 mFadvice = POSIX_FADV_NOREUSE; 207 } 208 else if (strcmp(advice, "willneed") == 0) 209 { 210 mFadvice = POSIX_FADV_WILLNEED; 211 } 212 else if (strcmp(advice, "dontneed") == 0) 213 { 214 mFadvice = POSIX_FADV_DONTNEED; 215 } 216 } 217 218 const char *TestCase::fadviseAsStr() const 219 { 220 switch (mFadvice) { 221 case POSIX_FADV_NORMAL: return "fadv_normal"; 222 case POSIX_FADV_SEQUENTIAL: return "fadv_sequential"; 223 case POSIX_FADV_RANDOM: return "fadv_random"; 224 case POSIX_FADV_NOREUSE: return "fadv_noreuse"; 225 case POSIX_FADV_WILLNEED: return "fadv_willneed"; 226 case POSIX_FADV_DONTNEED: return "fadv_dontneed"; 227 default: return "fadvice_unknown"; 228 } 229 } 230 231 232 } // namespace android_test 233