Commit 88926470 authored by Shane Snyder's avatar Shane Snyder
Browse files

fully implemented darshan-parser w/ all options

parent 814b1266
......@@ -20,9 +20,181 @@
#include "darshan-logutils.h"
/*
* Options
*/
#define OPTION_BASE (1 << 0) /* darshan log fields */
#define OPTION_TOTAL (1 << 1) /* aggregated fields */
#define OPTION_PERF (1 << 2) /* derived performance */
#define OPTION_FILE (1 << 3) /* file count totals */
#define OPTION_FILE_LIST (1 << 4) /* per-file summaries */
#define OPTION_FILE_LIST_DETAILED (1 << 6) /* per-file summaries with extra detail */
#define OPTION_ALL (\
OPTION_BASE|\
OPTION_TOTAL|\
OPTION_PERF|\
OPTION_FILE|\
OPTION_FILE_LIST|\
OPTION_FILE_LIST_DETAILED)
#define FILETYPE_SHARED (1 << 0)
#define FILETYPE_UNIQUE (1 << 1)
#define FILETYPE_PARTSHARED (1 << 2)
#define max(a,b) (((a) > (b)) ? (a) : (b))
/*
* Datatypes
*/
typedef struct hash_entry_s
{
UT_hash_handle hlink;
darshan_record_id rec_id;
int64_t type;
int64_t procs;
void *rec_dat;
double cumul_time;
double slowest_time;
} hash_entry_t;
typedef struct file_data_s
{
int64_t total;
int64_t total_size;
int64_t total_max;
int64_t read_only;
int64_t read_only_size;
int64_t read_only_max;
int64_t write_only;
int64_t write_only_size;
int64_t write_only_max;
int64_t read_write;
int64_t read_write_size;
int64_t read_write_max;
int64_t unique;
int64_t unique_size;
int64_t unique_max;
int64_t shared;
int64_t shared_size;
int64_t shared_max;
} file_data_t;
typedef struct perf_data_s
{
int64_t total_bytes;
double slowest_rank_time;
double slowest_rank_meta_time;
int slowest_rank_rank;
double shared_time_by_cumul;
double shared_time_by_open;
double shared_time_by_open_lastio;
double shared_time_by_slowest;
double shared_meta_time;
double agg_perf_by_cumul;
double agg_perf_by_open;
double agg_perf_by_open_lastio;
double agg_perf_by_slowest;
double *rank_cumul_io_time;
double *rank_cumul_md_time;
} perf_data_t;
/*
* Prototypes
*/
void posix_accum_file(struct darshan_posix_file *pfile, hash_entry_t *hfile, int64_t nprocs);
void posix_accum_perf(struct darshan_posix_file *pfile, perf_data_t *pdata);
void posix_calc_file(hash_entry_t *file_hash, file_data_t *fdata);
void posix_print_total_file(struct darshan_posix_file *pfile);
void posix_file_list(hash_entry_t *file_hash, struct darshan_record_ref *rec_hash, int detail_flag);
void mpiio_accum_file(struct darshan_mpiio_file *mfile, hash_entry_t *hfile, int64_t nprocs);
void mpiio_accum_perf(struct darshan_mpiio_file *mfile, perf_data_t *pdata);
void mpiio_calc_file(hash_entry_t *file_hash, file_data_t *fdata);
void mpiio_print_total_file(struct darshan_mpiio_file *mfile);
void mpiio_file_list(hash_entry_t *file_hash, struct darshan_record_ref *rec_hash, int detail_flag);
void calc_perf(perf_data_t *pdata, int64_t nprocs);
int usage (char *exename)
{
fprintf(stderr, "Usage: %s [options] <filename>\n", exename);
fprintf(stderr, " --all : all sub-options are enabled\n");
fprintf(stderr, " --base : darshan log field data [default]\n");
fprintf(stderr, " --file : total file counts\n");
fprintf(stderr, " --file-list : per-file summaries\n");
fprintf(stderr, " --file-list-detailed : per-file summaries with additional detail\n");
fprintf(stderr, " --perf : derived perf data\n");
fprintf(stderr, " --total : aggregated darshan field data\n");
exit(1);
}
int parse_args (int argc, char **argv, char **filename)
{
int index;
int mask;
static struct option long_opts[] =
{
{"all", 0, NULL, OPTION_ALL},
{"base", 0, NULL, OPTION_BASE},
{"file", 0, NULL, OPTION_FILE},
{"file-list", 0, NULL, OPTION_FILE_LIST},
{"file-list-detailed", 0, NULL, OPTION_FILE_LIST_DETAILED},
{"perf", 0, NULL, OPTION_PERF},
{"total", 0, NULL, OPTION_TOTAL},
{"help", 0, NULL, 0},
{0, 0, 0, 0}
};
mask = 0;
while(1)
{
int c = getopt_long(argc, argv, "", long_opts, &index);
if (c == -1) break;
switch(c)
{
case OPTION_ALL:
case OPTION_BASE:
case OPTION_FILE:
case OPTION_FILE_LIST:
case OPTION_FILE_LIST_DETAILED:
case OPTION_PERF:
case OPTION_TOTAL:
mask |= c;
break;
case 0:
case '?':
default:
usage(argv[0]);
break;
}
}
if (optind < argc)
{
*filename = argv[optind];
}
else
{
usage(argv[0]);
}
/* default mask value if none specified */
if (mask == 0)
{
mask = OPTION_BASE;
}
return mask;
}
int main(int argc, char **argv)
{
int ret;
int mask;
int i, j;
char *filename;
char tmp_string[4096] = {0};
......@@ -30,7 +202,7 @@ int main(int argc, char **argv)
struct darshan_header header;
struct darshan_job job;
struct darshan_record_ref *rec_hash = NULL;
struct darshan_record_ref *ref, *tmp;
struct darshan_record_ref *ref, *tmp_ref;
int mount_count;
char** mnt_pts;
char** fs_types;
......@@ -42,9 +214,18 @@ int main(int argc, char **argv)
char *mod_buf;
int mod_buf_sz;
/* TODO: argument parsing */
assert(argc == 2);
filename = argv[1];
hash_entry_t *file_hash = NULL;
hash_entry_t *curr = NULL;
hash_entry_t *tmp_file = NULL;
hash_entry_t total;
file_data_t fdata;
perf_data_t pdata;
memset(&total, 0, sizeof(total));
memset(&fdata, 0, sizeof(fdata));
memset(&pdata, 0, sizeof(pdata));
mask = parse_args(argc, argv, &filename);
fd = darshan_log_open(filename);
if(!fd)
......@@ -160,8 +341,18 @@ int main(int argc, char **argv)
if(!mod_buf)
return(-1);
DARSHAN_PRINT_HEADER();
/* TODO: does each module print header of what each counter means??? */
pdata.rank_cumul_io_time = malloc(sizeof(double)*job.nprocs);
pdata.rank_cumul_md_time = malloc(sizeof(double)*job.nprocs);
if (!pdata.rank_cumul_io_time || !pdata.rank_cumul_md_time)
{
darshan_log_close(fd);
return(-1);
}
else
{
memset(pdata.rank_cumul_io_time, 0, sizeof(double)*job.nprocs);
memset(pdata.rank_cumul_md_time, 0, sizeof(double)*job.nprocs);
}
for(i=0; i<DARSHAN_MAX_MODS; i++)
{
......@@ -169,9 +360,11 @@ int main(int argc, char **argv)
void *mod_buf_p;
void *rec_p = NULL;
darshan_record_id rec_id;
void *save_io, *save_md;
memset(mod_buf, 0, DARSHAN_DEF_COMP_BUF_SZ);
/* reset data structures for each module */
mod_buf_sz = DARSHAN_DEF_COMP_BUF_SZ;
memset(mod_buf, 0, DARSHAN_DEF_COMP_BUF_SZ);
/* check each module for any data */
ret = darshan_log_getmod(fd, i, mod_buf, &mod_buf_sz);
......@@ -179,7 +372,6 @@ int main(int argc, char **argv)
{
fprintf(stderr, "Error: failed to get module %s data\n",
darshan_module_names[i]);
fflush(stderr);
darshan_log_close(fd);
return(-1);
}
......@@ -198,23 +390,27 @@ int main(int argc, char **argv)
continue;
}
printf("\n# *******************************************************\n");
printf("# %s module data\n", darshan_module_names[i]);
printf("# *******************************************************\n");
/* this module has data to be parsed and printed */
mod_buf_p = mod_buf;
mod_bytes_left = mod_buf_sz;
mod_buf_p = mod_buf;
/* loop over each of this module's records and print them */
while (mod_bytes_left > 0)
{
char *mnt_pt = NULL;
char *fs_type = NULL;
hash_entry_t *hfile = NULL;
ret = mod_logutils[i]->log_get_record(fd, &mod_buf_p, &mod_bytes_left,
&rec_p, &rec_id);
ret = mod_logutils[i]->log_get_record(&mod_buf_p, &mod_bytes_left,
&rec_p, &rec_id, fd->swap_flag);
if(ret < 0)
{
fprintf(stderr, "Error: failed to parse module %s data record\n",
darshan_module_names[i]);
fflush(stderr);
darshan_log_close(fd);
return(-1);
}
......@@ -238,18 +434,189 @@ int main(int argc, char **argv)
if(!fs_type)
fs_type = "UNKNOWN";
/* print the corresponding module data for this record */
mod_logutils[i]->log_print_record(rec_p, ref->rec.name,
mnt_pt, fs_type);
if(mask & OPTION_BASE)
{
/* TODO: does each module print header of what each counter means??? */
DARSHAN_PRINT_HEADER();
/* print the corresponding module data for this record */
mod_logutils[i]->log_print_record(rec_p, ref->rec.name,
mnt_pt, fs_type);
}
/* we calculate more detailed stats for POSIX and MPI-IO modules,
* if the parser is executed with more than the base option
*/
if(i != DARSHAN_POSIX_MOD && i != DARSHAN_MPIIO_MOD)
break;
HASH_FIND(hlink, file_hash, &rec_id, sizeof(darshan_record_id), hfile);
if(!hfile)
{
hfile = malloc(sizeof(*hfile));
if(!hfile)
return(-1);
/* init */
memset(hfile, 0, sizeof(*hfile));
hfile->rec_id = rec_id;
hfile->type = 0;
hfile->procs = 0;
hfile->rec_dat = NULL;
hfile->cumul_time = 0.0;
hfile->slowest_time = 0.0;
HASH_ADD(hlink, file_hash, rec_id, sizeof(darshan_record_id), hfile);
}
if(i == DARSHAN_POSIX_MOD)
{
posix_accum_file((struct darshan_posix_file*)rec_p, &total, job.nprocs);
posix_accum_file((struct darshan_posix_file*)rec_p, hfile, job.nprocs);
posix_accum_perf((struct darshan_posix_file*)rec_p, &pdata);
}
else if(i == DARSHAN_MPIIO_MOD)
{
mpiio_accum_file((struct darshan_mpiio_file*)rec_p, &total, job.nprocs);
mpiio_accum_file((struct darshan_mpiio_file*)rec_p, hfile, job.nprocs);
mpiio_accum_perf((struct darshan_mpiio_file*)rec_p, &pdata);
}
}
/* Total Calc */
if(mask & OPTION_TOTAL)
{
if(i == DARSHAN_POSIX_MOD)
{
posix_print_total_file((struct darshan_posix_file*)total.rec_dat);
}
else if(i == DARSHAN_MPIIO_MOD)
{
mpiio_print_total_file((struct darshan_mpiio_file*)total.rec_dat);
}
}
/* File Calc */
if(mask & OPTION_FILE)
{
if(i == DARSHAN_POSIX_MOD)
{
posix_calc_file(file_hash, &fdata);
}
else if(i == DARSHAN_MPIIO_MOD)
{
mpiio_calc_file(file_hash, &fdata);
}
printf("\n# files\n");
printf("# -----\n");
printf("# total: %" PRId64 " %" PRId64 " %" PRId64 "\n",
fdata.total,
fdata.total_size,
fdata.total_max);
printf("# read_only: %" PRId64 " %" PRId64 " %" PRId64 "\n",
fdata.read_only,
fdata.read_only_size,
fdata.read_only_max);
printf("# write_only: %" PRId64 " %" PRId64 " %" PRId64 "\n",
fdata.write_only,
fdata.write_only_size,
fdata.write_only_max);
printf("# read_write: %" PRId64 " %" PRId64 " %" PRId64 "\n",
fdata.read_write,
fdata.read_write_size,
fdata.read_write_max);
printf("# unique: %" PRId64 " %" PRId64 " %" PRId64 "\n",
fdata.unique,
fdata.unique_size,
fdata.unique_max);
printf("# shared: %" PRId64 " %" PRId64 " %" PRId64 "\n",
fdata.shared,
fdata.shared_size,
fdata.shared_max);
}
/* Perf Calc */
if(mask & OPTION_PERF)
{
calc_perf(&pdata, job.nprocs);
printf("\n# performance\n");
printf("# -----------\n");
printf("# total_bytes: %" PRId64 "\n", pdata.total_bytes);
printf("#\n");
printf("# I/O timing for unique files (seconds):\n");
printf("# ...........................\n");
printf("# unique files: slowest_rank_io_time: %lf\n", pdata.slowest_rank_time);
printf("# unique files: slowest_rank_meta_time: %lf\n", pdata.slowest_rank_meta_time);
printf("# unique files: slowest rank: %d\n", pdata.slowest_rank_rank);
printf("#\n");
printf("# I/O timing for shared files (seconds):\n");
printf("# (multiple estimates shown; time_by_slowest is generally the most accurate)\n");
printf("# ...........................\n");
printf("# shared files: time_by_cumul_io_only: %lf\n", pdata.shared_time_by_cumul);
printf("# shared files: time_by_cumul_meta_only: %lf\n", pdata.shared_meta_time);
printf("# shared files: time_by_open: %lf\n", pdata.shared_time_by_open);
printf("# shared files: time_by_open_lastio: %lf\n", pdata.shared_time_by_open_lastio);
printf("# shared files: time_by_slowest: %lf\n", pdata.shared_time_by_slowest);
printf("#\n");
printf("# Aggregate performance, including both shared and unique files (MiB/s):\n");
printf("# (multiple estimates shown; agg_perf_by_slowest is generally the most accurate)\n");
printf("# ...........................\n");
printf("# agg_perf_by_cumul: %lf\n", pdata.agg_perf_by_cumul);
printf("# agg_perf_by_open: %lf\n", pdata.agg_perf_by_open);
printf("# agg_perf_by_open_lastio: %lf\n", pdata.agg_perf_by_open_lastio);
printf("# agg_perf_by_slowest: %lf\n", pdata.agg_perf_by_slowest);
}
if((mask & OPTION_FILE_LIST) || (mask & OPTION_FILE_LIST_DETAILED))
{
if(i == DARSHAN_POSIX_MOD)
{
if(mask & OPTION_FILE_LIST_DETAILED)
posix_file_list(file_hash, rec_hash, 1);
else
posix_file_list(file_hash, rec_hash, 0);
}
else if(i == DARSHAN_MPIIO_MOD)
{
if(mask & OPTION_FILE_LIST_DETAILED)
mpiio_file_list(file_hash, rec_hash, 1);
else
mpiio_file_list(file_hash, rec_hash, 0);
}
}
/* reset data structures for next module */
if(total.rec_dat) free(total.rec_dat);
memset(&total, 0, sizeof(total));
memset(&fdata, 0, sizeof(fdata));
save_io = pdata.rank_cumul_io_time;
save_md = pdata.rank_cumul_md_time;
memset(&pdata, 0, sizeof(pdata));
memset(save_io, 0, sizeof(double)*job.nprocs);
memset(save_md, 0, sizeof(double)*job.nprocs);
pdata.rank_cumul_io_time = save_io;
pdata.rank_cumul_md_time = save_md;
HASH_ITER(hlink, file_hash, curr, tmp_file)
{
HASH_DELETE(hlink, file_hash, curr);
if(curr->rec_dat) free(curr->rec_dat);
free(curr);
}
}
if(empty_mods == DARSHAN_MAX_MODS)
printf("# no module data available.\n");
printf("\n# no module data available.\n");
darshan_log_close(fd);
free(mod_buf);
free(pdata.rank_cumul_io_time);
free(pdata.rank_cumul_md_time);
/* free record hash data */
HASH_ITER(hlink, rec_hash, ref, tmp)
HASH_ITER(hlink, rec_hash, ref, tmp_ref)
{
HASH_DELETE(hlink, rec_hash, ref);
free(ref->rec.name);
......@@ -268,7 +635,949 @@ int main(int argc, char **argv)
free(fs_types);
}
darshan_log_close(fd);
return(0);
}
void posix_accum_file(struct darshan_posix_file *pfile,
hash_entry_t *hfile,
int64_t nprocs)
{
int i, j;
int set;
int min_ndx;
int64_t min;
struct darshan_posix_file* tmp;
hfile->procs += 1;
if(pfile->rank == -1)
{
hfile->slowest_time = pfile->fcounters[POSIX_F_SLOWEST_RANK_TIME];
}
else
{
hfile->slowest_time = max(hfile->slowest_time,
(pfile->fcounters[POSIX_F_META_TIME] +
pfile->fcounters[POSIX_F_READ_TIME] +
pfile->fcounters[POSIX_F_WRITE_TIME]));
}
if(pfile->rank == -1)
{
hfile->procs = nprocs;
hfile->type |= FILETYPE_SHARED;
}
else if(hfile->procs > 1)
{
hfile->type &= (~FILETYPE_UNIQUE);
hfile->type |= FILETYPE_PARTSHARED;
}
else
{
hfile->type |= FILETYPE_UNIQUE;
}
hfile->cumul_time += pfile->fcounters[POSIX_F_META_TIME] +
pfile->fcounters[POSIX_F_READ_TIME] +
pfile->fcounters[POSIX_F_WRITE_TIME];
if(hfile->rec_dat == NULL)
{
hfile->rec_dat = malloc(sizeof(struct darshan_posix_file));
assert(hfile->rec_dat);
tmp = (struct darshan_posix_file*)hfile->rec_dat;
memset(tmp, 0, sizeof(struct darshan_posix_file));
}
for(i = 0; i < POSIX_NUM_INDICES; i++)
{
switch(i)
{
case POSIX_MODE:
case POSIX_MEM_ALIGNMENT:
case POSIX_FILE_ALIGNMENT:
if(POSIX_FILE_PARTIAL(tmp))
tmp->counters[i] = pfile->counters[i];
break;
case POSIX_MAX_BYTE_READ:
case POSIX_MAX_BYTE_WRITTEN:
if (tmp->counters[i] < pfile->counters[i])
{
tmp->counters[i] = pfile->counters[i];
}
break;
case POSIX_STRIDE1_STRIDE:
case POSIX_STRIDE2_STRIDE:
case POSIX_STRIDE3_STRIDE:
case POSIX_STRIDE4_STRIDE:
case POSIX_ACCESS1_ACCESS:
case POSIX_ACCESS2_ACCESS:
case POSIX_ACCESS3_ACCESS:
case POSIX_ACCESS4_ACCESS:
/*
* do nothing here because these will be stored
* when the _COUNT is accessed.
*/
break;
case POSIX_STRIDE1_COUNT:
case POSIX_STRIDE2_COUNT:
case POSIX_STRIDE3_COUNT:
case POSIX_STRIDE4_COUNT:
set = 0;
min_ndx = POSIX_STRIDE1_COUNT;
min = tmp->counters[min_ndx];
for(j = POSIX_STRIDE1_COUNT; j <= POSIX_STRIDE4_COUNT; j++)
{
if(tmp->counters[j-4] == pfile->counters[i-4])
{
tmp->counters[j] += pfile->counters[i];
set = 1;
break;
}
if(tmp->counters[j] < min)
{
min_ndx = j;
min = tmp->counters[j];
}
}
if(!set && (pfile->counters[i] > min))
{
tmp->counters[min_ndx] = pfile->counters[i];
tmp->counters[min_ndx-4] = pfile->counters[i-4];
}
break;
case POSIX_ACCESS1_COUNT:
case POSIX_ACCESS2_COUNT:
case POSIX_ACCESS3_COUNT:
case POSIX_ACCESS4_COUNT:
set = 0;
min_ndx = POSIX_ACCESS1_COUNT;
min = tmp->counters[min_ndx];
for(j = POSIX_ACCESS1_COUNT; j <= POSIX_ACCESS4_COUNT; j++)
{
if(tmp->counters[j-4] == pfile->counters[i-4])
{
tmp->counters[j] += pfile->counters[i];
set = 1;
break;
}
if(tmp->counters[j] < min)
{