1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2010 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker *
4*288bf522SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker *
8*288bf522SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker *
10*288bf522SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker */
16*288bf522SAndroid Build Coastguard Worker
17*288bf522SAndroid Build Coastguard Worker /* A simple test of emmc random read and write performance. When testing write
18*288bf522SAndroid Build Coastguard Worker * performance, try it twice, once with O_SYNC compiled in, and once with it commented
19*288bf522SAndroid Build Coastguard Worker * out. Without O_SYNC, the close(2) blocks until all the dirty buffers are written
20*288bf522SAndroid Build Coastguard Worker * out, but the numbers tend to be higher.
21*288bf522SAndroid Build Coastguard Worker */
22*288bf522SAndroid Build Coastguard Worker
23*288bf522SAndroid Build Coastguard Worker #define _LARGEFILE64_SOURCE
24*288bf522SAndroid Build Coastguard Worker #include <string.h>
25*288bf522SAndroid Build Coastguard Worker #include <stdio.h>
26*288bf522SAndroid Build Coastguard Worker #include <sys/types.h>
27*288bf522SAndroid Build Coastguard Worker #include <sys/stat.h>
28*288bf522SAndroid Build Coastguard Worker #include <fcntl.h>
29*288bf522SAndroid Build Coastguard Worker #include <sys/time.h>
30*288bf522SAndroid Build Coastguard Worker #include <stdlib.h>
31*288bf522SAndroid Build Coastguard Worker #include <unistd.h>
32*288bf522SAndroid Build Coastguard Worker #include <math.h>
33*288bf522SAndroid Build Coastguard Worker
34*288bf522SAndroid Build Coastguard Worker #define TST_BLK_SIZE 4096
35*288bf522SAndroid Build Coastguard Worker /* Number of seconds to run the test */
36*288bf522SAndroid Build Coastguard Worker #define TEST_LEN 10
37*288bf522SAndroid Build Coastguard Worker
38*288bf522SAndroid Build Coastguard Worker struct stats {
39*288bf522SAndroid Build Coastguard Worker struct timeval start;
40*288bf522SAndroid Build Coastguard Worker struct timeval end;
41*288bf522SAndroid Build Coastguard Worker off64_t offset;
42*288bf522SAndroid Build Coastguard Worker };
43*288bf522SAndroid Build Coastguard Worker
usage(void)44*288bf522SAndroid Build Coastguard Worker static void usage(void) {
45*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Usage: rand_emmc_perf [ -r | -w ] [-o] [-s count] [-f full_stats_filename] <size_in_mb> <block_dev>\n");
46*288bf522SAndroid Build Coastguard Worker exit(1);
47*288bf522SAndroid Build Coastguard Worker }
48*288bf522SAndroid Build Coastguard Worker
print_stats(struct stats * stats_buf,int stats_count,char * full_stats_file)49*288bf522SAndroid Build Coastguard Worker static void print_stats(struct stats *stats_buf, int stats_count,
50*288bf522SAndroid Build Coastguard Worker char * full_stats_file)
51*288bf522SAndroid Build Coastguard Worker {
52*288bf522SAndroid Build Coastguard Worker int i;
53*288bf522SAndroid Build Coastguard Worker struct timeval t;
54*288bf522SAndroid Build Coastguard Worker struct timeval sum = { 0, 0 };
55*288bf522SAndroid Build Coastguard Worker struct timeval max = { 0, 0 };
56*288bf522SAndroid Build Coastguard Worker long long total_usecs;
57*288bf522SAndroid Build Coastguard Worker long long avg_usecs;
58*288bf522SAndroid Build Coastguard Worker long long max_usecs;
59*288bf522SAndroid Build Coastguard Worker long long variance = 0;;
60*288bf522SAndroid Build Coastguard Worker long long x;
61*288bf522SAndroid Build Coastguard Worker double sdev;
62*288bf522SAndroid Build Coastguard Worker FILE *full_stats = NULL;
63*288bf522SAndroid Build Coastguard Worker
64*288bf522SAndroid Build Coastguard Worker if (full_stats_file) {
65*288bf522SAndroid Build Coastguard Worker full_stats = fopen(full_stats_file, "w");
66*288bf522SAndroid Build Coastguard Worker if (full_stats == NULL) {
67*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Cannot open full stats output file %s, ignoring\n",
68*288bf522SAndroid Build Coastguard Worker full_stats_file);
69*288bf522SAndroid Build Coastguard Worker }
70*288bf522SAndroid Build Coastguard Worker }
71*288bf522SAndroid Build Coastguard Worker
72*288bf522SAndroid Build Coastguard Worker for (i = 0; i < stats_count; i++) {
73*288bf522SAndroid Build Coastguard Worker timersub(&stats_buf[i].end, &stats_buf[i].start, &t);
74*288bf522SAndroid Build Coastguard Worker if (timercmp(&t, &max, >)) {
75*288bf522SAndroid Build Coastguard Worker max = t;
76*288bf522SAndroid Build Coastguard Worker }
77*288bf522SAndroid Build Coastguard Worker if (full_stats) {
78*288bf522SAndroid Build Coastguard Worker fprintf(full_stats, "%lld\n", (t.tv_sec * 1000000LL) + t.tv_usec);
79*288bf522SAndroid Build Coastguard Worker }
80*288bf522SAndroid Build Coastguard Worker timeradd(&sum, &t, &sum);
81*288bf522SAndroid Build Coastguard Worker }
82*288bf522SAndroid Build Coastguard Worker
83*288bf522SAndroid Build Coastguard Worker if (full_stats) {
84*288bf522SAndroid Build Coastguard Worker fclose(full_stats);
85*288bf522SAndroid Build Coastguard Worker }
86*288bf522SAndroid Build Coastguard Worker
87*288bf522SAndroid Build Coastguard Worker max_usecs = (max.tv_sec * 1000000LL) + max.tv_usec;
88*288bf522SAndroid Build Coastguard Worker total_usecs = (sum.tv_sec * 1000000LL) + sum.tv_usec;
89*288bf522SAndroid Build Coastguard Worker avg_usecs = total_usecs / stats_count;
90*288bf522SAndroid Build Coastguard Worker printf("average random %d byte iop time = %lld usecs\n",
91*288bf522SAndroid Build Coastguard Worker TST_BLK_SIZE, avg_usecs);
92*288bf522SAndroid Build Coastguard Worker printf("maximum random %d byte iop time = %lld usecs\n",
93*288bf522SAndroid Build Coastguard Worker TST_BLK_SIZE, max_usecs);
94*288bf522SAndroid Build Coastguard Worker
95*288bf522SAndroid Build Coastguard Worker /* Now that we have the average (aka mean) go through the data
96*288bf522SAndroid Build Coastguard Worker * again and compute the standard deviation.
97*288bf522SAndroid Build Coastguard Worker * The formula is sqrt(sum_1_to_n((Xi - avg)^2)/n)
98*288bf522SAndroid Build Coastguard Worker */
99*288bf522SAndroid Build Coastguard Worker for (i = 0; i < stats_count; i++) {
100*288bf522SAndroid Build Coastguard Worker timersub(&stats_buf[i].end, &stats_buf[i].start, &t); /* Xi */
101*288bf522SAndroid Build Coastguard Worker x = (t.tv_sec * 1000000LL) + t.tv_usec; /* Convert to long long */
102*288bf522SAndroid Build Coastguard Worker x = x - avg_usecs; /* Xi - avg */
103*288bf522SAndroid Build Coastguard Worker x = x * x; /* (Xi - avg) ^ 2 */
104*288bf522SAndroid Build Coastguard Worker variance += x; /* Summation */
105*288bf522SAndroid Build Coastguard Worker }
106*288bf522SAndroid Build Coastguard Worker sdev = sqrt((double)variance/(double)stats_count);
107*288bf522SAndroid Build Coastguard Worker printf("standard deviation of iops is %.2f\n", sdev);
108*288bf522SAndroid Build Coastguard Worker }
109*288bf522SAndroid Build Coastguard Worker
stats_test(int fd,int write_mode,off64_t max_blocks,int stats_count,char * full_stats_file)110*288bf522SAndroid Build Coastguard Worker static void stats_test(int fd, int write_mode, off64_t max_blocks, int stats_count,
111*288bf522SAndroid Build Coastguard Worker char *full_stats_file)
112*288bf522SAndroid Build Coastguard Worker {
113*288bf522SAndroid Build Coastguard Worker struct stats *stats_buf;
114*288bf522SAndroid Build Coastguard Worker char buf[TST_BLK_SIZE] = { 0 };
115*288bf522SAndroid Build Coastguard Worker int i;
116*288bf522SAndroid Build Coastguard Worker
117*288bf522SAndroid Build Coastguard Worker stats_buf = malloc(stats_count * sizeof(struct stats));
118*288bf522SAndroid Build Coastguard Worker if (stats_buf == NULL) {
119*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Cannot allocate stats_buf\n");
120*288bf522SAndroid Build Coastguard Worker exit(1);
121*288bf522SAndroid Build Coastguard Worker }
122*288bf522SAndroid Build Coastguard Worker
123*288bf522SAndroid Build Coastguard Worker for (i = 0; i < stats_count; i++) {
124*288bf522SAndroid Build Coastguard Worker gettimeofday(&stats_buf[i].start, NULL);
125*288bf522SAndroid Build Coastguard Worker
126*288bf522SAndroid Build Coastguard Worker if (lseek64(fd, (rand() % max_blocks) * TST_BLK_SIZE, SEEK_SET) < 0) {
127*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "lseek64 failed\n");
128*288bf522SAndroid Build Coastguard Worker }
129*288bf522SAndroid Build Coastguard Worker
130*288bf522SAndroid Build Coastguard Worker if (write_mode) {
131*288bf522SAndroid Build Coastguard Worker if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
132*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Short write\n");
133*288bf522SAndroid Build Coastguard Worker }
134*288bf522SAndroid Build Coastguard Worker } else {
135*288bf522SAndroid Build Coastguard Worker if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
136*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Short read\n");
137*288bf522SAndroid Build Coastguard Worker }
138*288bf522SAndroid Build Coastguard Worker }
139*288bf522SAndroid Build Coastguard Worker
140*288bf522SAndroid Build Coastguard Worker gettimeofday(&stats_buf[i].end, NULL);
141*288bf522SAndroid Build Coastguard Worker }
142*288bf522SAndroid Build Coastguard Worker
143*288bf522SAndroid Build Coastguard Worker print_stats(stats_buf, stats_count, full_stats_file);
144*288bf522SAndroid Build Coastguard Worker }
145*288bf522SAndroid Build Coastguard Worker
perf_test(int fd,int write_mode,off64_t max_blocks)146*288bf522SAndroid Build Coastguard Worker static void perf_test(int fd, int write_mode, off64_t max_blocks)
147*288bf522SAndroid Build Coastguard Worker {
148*288bf522SAndroid Build Coastguard Worker struct timeval start, end, res;
149*288bf522SAndroid Build Coastguard Worker char buf[TST_BLK_SIZE] = { 0 };
150*288bf522SAndroid Build Coastguard Worker long long iops = 0;
151*288bf522SAndroid Build Coastguard Worker int msecs;
152*288bf522SAndroid Build Coastguard Worker
153*288bf522SAndroid Build Coastguard Worker res.tv_sec = 0;
154*288bf522SAndroid Build Coastguard Worker gettimeofday(&start, NULL);
155*288bf522SAndroid Build Coastguard Worker while (res.tv_sec < TEST_LEN) {
156*288bf522SAndroid Build Coastguard Worker if (lseek64(fd, (rand() % max_blocks) * TST_BLK_SIZE, SEEK_SET) < 0) {
157*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "lseek64 failed\n");
158*288bf522SAndroid Build Coastguard Worker }
159*288bf522SAndroid Build Coastguard Worker if (write_mode) {
160*288bf522SAndroid Build Coastguard Worker if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
161*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Short write\n");
162*288bf522SAndroid Build Coastguard Worker }
163*288bf522SAndroid Build Coastguard Worker } else {
164*288bf522SAndroid Build Coastguard Worker if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
165*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Short read\n");
166*288bf522SAndroid Build Coastguard Worker }
167*288bf522SAndroid Build Coastguard Worker }
168*288bf522SAndroid Build Coastguard Worker iops++;
169*288bf522SAndroid Build Coastguard Worker gettimeofday(&end, NULL);
170*288bf522SAndroid Build Coastguard Worker timersub(&end, &start, &res);
171*288bf522SAndroid Build Coastguard Worker }
172*288bf522SAndroid Build Coastguard Worker close(fd);
173*288bf522SAndroid Build Coastguard Worker
174*288bf522SAndroid Build Coastguard Worker /* The close can take a while when in write_mode as buffers are flushed.
175*288bf522SAndroid Build Coastguard Worker * So get the time again. */
176*288bf522SAndroid Build Coastguard Worker gettimeofday(&end, NULL);
177*288bf522SAndroid Build Coastguard Worker timersub(&end, &start, &res);
178*288bf522SAndroid Build Coastguard Worker
179*288bf522SAndroid Build Coastguard Worker msecs = (res.tv_sec * 1000) + (res.tv_usec / 1000);
180*288bf522SAndroid Build Coastguard Worker printf("%.0f %dbyte iops/sec\n", (float)iops * 1000 / msecs, TST_BLK_SIZE);
181*288bf522SAndroid Build Coastguard Worker }
182*288bf522SAndroid Build Coastguard Worker
main(int argc,char * argv[])183*288bf522SAndroid Build Coastguard Worker int main(int argc, char *argv[])
184*288bf522SAndroid Build Coastguard Worker {
185*288bf522SAndroid Build Coastguard Worker int fd, fd2;
186*288bf522SAndroid Build Coastguard Worker int write_mode = 0;
187*288bf522SAndroid Build Coastguard Worker int o_sync = 0;
188*288bf522SAndroid Build Coastguard Worker int stats_mode = 0;
189*288bf522SAndroid Build Coastguard Worker int stats_count;
190*288bf522SAndroid Build Coastguard Worker char *full_stats_file = NULL;
191*288bf522SAndroid Build Coastguard Worker off64_t max_blocks;
192*288bf522SAndroid Build Coastguard Worker unsigned int seed;
193*288bf522SAndroid Build Coastguard Worker int c;
194*288bf522SAndroid Build Coastguard Worker
195*288bf522SAndroid Build Coastguard Worker while ((c = getopt(argc, argv, "+rwos:f:")) != -1) {
196*288bf522SAndroid Build Coastguard Worker switch (c) {
197*288bf522SAndroid Build Coastguard Worker case '?':
198*288bf522SAndroid Build Coastguard Worker default:
199*288bf522SAndroid Build Coastguard Worker usage();
200*288bf522SAndroid Build Coastguard Worker break;
201*288bf522SAndroid Build Coastguard Worker
202*288bf522SAndroid Build Coastguard Worker case 'r':
203*288bf522SAndroid Build Coastguard Worker /* Do nothing, read mode is the default */
204*288bf522SAndroid Build Coastguard Worker break;
205*288bf522SAndroid Build Coastguard Worker
206*288bf522SAndroid Build Coastguard Worker case 'w':
207*288bf522SAndroid Build Coastguard Worker write_mode = 1;
208*288bf522SAndroid Build Coastguard Worker break;
209*288bf522SAndroid Build Coastguard Worker
210*288bf522SAndroid Build Coastguard Worker case 'o':
211*288bf522SAndroid Build Coastguard Worker o_sync = O_SYNC;
212*288bf522SAndroid Build Coastguard Worker break;
213*288bf522SAndroid Build Coastguard Worker
214*288bf522SAndroid Build Coastguard Worker case 's':
215*288bf522SAndroid Build Coastguard Worker stats_mode = 1;
216*288bf522SAndroid Build Coastguard Worker stats_count = atoi(optarg);
217*288bf522SAndroid Build Coastguard Worker break;
218*288bf522SAndroid Build Coastguard Worker
219*288bf522SAndroid Build Coastguard Worker case 'f':
220*288bf522SAndroid Build Coastguard Worker free(full_stats_file);
221*288bf522SAndroid Build Coastguard Worker full_stats_file = strdup(optarg);
222*288bf522SAndroid Build Coastguard Worker if (full_stats_file == NULL) {
223*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Cannot get full stats filename\n");
224*288bf522SAndroid Build Coastguard Worker }
225*288bf522SAndroid Build Coastguard Worker break;
226*288bf522SAndroid Build Coastguard Worker }
227*288bf522SAndroid Build Coastguard Worker }
228*288bf522SAndroid Build Coastguard Worker
229*288bf522SAndroid Build Coastguard Worker if (o_sync && !write_mode) {
230*288bf522SAndroid Build Coastguard Worker /* Can only specify o_sync in write mode. Probably doesn't matter,
231*288bf522SAndroid Build Coastguard Worker * but clear o_sync if in read mode */
232*288bf522SAndroid Build Coastguard Worker o_sync = 0;
233*288bf522SAndroid Build Coastguard Worker }
234*288bf522SAndroid Build Coastguard Worker
235*288bf522SAndroid Build Coastguard Worker if ((argc - optind) != 2) {
236*288bf522SAndroid Build Coastguard Worker usage();
237*288bf522SAndroid Build Coastguard Worker }
238*288bf522SAndroid Build Coastguard Worker
239*288bf522SAndroid Build Coastguard Worker /* Size is given in megabytes, so compute the number of TST_BLK_SIZE blocks. */
240*288bf522SAndroid Build Coastguard Worker max_blocks = atoll(argv[optind]) * ((1024*1024) / TST_BLK_SIZE);
241*288bf522SAndroid Build Coastguard Worker
242*288bf522SAndroid Build Coastguard Worker if ((fd = open(argv[optind + 1], O_RDWR | o_sync)) < 0) {
243*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Cannot open block device %s\n", argv[optind + 1]);
244*288bf522SAndroid Build Coastguard Worker exit(1);
245*288bf522SAndroid Build Coastguard Worker }
246*288bf522SAndroid Build Coastguard Worker
247*288bf522SAndroid Build Coastguard Worker fd2 = open("/dev/urandom", O_RDONLY);
248*288bf522SAndroid Build Coastguard Worker if (fd2 < 0) {
249*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Cannot open /dev/urandom\n");
250*288bf522SAndroid Build Coastguard Worker }
251*288bf522SAndroid Build Coastguard Worker if (read(fd2, &seed, sizeof(seed)) != sizeof(seed)) {
252*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Cannot read /dev/urandom\n");
253*288bf522SAndroid Build Coastguard Worker }
254*288bf522SAndroid Build Coastguard Worker close(fd2);
255*288bf522SAndroid Build Coastguard Worker srand(seed);
256*288bf522SAndroid Build Coastguard Worker
257*288bf522SAndroid Build Coastguard Worker if (stats_mode) {
258*288bf522SAndroid Build Coastguard Worker stats_test(fd, write_mode, max_blocks, stats_count, full_stats_file);
259*288bf522SAndroid Build Coastguard Worker } else {
260*288bf522SAndroid Build Coastguard Worker perf_test(fd, write_mode, max_blocks);
261*288bf522SAndroid Build Coastguard Worker }
262*288bf522SAndroid Build Coastguard Worker free(full_stats_file);
263*288bf522SAndroid Build Coastguard Worker
264*288bf522SAndroid Build Coastguard Worker exit(0);
265*288bf522SAndroid Build Coastguard Worker }
266*288bf522SAndroid Build Coastguard Worker
267