/* * (C) 2009 by Argonne National Laboratory. * See COPYRIGHT in top-level directory. */ #include "darshan-runtime-config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __USE_GNU #include #include "darshan.h" #ifndef HAVE_OFF64_T typedef int64_t off64_t; #endif extern char* __progname_full; #ifdef DARSHAN_PRELOAD #define __USE_GNU #include #include #define DARSHAN_FORWARD_DECL(name,ret,args) \ ret (*__real_ ## name)args = NULL; #define DARSHAN_DECL(__name) __name #define DARSHAN_MPI_CALL(func) __real_ ## func #define MAP_OR_FAIL(func) \ if (!(__real_ ## func)) \ { \ __real_ ## func = dlsym(RTLD_NEXT, #func); \ if(!(__real_ ## func)) { \ fprintf(stderr, "Darshan failed to map symbol: %s\n", #func); \ exit(1); \ } \ } extern double (*__real_PMPI_Wtime)(void); #else #define DARSHAN_FORWARD_DECL(name,ret,args) \ extern ret __real_ ## name args; #define DARSHAN_DECL(__name) __wrap_ ## __name #define MAP_OR_FAIL(func) #define DARSHAN_MPI_CALL(func) func #endif DARSHAN_FORWARD_DECL(creat, int, (const char* path, mode_t mode)); DARSHAN_FORWARD_DECL(creat64, int, (const char* path, mode_t mode)); DARSHAN_FORWARD_DECL(open, int, (const char *path, int flags, ...)); DARSHAN_FORWARD_DECL(open64, int, (const char *path, int flags, ...)); DARSHAN_FORWARD_DECL(close, int, (int fd)); DARSHAN_FORWARD_DECL(write, ssize_t, (int fd, const void *buf, size_t count)); DARSHAN_FORWARD_DECL(read, ssize_t, (int fd, void *buf, size_t count)); DARSHAN_FORWARD_DECL(lseek, off_t, (int fd, off_t offset, int whence)); DARSHAN_FORWARD_DECL(lseek64, off64_t, (int fd, off64_t offset, int whence)); DARSHAN_FORWARD_DECL(pread, ssize_t, (int fd, void *buf, size_t count, off_t offset)); DARSHAN_FORWARD_DECL(pread64, ssize_t, (int fd, void *buf, size_t count, off64_t offset)); DARSHAN_FORWARD_DECL(pwrite, ssize_t, (int fd, const void *buf, size_t count, off_t offset)); DARSHAN_FORWARD_DECL(pwrite64, ssize_t, (int fd, const void *buf, size_t count, off64_t offset )); DARSHAN_FORWARD_DECL(readv, ssize_t, (int fd, const struct iovec *iov, int iovcnt)); DARSHAN_FORWARD_DECL(writev, ssize_t, (int fd, const struct iovec *iov, int iovcnt)); DARSHAN_FORWARD_DECL(__fxstat, int, (int vers, int fd, struct stat *buf)); DARSHAN_FORWARD_DECL(__fxstat64, int, (int vers, int fd, struct stat64 *buf)); DARSHAN_FORWARD_DECL(__lxstat, int, (int vers, const char* path, struct stat *buf)); DARSHAN_FORWARD_DECL(__lxstat64, int, (int vers, const char* path, struct stat64 *buf)); DARSHAN_FORWARD_DECL(__xstat, int, (int vers, const char* path, struct stat *buf)); DARSHAN_FORWARD_DECL(__xstat64, int, (int vers, const char* path, struct stat64 *buf)); DARSHAN_FORWARD_DECL(mmap, void*, (void *addr, size_t length, int prot, int flags, int fd, off_t offset)); DARSHAN_FORWARD_DECL(mmap64, void*, (void *addr, size_t length, int prot, int flags, int fd, off64_t offset)); DARSHAN_FORWARD_DECL(fopen, FILE*, (const char *path, const char *mode)); DARSHAN_FORWARD_DECL(fopen64, FILE*, (const char *path, const char *mode)); DARSHAN_FORWARD_DECL(fclose, int, (FILE *fp)); DARSHAN_FORWARD_DECL(fread, size_t, (void *ptr, size_t size, size_t nmemb, FILE *stream)); DARSHAN_FORWARD_DECL(fwrite, size_t, (const void *ptr, size_t size, size_t nmemb, FILE *stream)); DARSHAN_FORWARD_DECL(fseek, int, (FILE *stream, long offset, int whence)); DARSHAN_FORWARD_DECL(fsync, int, (int fd)); DARSHAN_FORWARD_DECL(fdatasync, int, (int fd)); pthread_mutex_t cp_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; struct darshan_job_runtime* darshan_global_job = NULL; static int my_rank = -1; static struct stat64 cp_stat_buf; static int darshan_mem_alignment = 1; /* these are paths that we will not trace */ static char* exclusions[] = { "/etc/", "/dev/", "/usr/", "/bin/", "/boot/", "/lib/", "/opt/", "/sbin/", "/sys/", "/proc/", NULL }; static double posix_wtime(void); static void cp_access_counter(struct darshan_file_runtime* file, ssize_t size, enum cp_counter_type type); static struct darshan_file_ref* ref_by_handle( const void* handle, int handle_sz, enum darshan_handle_type handle_type); static struct darshan_file_runtime* darshan_file_by_fd(int fd); static void darshan_file_close_fd(int fd); static struct darshan_file_runtime* darshan_file_by_name_setfd(const char* name, int fd); #define CP_RECORD_WRITE(__ret, __fd, __count, __pwrite_flag, __pwrite_offset, __aligned, __stream_flag, __tm1, __tm2) do{ \ size_t stride; \ int64_t this_offset; \ int64_t file_alignment; \ struct darshan_file_runtime* file; \ double __elapsed = __tm2-__tm1; \ if(__ret < 0) break; \ file = darshan_file_by_fd(__fd); \ if(!file) break; \ if(__pwrite_flag) \ this_offset = __pwrite_offset; \ else \ this_offset = file->offset; \ file_alignment = CP_VALUE(file, CP_FILE_ALIGNMENT); \ if(this_offset > file->last_byte_written) \ CP_INC(file, CP_SEQ_WRITES, 1); \ if(this_offset == (file->last_byte_written + 1)) \ CP_INC(file, CP_CONSEC_WRITES, 1); \ if(this_offset > 0 && this_offset > file->last_byte_written \ && file->last_byte_written != 0) \ stride = this_offset - file->last_byte_written - 1; \ else \ stride = 0; \ file->last_byte_written = this_offset + __ret - 1; \ file->offset = this_offset + __ret; \ CP_MAX(file, CP_MAX_BYTE_WRITTEN, (this_offset + __ret -1)); \ CP_INC(file, CP_BYTES_WRITTEN, __ret); \ if(__stream_flag) \ CP_INC(file, CP_POSIX_FWRITES, 1); \ else \ CP_INC(file, CP_POSIX_WRITES, 1); \ CP_BUCKET_INC(file, CP_SIZE_WRITE_0_100, __ret); \ cp_access_counter(file, stride, CP_COUNTER_STRIDE); \ if(!__aligned) \ CP_INC(file, CP_MEM_NOT_ALIGNED, 1); \ if(file_alignment > 0 && (this_offset % file_alignment) != 0) \ CP_INC(file, CP_FILE_NOT_ALIGNED, 1); \ cp_access_counter(file, __ret, CP_COUNTER_ACCESS); \ if(file->last_io_type == CP_READ) \ CP_INC(file, CP_RW_SWITCHES, 1); \ file->last_io_type = CP_WRITE; \ CP_F_INC_NO_OVERLAP(file, __tm1, __tm2, file->last_posix_write_end, CP_F_POSIX_WRITE_TIME); \ if(CP_F_VALUE(file, CP_F_WRITE_START_TIMESTAMP) == 0) \ CP_F_SET(file, CP_F_WRITE_START_TIMESTAMP, __tm1); \ CP_F_SET(file, CP_F_WRITE_END_TIMESTAMP, __tm2); \ if(CP_F_VALUE(file, CP_F_MAX_WRITE_TIME) < __elapsed){ \ CP_F_SET(file, CP_F_MAX_WRITE_TIME, __elapsed); \ CP_SET(file, CP_MAX_WRITE_TIME_SIZE, __ret); } \ } while(0) #define CP_RECORD_READ(__ret, __fd, __count, __pread_flag, __pread_offset, __aligned, __stream_flag, __tm1, __tm2) do{ \ size_t stride; \ int64_t this_offset; \ struct darshan_file_runtime* file; \ int64_t file_alignment; \ double __elapsed = __tm2-__tm1; \ if(__ret < 0) break; \ file = darshan_file_by_fd(__fd); \ if(!file) break; \ if(__pread_flag)\ this_offset = __pread_offset; \ else \ this_offset = file->offset; \ file_alignment = CP_VALUE(file, CP_FILE_ALIGNMENT); \ if(this_offset > file->last_byte_read) \ CP_INC(file, CP_SEQ_READS, 1); \ if(this_offset == (file->last_byte_read + 1)) \ CP_INC(file, CP_CONSEC_READS, 1); \ if(this_offset > 0 && this_offset > file->last_byte_read \ && file->last_byte_read != 0) \ stride = this_offset - file->last_byte_read - 1; \ else \ stride = 0; \ file->last_byte_read = this_offset + __ret - 1; \ CP_MAX(file, CP_MAX_BYTE_READ, (this_offset + __ret -1)); \ file->offset = this_offset + __ret; \ CP_INC(file, CP_BYTES_READ, __ret); \ if(__stream_flag)\ CP_INC(file, CP_POSIX_FREADS, 1); \ else\ CP_INC(file, CP_POSIX_READS, 1); \ CP_BUCKET_INC(file, CP_SIZE_READ_0_100, __ret); \ cp_access_counter(file, stride, CP_COUNTER_STRIDE); \ if(!__aligned) \ CP_INC(file, CP_MEM_NOT_ALIGNED, 1); \ if(file_alignment > 0 && (this_offset % file_alignment) != 0) \ CP_INC(file, CP_FILE_NOT_ALIGNED, 1); \ cp_access_counter(file, __ret, CP_COUNTER_ACCESS); \ if(file->last_io_type == CP_WRITE) \ CP_INC(file, CP_RW_SWITCHES, 1); \ file->last_io_type = CP_READ; \ CP_F_INC_NO_OVERLAP(file, __tm1, __tm2, file->last_posix_read_end, CP_F_POSIX_READ_TIME); \ if(CP_F_VALUE(file, CP_F_READ_START_TIMESTAMP) == 0) \ CP_F_SET(file, CP_F_READ_START_TIMESTAMP, __tm1); \ CP_F_SET(file, CP_F_READ_END_TIMESTAMP, __tm2); \ if(CP_F_VALUE(file, CP_F_MAX_READ_TIME) < __elapsed){ \ CP_F_SET(file, CP_F_MAX_READ_TIME, __elapsed); \ CP_SET(file, CP_MAX_READ_TIME_SIZE, __ret); } \ } while(0) #define CP_LOOKUP_RECORD_STAT(__path, __statbuf, __tm1, __tm2) do { \ char* exclude; \ int tmp_index = 0; \ struct darshan_file_runtime* file; \ while((exclude = exclusions[tmp_index])) { \ if(!(strncmp(exclude, __path, strlen(exclude)))) \ break; \ tmp_index++; \ } \ if(exclude) break; \ file = darshan_file_by_name(__path); \ if (file) \ { \ CP_RECORD_STAT(file, __statbuf, __tm1, __tm2); \ } \ } while(0) #define CP_RECORD_STAT(__file, __statbuf, __tm1, __tm2) do { \ if(!CP_VALUE((__file), CP_FILE_ALIGNMENT)){ \ CP_SET((__file), CP_DEVICE, (__statbuf)->st_dev); \ CP_SET((__file), CP_FILE_ALIGNMENT, (__statbuf)->st_blksize); \ CP_SET((__file), CP_SIZE_AT_OPEN, (__statbuf)->st_size); \ }\ (__file)->log_file->rank = my_rank; \ CP_F_INC_NO_OVERLAP(file, __tm1, __tm2, file->last_posix_meta_end, CP_F_POSIX_META_TIME); \ CP_INC(__file, CP_POSIX_STATS, 1); \ } while(0) static inline dev_t get_device(const char* path, struct stat64* statbuf) { dev_t device = 0; #ifdef __CP_ST_DEV_WORKAROUND struct stat64 dirstat; char* tmp_path = strdup(path); char* parent = dirname(tmp_path); if(parent && stat64(parent, &dirstat) == 0) device = dirstat.st_dev; if(tmp_path) free(tmp_path); #else device = statbuf->st_dev; #endif return(device); } #ifdef __CP_STAT_AT_OPEN #define CP_STAT_FILE(_f, _p) do { \ if(!CP_VALUE(_f, CP_FILE_ALIGNMENT)){ \ if(stat64(_p, &cp_stat_buf) == 0) { \ CP_SET(_f, CP_DEVICE, get_device(_p, &cp_stat_buf)); \ CP_SET(_f, CP_FILE_ALIGNMENT, cp_stat_buf.st_blksize); \ CP_SET(_f, CP_SIZE_AT_OPEN, cp_stat_buf.st_size); \ }\ }\ }while(0) #else #define CP_STAT_FILE(_f, _p) do { }while(0) #endif #define CP_RECORD_OPEN(__ret, __path, __mode, __stream_flag, __tm1, __tm2) do { \ struct darshan_file_runtime* file; \ char* exclude; \ int tmp_index = 0; \ if(__ret < 0) break; \ while((exclude = exclusions[tmp_index])) { \ if(!(strncmp(exclude, __path, strlen(exclude)))) \ break; \ tmp_index++; \ } \ if(exclude) break; \ file = darshan_file_by_name_setfd(__path, __ret); \ if(!file) break; \ CP_STAT_FILE(file, __path); \ file->log_file->rank = my_rank; \ if(__mode) \ CP_SET(file, CP_MODE, __mode); \ file->offset = 0; \ file->last_byte_written = 0; \ file->last_byte_read = 0; \ if(__stream_flag)\ CP_INC(file, CP_POSIX_FOPENS, 1); \ else \ CP_INC(file, CP_POSIX_OPENS, 1); \ if(CP_F_VALUE(file, CP_F_OPEN_TIMESTAMP) == 0) \ CP_F_SET(file, CP_F_OPEN_TIMESTAMP, posix_wtime()); \ CP_F_INC_NO_OVERLAP(file, __tm1, __tm2, file->last_posix_meta_end, CP_F_POSIX_META_TIME); \ } while (0) int DARSHAN_DECL(close)(int fd) { struct darshan_file_runtime* file; int tmp_fd = fd; double tm1, tm2; int ret; MAP_OR_FAIL(close); tm1 = darshan_wtime(); ret = __real_close(fd); tm2 = darshan_wtime(); CP_LOCK(); file = darshan_file_by_fd(tmp_fd); if(file) { file->last_byte_written = 0; file->last_byte_read = 0; CP_F_SET(file, CP_F_CLOSE_TIMESTAMP, posix_wtime()); CP_F_INC_NO_OVERLAP(file, tm1, tm2, file->last_posix_meta_end, CP_F_POSIX_META_TIME); darshan_file_close_fd(tmp_fd); } CP_UNLOCK(); return(ret); } int DARSHAN_DECL(fclose)(FILE *fp) { struct darshan_file_runtime* file; int tmp_fd = fileno(fp); double tm1, tm2; int ret; MAP_OR_FAIL(fclose); tm1 = darshan_wtime(); ret = __real_fclose(fp); tm2 = darshan_wtime(); CP_LOCK(); file = darshan_file_by_fd(tmp_fd); if(file) { file->last_byte_written = 0; file->last_byte_read = 0; CP_F_SET(file, CP_F_CLOSE_TIMESTAMP, posix_wtime()); CP_F_INC_NO_OVERLAP(file, tm1, tm2, file->last_posix_meta_end, CP_F_POSIX_META_TIME); darshan_file_close_fd(tmp_fd); } CP_UNLOCK(); return(ret); } int DARSHAN_DECL(fsync)(int fd) { int ret; struct darshan_file_runtime* file; double tm1, tm2; MAP_OR_FAIL(fsync); tm1 = darshan_wtime(); ret = __real_fsync(fd); tm2 = darshan_wtime(); if(ret < 0) return(ret); CP_LOCK(); file = darshan_file_by_fd(fd); if(file) { CP_F_INC_NO_OVERLAP(file, tm1, tm2, file->last_posix_write_end, CP_F_POSIX_WRITE_TIME); \ CP_INC(file, CP_POSIX_FSYNCS, 1); } CP_UNLOCK(); return(ret); } int DARSHAN_DECL(fdatasync)(int fd) { int ret; struct darshan_file_runtime* file; double tm1, tm2; MAP_OR_FAIL(fdatasync); tm1 = darshan_wtime(); ret = __real_fdatasync(fd); tm2 = darshan_wtime(); if(ret < 0) return(ret); CP_LOCK(); file = darshan_file_by_fd(fd); if(file) { CP_F_INC_NO_OVERLAP(file, tm1, tm2, file->last_posix_write_end, CP_F_POSIX_WRITE_TIME); \ CP_INC(file, CP_POSIX_FDSYNCS, 1); } CP_UNLOCK(); return(ret); } void* DARSHAN_DECL(mmap64)(void *addr, size_t length, int prot, int flags, int fd, off64_t offset) { void* ret; struct darshan_file_runtime* file; MAP_OR_FAIL(mmap64); ret = __real_mmap64(addr, length, prot, flags, fd, offset); if(ret == MAP_FAILED) return(ret); CP_LOCK(); file = darshan_file_by_fd(fd); if(file) { CP_INC(file, CP_POSIX_MMAPS, 1); } CP_UNLOCK(); return(ret); } void* DARSHAN_DECL(mmap)(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { void* ret; struct darshan_file_runtime* file; MAP_OR_FAIL(mmap); ret = __real_mmap(addr, length, prot, flags, fd, offset); if(ret == MAP_FAILED) return(ret); CP_LOCK(); file = darshan_file_by_fd(fd); if(file) { CP_INC(file, CP_POSIX_MMAPS, 1); } CP_UNLOCK(); return(ret); } int DARSHAN_DECL(creat)(const char* path, mode_t mode) { int ret; double tm1, tm2; MAP_OR_FAIL(creat); tm1 = darshan_wtime(); ret = __real_creat(path, mode); tm2 = darshan_wtime(); CP_LOCK(); CP_RECORD_OPEN(ret, path, mode, 0, tm1, tm2); CP_UNLOCK(); return(ret); } int DARSHAN_DECL(creat64)(const char* path, mode_t mode) { int ret; double tm1, tm2; MAP_OR_FAIL(creat64); tm1 = darshan_wtime(); ret = __real_creat64(path, mode); tm2 = darshan_wtime(); CP_LOCK(); CP_RECORD_OPEN(ret, path, mode, 0, tm1, tm2); CP_UNLOCK(); return(ret); } int DARSHAN_DECL(open64)(const char* path, int flags, ...) { int mode = 0; int ret; double tm1, tm2; MAP_OR_FAIL(open64); if (flags & O_CREAT) { va_list arg; va_start(arg, flags); mode = va_arg(arg, int); va_end(arg); tm1 = darshan_wtime(); ret = __real_open64(path, flags, mode); tm2 = darshan_wtime(); } else { tm1 = darshan_wtime(); ret = __real_open64(path, flags); tm2 = darshan_wtime(); } CP_LOCK(); CP_RECORD_OPEN(ret, path, mode, 0, tm1, tm2); CP_UNLOCK(); return(ret); } int DARSHAN_DECL(open)(const char *path, int flags, ...) { int mode = 0; int ret; double tm1, tm2; MAP_OR_FAIL(open); if (flags & O_CREAT) { va_list arg; va_start(arg, flags); mode = va_arg(arg, int); va_end(arg); tm1 = darshan_wtime(); ret = __real_open(path, flags, mode); tm2 = darshan_wtime(); } else { tm1 = darshan_wtime(); ret = __real_open(path, flags); tm2 = darshan_wtime(); } CP_LOCK(); CP_RECORD_OPEN(ret, path, mode, 0, tm1, tm2); CP_UNLOCK(); return(ret); } FILE* DARSHAN_DECL(fopen64)(const char *path, const char *mode) { FILE* ret; int fd; double tm1, tm2; MAP_OR_FAIL(fopen64); tm1 = darshan_wtime(); ret = __real_fopen64(path, mode); tm2 = darshan_wtime(); if(ret == 0) fd = -1; else fd = fileno(ret); CP_LOCK(); CP_RECORD_OPEN(fd, path, 0, 1, tm1, tm2); CP_UNLOCK(); return(ret); } FILE* DARSHAN_DECL(fopen)(const char *path, const char *mode) { FILE* ret; int fd; double tm1, tm2; MAP_OR_FAIL(fopen); tm1 = darshan_wtime(); ret = __real_fopen(path, mode); tm2 = darshan_wtime(); if(ret == 0) fd = -1; else fd = fileno(ret); CP_LOCK(); CP_RECORD_OPEN(fd, path, 0, 1, tm1, tm2); CP_UNLOCK(); return(ret); } int DARSHAN_DECL(__xstat64)(int vers, const char *path, struct stat64 *buf) { int ret; double tm1, tm2; MAP_OR_FAIL(__xstat64); tm1 = darshan_wtime(); ret = __real___xstat64(vers, path, buf); tm2 = darshan_wtime(); if(ret < 0 || !S_ISREG(buf->st_mode)) return(ret); CP_LOCK(); CP_LOOKUP_RECORD_STAT(path, buf, tm1, tm2); CP_UNLOCK(); return(ret); } int DARSHAN_DECL(__lxstat64)(int vers, const char *path, struct stat64 *buf) { int ret; double tm1, tm2; MAP_OR_FAIL(__lxstat64); tm1 = darshan_wtime(); ret = __real___lxstat64(vers, path, buf); tm2 = darshan_wtime(); if(ret < 0 || !S_ISREG(buf->st_mode)) return(ret); CP_LOCK(); CP_LOOKUP_RECORD_STAT(path, buf, tm1, tm2); CP_UNLOCK(); return(ret); } int DARSHAN_DECL(__fxstat64)(int vers, int fd, struct stat64 *buf) { int ret; struct darshan_file_runtime* file; double tm1, tm2; MAP_OR_FAIL(__fxstat64); tm1 = darshan_wtime(); ret = __real___fxstat64(vers, fd, buf); tm2 = darshan_wtime(); if(ret < 0 || !S_ISREG(buf->st_mode)) return(ret); /* skip logging if this was triggered internally */ if(buf == &cp_stat_buf) return(ret); CP_LOCK(); file = darshan_file_by_fd(fd); if(file) { CP_RECORD_STAT(file, buf, tm1, tm2); } CP_UNLOCK(); return(ret); } int DARSHAN_DECL(__xstat)(int vers, const char *path, struct stat *buf) { int ret; double tm1, tm2; MAP_OR_FAIL(__xstat); tm1 = darshan_wtime(); ret = __real___xstat(vers, path, buf); tm2 = darshan_wtime(); if(ret < 0 || !S_ISREG(buf->st_mode)) return(ret); CP_LOCK(); CP_LOOKUP_RECORD_STAT(path, buf, tm1, tm2); CP_UNLOCK(); return(ret); } int DARSHAN_DECL(__lxstat)(int vers, const char *path, struct stat *buf) { int ret; double tm1, tm2; MAP_OR_FAIL(__lxstat); tm1 = darshan_wtime(); ret = __real___lxstat(vers, path, buf); tm2 = darshan_wtime(); if(ret < 0 || !S_ISREG(buf->st_mode)) return(ret); CP_LOCK(); CP_LOOKUP_RECORD_STAT(path, buf, tm1, tm2); CP_UNLOCK(); return(ret); } int DARSHAN_DECL(__fxstat)(int vers, int fd, struct stat *buf) { int ret; struct darshan_file_runtime* file; double tm1, tm2; MAP_OR_FAIL(__fxstat); tm1 = darshan_wtime(); ret = __real___fxstat(vers, fd, buf); tm2 = darshan_wtime(); if(ret < 0 || !S_ISREG(buf->st_mode)) return(ret); /* skip logging if this was triggered internally */ if((void*)buf == (void*)&cp_stat_buf) return(ret); CP_LOCK(); file = darshan_file_by_fd(fd); if(file) { CP_RECORD_STAT(file, buf, tm1, tm2); } CP_UNLOCK(); return(ret); } ssize_t DARSHAN_DECL(pread64)(int fd, void *buf, size_t count, off64_t offset) { ssize_t ret; int aligned_flag = 0; double tm1, tm2; MAP_OR_FAIL(pread64); if((unsigned long)buf % darshan_mem_alignment == 0) aligned_flag = 1; tm1 = darshan_wtime(); ret = __real_pread64(fd, buf, count, offset); tm2 = darshan_wtime(); CP_LOCK(); CP_RECORD_READ(ret, fd, count, 1, offset, aligned_flag, 0, tm1, tm2); CP_UNLOCK(); return(ret); } ssize_t DARSHAN_DECL(pread)(int fd, void *buf, size_t count, off_t offset) { ssize_t ret; int aligned_flag = 0; double tm1, tm2; MAP_OR_FAIL(pread); if((unsigned long)buf % darshan_mem_alignment == 0) aligned_flag = 1; tm1 = darshan_wtime(); ret = __real_pread(fd, buf, count, offset); tm2 = darshan_wtime(); CP_LOCK(); CP_RECORD_READ(ret, fd, count, 1, offset, aligned_flag, 0, tm1, tm2); CP_UNLOCK(); return(ret); } ssize_t DARSHAN_DECL(pwrite)(int fd, const void *buf, size_t count, off_t offset) { ssize_t ret; int aligned_flag = 0; double tm1, tm2; MAP_OR_FAIL(pwrite); if((unsigned long)buf % darshan_mem_alignment == 0) aligned_flag = 1; tm1 = darshan_wtime(); ret = __real_pwrite(fd, buf, count, offset); tm2 = darshan_wtime(); CP_LOCK(); CP_RECORD_WRITE(ret, fd, count, 1, offset, aligned_flag, 0, tm1, tm2); CP_UNLOCK(); return(ret); } ssize_t DARSHAN_DECL(pwrite64)(int fd, const void *buf, size_t count, off64_t offset) { ssize_t ret; int aligned_flag = 0; double tm1, tm2; MAP_OR_FAIL(pwrite64); if((unsigned long)buf % darshan_mem_alignment == 0) aligned_flag = 1; tm1 = darshan_wtime(); ret = __real_pwrite64(fd, buf, count, offset); tm2 = darshan_wtime(); CP_LOCK(); CP_RECORD_WRITE(ret, fd, count, 1, offset, aligned_flag, 0, tm1, tm2); CP_UNLOCK(); return(ret); } ssize_t DARSHAN_DECL(readv)(int fd, const struct iovec *iov, int iovcnt) { ssize_t ret; int aligned_flag = 1; int i; double tm1, tm2; MAP_OR_FAIL(readv); for(i=0; i 0) CP_RECORD_READ(size*ret, fileno(stream), (size*nmemb), 0, 0, aligned_flag, 1, tm1, tm2); else CP_RECORD_READ(ret, fileno(stream), (size*nmemb), 0, 0, aligned_flag, 1, tm1, tm2); CP_UNLOCK(); return(ret); } ssize_t DARSHAN_DECL(read)(int fd, void *buf, size_t count) { ssize_t ret; int aligned_flag = 0; double tm1, tm2; MAP_OR_FAIL(read); if((unsigned long)buf % darshan_mem_alignment == 0) aligned_flag = 1; tm1 = darshan_wtime(); ret = __real_read(fd, buf, count); tm2 = darshan_wtime(); CP_LOCK(); CP_RECORD_READ(ret, fd, count, 0, 0, aligned_flag, 0, tm1, tm2); CP_UNLOCK(); return(ret); } ssize_t DARSHAN_DECL(write)(int fd, const void *buf, size_t count) { ssize_t ret; int aligned_flag = 0; double tm1, tm2; MAP_OR_FAIL(write); if((unsigned long)buf % darshan_mem_alignment == 0) aligned_flag = 1; tm1 = darshan_wtime(); ret = __real_write(fd, buf, count); tm2 = darshan_wtime(); CP_LOCK(); CP_RECORD_WRITE(ret, fd, count, 0, 0, aligned_flag, 0, tm1, tm2); CP_UNLOCK(); return(ret); } size_t DARSHAN_DECL(fwrite)(const void *ptr, size_t size, size_t nmemb, FILE *stream) { size_t ret; int aligned_flag = 0; double tm1, tm2; MAP_OR_FAIL(fwrite); if((unsigned long)ptr % darshan_mem_alignment == 0) aligned_flag = 1; tm1 = darshan_wtime(); ret = __real_fwrite(ptr, size, nmemb, stream); tm2 = darshan_wtime(); CP_LOCK(); if(ret > 0) CP_RECORD_WRITE(size*ret, fileno(stream), (size*nmemb), 0, 0, aligned_flag, 1, tm1, tm2); else CP_RECORD_WRITE(ret, fileno(stream), 0, 0, 0, aligned_flag, 1, tm1, tm2); CP_UNLOCK(); return(ret); } off64_t DARSHAN_DECL(lseek64)(int fd, off64_t offset, int whence) { off64_t ret; struct darshan_file_runtime* file; double tm1, tm2; MAP_OR_FAIL(lseek64); tm1 = darshan_wtime(); ret = __real_lseek64(fd, offset, whence); tm2 = darshan_wtime(); if(ret >= 0) { CP_LOCK(); file = darshan_file_by_fd(fd); if(file) { file->offset = ret; CP_F_INC_NO_OVERLAP(file, tm1, tm2, file->last_posix_meta_end, CP_F_POSIX_META_TIME); CP_INC(file, CP_POSIX_SEEKS, 1); } CP_UNLOCK(); } return(ret); } off_t DARSHAN_DECL(lseek)(int fd, off_t offset, int whence) { off_t ret; struct darshan_file_runtime* file; double tm1, tm2; MAP_OR_FAIL(lseek); tm1 = darshan_wtime(); ret = __real_lseek(fd, offset, whence); tm2 = darshan_wtime(); if(ret >= 0) { CP_LOCK(); file = darshan_file_by_fd(fd); if(file) { file->offset = ret; CP_F_INC_NO_OVERLAP(file, tm1, tm2, file->last_posix_meta_end, CP_F_POSIX_META_TIME); CP_INC(file, CP_POSIX_SEEKS, 1); } CP_UNLOCK(); } return(ret); } int DARSHAN_DECL(fseek)(FILE *stream, long offset, int whence) { int ret; struct darshan_file_runtime* file; double tm1, tm2; MAP_OR_FAIL(fseek); tm1 = darshan_wtime(); ret = __real_fseek(stream, offset, whence); tm2 = darshan_wtime(); if(ret >= 0) { CP_LOCK(); file = darshan_file_by_fd(fileno(stream)); if(file) { file->offset = ret; CP_F_INC_NO_OVERLAP(file, tm1, tm2, file->last_posix_meta_end, CP_F_POSIX_META_TIME); CP_INC(file, CP_POSIX_FSEEKS, 1); } CP_UNLOCK(); } return(ret); } void darshan_finalize(struct darshan_job_runtime* job) { if(!job) { return; } free(job); } void darshan_initialize(int argc, char** argv, int nprocs, int rank) { int i; char* disable; char* disable_timing; char* envstr; char* truncate_string = ""; int truncate_offset; int chars_left = 0; int ret; int tmpval; disable = getenv("DARSHAN_DISABLE"); if(disable) { /* turn off tracing */ return; } disable_timing = getenv("DARSHAN_DISABLE_TIMING"); if(darshan_global_job != NULL) { return; } #if (__CP_MEM_ALIGNMENT < 1) #error Darshan must be configured with a positive value for --with-mem-align #endif envstr = getenv("DARSHAN_MEMALIGN"); 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 = __CP_MEM_ALIGNMENT; } /* avoid floating point errors on faulty input */ if (darshan_mem_alignment < 1) { darshan_mem_alignment = 1; } /* allocate structure to track darshan_global_job information */ darshan_global_job = malloc(sizeof(*darshan_global_job)); if(!darshan_global_job) { return; } memset(darshan_global_job, 0, sizeof(*darshan_global_job)); if(disable_timing) { darshan_global_job->flags |= CP_FLAG_NOTIMING; } /* set up file records */ for(i=0; ifile_runtime_array[i].log_file = &darshan_global_job->file_array[i]; } strcpy(darshan_global_job->log_job.version_string, CP_VERSION); darshan_global_job->log_job.magic_nr = CP_MAGIC_NR; darshan_global_job->log_job.uid = getuid(); darshan_global_job->log_job.start_time = time(NULL); darshan_global_job->log_job.nprocs = nprocs; my_rank = rank; /* record exe and arguments */ for(i=0; iexe); strncat(darshan_global_job->exe, argv[i], chars_left); if(i < (argc-1)) { chars_left = CP_EXE_LEN-strlen(darshan_global_job->exe); strncat(darshan_global_job->exe, " ", chars_left); } } /* if we don't see any arguments, then use glibc symbol to get * program name at least (this happens in fortran) */ if(argc == 0) { chars_left = CP_EXE_LEN-strlen(darshan_global_job->exe); strncat(darshan_global_job->exe, __progname_full, chars_left); chars_left = CP_EXE_LEN-strlen(darshan_global_job->exe); strncat(darshan_global_job->exe, " ", chars_left); } if(chars_left == 0) { /* we ran out of room; mark that string was truncated */ truncate_offset = CP_EXE_LEN - strlen(truncate_string); sprintf(&darshan_global_job->exe[truncate_offset], "%s", truncate_string); } } /* darshan_condense() * * collapses all file statistics into a single unified set of counters; used * when we have opened too many files to track independently */ void darshan_condense(void) { struct darshan_file_runtime* base_file; struct darshan_file_runtime* iter_file; int i; int j; if(!darshan_global_job) return; base_file = &darshan_global_job->file_runtime_array[0]; /* iterate through files */ for(j=1; jfile_count; j++) { iter_file = &darshan_global_job->file_runtime_array[j]; /* iterate through records */ for(i=0; i CP_F_VALUE(base_file, i)) { CP_F_SET(base_file, i, CP_F_VALUE(iter_file, i)); CP_SET(base_file, CP_MAX_WRITE_TIME_SIZE, CP_VALUE(iter_file, CP_MAX_WRITE_TIME_SIZE)); } break; case CP_F_MAX_READ_TIME: if(CP_F_VALUE(iter_file, i) > CP_F_VALUE(base_file, i)) { CP_F_SET(base_file, i, CP_F_VALUE(iter_file, i)); CP_SET(base_file, CP_MAX_READ_TIME_SIZE, CP_VALUE(iter_file, CP_MAX_READ_TIME_SIZE)); } break; default: CP_F_SET(base_file, i, CP_F_VALUE(iter_file, i) + CP_F_VALUE(base_file, i)); break; } } } base_file->log_file->hash = 0; darshan_global_job->flags |= CP_FLAG_CONDENSED; darshan_global_job->file_count = 1; /* clear hash tables for safety */ memset(darshan_global_job->name_table, 0, CP_HASH_SIZE*sizeof(struct darshan_file_runtime*)); memset(darshan_global_job->handle_table, 0, CP_HASH_SIZE*sizeof(*darshan_global_job->handle_table)); return; } static struct darshan_file_runtime* darshan_file_by_name_setfd(const char* name, int fd) { struct darshan_file_runtime* tmp_file; tmp_file = darshan_file_by_name_sethandle(name, &fd, sizeof(fd), DARSHAN_FD); return(tmp_file); } static void darshan_file_close_fd(int fd) { darshan_file_closehandle(&fd, sizeof(fd), DARSHAN_FD); return; } static struct darshan_file_runtime* darshan_file_by_fd(int fd) { struct darshan_file_runtime* tmp_file; tmp_file = darshan_file_by_handle(&fd, sizeof(fd), DARSHAN_FD); return(tmp_file); } static int access_comparison(const void* a_p, const void* b_p) { const struct cp_access_counter* a = a_p; const struct cp_access_counter* b = b_p; if(a->size < b->size) return(-1); if(a->size > b->size) return(1); return(0); } /* cp_access_counter() * * records the occurance of a particular access size for a file, * current implementation uses glibc red black tree */ static void cp_access_counter(struct darshan_file_runtime* file, ssize_t size, enum cp_counter_type type) { struct cp_access_counter* counter; struct cp_access_counter* found; void* tmp; void** root; int* count; struct cp_access_counter tmp_counter; /* don't count sizes or strides of 0 */ if(size == 0) return; switch(type) { case CP_COUNTER_ACCESS: root = &file->access_root; count = &file->access_count; break; case CP_COUNTER_STRIDE: root = &file->stride_root; count = &file->stride_count; break; default: return; } /* check to see if this size is already recorded */ tmp_counter.size = size; tmp_counter.freq = 1; tmp = tfind(&tmp_counter, root, access_comparison); if(tmp) { found = *(struct cp_access_counter**)tmp; found->freq++; return; } /* we can add a new one as long as we haven't hit the limit */ if(*count < CP_MAX_ACCESS_COUNT_RUNTIME) { counter = malloc(sizeof(*counter)); if(!counter) { return; } counter->size = size; counter->freq = 1; tmp = tsearch(counter, root, access_comparison); found = *(struct cp_access_counter**)tmp; /* if we get a new answer out here we are in trouble; this was * already checked with the tfind() */ assert(found == counter); (*count)++; } return; } #if 0 void darshan_shutdown_bench(int argc, char** argv, int rank, int nprocs) { int* fd_array; int64_t* size_array; int i; int nfiles; char path[256]; int iters; /* combinations to build: * - 1 unique file per proc * - 1 shared file per proc * - 1024 unique file per proc * - 1024 shared per proc */ srand(rank); fd_array = malloc(sizeof(int)*CP_MAX_FILES); size_array = malloc(sizeof(int64_t)*CP_MAX_ACCESS_COUNT_RUNTIME); assert(fd_array&&size_array); for(i=0; i\t\t\t\t\n"); for(j=0; j<2; j++) { /* warm up */ /* reset darshan to start clean */ darshan_walk_file_accesses(darshan_global_job); darshan_finalize(darshan_global_job); darshan_global_job = NULL; darshan_initialize(argc, argv, 1, 0); nfiles = 1; /* populate entries for each file */ for(i=0; i\t\t\t\t\n"); */ printf("%d\t%d\t%d\t%f\t%.12f\n", iters, nfiles, (j==0?CP_MAX_ACCESS_COUNT_RUNTIME:1), tm2-tm1, (tm2-tm1)/iters); if(nfiles == 1) nfiles = 0; } } free(fd_array); free(size_array); } #endif static double posix_wtime(void) { return DARSHAN_MPI_CALL(PMPI_Wtime)(); } double darshan_wtime(void) { if(!darshan_global_job || darshan_global_job->flags & CP_FLAG_NOTIMING) { return(0); } return(posix_wtime()); } struct darshan_file_runtime* darshan_file_by_name(const char* name) { struct darshan_file_runtime* tmp_file; uint64_t tmp_hash = 0; char* suffix_pointer; int hash_index; if(!darshan_global_job) return(NULL); /* if we have already condensed the data, then just hand the first file * back */ if(darshan_global_job->flags & CP_FLAG_CONDENSED) { return(&darshan_global_job->file_runtime_array[0]); } tmp_hash = darshan_hash((void*)name, strlen(name), 0); /* search hash table */ hash_index = tmp_hash & CP_HASH_MASK; tmp_file = darshan_global_job->name_table[hash_index]; while(tmp_file) { if(tmp_file->log_file->hash == tmp_hash) { return(tmp_file); } tmp_file = tmp_file->name_next; } /* see if we need to condense */ if(darshan_global_job->file_count >= CP_MAX_FILES) { darshan_condense(); return(&darshan_global_job->file_runtime_array[0]); } /* new, unique file */ tmp_file = &darshan_global_job->file_runtime_array[darshan_global_job->file_count]; CP_SET(tmp_file, CP_MEM_ALIGNMENT, darshan_mem_alignment); tmp_file->log_file->hash = tmp_hash; /* record last N characters of file name too */ suffix_pointer = (char*)name; if(strlen(name) > CP_NAME_SUFFIX_LEN) { suffix_pointer += (strlen(name) - CP_NAME_SUFFIX_LEN); } strcpy(tmp_file->log_file->name_suffix, suffix_pointer); /* if the "stat at open" functionality is disabled, then go ahead and * mark certain counters with invalid values to make sure that they are * not mis-interpretted. */ #ifndef __CP_STAT_AT_OPEN CP_SET(tmp_file, CP_SIZE_AT_OPEN, -1); CP_SET(tmp_file, CP_FILE_ALIGNMENT, -1); CP_SET(tmp_file, CP_FILE_NOT_ALIGNED, -1); #endif darshan_global_job->file_count++; /* put into hash table, head of list at that index */ tmp_file->name_prev = NULL; tmp_file->name_next = darshan_global_job->name_table[hash_index]; if(tmp_file->name_next) tmp_file->name_next->name_prev = tmp_file; darshan_global_job->name_table[hash_index] = tmp_file; return(tmp_file); } struct darshan_file_runtime* darshan_file_by_name_sethandle( const char* name, const void* handle, int handle_sz, enum darshan_handle_type handle_type) { struct darshan_file_runtime* file; uint64_t tmp_hash; int hash_index; struct darshan_file_ref* tmp_ref; if(!darshan_global_job) { return(NULL); } /* find file record by name first */ file = darshan_file_by_name(name); if(!file) return(NULL); /* search hash table */ tmp_ref = ref_by_handle(handle, handle_sz, handle_type); if(tmp_ref) { /* we have a reference. Make sure it points to the correct file * and return it */ tmp_ref->file = file; return(file); } /* if we hit this point, then we don't have a reference for this handle * in the table yet. Add it. */ tmp_hash = darshan_hash(handle, handle_sz, 0); hash_index = tmp_hash & CP_HASH_MASK; tmp_ref = malloc(sizeof(*tmp_ref)); if(!tmp_ref) return(NULL); memset(tmp_ref, 0, sizeof(*tmp_ref)); tmp_ref->file = file; memcpy(tmp_ref->handle, handle, handle_sz); tmp_ref->handle_sz = handle_sz; tmp_ref->handle_type = handle_type; tmp_ref->prev = NULL; tmp_ref->next = darshan_global_job->handle_table[hash_index]; if(tmp_ref->next) tmp_ref->next->prev = tmp_ref; darshan_global_job->handle_table[hash_index] = tmp_ref; return(file); } struct darshan_file_runtime* darshan_file_by_handle( const void* handle, int handle_sz, enum darshan_handle_type handle_type) { struct darshan_file_ref* tmp_ref; if(!darshan_global_job) { return(NULL); } tmp_ref = ref_by_handle(handle, handle_sz, handle_type); if(tmp_ref) return(tmp_ref->file); else return(NULL); return(NULL); } void darshan_file_closehandle( const void* handle, int handle_sz, enum darshan_handle_type handle_type) { struct darshan_file_ref* tmp_ref; uint64_t tmp_hash; int hash_index; if(!darshan_global_job) { return; } /* search hash table */ tmp_hash = darshan_hash(handle, handle_sz, 0); hash_index = tmp_hash & CP_HASH_MASK; tmp_ref = darshan_global_job->handle_table[hash_index]; while(tmp_ref) { if(tmp_ref->handle_sz == handle_sz && tmp_ref->handle_type == handle_type && memcmp(tmp_ref->handle, handle, handle_sz) == 0) { /* we have a reference. */ if(!tmp_ref->prev) { /* head of list */ darshan_global_job->handle_table[hash_index] = tmp_ref->next; if(tmp_ref->next) tmp_ref->next->prev = NULL; } else { /* not head of list */ if(tmp_ref->prev) tmp_ref->prev->next = tmp_ref->next; if(tmp_ref->next) tmp_ref->next->prev = tmp_ref->prev; } free(tmp_ref); return; } tmp_ref = tmp_ref->next; } return; } static struct darshan_file_ref* ref_by_handle( const void* handle, int handle_sz, enum darshan_handle_type handle_type) { uint64_t tmp_hash; int hash_index; struct darshan_file_ref* tmp_ref; if(!darshan_global_job) { return(NULL); } /* search hash table */ tmp_hash = darshan_hash(handle, handle_sz, 0); hash_index = tmp_hash & CP_HASH_MASK; tmp_ref = darshan_global_job->handle_table[hash_index]; while(tmp_ref) { if(tmp_ref->handle_sz == handle_sz && tmp_ref->handle_type == handle_type && memcmp(tmp_ref->handle, handle, handle_sz) == 0) { /* we have a reference. */ return(tmp_ref); } tmp_ref = tmp_ref->next; } return(NULL); } /* * Local variables: * c-indent-level: 4 * c-basic-offset: 4 * End: * * vim: ts=8 sts=4 sw=4 expandtab */