The threads/process jobs should use _exit() so they don't run
the main atexit() function.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
random Dump info related to random offset generation
parse Dump info related to option matching and parsing
diskutil Dump info related to disk utilization updates
random Dump info related to random offset generation
parse Dump info related to option matching and parsing
diskutil Dump info related to disk utilization updates
+ job:x Dump info only related to job number x
? or help Show available debug options.
You can specify as many as you want, eg --debug=file,mem will enable
? or help Show available debug options.
You can specify as many as you want, eg --debug=file,mem will enable
FD_RANDOM,
FD_PARSE,
FD_DISKUTIL,
FD_RANDOM,
FD_PARSE,
FD_DISKUTIL,
struct debug_level {
const char *name;
unsigned long shift;
struct debug_level {
const char *name;
unsigned long shift;
};
extern struct debug_level debug_levels[];
extern unsigned long fio_debug;
};
extern struct debug_level debug_levels[];
extern unsigned long fio_debug;
+extern unsigned int fio_debug_jobno, *fio_debug_jobp;
#define dprint(type, str, args...) \
do { \
#define dprint(type, str, args...) \
do { \
+ pid_t pid = getpid(); \
assert(type < FD_DEBUG_MAX); \
if ((((1 << type)) & fio_debug) == 0) \
break; \
assert(type < FD_DEBUG_MAX); \
if ((((1 << type)) & fio_debug) == 0) \
break; \
+ if (fio_debug_jobp && *fio_debug_jobp != -1U \
+ && pid != *fio_debug_jobp) \
+ break; \
log_info("%-8s ", debug_levels[(type)].name); \
log_info("%-8s ", debug_levels[(type)].name); \
+ log_info("%-5u ", pid); \
log_info(str, ##args); \
} while (0)
log_info(str, ##args); \
} while (0)
+void file_hash_exit(void)
+{
+ unsigned int i, has_entries = 0;
+
+ fio_mutex_down(hash_lock);
+ for (i = 0; i < HASH_BUCKETS; i++)
+ has_entries += !list_empty(&file_hash[i]);
+ fio_mutex_up(hash_lock);
+
+ if (has_entries)
+ log_err("fio: file hash not empty on exit\n");
+
+ file_hash = NULL;
+ fio_mutex_remove(hash_lock);
+ hash_lock = NULL;
+}
+
void file_hash_init(void *ptr)
{
unsigned int i;
void file_hash_init(void *ptr)
{
unsigned int i;
extern unsigned int file_hash_size;
extern void file_hash_init(void *);
extern unsigned int file_hash_size;
extern void file_hash_init(void *);
+extern void file_hash_exit(void);
extern struct fio_file *lookup_file_hash(const char *);
extern struct fio_file *add_file_hash(struct fio_file *);
extern void remove_file_hash(struct fio_file *);
extern struct fio_file *lookup_file_hash(const char *);
extern struct fio_file *add_file_hash(struct fio_file *);
extern void remove_file_hash(struct fio_file *);
if (pthread_detach(td->thread) < 0)
perror("pthread_detach");
} else {
if (pthread_detach(td->thread) < 0)
perror("pthread_detach");
} else {
dprint(FD_PROCESS, "will fork\n");
dprint(FD_PROCESS, "will fork\n");
+ pid = fork();
+ if (!pid) {
int ret = fork_main(shm_id, i);
int ret = fork_main(shm_id, i);
+ _exit(ret);
+ } else if (i == fio_debug_jobno)
+ *fio_debug_jobp = pid;
}
fio_mutex_down(startup_mutex);
}
}
fio_mutex_down(startup_mutex);
}
static int prev_group_jobs;
unsigned long fio_debug = 0;
static int prev_group_jobs;
unsigned long fio_debug = 0;
+unsigned int fio_debug_jobno = -1;
+unsigned int *fio_debug_jobp = NULL;
/*
* Command line options. These will contain the above, plus a few
/*
* Command line options. These will contain the above, plus a few
struct shmid_ds sbuf;
if (threads) {
struct shmid_ds sbuf;
if (threads) {
- shmdt((void *) threads);
+ file_hash_exit();
+ fio_debug_jobp = NULL;
+ shmdt(tp);
shmctl(shm_id, IPC_RMID, &sbuf);
}
shmctl(shm_id, IPC_RMID, &sbuf);
}
size_t size = max_jobs * sizeof(struct thread_data);
size += file_hash_size;
size_t size = max_jobs * sizeof(struct thread_data);
size += file_hash_size;
+ size += sizeof(unsigned int);
shm_id = shmget(0, size, IPC_CREAT | 0600);
if (shm_id != -1)
shm_id = shmget(0, size, IPC_CREAT | 0600);
if (shm_id != -1)
memset(threads, 0, max_jobs * sizeof(struct thread_data));
hash = (void *) threads + max_jobs * sizeof(struct thread_data);
memset(threads, 0, max_jobs * sizeof(struct thread_data));
hash = (void *) threads + max_jobs * sizeof(struct thread_data);
+ fio_debug_jobp = (void *) hash + file_hash_size;
+ *fio_debug_jobp = -1;
file_hash_init(hash);
atexit(free_shm);
return 0;
file_hash_init(hash);
atexit(free_shm);
return 0;
{ .name = "random", .shift = FD_RANDOM },
{ .name = "parse", .shift = FD_PARSE },
{ .name = "diskutil", .shift = FD_DISKUTIL },
{ .name = "random", .shift = FD_RANDOM },
{ .name = "parse", .shift = FD_PARSE },
{ .name = "diskutil", .shift = FD_DISKUTIL },
+ { .name = "job", .shift = FD_JOB },
}
log_info("all\n");
return 1;
}
log_info("all\n");
return 1;
- } else if (!strcmp(string, "all")) {
- fio_debug = ~0UL;
- return 0;
}
while ((opt = strsep(&p, ",")) != NULL) {
int found = 0;
}
while ((opt = strsep(&p, ",")) != NULL) {
int found = 0;
+ if (!strncmp(opt, "all", 3)) {
+ log_info("fio: set all debug options\n");
+ fio_debug = ~0UL;
+ continue;
+ }
+
for (i = 0; debug_levels[i].name; i++) {
dl = &debug_levels[i];
for (i = 0; debug_levels[i].name; i++) {
dl = &debug_levels[i];
- if (!strncmp(opt, dl->name, strlen(opt))) {
+ found = !strncmp(opt, dl->name, strlen(dl->name));
+ if (!found)
+ continue;
+
+ if (dl->shift == FD_JOB) {
+ opt = strchr(opt, ':');
+ if (!opt) {
+ log_err("fio: missing job number\n");
+ break;
+ }
+ opt++;
+ fio_debug_jobno = atoi(opt);
+ log_info("fio: set debug jobno %d\n",
+ fio_debug_jobno);
+ } else {
log_info("fio: set debug option %s\n", opt);
log_info("fio: set debug option %s\n", opt);
fio_debug |= (1UL << dl->shift);
fio_debug |= (1UL << dl->shift);