blob: 58b60556138abab552d93b97c0f2f9b354f8a282 [file] [log] [blame]
/*
* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/*
* Does time test of sync for creating files, reading files
* and deleting files.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <eprintf.h>
#include <esys.h>
#include <puny.h>
#include <style.h>
#include <timer.h>
#include <twister.h>
#include <util.h>
enum { MAX_NAME = 12,
DEFAULT_FILE_SIZE = 1 << 14,
BYTES_TO_READ = 1,
NUM_START_FILES = 1 << 9,
NUM_FILES = 1 << 18 };
struct file {
char name[MAX_NAME];
};
static void cleanup(void);
struct file *File;
u64 Num_files = NUM_FILES;
u64 Num_bytes_to_read = BYTES_TO_READ;
bool Prompt = FALSE;
static void prompt(const char *label)
{
int c;
if (Prompt) {
printf("%s > ", label);
for (;;) {
c = getchar();
switch (c) {
case EOF:
case 'q':
cleanup();
exit(0);
break;
case 'p':
Prompt = FALSE;
break;
case '\n':
return;
default:
/* ignore; */
break;
}
}
}
}
static void fill(u8 *buf, int n)
{
int i;
for (i = 0; i < n; i++) {
buf[i] = twister_random();
}
}
static void createfiles(int num_files)
{
u8 *buf = emalloc(Option.file_size);
int fd;
int i;
fill(buf, Option.file_size);
for (i = 0; i < num_files; i++) {
gen_name(File[i].name, MAX_NAME);
fd = ecreat(File[i].name);
ewrite(fd, buf, Option.file_size);
eclose(fd);
}
free(buf);
}
static void unlinkfiles(int num_files)
{
int i;
for (i = 0; i < num_files; i++) {
eunlink(File[i].name);
}
}
static void readfiles(int num_files)
{
u64 bytes_to_read = Num_bytes_to_read;
u8 *buf;
int fd;
int i;
if (bytes_to_read > Option.file_size)
bytes_to_read = Option.file_size;
buf = emalloc(bytes_to_read);
for (i = 0; i < num_files; i++) {
fd = eopen(File[i].name, O_RDONLY);
eread(fd, buf, bytes_to_read);
eclose(fd);
}
free(buf);
}
static void time_sync(const char *label, int n)
{
u64 start;
u64 finish;
start = nsecs();
esync();
finish = nsecs();
printf("%10s %8d. %g ms\n",
label, n, (double)(finish - start)/1000000.0);
prompt("sync done");
}
void crsyncdel(int n)
{
createfiles(n);
prompt("create done");
time_sync("create", n);
readfiles(n);
prompt("read done");
time_sync("read", n);
unlinkfiles(n);
prompt("unlink done");
time_sync("unlink", n);
}
static void cleanup(void)
{
static bool cleaning_up = FALSE;
char cmd[1024];
int rc;
if (!Option.cleanup || cleaning_up) return;
cleaning_up = TRUE;
echdir("..");
rc = snprintf(cmd, sizeof(cmd), "rm -fr %s", Option.dir);
if (rc >= sizeof(cmd)) {
eprintf("counldn't cleanup %s", cmd);
}
esystem(cmd);
}
static void setup(void)
{
emkdir(Option.dir);
echdir(Option.dir);
File = ezalloc(sizeof(*File) * Num_files);
set_cleanup(cleanup);
}
void usage(void)
{
pr_usage("-p -d<directory> -n<number of files> -z<size in bytes>\n"
" Times sync after creating files, reading them and then\n"
" deleting them. Uses powers of 2 starting with %d.\n"
"\td - directory to create for files\n"
"\tn - maximum number files to create\n"
"\tp - prompt after each set of operations\n"
"\tz - size bytes of each file",
NUM_START_FILES);
}
bool myopt(int c)
{
switch (c) {
case 'n':
Num_files = strtoll(optarg, NULL, 0);
break;
case 'p':
Prompt = TRUE;
break;
default:
return FALSE;
}
return TRUE;
}
int main(int argc, char *argv[])
{
int i;
Option.file_size = DEFAULT_FILE_SIZE;
punyopt(argc, argv, myopt, "n:p");
setup();
esync();
/*
* Number of files grows by powers of two until the
* specified number of files is reached. I start
* at a large enough number so I see more than just
* noise.
*/
for (i = NUM_START_FILES; i <= Num_files; i <<= 1) {
crsyncdel(i);
}
cleanup();
return 0;
}