2 * Copyright (c) International Business Machines Corp., 2001-2004
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
12 * the GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <sys/types.h>
29 /* First zero out struct, set num_dirs, and strdups basedir */
30 void init_ffsb_fs(ffsb_fs_t *fs, char *basedir, uint32_t num_data_dirs,
31 uint32_t numstartfiles, unsigned flags)
33 memset(fs, 0, sizeof(ffsb_fs_t));
34 fs->basedir = ffsb_strdup(basedir);
35 fs->num_dirs = num_data_dirs;
36 fs->num_start_files = numstartfiles;
38 fs->create_blocksize = FFSB_FS_DEFAULT_CREATE_BLOCKSIZE;
39 fs->age_blocksize = FFSB_FS_DEFAULT_AGE_BLOCKSIZE;
44 * Does not remove files/dirs on disk, only frees up data
47 void destroy_ffsb_fs(ffsb_fs_t *fs)
50 destroy_filelist(&fs->files);
51 destroy_filelist(&fs->fill);
52 destroy_filelist(&fs->meta);
55 void clone_ffsb_fs(ffsb_fs_t *target, ffsb_fs_t *orig)
57 target->basedir = orig->basedir;
58 target->flags = orig->flags;
60 /* !!!! hackish, write a filelist_clone() function later */
61 memcpy(&target->files, &orig->files, sizeof(orig->files));
62 memcpy(&target->fill, &orig->fill, sizeof(orig->fill));
63 memcpy(&target->meta, &orig->meta, sizeof(orig->meta));
65 target->num_dirs = orig->num_dirs;
66 target->num_start_files = orig->num_start_files;
67 target->minfilesize = orig->minfilesize;
68 target->maxfilesize = orig->maxfilesize;
70 target->start_fsutil = orig->start_fsutil;
71 target->desired_fsutil = orig->desired_fsutil;
73 target->age_fs = orig->age_fs;
74 target->num_age_dirs = orig->num_age_dirs;
75 target->aging_tg = orig->aging_tg;
77 target->create_blocksize = orig->create_blocksize;
78 target->age_blocksize = orig->age_blocksize;
80 memcpy(target->op_data, orig->op_data, sizeof(void *) * FFSB_NUMOPS);
83 static void add_files(ffsb_fs_t *fs, struct benchfiles *bf, int num,
84 uint64_t minsize, uint64_t maxsize, unsigned blocksize)
86 struct ffsb_file *cur;
87 int i, fd, condition = 0, has_directio = 0;
89 char *buf = ffsb_malloc(blocksize);
90 uint64_t initial_free = getfsutil_size(fs->basedir);
92 if (fs_get_directio(fs)) {
94 fs_set_directio(fs, 0);
103 else if (fs->init_size) {
104 if (getfsutil(fs->basedir) != initial_free ||
105 fs->init_size > (getfsutil_size(fs->basedir) -
111 else if (fs->init_fsutil) {
112 if (fs->init_fsutil > getfsutil(fs->basedir))
120 if (fs->num_weights) {
121 int num = 1 + getrandom(&rd, fs->sum_weights);
124 while (fs->size_weights[curop].weight < num) {
125 num -= fs->size_weights[curop].weight;
128 size = fs->size_weights[curop].size;
131 size = minsize + getllrandom(&rd, maxsize - minsize);
133 cur = add_file(bf, size, &rd);
134 fd = fhopencreate(cur->name, NULL, fs);
135 writefile_helper(fd, size, blocksize, buf, NULL, fs);
136 fhclose(fd, NULL, fs);
137 unlock_file_writer(cur);
141 else if (fs->init_size) {
142 if (fs->init_size > getfsutil_size(fs->basedir) -
148 else if (fs->init_fsutil) {
149 if (fs->init_fsutil > getfsutil(fs->basedir))
158 fs_set_directio(fs, 1);
161 static void age_fs(ffsb_fs_t *fs, double utilization);
162 static ffsb_fs_t *construct_new_fileset(ffsb_fs_t *fs);
163 static ffsb_fs_t *check_existing_fileset(ffsb_fs_t *fs);
165 void *construct_ffsb_fs(void *data)
167 ffsb_fs_t *fs = (ffsb_fs_t *)data;
168 ffsb_fs_t *ret = NULL;
170 if (fs_get_reuse_fs(fs)) {
171 printf("checking existing fs: %s\n", fs->basedir);
172 ret = check_existing_fileset(fs);
174 printf("recreating new fileset\n");
175 ret = construct_new_fileset(fs);
178 printf("creating new fileset %s\n", fs->basedir);
179 ret = construct_new_fileset(fs);
182 printf("fs setup on %s failed\n", fs->basedir);
188 static int verify_file(struct benchfiles *bf, char *fname, void *fs_ptr)
190 ffsb_fs_t *fs = (ffsb_fs_t *)fs_ptr;
191 uint64_t minsize = fs->minfilesize;
192 uint64_t maxsize = fs->maxfilesize;
193 uint64_t filesize = 0;
197 /* If it is a directory and it passed the name verification we
198 * don't need to do anything here
200 dirptr = opendir(fname);
206 fd = open(fname, O_RDONLY);
207 /* If we can't open it for read we're done */
209 printf("verify_file: error opening %s for readonly\n", fname);
214 filesize = ffsb_get_filesize(fname);
216 if (filesize < minsize || filesize > maxsize) {
217 printf("size %"PRIu64" bytes for file %s is invalid\n",
225 /* Record the number of files and directorys there are supposed to be
226 * grab (check and build the structures) the regular data fileset then
227 * check to make sure the number of directories and files in that
228 * filelist matches up. Then grab the meta filelist and verify that
229 * the meta filelist is empty. Set up the filelist for fill (aging)
230 * and setup the ops for the benchmark.
232 static ffsb_fs_t *check_existing_fileset(ffsb_fs_t *fs)
234 char buf[FILENAME_MAX * 3];
236 uint32_t num_dirs = fs->num_dirs;
237 uint32_t num_files = fs->num_start_files;
240 printf("Aging and reusing the fileset are mutually "
242 printf("aborting\n");
246 /* Set up bench/age dir */
248 snprintf(buf, FILENAME_MAX, "%s/%s", fs->basedir, FILES_BASE)) {
249 printf("pathname \"%s\" is too long, aborting\n", buf);
253 /* Make a "dummy" filelist that has numsubdirs set to 0 and
254 * numstartfiles set to 0
256 init_filelist(&fs->files, buf, FILES_BASE, 0, 0);
258 retval = grab_old_fileset(&fs->files, buf, verify_file, fs);
263 if ((get_listsize(&fs->files) != num_files) ||
264 (get_numsubdirs(&fs->files) != num_dirs)) {
265 printf("check_existing_fileset: number of files (%u)"
266 " or directorys (%u) don't match up\n",
267 get_listsize(&fs->files), get_numsubdirs(&fs->files));
268 destroy_filelist(&fs->files);
273 snprintf(buf, FILENAME_MAX, "%s/%s", fs->basedir, META_BASE)) {
274 printf("pathname \"%s\" is too long, aborting\n", buf);
278 init_filelist(&fs->meta, buf, META_BASE, 0, 1);
279 retval = grab_old_fileset(&fs->meta, buf, verify_file, fs);
282 destroy_filelist(&fs->files);
286 if ((get_listsize(&fs->meta) != 0) ||
287 (get_numsubdirs(&fs->meta) != 0)) {
288 printf("check_existing_fileset: meta directory isn't empty\n"
290 destroy_filelist(&fs->files);
291 destroy_filelist(&fs->meta);
295 /* Even though we won't use it, we still need to be consistent
298 init_filelist(&fs->fill, buf, AGE_BASE, 0, 0);
300 /* Have to do this or everything else could break. */
307 * clean up fs, "rm -rf data meta"
309 * set up the dirs: files, meta
311 * have ffsb_ops setup their data
312 * create starting files in files
314 static ffsb_fs_t *construct_new_fileset(ffsb_fs_t *fs)
316 char buf[FILENAME_MAX * 3];
318 /* TODO: Convert this quick and dirty rm -rf to a "real"
319 * programmatic version, that doesn't rely on the rm command.
321 if (FILENAME_MAX * 3 <= snprintf(buf, FILENAME_MAX * 3,
322 "rm -rf %s/data %s/meta",
323 fs->basedir, fs->basedir)) {
324 printf("pathname too long for command \"%s\"\n", buf);
328 if (ffsb_system(buf) < 0) {
333 fs->start_fsutil = getfsutil(fs->basedir);
335 /* Set up bench/age dir */
337 snprintf(buf, FILENAME_MAX, "%s/%s", fs->basedir, FILES_BASE)) {
338 printf("pathname \"%s\" is too long, aborting\n", buf);
344 /* Regular files and aging share this directory */
345 init_filelist(&fs->files, buf, FILES_BASE, fs->num_dirs, 1);
346 init_filelist(&fs->fill, buf, AGE_BASE, fs->num_age_dirs, 1);
348 /* Set up meta dir */
349 snprintf(buf, FILENAME_MAX, "%s/%s", fs->basedir, META_BASE);
353 init_filelist(&fs->meta, buf, META_BASE, 0, 1);
357 age_fs(fs, fs->desired_fsutil);
359 /* Call back into ops, set for benchmark */
362 /* Create initial fileset */
363 add_files(fs, &fs->files, fs->num_start_files, fs->minfilesize,
364 fs->maxfilesize, fs->create_blocksize);
374 static int fs_get_util(void *data)
376 struct poll_data *pd = (struct poll_data *) data;
377 double fsutil = getfsutil(pd->fs->basedir);
379 if (fsutil >= pd->util)
385 static void age_fs(ffsb_fs_t *fs, double utilization)
387 ffsb_barrier_t barrier;
389 struct poll_data pdata;
390 ffsb_tg_t *tg = fs_get_aging_tg(fs);
391 tg_run_params_t params;
394 printf("aging fs %s from %.2lf to %.2lf\n", fs->basedir,
395 fs->start_fsutil, utilization);
396 ffsb_barrier_init(&barrier, tg_get_numthreads(tg));
398 init_ffsb_config_1fs(&fc, fs, tg);
401 pdata.util = utilization;
404 params.poll_fn = fs_get_util;
405 params.poll_data = &pdata;
406 params.wait_time = 1;
409 params.tg_barrier = NULL;
410 params.thread_barrier = &barrier;
412 /* Call back into ops, setup for aging */
415 /* Throw in some files to start off, so there's something */
416 add_files(fs, &fs->fill, 10, 0, 0, fs->age_blocksize);
418 pthread_create(&thread, NULL, tg_run, ¶ms);
419 pthread_join(thread, NULL);
422 void fs_set_create_blocksize(ffsb_fs_t *fs, uint32_t blocksize)
424 fs->create_blocksize = blocksize;
427 void fs_set_age_blocksize(ffsb_fs_t *fs, uint32_t blocksize)
429 fs->age_blocksize = blocksize;
432 uint32_t fs_get_create_blocksize(ffsb_fs_t *fs)
434 return fs->create_blocksize;
437 uint32_t fs_get_age_blocksize(ffsb_fs_t *fs)
439 return fs->age_blocksize;
442 char *fs_get_basedir(ffsb_fs_t *fs)
447 uint32_t fs_get_numstartfiles(ffsb_fs_t *fs)
449 return fs->num_start_files;
452 uint32_t fs_get_numdirs(ffsb_fs_t *fs)
457 int fs_get_libcio(ffsb_fs_t *fs)
459 return fs->flags & FFSB_FS_LIBCIO;
462 void fs_set_libcio(ffsb_fs_t *fs, int lio)
465 fs->flags |= FFSB_FS_LIBCIO;
467 fs->flags &= ~0 & ~FFSB_FS_LIBCIO;
470 int fs_get_directio(ffsb_fs_t *fs)
472 return fs->flags & FFSB_FS_DIRECTIO;
475 void fs_set_directio(ffsb_fs_t *fs, int dio)
478 fs->flags |= FFSB_FS_DIRECTIO;
480 fs->flags &= ~0 & ~FFSB_FS_DIRECTIO;
483 int fs_get_alignio(ffsb_fs_t *fs)
485 return fs->flags & FFSB_FS_ALIGNIO4K;
488 void fs_set_alignio(ffsb_fs_t *fs, int aio)
491 fs->flags |= FFSB_FS_ALIGNIO4K;
493 fs->flags &= ~0 & ~FFSB_FS_ALIGNIO4K;
496 int fs_get_reuse_fs(ffsb_fs_t *fs)
498 return fs->flags & FFSB_FS_REUSE_FS;
501 void fs_set_reuse_fs(ffsb_fs_t *fs, int rfs)
504 fs->flags |= FFSB_FS_REUSE_FS;
506 fs->flags &= ~0 & ~FFSB_FS_REUSE_FS;
509 struct benchfiles *fs_get_datafiles(ffsb_fs_t *fs)
514 struct benchfiles *fs_get_metafiles(ffsb_fs_t *fs)
519 struct benchfiles *fs_get_agefiles(ffsb_fs_t *fs)
524 void fs_set_aging_tg(ffsb_fs_t *fs, struct ffsb_tg *tg, double util)
528 fs->desired_fsutil = util;
531 struct ffsb_tg *fs_get_aging_tg(ffsb_fs_t *fs)
536 int fs_get_agefs(ffsb_fs_t *fs)
541 /* TODO: Implement this!!!*/
542 void fs_set_num_age_dirs(ffsb_fs_t *fs, uint32_t numdirs)
544 fs->num_age_dirs = numdirs;
547 void fs_set_opdata(ffsb_fs_t *fs, void *data, unsigned opnum)
549 fs->op_data[opnum] = data;
552 void *fs_get_opdata(ffsb_fs_t *fs, unsigned opnum)
554 return fs->op_data[opnum];
557 void fs_set_min_filesize(ffsb_fs_t *fs, uint64_t size)
559 fs->minfilesize = size;
562 void fs_set_max_filesize(ffsb_fs_t *fs, uint64_t size)
564 fs->maxfilesize = size;
567 uint64_t fs_get_min_filesize(ffsb_fs_t *fs)
569 return fs->minfilesize;
572 uint64_t fs_get_max_filesize(ffsb_fs_t *fs)
574 return fs->maxfilesize;
577 double fs_get_desired_fsutil(ffsb_fs_t *fs)
579 return fs->desired_fsutil;
582 void fs_print_config(ffsb_fs_t *fs)
586 printf("FileSystem %s\n", fs->basedir);
587 printf("==========\n");
588 printf("\t num_dirs = %u\n", fs->num_dirs);
589 printf("\t starting files = %u\n", fs->num_start_files);
591 if (fs->num_weights) {
593 printf("\t Fileset weight:\n");
594 for (i = 0; i < fs->num_weights; i++)
595 printf("\t\t %12"PRIu64" (%6s) -> %u (%.2f%%)\n",
596 fs->size_weights[i].size,
597 ffsb_printsize(buf, fs->size_weights[i].size, 256),
598 fs->size_weights[i].weight,
599 ((float)fs->size_weights[i].weight /
600 (float)fs->sum_weights) * 100);
603 printf("\t min file size = %"PRIu64"\t(%s)\n", fs->minfilesize,
604 ffsb_printsize(buf, fs->minfilesize, 256));
605 printf("\t max file size = %"PRIu64"\t(%s)\n", fs->maxfilesize,
606 ffsb_printsize(buf, fs->maxfilesize, 256));
608 printf("\t directio = %s\n", (fs->flags & FFSB_FS_DIRECTIO) ?
610 printf("\t alignedio = %s\n", (fs->flags & FFSB_FS_ALIGNIO4K) ?
612 printf("\t bufferedio = %s\n", (fs->flags & FFSB_FS_LIBCIO) ?
615 printf("\t aging is %s\n", (fs->age_fs) ? "on" : "off");
616 printf("\t current utilization = %.2f%%\n", getfsutil(fs->basedir)*100);
618 printf("\t desired utilization = %.2lf%%\n", fs->desired_fsutil * 100);
620 tg_print_config_aging(fs->aging_tg, fs->basedir);
625 intptr_t fs_needs_stats(ffsb_fs_t *fs, syscall_t sys)
627 return (fs != NULL) ? (intptr_t)(fs->fsd.config) : 0;
630 void fs_add_stat(ffsb_fs_t *fs, syscall_t sys, uint32_t val)
633 ffsb_add_data(&fs->fsd, sys, val);