blob: ad7219b1ef01d8a982bc2881b1b86f106b6dfcf2 [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 = 32, BLK_SIZE = 4096 };
struct {
u64 num_opens;
u64 num_dirs;
u64 num_files;
u64 num_deleted;
u64 num_read;
u64 num_written;
} Inst;
typedef struct arg_s { /* per task arguments */
unsigned seed;
unint id;
unint num_files;
unint size;
unint fiddle;
} arg_s;
static void randomize (char *buf, unsigned size, arg_s *a)
{
static char rnd_char[] = "abcdefghijklmnopqrstuvwxyz\n";
unsigned i;
for (i = 0; i < size; i++) {
*buf++ = rnd_char[urand_r(sizeof(rnd_char), &a->seed)];
}
}
void pr_inst (void)
{
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 clear_inst (void)
{
zero(Inst);
}
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);
}
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);
}
static int write_block (int fd, int block, arg_s *arg)
{
char buf[BLK_SIZE];
u64 offset;
int rc;
randomize(buf, sizeof(buf), arg);
offset = block * sizeof(buf);
lseek(fd, offset, 0);
rc = write(fd, buf, sizeof(buf));
if (rc == -1) {
eprintf("write_block:");
return -1;
}
return 0;
}
void fill (int fd, unsigned size, arg_s *arg)
{
char buf[BLK_SIZE];
unsigned long i;
randomize(buf, sizeof(buf), arg);
for (i = 0; i < size; i++) {
if (write(fd, buf, sizeof(buf)) < 0) {
fatal("write:");
}
}
Inst.num_written += size;
}
int cr_file (char *name, unsigned size, arg_s *arg)
{
int fd;
fd = creat(name, 0666);
if (fd == -1) {
eprintf("cr_file \"%s\" :", name);
return -1;
}
++Inst.num_files;
fill(fd, size, 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;
PRs(name);
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 fiddle (char *path, arg_s *a)
{
int fd;
int rc;
int i;
fd = open_file(path);
if (fd == -1) return;
for (i = a->size; --i, i > 0; ) {
rc = write_block(fd, i, a);
if (rc) return;
}
close(fd);
}
void mk_path (char *path, char *dir, int i)
{
sprintf(path, "%s/file_%d", dir, i);
}
void *test (void *arg)
{
char path[MAX_PATH];
char dir[MAX_NAME];
arg_s *a = arg;
int i;
int rc;
// make and cd to directory for thread to play in
snprintf(dir, MAX_NAME-1, "fiddle_dir_%ld", a->id);
cr_dir(dir);
// create the number of files with the specific amount of data
for (i = 0; i < a->num_files; i++) {
mk_path(path, dir, i);
rc = cr_file(path, a->size, a);
if (rc) break;
}
a->num_files = i;
// randomly open files and fiddle with their data
for (i = 0; i < a->fiddle; i++) {
mk_path(path, dir, urand_r(a->num_files, &a->seed));
fiddle(path, a);
}
// delete the files
for (i = 0; i < a->num_files; i++) {
mk_path(path, dir, i);
del_file(path);
}
// remove directory
del_dir(dir);
return NULL;
}
void start_threads (
unsigned threads,
unsigned num_files,
unsigned size,
unsigned fiddle)
{
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++) {
a->seed = random();
a->id = i;
a->num_files = num_files;
a->size = size;
a->fiddle = fiddle;
rc = pthread_create( &thread[i], NULL, test, a);
if (rc) {
eprintf("pthread_create %d\n", rc);
break;
}
}
while (i--) {
pthread_join(thread[i], NULL);
}
}
u64 Numfiles = 2;
u64 Fiddle = 2;
bool myopt (int c)
{
switch (c) {
case 'k':
Numfiles = strtoll(optarg, NULL, 0);
break;
case 'q':
Fiddle = strtoll(optarg, NULL, 0);
break;
default:
return FALSE;
}
return TRUE;
}
void usage (void)
{
pr_usage("-t<threads> -k<num_files> -z<size>"
" -q<fiddle> -i<iterations>");
}
int main (int argc, char *argv[])
{
unsigned threads;
unsigned num_files;
unsigned size;
unsigned fiddle;
unsigned iterations;
unsigned i;
punyopt(argc, argv, myopt, "k:q:");
threads = Option.numthreads;
num_files = Numfiles;
size = Option.file_size;
iterations = Option.iterations;
fiddle = Fiddle;
if (!threads || !num_files || !size || !fiddle || !iterations) {
usage();
}
for (i = 0; i < iterations; i++) {
srandom(137);
startTimer();
start_threads(threads, num_files, size, fiddle);
stopTimer();
pr_inst();
prTimer();
printf("\n");
clear_inst();
}
return 0;
}