added latency tool
[tridge/junkcode.git] / disktest.c
1 #define _FILE_OFFSET_BITS 64
2
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <errno.h>
7 #include <time.h>
8 #include <sys/ioctl.h>
9 #include <asm/unistd.h>
10 #include <asm/fcntl.h>
11 #include <sys/mount.h>
12 #include <sys/time.h>
13
14 static int blocks;
15 static int block_size = 1024;
16 static unsigned read_prob = 50;
17 static unsigned num_reads, num_writes, num_fails;
18 static unsigned rep_time = 10;
19
20 void bit_set(unsigned char *bm, off_t i)
21 {
22         bm[i/8] |= (1<<(i%8));
23 }
24
25 unsigned bit_query(unsigned char *bm, off_t i)
26 {
27         return  (bm[i/8] & (1<<(i%8))) ? 1 : 0;
28 }
29
30 static void do_seek(int fd, off_t ofs)
31 {
32         if (lseek(fd, ofs, SEEK_SET) != ofs) {
33                 perror("lseek");
34                 exit(1);
35         }
36 }
37
38 static void init_buf(unsigned *buf, unsigned bnum)
39 {
40         unsigned i;
41         srandom(bnum);
42         buf[0] = bnum;
43         for (i=1;i<block_size/4;i++) buf[i] = random();
44 }
45
46 static void write_block(int fd, unsigned *buf, off_t i)
47 {
48         do_seek(fd, i*(off_t)block_size);
49         if (write(fd, buf, block_size) != block_size) {
50                 fprintf(stderr,"write failed on block %u\n", (unsigned)i);
51                 exit(1);
52         }
53 }
54
55 static void check_block(int fd, unsigned *buf, off_t i)
56 {
57         unsigned buf2[block_size/4];
58
59         do_seek(fd, i*(off_t)block_size);
60         if (read(fd, buf2, block_size) != block_size) {
61                 fprintf(stderr,"read failed on block %u\n", (unsigned)i);
62                 exit(1);
63         }
64         if (memcmp(buf, buf2, block_size) != 0) {
65                 int j, count=0, first = -1;
66                 for (j=0; j<block_size/4; j++) {
67                         if (buf[j] != buf2[j]) {
68                                 count++;
69                                 if (first == -1) first = j;
70                         }
71                 }
72                 printf("compare failed on block %u (%d words differ) 1st error at word %u\n", 
73                        (unsigned)i, count, first);
74                 fd = open("buf1.dat", O_WRONLY|O_CREAT|O_TRUNC, 0644);
75                 write(fd, buf, block_size);
76                 close(fd);
77                 fd = open("buf2.dat", O_WRONLY|O_CREAT|O_TRUNC, 0644);
78                 write(fd, buf2, block_size);
79                 close(fd);
80                 printf("Wrote good data to buf1.dat\n");
81                 printf("Wrote bad data to buf2.dat\n");
82                 num_fails++;
83         }
84 }
85
86
87 static void try_block(int fd, off_t i, unsigned char *bitmap)
88 {
89         unsigned *buf;
90         buf = (unsigned *)memalign(block_size, block_size);
91
92         if (!bit_query(bitmap, i) || (random()%100 > read_prob)) {
93                 bit_set(bitmap, i);
94                 init_buf(buf, i);
95                 write_block(fd, buf, i);
96                 num_writes++;
97         } else {
98                 init_buf(buf, i);
99                 check_block(fd, buf, i);
100                 num_reads++;
101         }
102
103         free(buf);
104 }
105
106
107 static void disk_test(char *dev)
108 {
109         int fd;
110         int count=0, count2;
111         unsigned char *bitmap;
112         off_t i, j;
113         time_t t1, t2;
114         unsigned blk;
115
116         fd = open(dev, O_RDWR|O_SYNC|O_LARGEFILE);
117         if (fd == -1) {
118                 perror(dev);
119                 return;
120         }
121
122         if (blocks == 0) {
123                 if (ioctl(fd, BLKGETSIZE, &blocks) != 0) {
124                         fprintf(stderr,"BLKGETSIZE failed\n");
125                         exit(1);
126                 }
127
128                 blocks /= (block_size/512);
129         }
130
131         bitmap = calloc((blocks+7)/8, 1);
132         if (!bitmap) {
133                 fprintf(stderr,"malloc of bitmap failed\n");
134                 exit(1);
135         }
136
137         srandom(time(NULL));
138
139         printf("starting disktest on %s with %u blocks of size %u\n", 
140                dev, blocks, block_size);
141         printf("using read probability of %u%%\n", read_prob);
142
143         t1 = time(NULL);
144         count2 = 0;
145         blk = 0;
146
147         while (1) {
148                 i = ((unsigned)random()) % blocks;
149
150                 try_block(fd, blk % blocks, bitmap);
151                 try_block(fd, i, bitmap);
152
153                 blk++;
154                 count += 2;
155                 count2 += 2;
156
157                 t2 = time(NULL);
158
159                 if (t2 - t1 >= rep_time) {
160                         printf("%s %d blocks (%d reads, %d writes, %d fails, %.2fMB/sec)\n",
161                                dev, count, num_reads, num_writes, num_fails, 
162                                1.0e-6*(count2*block_size)/(t2-t1));
163                         srandom(random() | time(NULL));
164                         t1 = t2;
165                         count2=0;
166                 }
167                 fflush(stdout);
168         }
169
170         close(fd);
171 }
172
173
174 static void usage(void)
175 {
176         fprintf(stderr,
177 "\n" \
178 "usage: disktest [options] <device>\n" \
179 "\n" \
180 "options: \n" \
181 "         -B <blocks>           set block count\n" \
182 "         -s <blk_size>         set block size\n" \
183 "         -R <value>            set read probability (1-100)\n" \
184 "         -t <value>            set report time in seconds\n" \
185 "\n");
186         exit(1);
187 }
188
189
190 int main(int argc, char *argv[])
191 {
192         char *dev;
193         int opt;
194         extern char *optarg;
195
196         while ((opt = getopt(argc, argv, "B:s:R:t:h")) != EOF) {
197                 switch (opt) {
198                 case 'B':
199                         blocks = atoi(optarg);
200                         break;
201                 case 's':
202                         block_size = atoi(optarg);
203                         break;
204                 case 'R':
205                         read_prob = atoi(optarg);
206                         break;
207                 case 't':
208                         rep_time = atoi(optarg);
209                         break;
210                 default:
211                         usage();
212                         break;
213                 }
214         }
215
216         argv += optind;
217         argc -= optind;
218
219         if (argc < 1) usage();
220
221         dev = argv[0];
222
223         setlinebuf(stdout);
224
225         disk_test(dev);
226
227         return 0;
228 }
229