| /* |
| * fname_benchmark.c |
| * |
| * This program is a microbenchmark which measures the time it takes |
| * to create, lookup, and unlink files. |
| */ |
| |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/time.h> |
| #include <sys/resource.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <getopt.h> |
| |
| char *buf; |
| int bufsize = 0; |
| |
| static void file_create(int n) |
| { |
| int fd, ret; |
| char name[256]; |
| |
| sprintf(name, "f%04d", n); |
| fd = open(name, O_CREAT|O_WRONLY, 0777); |
| if (fd < 0) { |
| fprintf(stderr, "open %s for read failed: %s\n", |
| name, strerror(errno)); |
| exit(1); |
| } |
| if (bufsize) { |
| ret = write(fd, buf, bufsize); |
| if (ret != bufsize) { |
| if (ret < 0) |
| fprintf(stderr, "Writing %s failed: %s\n", |
| name, strerror(errno)); |
| else |
| fprintf(stderr, "Short write of %s: %d\n", |
| name, ret); |
| } |
| } |
| close(fd); |
| } |
| |
| static void file_read(int n) |
| { |
| int fd, ret; |
| char name[256]; |
| |
| sprintf(name, "f%04d", n); |
| fd = open(name, O_RDONLY, 0777); |
| if (fd < 0) { |
| fprintf(stderr, "open %s for read failed: %s\n", |
| name, strerror(errno)); |
| exit(1); |
| } |
| if (bufsize) { |
| ret = read(fd, buf, bufsize); |
| if (ret != bufsize) { |
| if (ret < 0) |
| fprintf(stderr, "Reading %s failed: %s\n", |
| name, strerror(errno)); |
| else |
| fprintf(stderr, "Short read of %s: %d\n", |
| name, ret); |
| } |
| } |
| close(fd); |
| } |
| |
| static void file_unlink(int n) |
| { |
| int fd, ret; |
| char name[256]; |
| |
| sprintf(name, "f%04d", n); |
| ret = unlink(name); |
| if (ret < 0) { |
| fprintf(stderr, "unlink %s failed: %s\n", |
| name, strerror(errno)); |
| exit(1); |
| } |
| } |
| |
| static void inline timeval_add(struct timeval *tv1, |
| struct timeval *tv2) |
| { |
| tv1->tv_sec += tv2->tv_sec; |
| tv1->tv_usec += tv2->tv_usec; |
| if (tv1->tv_usec >= 1000000) { |
| tv1->tv_usec -= 1000000; |
| tv1->tv_sec++; |
| } |
| } |
| |
| static void inline timeval_sub(struct timeval *tv1, |
| struct timeval *tv2) |
| { |
| tv1->tv_sec -= tv2->tv_sec; |
| if (tv1->tv_usec < tv2->tv_usec) { |
| tv1->tv_usec += 1000000; |
| tv1->tv_sec--; |
| } |
| tv1->tv_usec -= tv2->tv_usec; |
| } |
| |
| struct time_stat { |
| struct timeval usr; |
| struct timeval sys; |
| }; |
| |
| struct time_stat create_stat, lookup_stat, unlink_stat; |
| |
| static void upd_stat(struct rusage *start, struct time_stat *s) |
| { |
| struct rusage end; |
| |
| getrusage(RUSAGE_SELF, &end); |
| timeval_sub(&end.ru_utime, &start->ru_utime); |
| timeval_sub(&end.ru_stime, &start->ru_stime); |
| timeval_add(&s->usr, &end.ru_utime); |
| timeval_add(&s->sys, &end.ru_stime); |
| } |
| |
| static void print_stat(const char *label, struct time_stat *s) |
| { |
| printf("%s usr %6.4f sys %6.4f\n", label, |
| (float) s->usr.tv_sec + (float) s->usr.tv_usec / 1000000, |
| (float) s->sys.tv_sec + (float) s->sys.tv_usec / 1000000); |
| } |
| |
| static void drop_cache(void) |
| { |
| int fd; |
| |
| sync(); |
| fd = open("/proc/sys/vm/drop_caches", O_RDONLY); |
| if (fd < 0) { |
| perror("open of drop_caches"); |
| exit(1); |
| } |
| write(fd, "3\n", 2); |
| close(fd); |
| } |
| |
| int main(int argc, char **argv) |
| { |
| int num_files = 1000; |
| int repeat = 100; |
| int c, i, j; |
| int do_drop = 1; |
| struct rusage r; |
| struct time_stat total; |
| |
| while ((c = getopt (argc, argv, "b:n:r:d:")) != EOF) |
| { |
| switch(c) { |
| case 'b': |
| bufsize = atoi(optarg); |
| if (bufsize < 0) { |
| fprintf(stderr, "illegal bufsize %d\n", |
| bufsize); |
| exit(1); |
| } |
| break; |
| case 'n': |
| num_files = atoi(optarg); |
| if (num_files <= 0) { |
| fprintf(stderr, "illegal num_files %d\n", |
| num_files); |
| exit(1); |
| } |
| break; |
| case 'r': |
| repeat = atoi(optarg); |
| if (repeat <= 0) { |
| fprintf(stderr, "illegal repeat count %d\n", |
| repeat); |
| exit(1); |
| } |
| break; |
| case 'd': |
| do_drop = atoi(optarg); |
| break; |
| } |
| } |
| |
| if (bufsize) { |
| buf = malloc(bufsize); |
| if (!buf) { |
| fprintf(stderr, "failed to allocate buffer\n"); |
| exit(1); |
| } |
| } |
| for (i = 0; i < repeat; i++) { |
| getrusage(RUSAGE_SELF, &r); |
| for (j = 0; j < num_files; j++) |
| file_create(j); |
| upd_stat(&r, &create_stat); |
| |
| if (do_drop) |
| drop_cache(); |
| |
| getrusage(RUSAGE_SELF, &r); |
| for (j = 0; j < num_files; j++) |
| file_read(j); |
| upd_stat(&r, &lookup_stat); |
| |
| if (do_drop) |
| drop_cache(); |
| getrusage(RUSAGE_SELF, &r); |
| for (j = 0; j < num_files; j++) |
| file_unlink(j); |
| upd_stat(&r, &unlink_stat); |
| } |
| printf("buf_size %d num_files %d repeat %d do_drop %d\n", |
| bufsize, num_files, repeat, do_drop); |
| print_stat("create", &create_stat); |
| print_stat("lookup", &lookup_stat); |
| print_stat("unlink", &unlink_stat); |
| getrusage(RUSAGE_SELF, &r); |
| total.usr = r.ru_utime; |
| total.sys = r.ru_stime; |
| print_stat("total", &total); |
| } |