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 37static void usage(void) { 38 fprintf(stderr, "Usage: rand_emmc_perf [ -r | -w ] [-o] <size_in_mb> <block_dev>\n"); 39 exit(1); 40} 41 42int 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