testcase.cpp revision e1b480b11c19f014a2a6ceddd28883275a4ba0e3
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
36namespace {
37const bool kVerbose = false;
38}
39
40namespace android_test {
41
42TestCase::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
69TestCase::~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
78bool 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
143void TestCase::setIter(size_t iter)
144{
145    mIter = iter;
146}
147
148void 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
171bool 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
183void TestCase::setSync(Sync s)
184{
185    mSync = s;
186}
187
188const char *TestCase::syncAsStr() const
189{
190    return mSync == NO_SYNC ? "disabled" : (mSync == FSYNC ? "fsync" : "sync");
191}
192
193void 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
218const 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