rand_emmc_perf.c revision 32243fadeab8cf244861e3df89744b78ba3eff92
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* A simple test of emmc random read and write performance.  When testing write
18 * performance, try it twice, once with O_SYNC compiled in, and once with it commented
19 * out.  Without O_SYNC, the close(2) blocks until all the dirty buffers are written
20 * out, but the numbers tend to be higher.
21 */
22
23#define _LARGEFILE64_SOURCE
24#include <string.h>
25#include <stdio.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <sys/time.h>
30#include <stdlib.h>
31#include <unistd.h>
32
33#define TST_BLK_SIZE 4096
34/* Number of seconds to run the test */
35#define TEST_LEN 10
36
37static void usage(void) {
38        fprintf(stderr, "Usage: rand_emmc_perf [ -r | -w ] [-o] <size_in_mb> <block_dev>\n");
39        exit(1);
40}
41
42int main(int argc, char *argv[])
43{
44    long max_blocks;
45    int fd, fd2, write_mode = 0, iops = 0;
46    struct timeval start, end, res;
47    unsigned int seed;
48    char buf[TST_BLK_SIZE] = { 0 };
49    int c;
50    int o_sync = 0;
51
52    while ((c = getopt(argc, argv, "+rwo")) != -1) {
53        switch (c) {
54          case '?':
55          default:
56            usage();
57            break;
58
59          case 'r':
60            /* Do nothing, read mode is the default */
61            break;
62
63          case 'w':
64            write_mode = 1;
65            break;
66
67          case 'o':
68            o_sync = O_SYNC;
69            break;
70        }
71    }
72
73    if (o_sync && !write_mode) {
74        /* Can only specify o_sync in write mode.  Probably doesn't matter,
75         * but clear o_sync if in read mode */
76        o_sync = 0;
77    }
78
79    if ((argc - optind) != 2) {
80        usage();
81    }
82
83    /* Size is given in megabytes, so compute the number of TST_BLK_SIZE blocks. */
84    max_blocks = atol(argv[optind]) * ((1024*1024) / TST_BLK_SIZE);
85
86    if ((fd = open(argv[optind + 1], O_RDWR | o_sync)) < 0) {
87        fprintf(stderr, "Cannot open block device %s\n", argv[optind + 1]);
88        exit(1);
89    }
90
91    fd2 = open("/dev/urandom", O_RDONLY);
92    if (fd2 < 0) {
93        fprintf(stderr, "Cannot open /dev/urandom\n");
94    }
95    if (read(fd2, &seed, sizeof(seed)) != sizeof(seed)) {
96        fprintf(stderr, "Cannot read /dev/urandom\n");
97    }
98    close(fd2);
99    srand(seed);
100
101    res.tv_sec = 0;
102    gettimeofday(&start, 0);
103    while (res.tv_sec < TEST_LEN) {
104        if (lseek64(fd, (rand() % max_blocks) * TST_BLK_SIZE, SEEK_SET) < 0) {
105            fprintf(stderr, "lseek64 failed\n");
106        }
107        if (write_mode) {
108            if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
109                fprintf(stderr, "Short write\n");
110            }
111        } else {
112            if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
113                fprintf(stderr, "Short read\n");
114            }
115        }
116        iops++;
117        gettimeofday(&end, 0);
118        timersub(&end, &start, &res);
119    }
120    close(fd);
121
122    /* The close can take a while when in write_mode as buffers are flushed.
123     * So get the time again. */
124    gettimeofday(&end, 0);
125    timersub(&end, &start, &res);
126
127    printf("%d iops/sec\n", iops / (int) res.tv_sec);
128
129    exit(0);
130}
131
132