/* * Copyright (C) 2015 University of Chicago. * See COPYRIGHT notice in top-level directory. * */ #define _XOPEN_SOURCE 500 #define _GNU_SOURCE #include "darshan-runtime-config.h" #include #ifdef HAVE_MNTENT_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uthash.h" #include "darshan.h" #include "darshan-core.h" #include "darshan-dynamic.h" extern char* __progname; extern char* __progname_full; /* internal variable delcarations */ static struct darshan_core_runtime *darshan_core = NULL; static pthread_mutex_t darshan_core_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; static int my_rank = -1; static int nprocs = -1; static int darshan_mem_alignment = 1; static long darshan_mod_mem_quota = DARSHAN_MOD_MEM_MAX; /* paths prefixed with the following directories are not traced by darshan */ char* darshan_path_exclusions[] = { "/etc/", "/dev/", "/usr/", "/bin/", "/boot/", "/lib/", "/opt/", "/sbin/", "/sys/", "/proc/", "/var/", NULL }; #ifdef DARSHAN_BGQ extern void bgq_runtime_initialize(); #endif /* array of init functions for modules which need to be statically * initialized by darshan at startup time */ void (*mod_static_init_fns[])(void) = { #ifdef DARSHAN_BGQ &bgq_runtime_initialize, #endif NULL }; #define DARSHAN_CORE_LOCK() pthread_mutex_lock(&darshan_core_mutex) #define DARSHAN_CORE_UNLOCK() pthread_mutex_unlock(&darshan_core_mutex) /* FS mount information */ #define DARSHAN_MAX_MNTS 64 #define DARSHAN_MAX_MNT_PATH 256 #define DARSHAN_MAX_MNT_TYPE 32 struct mnt_data { int block_size; char path[DARSHAN_MAX_MNT_PATH]; char type[DARSHAN_MAX_MNT_TYPE]; }; static struct mnt_data mnt_data_array[DARSHAN_MAX_MNTS]; static int mnt_data_count = 0; /* prototypes for internal helper functions */ #ifdef __DARSHAN_ENABLE_MMAP_LOGS static void *darshan_init_mmap_log( struct darshan_core_runtime* core, int jobid); #endif static void darshan_log_record_hints_and_ver( struct darshan_core_runtime* core); static void darshan_get_exe_and_mounts( struct darshan_core_runtime *core, int argc, char **argv); static int darshan_add_name_record_ref( struct darshan_core_runtime *core, darshan_record_id rec_id, const char *name, darshan_module_id mod_id); static int darshan_block_size_from_path( const char *path); static void darshan_get_user_name( char *user); static void darshan_get_logfile_name( char* logfile_name, int jobid, struct tm* start_tm); static void darshan_get_shared_records( struct darshan_core_runtime *core, darshan_record_id **shared_recs, int *shared_rec_cnt); static int darshan_log_open_all( char *logfile_name, MPI_File *log_fh); static int darshan_deflate_buffer( void **pointers, int *lengths, int count, char *comp_buf, int *comp_buf_length); static int darshan_log_write_name_record_hash( MPI_File log_fh, struct darshan_core_runtime *core, uint64_t *inout_off); static int darshan_log_append_all( MPI_File log_fh, struct darshan_core_runtime *core, void *buf, int count, uint64_t *inout_off); static void darshan_core_cleanup( struct darshan_core_runtime* core); /* *********************************** */ void darshan_core_initialize(int argc, char **argv) { struct darshan_core_runtime *init_core = NULL; int internal_timing_flag = 0; double init_start, init_time, init_max; char *envstr; char *jobid_str; int jobid; int ret; int tmpval; int i; DARSHAN_MPI_CALL(PMPI_Comm_size)(MPI_COMM_WORLD, &nprocs); DARSHAN_MPI_CALL(PMPI_Comm_rank)(MPI_COMM_WORLD, &my_rank); if(getenv("DARSHAN_INTERNAL_TIMING")) internal_timing_flag = 1; if(internal_timing_flag) init_start = DARSHAN_MPI_CALL(PMPI_Wtime)(); /* setup darshan runtime if darshan is enabled and hasn't been initialized already */ if(!getenv("DARSHAN_DISABLE") && !darshan_core) { #if (__DARSHAN_MEM_ALIGNMENT < 1) #error Darshan must be configured with a positive value for --with-mem-align #endif envstr = getenv(DARSHAN_MEM_ALIGNMENT_OVERRIDE); if(envstr) { ret = sscanf(envstr, "%d", &tmpval); /* silently ignore if the env variable is set poorly */ if(ret == 1 && tmpval > 0) { darshan_mem_alignment = tmpval; } } else { darshan_mem_alignment = __DARSHAN_MEM_ALIGNMENT; } /* avoid floating point errors on faulty input */ if(darshan_mem_alignment < 1) { darshan_mem_alignment = 1; } /* Use DARSHAN_JOBID_OVERRIDE for the env var for __DARSHAN_JOBID */ envstr = getenv(DARSHAN_JOBID_OVERRIDE); if(!envstr) { envstr = __DARSHAN_JOBID; } /* find a job id */ jobid_str = getenv(envstr); if(jobid_str) { /* in cobalt we can find it in env var */ ret = sscanf(jobid_str, "%d", &jobid); } if(!jobid_str || ret != 1) { /* use pid as fall back */ jobid = getpid(); } /* allocate structure to track darshan core runtime information */ init_core = malloc(sizeof(*init_core)); if(init_core) { memset(init_core, 0, sizeof(*init_core)); init_core->wtime_offset = DARSHAN_MPI_CALL(PMPI_Wtime)(); /* TODO: do we alloc new memory as we go or just do everything up front? */ #ifndef __DARSHAN_ENABLE_MMAP_LOGS /* just allocate memory for each log file region */ init_core->log_hdr_p = malloc(sizeof(struct darshan_header)); init_core->log_job_p = malloc(sizeof(struct darshan_job)); init_core->log_exemnt_p = malloc(DARSHAN_EXE_LEN+1); init_core->log_name_p = malloc(DARSHAN_NAME_RECORD_BUF_SIZE); init_core->log_mod_p = malloc(darshan_mod_mem_quota); if(!(init_core->log_hdr_p) || !(init_core->log_job_p) || !(init_core->log_exemnt_p) || !(init_core->log_name_p) || !(init_core->log_mod_p)) { free(init_core); return; } /* if allocation succeeds, zero fill memory regions */ memset(init_core->log_hdr_p, 0, sizeof(struct darshan_header)); memset(init_core->log_job_p, 0, sizeof(struct darshan_job)); memset(init_core->log_exemnt_p, 0, DARSHAN_EXE_LEN+1); memset(init_core->log_name_p, 0, DARSHAN_NAME_RECORD_BUF_SIZE); memset(init_core->log_mod_p, 0, darshan_mod_mem_quota); #else /* if mmap logs are enabled, we need to initialize the mmap region * before setting the corresponding log file region pointers */ void *mmap_p = darshan_init_mmap_log(init_core, jobid); if(!mmap_p) { free(init_core); return; } /* set the memory pointers for each log file region */ init_core->log_hdr_p = (struct darshan_header *)mmap_p; init_core->log_job_p = (struct darshan_job *) ((char *)init_core->log_hdr_p + sizeof(struct darshan_header)); init_core->log_exemnt_p = (char *) ((char *)init_core->log_job_p + sizeof(struct darshan_job)); init_core->log_name_p = (void *) ((char *)init_core->log_exemnt_p + DARSHAN_EXE_LEN + 1); init_core->log_mod_p = (void *) ((char *)init_core->log_name_p + DARSHAN_NAME_RECORD_BUF_SIZE); /* set header fields needed for the mmap log mechanism */ init_core->log_hdr_p->comp_type = DARSHAN_NO_COMP; init_core->log_hdr_p->name_map.off = ((char *)init_core->log_name_p - (char *)init_core->log_hdr_p); #endif /* set known header fields for the log file */ strcpy(init_core->log_hdr_p->version_string, DARSHAN_LOG_VERSION); init_core->log_hdr_p->magic_nr = DARSHAN_MAGIC_NR; /* set known job-level metadata fields for the log file */ init_core->log_job_p->uid = getuid(); init_core->log_job_p->start_time = time(NULL); init_core->log_job_p->nprocs = nprocs; init_core->log_job_p->jobid = (int64_t)jobid; /* if we are using any hints to write the log file, then record those * hints with the darshan job information */ darshan_log_record_hints_and_ver(init_core); /* collect information about command line and mounted file systems */ darshan_get_exe_and_mounts(init_core, argc, argv); /* bootstrap any modules with static initialization routines */ i = 0; while(mod_static_init_fns[i]) { (*mod_static_init_fns[i])(); i++; } darshan_core = init_core; } } if(internal_timing_flag) { init_time = DARSHAN_MPI_CALL(PMPI_Wtime)() - init_start; DARSHAN_MPI_CALL(PMPI_Reduce)(&init_time, &init_max, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); if(my_rank == 0) { fprintf(stderr, "#darshan:\t\t