rand_emmc_perf.c revision 2633ce5ca5024d5565c9068c29ec39a8c3ed10e9
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#include <string.h>
24#include <stdio.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <fcntl.h>
28#include <sys/time.h>
29#include <stdlib.h>
30
31#define TST_BLK_SIZE 4096
32/* Number of seconds to run the test */
33#define TEST_LEN 10
34
35static void usage(void) {
36        fprintf(stderr, "Usage: rand_emmc_perf [ -r | -w ] [-o] <size_in_mb> <block_dev>\n");
37        exit(1);
38}
39
40int main(int argc, char *argv[])
41{
42    long max_blocks;
43    int fd, fd2, write_mode = 0, iops = 0;
44    struct timeval start, end, res;
45    unsigned int seed;
46    char buf[TST_BLK_SIZE] = { 0 };
47    int c;
48    int o_sync = 0;
49
50    while ((c = getopt(argc, argv, "+rwo")) != -1) {
51        switch (c) {
52          case '?':
53          default:
54            usage();
55            break;
56
57          case 'r':
58            /* Do nothing, read mode is the default */
59            break;
60
61          case 'w':
62            write_mode = 1;
63            break;
64
65          case 'o':
66            o_sync = O_SYNC;
67            break;
68        }
69    }
70
71    if (o_sync && !write_mode) {
72        /* Can only specify o_sync in write mode.  Probably doesn't matter,
73         * but clear o_sync if in read mode */
74        o_sync = 0;
75    }
76
77    if ((argc - optind) != 2) {
78        usage();
79    }
80
81    /* Size is given in megabytes, so compute the number of TST_BLK_SIZE blocks. */
82    max_blocks = atol(argv[2]) * ((1024*1024) / TST_BLK_SIZE);
83
84    if ((fd = open(argv[3], O_RDWR | o_sync)) < 0) {
85        fprintf(stderr, "Cannot open block device %s\n", argv[2]);
86        exit(1);
87    }
88
89    fd2 = open("/dev/urandom\n", O_RDONLY);
90    if (fd2 < 0) {
91        fprintf(stderr, "Cannot open /dev/urandom\n");
92    }
93    if (read(fd2, &seed, sizeof(seed)) != sizeof(seed)) {
94        fprintf(stderr, "Cannot read /dev/urandom\n");
95    }
96    close(fd2);
97    srand(seed);
98
99    res.tv_sec = 0;
100    gettimeofday(&start, 0);
101    while (res.tv_sec < TEST_LEN) {
102        if (lseek64(fd, (rand() % max_blocks) * TST_BLK_SIZE, SEEK_SET) < 0) {
103            fprintf(stderr, "lseek64 failed\n");
104        }
105        if (write_mode) {
106            if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
107                fprintf(stderr, "Short write\n");
108            }
109        } else {
110            if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
111                fprintf(stderr, "Short read\n");
112            }
113        }
114        iops++;
115        gettimeofday(&end, 0);
116        timersub(&end, &start, &res);
117    }
118    close(fd);
119
120    /* The close can take a while when in write_mode as buffers are flushed.
121     * So get the time again. */
122    gettimeofday(&end, 0);
123    timersub(&end, &start, &res);
124
125    printf("%d iops/sec\n", iops / (int) res.tv_sec);
126
127    exit(0);
128}
129
130