blob: 4ecaa35d8d3633d12df4c5a25b7bf6bae7ca771d [file] [log] [blame]
/****************************************************************************
| (C) Copyright 2008 Novell, Inc. All Rights Reserved.
|
| GPLv2: This program is free software; you can redistribute it
| and/or modify it under the terms of version 2 of the GNU General
| Public License as published by the Free Software Foundation.
|
| This program is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
+-------------------------------------------------------------------------*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <debug.h>
#include <style.h>
#include <mystdlib.h>
#include <eprintf.h>
#include <puny.h>
enum { MAX_PATH = 1024, MAX_NAME = 8 };
typedef struct inst_s {
u64 num_opens;
u64 num_dirs;
u64 num_files;
u64 num_deleted;
u64 num_read;
u64 num_written;
} inst_s;
typedef struct arg_s {
char from[256];
char to[256];
unsigned width;
unsigned depth;
unsigned seed;
} arg_s;
struct {
bool rate;
unsigned width;
unsigned depth;
char *from;
char *to;
} Myopt = {
.rate = FALSE,
.width = 3,
.depth = 5,
.from = "ztree",
.to = "copy" };
inst_s Inst;
void pr_inst (inst_s *inst)
{
printf("opens = %10llu\n", inst->num_opens);
printf("created = %10llu\n", inst->num_dirs+inst->num_files);
printf("dirs = %10llu\n", inst->num_dirs);
printf("files = %10llu\n", inst->num_files);
printf("deleted = %10llu\n", inst->num_deleted);
printf("read = %10llu\n", inst->num_read);
printf("written = %10llu\n", inst->num_written);
}
void pr_delta (inst_s *d)
{
printf("%10llu %10llu %10llu %10llu %10llu %10llu %10llu\n",
d->num_opens, d->num_dirs+d->num_files, d->num_dirs,
d->num_files, d->num_deleted, d->num_read, d->num_written);
}
void clear_inst (void)
{
zero(Inst);
}
void prompt (char *p)
{
printf("%s$ ", p);
getchar();
}
void add_name (char *parent, char *child)
{
char *c;
c = &parent[strlen(parent)];
cat(c, "/", child, NULL);
}
void drop_name (char *path)
{
char *c;
for (c = &path[strlen(path)]; c != path; c--) {
if (*c == '/') {
break;
}
}
*c = '\0';
}
void gen_name (char *c, arg_s *arg)
{
unsigned i;
static char file_name_char[] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"_0123456789";
for (i = 0; i < MAX_NAME - 1; i++) {
*c++ = file_name_char[urand_r(sizeof(file_name_char)-1,
&arg->seed)];
}
*c = '\0';
}
int is_dir (const char *dir)
{
struct stat stbuf;
int rc;
rc = stat(dir, &stbuf);
if (rc) {
eprintf("is_dir stat \"%s\" :", dir);
return 0;
}
return S_ISDIR(stbuf.st_mode);
}
void cd (char *dir)
{
int rc;
rc = chdir(dir);
if (rc){
eprintf("chdir \"%s\" :", dir);
}
}
void cleanup (char *dir)
{
cd("..");
int rc = rmdir(dir);
if (rc) fatal("rmdir %s:", dir);
}
void fatal_cleanup (void)
{
static bool cleaning_up = FALSE;
char cmd[1024];
int rc;
if (!Option.cleanup || cleaning_up) return;
cleaning_up = TRUE;
cd("..");
rc = snprintf(cmd, sizeof(cmd), "rm -fr %s", Option.dir);
if (rc > sizeof(cmd) - 2) return; /* shouldn't be that big */
rc = system(cmd);
if (rc) {
fatal("'%s' failed %d:", cmd, rc);
}
}
void init (char *dir)
{
int rc = mkdir(dir, 0700);
if (rc) fatal("mkdir %s:", dir);
cd(dir);
set_cleanup(fatal_cleanup);
}
int open_file (char *name)
{
int fd;
fd = open(name, O_RDWR);
if (fd == -1) {
eprintf("open_file \"%s\" :", name);
return fd;
}
++Inst.num_opens;
return fd;
}
DIR *open_dir (char *name)
{
DIR *dir;
dir = opendir(name);
if (!dir) {
eprintf("open_dir \"%s\" :", name);
return NULL;
}
++Inst.num_opens;
return dir;
}
void close_dir (DIR *dir)
{
closedir(dir);
}
void fill (int fd, arg_s *arg)
{
static char rnd_char[] = "abcdefghijklmnopqrstuvwxyz\n";
char buf[4096];
unsigned long i, n;
n = (urand_r(10, &arg->seed)+1)
* (urand_r(10, &arg->seed)+1)
* (urand_r(10, &arg->seed)+1);
for (i = 0; i < sizeof(buf); i++) {
buf[i] = rnd_char[urand_r(sizeof(rnd_char)-1, &arg->seed)];
}
for (i = 0; i < n; i++) {
if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
fatal("write:");
}
}
Inst.num_written += n * sizeof(buf);
}
int cr_file (char *name, arg_s *arg)
{
int fd;
fd = creat(name, 0666);
if (fd == -1) {
eprintf("cr_file \"%s\" :", name);
return -1;
}
++Inst.num_files;
fill(fd, arg);
close(fd);
return 0;
}
int copy_file (char *from, char *to)
{
char buf[4096];
int from_fd;
int to_fd;
int n;
int rc;
from_fd = open_file(from);
if (from_fd == -1) {
eprintf("copy_file open \"%s\" :", from);
return -1;
}
to_fd = creat(to, 0666);
if (to_fd == -1) {
eprintf("copy_file creat \"%s\" :", to);
return -1;
}
for (;;) {
n = read(from_fd, buf, sizeof(buf));
if (n == 0) break;
if (n == -1) {
eprintf("copy_file read \"%s\" :", from);
return -1;
}
Inst.num_read += n;
rc = write(to_fd, buf, n);
if (rc != n) {
eprintf("copy_file write \"%s\" :", to);
return -1;
}
Inst.num_written += n;
}
close(to_fd);
close(from_fd);
return 0;
}
void cr_dir (char *name)
{
int rc;
rc = mkdir(name, 0777);
if (rc) {
eprintf("cr_dir \"%s\" :", name);
return;
}
++Inst.num_dirs;
}
void del_file (char *name)
{
int rc;
rc = unlink(name);
if (rc) {
eprintf("del_file \"%s\" :", name);
return;
}
++Inst.num_deleted;
}
void del_dir (char *name)
{
int rc;
rc = rmdir(name);
if (rc) {
eprintf("del_dir \"%s\" :", name);
return;
}
++Inst.num_deleted;
}
void rand_file (char *path, arg_s *arg)
{
char name[MAX_NAME];
gen_name(name, arg);
add_name(path, name);
cr_file(path, arg);
drop_name(path);
}
void rand_dir (char *path, arg_s *arg)
{
char name[MAX_NAME];
gen_name(name, arg);
add_name(path, name);
cr_dir(path);
}
void mk_dir (char *path, unsigned width, unsigned depth, arg_s *arg)
{
unsigned i;
for (i = 0; i < width; i++) {
if (depth) {
rand_dir(path, arg);
mk_dir(path, width, depth-1, arg);
drop_name(path);
} else {
rand_file(path, arg);
}
}
}
void mk_tree (char *name, int width, int depth, arg_s *arg)
{
char path[MAX_PATH];
strcpy(path, name);
cr_dir(path);
mk_dir(path, width, depth, arg);
}
static void pr_indent (unsigned level)
{
while (level--) {
printf(" ");
}
}
void walk_dir (char *path, unsigned level)
{
struct dirent *d;
DIR *dir;
dir = open_dir(path);
for (;;) {
d = readdir(dir);
if (!d) break;
if ((strcmp(d->d_name, ".") == 0) ||
(strcmp(d->d_name, "..") == 0)) {
continue;
}
pr_indent(level); printf("%s\n", d->d_name);
add_name(path, d->d_name);
if (is_dir(path)) {
walk_dir(path, level+1);
}
drop_name(path);
}
close_dir(dir);
}
void walk_tree (char *name)
{
char path[MAX_PATH];
strcpy(path, name);
walk_dir(path, 0);
}
void copy_dir (char *from, char *to)
{
struct dirent *d;
DIR *dir;
dir = open_dir(from);
cr_dir(to);
for (;;) {
d = readdir(dir);
if (!d) break;
if ((strcmp(d->d_name, ".") == 0) ||
(strcmp(d->d_name, "..") == 0)) {
continue;
}
add_name(to, d->d_name);
add_name(from, d->d_name);
if (is_dir(from)) {
copy_dir(from, to);
} else {
copy_file(from, to);
}
drop_name(from);
drop_name(to);
}
close_dir(dir);
}
void copy_tree (char *from, char *to)
{
char path_from[MAX_PATH];
char path_to[MAX_PATH];
strcpy(path_from, from);
strcpy(path_to, to);
copy_dir(path_from, path_to);
}
void delete_dir (char *path)
{
struct dirent *d;
DIR *dir;
dir = open_dir(path);
for (;;) {
d = readdir(dir);
if (!d) break;
if ((strcmp(d->d_name, ".") == 0) ||
(strcmp(d->d_name, "..") == 0)) {
continue;
}
add_name(path, d->d_name);
if (is_dir(path)) {
delete_dir(path);
} else {
del_file(path);
}
drop_name(path);
}
close_dir(dir);
del_dir(path);
}
void delete_tree (char *name)
{
char path[MAX_PATH];
strcpy(path, name);
delete_dir(path);
}
void *ztree (void *arg)
{
arg_s *a = arg;
//printf("Begin mk_tree %s\n", a->from);
mk_tree(a->from, a->width, a->depth, arg);
// walk_tree(a->from);
//printf("Begin copy_tree %s\n", a->to);
copy_tree(a->from, a->to);
// walk_tree(a->to);
#if 1
//printf("Begin delete_tree %s\n", a->from);
delete_tree(a->from);
//printf("Begin delete_tree %s\n", a->to);
delete_tree(a->to);
#endif
return NULL;
}
void rate (void)
{
#define SET_DELTA(x) delta.x = new.x - old.x
static inst_s old = { 0 };
static inst_s new;
static inst_s delta;
for (;;) {
sleep(1);
new = Inst;
SET_DELTA(num_opens);
SET_DELTA(num_dirs);
SET_DELTA(num_files);
SET_DELTA(num_deleted);
SET_DELTA(num_read);
SET_DELTA(num_written);
pr_delta( &delta);
if (delta.num_opens+delta.num_dirs+delta.num_files+
delta.num_deleted+delta.num_read+
delta.num_written == 0) {
zero(old);
return;
}
old = new;
}
}
void start_threads (unsigned threads, unsigned width, unsigned depth, char *from, char *to)
{
pthread_t *thread;
unsigned i;
int rc;
arg_s *arg;
arg_s *a;
thread = ezalloc(threads * sizeof(pthread_t));
arg = ezalloc(threads * sizeof(arg_s));
for (i = 0, a = arg; i < threads; i++, a++) {
sprintf(a->from, "%s_%d", from, i);
sprintf(a->to, "%s_%d", to, i);
a->width = width;
a->depth = depth;
a->seed = random();
rc = pthread_create( &thread[i], NULL, ztree, a);
if (rc) {
eprintf("pthread_create %d\n", rc);
break;
}
}
if (Myopt.rate) rate();
while (i--) {
pthread_join(thread[i], NULL);
}
}
void usage (void)
{
pr_usage("-r -i<iterations> -t<threads> -w<width> -k<depth>"
" -d<start> -f<from> -o<to>");
}
bool myopt (int c)
{
switch (c) {
case 'r':
Myopt.rate = TRUE;
break;
case 'k':
Myopt.depth = strtoll(optarg, NULL, 0);
break;
case 'w':
Myopt.width = strtoll(optarg, NULL, 0);
break;
case 'f':
Myopt.from = optarg;
break;
case 'o':
Myopt.to = optarg;
break;
default:
return FALSE;
}
return TRUE;
}
int main (int argc, char *argv[])
{
char *dir;
char *from;
char *to;
unsigned threads;
unsigned width;
unsigned depth;
unsigned i;
Option.iterations = 4;
Option.numthreads = 2;
punyopt(argc, argv, myopt, "rk:w:f:o:");
threads = Option.numthreads;
dir = Option.dir;
width = Myopt.width;
depth = Myopt.depth;
from = Myopt.from;
to = Myopt.to;
init(dir);
for (i = 0; i < Option.iterations; i++) {
srandom(137);
startTimer();
start_threads(threads, width, depth, from, to);
stopTimer();
pr_inst( &Inst);
prTimer();
printf("\n");
clear_inst();
}
cleanup(dir);
return 0;
}