Home | History | Annotate | Download | only in sdcard
      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