xref: /aosp_15_r20/system/extras/tests/ext4/rand_emmc_perf.c (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
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