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