• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
usage(void)37 static void usage(void) {
38         fprintf(stderr, "Usage: rand_emmc_perf [ -r | -w ] [-o] <size_in_mb> <block_dev>\n");
39         exit(1);
40 }
41 
main(int argc,char * argv[])42 int main(int argc, char *argv[])
43 {
44     unsigned long 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