darshan-stdio.c 33.3 KB
Newer Older
1 2 3 4 5 6
/*
 * Copyright (C) 2015 University of Chicago.
 * See COPYRIGHT notice in top-level directory.
 *
 */

Philip Carns's avatar
Philip Carns committed
7 8
/* TODO list (general) for this module:
 * - add stdio page to darshan-job-summary
Philip Carns's avatar
Philip Carns committed
9 10
 * - update darshan-parser to include stdio information in any relevant 
 *   performance estimate / summary modes
Philip Carns's avatar
Philip Carns committed
11 12
 * - figure out what to do about posix module compatibility
 *   - remove stdio counters in POSIX or keep and set to -1?
Philip Carns's avatar
Philip Carns committed
13 14 15 16 17
 *   - affected counters in posix module:
 *     - POSIX_FOPENS
 *     - POSIX_FREADS
 *     - POSIX_FWRITES
 *     - POSIX_FSEEKS
Philip Carns's avatar
Philip Carns committed
18 19
 */

Philip Carns's avatar
Philip Carns committed
20 21 22 23 24
/* catalog of stdio functions instrumented by this module
 *
 * functions for opening streams
 * --------------
 * FILE    *fdopen(int, const char *);                      DONE
Philip Carns's avatar
Philip Carns committed
25
 * FILE    *fopen(const char *, const char *);              DONE
Philip Carns's avatar
Philip Carns committed
26
 * FILE    *fopen64(const char *, const char *);            DONE
Philip Carns's avatar
Philip Carns committed
27
 * FILE    *freopen(const char *, const char *, FILE *);    DONE
Philip Carns's avatar
Philip Carns committed
28
 * FILE    *freopen64(const char *, const char *, FILE *);  DONE
Philip Carns's avatar
Philip Carns committed
29 30 31 32 33 34 35
 *
 * functions for closing streams
 * --------------
 * int      fclose(FILE *);                                 DONE
 *
 * functions for flushing streams
 * --------------
Philip Carns's avatar
Philip Carns committed
36
 * int      fflush(FILE *);                                 DONE
Philip Carns's avatar
Philip Carns committed
37 38 39
 *
 * functions for reading data
 * --------------
Philip Carns's avatar
Philip Carns committed
40
 * int      fgetc(FILE *);                                  DONE
Philip Carns's avatar
Philip Carns committed
41
 * char    *fgets(char *, int, FILE *);                     DONE
Philip Carns's avatar
Philip Carns committed
42
 * size_t   fread(void *, size_t, size_t, FILE *);          DONE
Philip Carns's avatar
Philip Carns committed
43 44
 * int      fscanf(FILE *, const char *, ...);              DONE
 * int      vfscanf(FILE *, const char *, va_list);         DONE
Philip Carns's avatar
Philip Carns committed
45
 * int      getc(FILE *);                                   DONE
Philip Carns's avatar
Philip Carns committed
46
 * int      getw(FILE *);                                   DONE
Philip Carns's avatar
Philip Carns committed
47 48 49
 *
 * functions for writing data
 * --------------
Philip Carns's avatar
Philip Carns committed
50 51
 * int      fprintf(FILE *, const char *, ...);             DONE
 * int      vfprintf(FILE *, const char *, va_list);        DONE
Philip Carns's avatar
Philip Carns committed
52
 * int      fputc(int, FILE *);                             DONE
Philip Carns's avatar
Philip Carns committed
53
 * int      fputs(const char *, FILE *);                    DONE
Philip Carns's avatar
Philip Carns committed
54
 * size_t   fwrite(const void *, size_t, size_t, FILE *);   DONE
Philip Carns's avatar
Philip Carns committed
55
 * int      putc(int, FILE *);                              DONE
Philip Carns's avatar
Philip Carns committed
56
 * int      putw(int, FILE *);                              DONE
Philip Carns's avatar
Philip Carns committed
57 58 59 60
 *
 * functions for changing file position
 * --------------
 * int      fseek(FILE *, long int, int);                   DONE
Philip Carns's avatar
Philip Carns committed
61
 * int      fseeko(FILE *, off_t, int);                     DONE
Philip Carns's avatar
Philip Carns committed
62
 * int      fseeko64(FILE *, off_t, int);                   DONE
Philip Carns's avatar
Philip Carns committed
63 64
 * int      fsetpos(FILE *, const fpos_t *);                DONE
 * int      fsetpos64(FILE *, const fpos_t *);              DONE
Philip Carns's avatar
Philip Carns committed
65
 * void     rewind(FILE *);                                 DONE
Philip Carns's avatar
Philip Carns committed
66
 *
67 68 69 70 71
 * Omissions: 
 *   - _unlocked() variants of the various flush, read, and write
 *     functions.  There are many of these, but they are not available on all
 *     systems and the man page advises not to use them.
 *   - ungetc()
Philip Carns's avatar
Philip Carns committed
72 73
 */

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
#define _XOPEN_SOURCE 500
#define _GNU_SOURCE

#include "darshan-runtime-config.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/uio.h>
#include <sys/mman.h>
#include <search.h>
#include <assert.h>
#include <libgen.h>
#include <pthread.h>

#include "darshan.h"
#include "darshan-dynamic.h"

DARSHAN_FORWARD_DECL(fopen, FILE*, (const char *path, const char *mode));
DARSHAN_FORWARD_DECL(fopen64, FILE*, (const char *path, const char *mode));
Philip Carns's avatar
Philip Carns committed
100
DARSHAN_FORWARD_DECL(fdopen, FILE*, (int fd, const char *mode));
Philip Carns's avatar
Philip Carns committed
101
DARSHAN_FORWARD_DECL(freopen, FILE*, (const char *path, const char *mode, FILE *stream));
Philip Carns's avatar
Philip Carns committed
102
DARSHAN_FORWARD_DECL(freopen64, FILE*, (const char *path, const char *mode, FILE *stream));
103
DARSHAN_FORWARD_DECL(fclose, int, (FILE *fp));
Philip Carns's avatar
Philip Carns committed
104
DARSHAN_FORWARD_DECL(fflush, int, (FILE *fp));
105
DARSHAN_FORWARD_DECL(fwrite, size_t, (const void *ptr, size_t size, size_t nmemb, FILE *stream));
Philip Carns's avatar
Philip Carns committed
106
DARSHAN_FORWARD_DECL(fputc, int, (int c, FILE *stream));
Philip Carns's avatar
Philip Carns committed
107
DARSHAN_FORWARD_DECL(putw, int, (int w, FILE *stream));
Philip Carns's avatar
Philip Carns committed
108
DARSHAN_FORWARD_DECL(fputs, int, (const char *s, FILE *stream));
Philip Carns's avatar
Philip Carns committed
109 110
DARSHAN_FORWARD_DECL(fprintf, int, (FILE *stream, const char *format, ...));
DARSHAN_FORWARD_DECL(vfprintf, int, (FILE *stream, const char *format, va_list));
111
DARSHAN_FORWARD_DECL(fread, size_t, (void *ptr, size_t size, size_t nmemb, FILE *stream));
Philip Carns's avatar
Philip Carns committed
112
DARSHAN_FORWARD_DECL(fgetc, int, (FILE *stream));
Philip Carns's avatar
Philip Carns committed
113
DARSHAN_FORWARD_DECL(getw, int, (FILE *stream));
Philip Carns's avatar
Philip Carns committed
114
DARSHAN_FORWARD_DECL(_IO_getc, int, (FILE *stream));
Philip Carns's avatar
Philip Carns committed
115
DARSHAN_FORWARD_DECL(_IO_putc, int, (int, FILE *stream));
Philip Carns's avatar
Philip Carns committed
116
DARSHAN_FORWARD_DECL(fscanf, int, (FILE *stream, const char *format, ...));
Philip Carns's avatar
Philip Carns committed
117
DARSHAN_FORWARD_DECL(__isoc99_fscanf, int, (FILE *stream, const char *format, ...));
Philip Carns's avatar
Philip Carns committed
118
DARSHAN_FORWARD_DECL(vfscanf, int, (FILE *stream, const char *format, va_list ap));
Philip Carns's avatar
Philip Carns committed
119
DARSHAN_FORWARD_DECL(fgets, char*, (char *s, int size, FILE *stream));
120
DARSHAN_FORWARD_DECL(fseek, int, (FILE *stream, long offset, int whence));
Philip Carns's avatar
Philip Carns committed
121
DARSHAN_FORWARD_DECL(fseeko, int, (FILE *stream, off_t offset, int whence));
Philip Carns's avatar
Philip Carns committed
122
DARSHAN_FORWARD_DECL(fseeko64, int, (FILE *stream, off_t offset, int whence));
Philip Carns's avatar
Philip Carns committed
123 124
DARSHAN_FORWARD_DECL(fsetpos, int, (FILE *stream, const fpos_t *pos));
DARSHAN_FORWARD_DECL(fsetpos64, int, (FILE *stream, const fpos_t *pos));
Philip Carns's avatar
Philip Carns committed
125
DARSHAN_FORWARD_DECL(rewind, void, (FILE *stream));
126

127 128
/* structure to track stdio stats at runtime */
struct stdio_file_record_ref
129
{
130
    struct darshan_stdio_file* file_rec;
131 132 133 134 135 136 137 138 139 140 141 142
    int64_t offset;
    double last_meta_end;
    double last_read_end;
    double last_write_end;
};

/* The stdio_runtime structure maintains necessary state for storing
 * STDIO file records and for coordinating with darshan-core at 
 * shutdown time.
 */
struct stdio_runtime
{
143 144 145
    void *rec_id_hash;
    void *stream_hash;
    int file_rec_count;
146 147 148 149 150 151 152 153 154
};

static struct stdio_runtime *stdio_runtime = NULL;
static pthread_mutex_t stdio_runtime_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
static int instrumentation_disabled = 0;
static int darshan_mem_alignment = 1;
static int my_rank = -1;

static void stdio_runtime_initialize(void);
155 156 157 158 159 160
static void stdio_shutdown(
    MPI_Comm mod_comm,
    darshan_record_id *shared_recs,
    int shared_rec_count,
    void **stdio_buf,
    int *stdio_buf_sz);
161 162
static void stdio_record_reduction_op(void* infile_v, void* inoutfile_v,
    int *len, MPI_Datatype *datatype);
163 164 165
static struct stdio_file_record_ref *stdio_track_new_file_record(
    darshan_record_id rec_id, const char *path);
static void stdio_cleanup_runtime();
166 167 168 169

#define STDIO_LOCK() pthread_mutex_lock(&stdio_runtime_mutex)
#define STDIO_UNLOCK() pthread_mutex_unlock(&stdio_runtime_mutex)

170 171 172 173 174 175 176 177 178 179 180 181 182
#define STDIO_PRE_RECORD() do { \
    STDIO_LOCK(); \
    if(!stdio_runtime && !instrumentation_disabled) stdio_runtime_initialize(); \
    if(!stdio_runtime) { \
        STDIO_UNLOCK(); \
        return(ret); \
    } \
} while(0)

#define STDIO_POST_RECORD() do { \
    STDIO_UNLOCK(); \
} while(0)

Philip Carns's avatar
Philip Carns committed
183
#define STDIO_RECORD_OPEN(__ret, __path, __tm1, __tm2) do { \
184 185 186
    darshan_record_id rec_id; \
    struct stdio_file_record_ref* rec_ref; \
    char *newpath; \
Philip Carns's avatar
Philip Carns committed
187
    if(__ret == NULL) break; \
188 189 190 191 192
    newpath = darshan_clean_file_path(__path); \
    if(!newpath) newpath = (char*)__path; \
    if(darshan_core_excluded_path(newpath)) { \
        if(newpath != (char*)__path) free(newpath); \
        break; \
Philip Carns's avatar
Philip Carns committed
193
    } \
194
    rec_id = darshan_core_gen_record_id(newpath); \
Philip Carns's avatar
Philip Carns committed
195
    rec_ref = darshan_lookup_record_ref(stdio_runtime->rec_id_hash, &rec_id, sizeof(rec_id)); \
196 197 198 199 200 201 202 203 204 205 206 207 208 209
    if(!rec_ref) rec_ref = stdio_track_new_file_record(rec_id, newpath); \
    if(!rec_ref) { \
        if(newpath != (char*)__path) free(newpath); \
        break; \
    } \
    rec_ref->offset = 0; \
    rec_ref->file_rec->counters[STDIO_OPENS] += 1; \
    if(rec_ref->file_rec->fcounters[STDIO_F_OPEN_START_TIMESTAMP] == 0 || \
     rec_ref->file_rec->fcounters[STDIO_F_OPEN_START_TIMESTAMP] > __tm1) \
        rec_ref->file_rec->fcounters[STDIO_F_OPEN_START_TIMESTAMP] = __tm1; \
    rec_ref->file_rec->fcounters[STDIO_F_OPEN_END_TIMESTAMP] = __tm2; \
    DARSHAN_TIMER_INC_NO_OVERLAP(rec_ref->file_rec->fcounters[STDIO_F_META_TIME], __tm1, __tm2, rec_ref->last_meta_end); \
    darshan_add_record_ref(&(stdio_runtime->stream_hash), &(__ret), sizeof(__ret), rec_ref); \
    if(newpath != (char*)__path) free(newpath); \
Philip Carns's avatar
Philip Carns committed
210 211 212
} while(0)


213
#define STDIO_RECORD_READ(__fp, __bytes,  __tm1, __tm2) do{ \
214
    struct stdio_file_record_ref* rec_ref; \
215
    int64_t this_offset; \
Philip Carns's avatar
Philip Carns committed
216
    rec_ref = darshan_lookup_record_ref(stdio_runtime->stream_hash, &(__fp), sizeof(__fp)); \
217 218 219 220 221 222 223 224 225 226 227 228
    if(!rec_ref) break; \
    this_offset = rec_ref->offset; \
    rec_ref->offset = this_offset + __bytes; \
    if(rec_ref->file_rec->counters[STDIO_MAX_BYTE_READ] < (this_offset + __bytes - 1)) \
        rec_ref->file_rec->counters[STDIO_MAX_BYTE_READ] = (this_offset + __bytes - 1); \
    rec_ref->file_rec->counters[STDIO_BYTES_READ] += __bytes; \
    rec_ref->file_rec->counters[STDIO_READS] += 1; \
    if(rec_ref->file_rec->fcounters[STDIO_F_READ_START_TIMESTAMP] == 0 || \
     rec_ref->file_rec->fcounters[STDIO_F_READ_START_TIMESTAMP] > __tm1) \
        rec_ref->file_rec->fcounters[STDIO_F_READ_START_TIMESTAMP] = __tm1; \
    rec_ref->file_rec->fcounters[STDIO_F_READ_END_TIMESTAMP] = __tm2; \
    DARSHAN_TIMER_INC_NO_OVERLAP(rec_ref->file_rec->fcounters[STDIO_F_READ_TIME], __tm1, __tm2, rec_ref->last_write_end); \
229 230
} while(0)

Philip Carns's avatar
Philip Carns committed
231
#define STDIO_RECORD_WRITE(__fp, __bytes,  __tm1, __tm2, __fflush_flag) do{ \
232
    struct stdio_file_record_ref* rec_ref; \
233
    int64_t this_offset; \
Philip Carns's avatar
Philip Carns committed
234
    rec_ref = darshan_lookup_record_ref(stdio_runtime->stream_hash, &(__fp), sizeof(__fp)); \
235 236 237 238 239 240
    if(!rec_ref) break; \
    this_offset = rec_ref->offset; \
    rec_ref->offset = this_offset + __bytes; \
    if(rec_ref->file_rec->counters[STDIO_MAX_BYTE_WRITTEN] < (this_offset + __bytes - 1)) \
        rec_ref->file_rec->counters[STDIO_MAX_BYTE_WRITTEN] = (this_offset + __bytes - 1); \
    rec_ref->file_rec->counters[STDIO_BYTES_WRITTEN] += __bytes; \
Philip Carns's avatar
Philip Carns committed
241
    if(__fflush_flag) \
242
        rec_ref->file_rec->counters[STDIO_FLUSHES] += 1; \
Philip Carns's avatar
Philip Carns committed
243
    else \
244 245 246 247 248 249
        rec_ref->file_rec->counters[STDIO_WRITES] += 1; \
    if(rec_ref->file_rec->fcounters[STDIO_F_WRITE_START_TIMESTAMP] == 0 || \
     rec_ref->file_rec->fcounters[STDIO_F_WRITE_START_TIMESTAMP] > __tm1) \
        rec_ref->file_rec->fcounters[STDIO_F_WRITE_START_TIMESTAMP] = __tm1; \
    rec_ref->file_rec->fcounters[STDIO_F_WRITE_END_TIMESTAMP] = __tm2; \
    DARSHAN_TIMER_INC_NO_OVERLAP(rec_ref->file_rec->fcounters[STDIO_F_WRITE_TIME], __tm1, __tm2, rec_ref->last_write_end); \
250
} while(0)
Philip Carns's avatar
Philip Carns committed
251

Philip Carns's avatar
Philip Carns committed
252
FILE* DARSHAN_DECL(fopen)(const char *path, const char *mode)
Philip Carns's avatar
Philip Carns committed
253 254 255 256
{
    FILE* ret;
    double tm1, tm2;

Philip Carns's avatar
Philip Carns committed
257
    MAP_OR_FAIL(fopen);
Philip Carns's avatar
Philip Carns committed
258 259

    tm1 = darshan_core_wtime();
Philip Carns's avatar
Philip Carns committed
260
    ret = __real_fopen(path, mode);
Philip Carns's avatar
Philip Carns committed
261 262
    tm2 = darshan_core_wtime();

263
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
264
    STDIO_RECORD_OPEN(ret, path, tm1, tm2);
265
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
266 267 268 269

    return(ret);
}

Philip Carns's avatar
Philip Carns committed
270
FILE* DARSHAN_DECL(fopen64)(const char *path, const char *mode)
271 272
{
    FILE* ret;
Philip Carns's avatar
Philip Carns committed
273
    double tm1, tm2;
274 275 276

    MAP_OR_FAIL(fopen);

Philip Carns's avatar
Philip Carns committed
277
    tm1 = darshan_core_wtime();
Philip Carns's avatar
Philip Carns committed
278
    ret = __real_fopen64(path, mode);
Philip Carns's avatar
Philip Carns committed
279 280
    tm2 = darshan_core_wtime();

281
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
282
    STDIO_RECORD_OPEN(ret, path, tm1, tm2);
283
    STDIO_POST_RECORD();
284 285 286 287

    return(ret);
}

Philip Carns's avatar
Philip Carns committed
288
FILE* DARSHAN_DECL(fdopen)(int fd, const char *mode)
289 290
{
    FILE* ret;
Philip Carns's avatar
Philip Carns committed
291
    double tm1, tm2;
292

Philip Carns's avatar
Philip Carns committed
293
    MAP_OR_FAIL(fdopen);
294

Philip Carns's avatar
Philip Carns committed
295
    tm1 = darshan_core_wtime();
Philip Carns's avatar
Philip Carns committed
296 297 298
    ret = __real_fdopen(fd, mode);
    tm2 = darshan_core_wtime();

299
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
300
    STDIO_RECORD_OPEN(ret, "UNKNOWN-FDOPEN", tm1, tm2);
301
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
302 303 304 305 306 307 308 309 310 311 312 313 314

    return(ret);
}

FILE* DARSHAN_DECL(freopen)(const char *path, const char *mode, FILE *stream)
{
    FILE* ret;
    double tm1, tm2;

    MAP_OR_FAIL(freopen);

    tm1 = darshan_core_wtime();
    ret = __real_freopen(path, mode, stream);
Philip Carns's avatar
Philip Carns committed
315 316
    tm2 = darshan_core_wtime();

317
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
318
    STDIO_RECORD_OPEN(ret, path, tm1, tm2);
319
    STDIO_POST_RECORD();
320 321 322 323

    return(ret);
}

Philip Carns's avatar
Philip Carns committed
324 325 326 327 328 329 330 331 332 333 334
FILE* DARSHAN_DECL(freopen64)(const char *path, const char *mode, FILE *stream)
{
    FILE* ret;
    double tm1, tm2;

    MAP_OR_FAIL(freopen64);

    tm1 = darshan_core_wtime();
    ret = __real_freopen64(path, mode, stream);
    tm2 = darshan_core_wtime();

335
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
336
    STDIO_RECORD_OPEN(ret, path, tm1, tm2);
337
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
338 339 340 341 342

    return(ret);
}


Philip Carns's avatar
Philip Carns committed
343 344 345 346 347 348 349 350 351 352 353
int DARSHAN_DECL(fflush)(FILE *fp)
{
    double tm1, tm2;
    int ret;

    MAP_OR_FAIL(fflush);

    tm1 = darshan_core_wtime();
    ret = __real_fflush(fp);
    tm2 = darshan_core_wtime();

354
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
355 356
    if(ret >= 0)
        STDIO_RECORD_WRITE(fp, 0, tm1, tm2, 1);
357
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
358 359 360 361

    return(ret);
}

362 363 364 365
int DARSHAN_DECL(fclose)(FILE *fp)
{
    double tm1, tm2;
    int ret;
366
    struct stdio_file_record_ref *rec_ref;
367 368 369 370 371 372 373

    MAP_OR_FAIL(fclose);

    tm1 = darshan_core_wtime();
    ret = __real_fclose(fp);
    tm2 = darshan_core_wtime();

374 375 376
    STDIO_PRE_RECORD();
    rec_ref = darshan_lookup_record_ref(stdio_runtime->stream_hash, &fp, sizeof(fp));
    if(rec_ref)
377
    {
378 379 380 381
        if(rec_ref->file_rec->fcounters[STDIO_F_CLOSE_START_TIMESTAMP] == 0 ||
         rec_ref->file_rec->fcounters[STDIO_F_CLOSE_START_TIMESTAMP] > tm1)
           rec_ref->file_rec->fcounters[STDIO_F_CLOSE_START_TIMESTAMP] = tm1;
        rec_ref->file_rec->fcounters[STDIO_F_CLOSE_END_TIMESTAMP] = tm2;
382
        DARSHAN_TIMER_INC_NO_OVERLAP(
383 384 385
            rec_ref->file_rec->fcounters[STDIO_F_META_TIME],
            tm1, tm2, rec_ref->last_meta_end);
        darshan_delete_record_ref(&(stdio_runtime->stream_hash), &fp, sizeof(fp));
386
    }
387
    STDIO_POST_RECORD();
388 389 390 391

    return(ret);
}

392 393 394 395 396 397 398 399 400 401 402
size_t DARSHAN_DECL(fwrite)(const void *ptr, size_t size, size_t nmemb, FILE *stream)
{
    size_t ret;
    double tm1, tm2;

    MAP_OR_FAIL(fwrite);

    tm1 = darshan_core_wtime();
    ret = __real_fwrite(ptr, size, nmemb, stream);
    tm2 = darshan_core_wtime();

403
    STDIO_PRE_RECORD();
404
    if(ret > 0)
Philip Carns's avatar
Philip Carns committed
405
        STDIO_RECORD_WRITE(stream, size*ret, tm1, tm2, 0);
406
    STDIO_POST_RECORD();
407 408 409 410

    return(ret);
}

Philip Carns's avatar
Philip Carns committed
411 412 413 414 415 416 417 418 419 420 421 422

int DARSHAN_DECL(fputc)(int c, FILE *stream)
{
    int ret;
    double tm1, tm2;

    MAP_OR_FAIL(fputc);

    tm1 = darshan_core_wtime();
    ret = __real_fputc(c, stream);
    tm2 = darshan_core_wtime();

423
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
424 425
    if(ret != EOF)
        STDIO_RECORD_WRITE(stream, 1, tm1, tm2, 0);
426
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
427 428 429 430

    return(ret);
}

Philip Carns's avatar
Philip Carns committed
431 432 433 434 435 436 437 438 439 440 441
int DARSHAN_DECL(putw)(int w, FILE *stream)
{
    int ret;
    double tm1, tm2;

    MAP_OR_FAIL(putw);

    tm1 = darshan_core_wtime();
    ret = __real_putw(w, stream);
    tm2 = darshan_core_wtime();

442
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
443 444
    if(ret != EOF)
        STDIO_RECORD_WRITE(stream, sizeof(int), tm1, tm2, 0);
445
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
446 447 448 449 450

    return(ret);
}


Philip Carns's avatar
Philip Carns committed
451 452 453 454 455 456 457 458 459 460 461 462

int DARSHAN_DECL(fputs)(const char *s, FILE *stream)
{
    int ret;
    double tm1, tm2;

    MAP_OR_FAIL(fputs);

    tm1 = darshan_core_wtime();
    ret = __real_fputs(s, stream);
    tm2 = darshan_core_wtime();

463
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
464 465
    if(ret != EOF && ret > 0)
        STDIO_RECORD_WRITE(stream, strlen(s), tm1, tm2, 0);
466
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
467 468 469 470

    return(ret);
}

Philip Carns's avatar
Philip Carns committed
471 472 473 474 475 476 477 478 479 480 481 482 483 484
int DARSHAN_DECL(vfprintf)(FILE *stream, const char *format, va_list ap)
{
    int ret;
    double tm1, tm2;
    long start_off, end_off;

    MAP_OR_FAIL(vfprintf);

    tm1 = darshan_core_wtime();
    start_off = ftell(stream);
    ret = __real_vfprintf(stream, format, ap);
    end_off = ftell(stream);
    tm2 = darshan_core_wtime();

485
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
486 487
    if(ret > 0)
        STDIO_RECORD_WRITE(stream, (end_off-start_off), tm1, tm2, 0);
488
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513

    return(ret);
}


int DARSHAN_DECL(fprintf)(FILE *stream, const char *format, ...)
{
    int ret;
    double tm1, tm2;
    va_list ap;
    long start_off, end_off;

    MAP_OR_FAIL(vfprintf);

    tm1 = darshan_core_wtime();
    /* NOTE: we intentionally switch to vfprintf here to handle the variable
     * length arguments.
     */
    start_off = ftell(stream);
    va_start(ap, format);
    ret = __real_vfprintf(stream, format, ap);
    va_end(ap);
    end_off = ftell(stream);
    tm2 = darshan_core_wtime();

514
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
515 516
    if(ret > 0)
        STDIO_RECORD_WRITE(stream, (end_off-start_off), tm1, tm2, 0);
517
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
518 519 520 521

    return(ret);
}

522 523 524 525 526 527 528 529 530 531 532
size_t DARSHAN_DECL(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
    size_t ret;
    double tm1, tm2;

    MAP_OR_FAIL(fread);

    tm1 = darshan_core_wtime();
    ret = __real_fread(ptr, size, nmemb, stream);
    tm2 = darshan_core_wtime();

533
    STDIO_PRE_RECORD();
534 535
    if(ret > 0)
        STDIO_RECORD_READ(stream, size*ret, tm1, tm2);
536
    STDIO_POST_RECORD();
537 538 539 540

    return(ret);
}

Philip Carns's avatar
Philip Carns committed
541 542 543 544 545 546 547 548 549 550 551
size_t DARSHAN_DECL(fgetc)(FILE *stream)
{
    int ret;
    double tm1, tm2;

    MAP_OR_FAIL(fgetc);

    tm1 = darshan_core_wtime();
    ret = __real_fgetc(stream);
    tm2 = darshan_core_wtime();

552
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
553 554
    if(ret != EOF)
        STDIO_RECORD_READ(stream, 1, tm1, tm2);
555
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571

    return(ret);
}

/* NOTE: stdio.h typically implements getc() as a macro pointing to _IO_getc */
size_t DARSHAN_DECL(_IO_getc)(FILE *stream)
{
    int ret;
    double tm1, tm2;

    MAP_OR_FAIL(_IO_getc);

    tm1 = darshan_core_wtime();
    ret = __real__IO_getc(stream);
    tm2 = darshan_core_wtime();

572
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
573 574
    if(ret != EOF)
        STDIO_RECORD_READ(stream, 1, tm1, tm2);
575
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
576 577 578 579

    return(ret);
}

Philip Carns's avatar
Philip Carns committed
580 581 582 583 584 585 586 587 588 589 590 591
/* NOTE: stdio.h typically implements putc() as a macro pointing to _IO_putc */
size_t DARSHAN_DECL(_IO_putc)(int c, FILE *stream)
{
    int ret;
    double tm1, tm2;

    MAP_OR_FAIL(_IO_putc);

    tm1 = darshan_core_wtime();
    ret = __real__IO_putc(c, stream);
    tm2 = darshan_core_wtime();

592
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
593 594
    if(ret != EOF)
        STDIO_RECORD_WRITE(stream, 1, tm1, tm2, 0);
595
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
596 597 598

    return(ret);
}
Philip Carns's avatar
Philip Carns committed
599 600 601 602 603 604 605 606 607 608 609
size_t DARSHAN_DECL(getw)(FILE *stream)
{
    int ret;
    double tm1, tm2;

    MAP_OR_FAIL(getw);

    tm1 = darshan_core_wtime();
    ret = __real_getw(stream);
    tm2 = darshan_core_wtime();

610
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
611 612
    if(ret != EOF || ferror(stream) == 0)
        STDIO_RECORD_READ(stream, sizeof(int), tm1, tm2);
613
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
614 615 616 617

    return(ret);
}

Philip Carns's avatar
Philip Carns committed
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
/* NOTE: some glibc versions use __isoc99_fscanf as the underlying symbol
 * rather than fscanf
 */
int DARSHAN_DECL(__isoc99_fscanf)(FILE *stream, const char *format, ...)
{
    int ret;
    double tm1, tm2;
    va_list ap;
    long start_off, end_off;

    MAP_OR_FAIL(vfscanf);

    tm1 = darshan_core_wtime();
    /* NOTE: we intentionally switch to vfscanf here to handle the variable
     * length arguments.
     */
    start_off = ftell(stream);
    va_start(ap, format);
    ret = __real_vfscanf(stream, format, ap);
    va_end(ap);
    end_off = ftell(stream);
    tm2 = darshan_core_wtime();

641
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
642 643
    if(ret != 0)
        STDIO_RECORD_READ(stream, (end_off-start_off), tm1, tm2);
644
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
645 646 647 648

    return(ret);
}

Philip Carns's avatar
Philip Carns committed
649

Philip Carns's avatar
Philip Carns committed
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
int DARSHAN_DECL(fscanf)(FILE *stream, const char *format, ...)
{
    int ret;
    double tm1, tm2;
    va_list ap;
    long start_off, end_off;

    MAP_OR_FAIL(vfscanf);

    tm1 = darshan_core_wtime();
    /* NOTE: we intentionally switch to vfscanf here to handle the variable
     * length arguments.
     */
    start_off = ftell(stream);
    va_start(ap, format);
    ret = __real_vfscanf(stream, format, ap);
    va_end(ap);
    end_off = ftell(stream);
    tm2 = darshan_core_wtime();

670
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
671
    if(ret != 0)
Philip Carns's avatar
Philip Carns committed
672
        STDIO_RECORD_READ(stream, (end_off-start_off), tm1, tm2);
673
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691

    return(ret);
}

int DARSHAN_DECL(vfscanf)(FILE *stream, const char *format, va_list ap)
{
    int ret;
    double tm1, tm2;
    long start_off, end_off;

    MAP_OR_FAIL(vfscanf);

    tm1 = darshan_core_wtime();
    start_off = ftell(stream);
    ret = __real_vfscanf(stream, format, ap);
    end_off = ftell(stream);
    tm2 = darshan_core_wtime();

692
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
693 694
    if(ret != 0)
        STDIO_RECORD_READ(stream, end_off-start_off, tm1, tm2);
695
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
696 697 698 699 700

    return(ret);
}


Philip Carns's avatar
Philip Carns committed
701 702 703 704 705 706 707 708 709 710 711
char* DARSHAN_DECL(fgets)(char *s, int size, FILE *stream)
{
    char *ret;
    double tm1, tm2;

    MAP_OR_FAIL(fgets);

    tm1 = darshan_core_wtime();
    ret = __real_fgets(s, size, stream);
    tm2 = darshan_core_wtime();

712
    STDIO_PRE_RECORD();
Philip Carns's avatar
Philip Carns committed
713 714
    if(ret != NULL)
        STDIO_RECORD_READ(stream, strlen(ret), tm1, tm2);
715
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
716 717 718 719 720

    return(ret);
}


Philip Carns's avatar
Philip Carns committed
721 722 723
void DARSHAN_DECL(rewind)(FILE *stream)
{
    double tm1, tm2;
724
    struct stdio_file_record_ref *rec_ref;
Philip Carns's avatar
Philip Carns committed
725 726 727 728 729 730 731

    MAP_OR_FAIL(rewind);

    tm1 = darshan_core_wtime();
    __real_rewind(stream);
    tm2 = darshan_core_wtime();

732 733 734
    /* NOTE: we don't use STDIO_PRE_RECORD here because there is no return
     * value in this wrapper.
     */
Philip Carns's avatar
Philip Carns committed
735
    STDIO_LOCK();
736 737 738 739 740 741 742 743 744
    if(!stdio_runtime && !instrumentation_disabled) stdio_runtime_initialize();
    if(!stdio_runtime) {
        STDIO_UNLOCK();
        return;
    }

    rec_ref = darshan_lookup_record_ref(stdio_runtime->stream_hash, &stream, sizeof(stream));

    if(rec_ref)
Philip Carns's avatar
Philip Carns committed
745
    {
746
        rec_ref->offset = 0;
Philip Carns's avatar
Philip Carns committed
747
        DARSHAN_TIMER_INC_NO_OVERLAP(
748 749 750
            rec_ref->file_rec->fcounters[STDIO_F_META_TIME],
            tm1, tm2, rec_ref->last_meta_end);
        rec_ref->file_rec->counters[STDIO_SEEKS] += 1;
Philip Carns's avatar
Philip Carns committed
751
    }
752
    STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
753 754 755 756

    return;
}

757 758 759
int DARSHAN_DECL(fseek)(FILE *stream, long offset, int whence)
{
    int ret;
760
    struct stdio_file_record_ref *rec_ref;
761 762 763 764 765 766 767 768 769 770
    double tm1, tm2;

    MAP_OR_FAIL(fseek);

    tm1 = darshan_core_wtime();
    ret = __real_fseek(stream, offset, whence);
    tm2 = darshan_core_wtime();

    if(ret >= 0)
    {
771 772 773
        STDIO_PRE_RECORD();
        rec_ref = darshan_lookup_record_ref(stdio_runtime->stream_hash, &stream, sizeof(stream));
        if(rec_ref)
Philip Carns's avatar
Philip Carns committed
774
        {
775
            rec_ref->offset = ftell(stream);
Philip Carns's avatar
Philip Carns committed
776
            DARSHAN_TIMER_INC_NO_OVERLAP(
777 778 779
                rec_ref->file_rec->fcounters[STDIO_F_META_TIME],
                tm1, tm2, rec_ref->last_meta_end);
            rec_ref->file_rec->counters[STDIO_SEEKS] += 1;
Philip Carns's avatar
Philip Carns committed
780
        }
781
        STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
782 783 784 785 786 787 788 789
    }

    return(ret);
}

int DARSHAN_DECL(fseeko)(FILE *stream, off_t offset, int whence)
{
    int ret;
790
    struct stdio_file_record_ref *rec_ref;
Philip Carns's avatar
Philip Carns committed
791 792 793 794 795 796 797 798 799 800
    double tm1, tm2;

    MAP_OR_FAIL(fseeko);

    tm1 = darshan_core_wtime();
    ret = __real_fseeko(stream, offset, whence);
    tm2 = darshan_core_wtime();

    if(ret >= 0)
    {
801 802 803
        STDIO_PRE_RECORD();
        rec_ref = darshan_lookup_record_ref(stdio_runtime->stream_hash, &stream, sizeof(stream));
        if(rec_ref)
Philip Carns's avatar
Philip Carns committed
804
        {
805
            rec_ref->offset = ftell(stream);
Philip Carns's avatar
Philip Carns committed
806
            DARSHAN_TIMER_INC_NO_OVERLAP(
807 808 809
                rec_ref->file_rec->fcounters[STDIO_F_META_TIME],
                tm1, tm2, rec_ref->last_meta_end);
            rec_ref->file_rec->counters[STDIO_SEEKS] += 1;
Philip Carns's avatar
Philip Carns committed
810
        }
811
        STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
812 813 814 815 816 817 818 819
    }

    return(ret);
}

int DARSHAN_DECL(fseeko64)(FILE *stream, off_t offset, int whence)
{
    int ret;
820
    struct stdio_file_record_ref *rec_ref;
Philip Carns's avatar
Philip Carns committed
821 822 823 824 825 826 827 828 829 830
    double tm1, tm2;

    MAP_OR_FAIL(fseeko64);

    tm1 = darshan_core_wtime();
    ret = __real_fseeko64(stream, offset, whence);
    tm2 = darshan_core_wtime();

    if(ret >= 0)
    {
831 832 833
        STDIO_PRE_RECORD();
        rec_ref = darshan_lookup_record_ref(stdio_runtime->stream_hash, &stream, sizeof(stream));
        if(rec_ref)
834
        {
835
            rec_ref->offset = ftell(stream);
836
            DARSHAN_TIMER_INC_NO_OVERLAP(
837 838 839
                rec_ref->file_rec->fcounters[STDIO_F_META_TIME],
                tm1, tm2, rec_ref->last_meta_end);
            rec_ref->file_rec->counters[STDIO_SEEKS] += 1;
840
        }
841
        STDIO_POST_RECORD();
842 843 844 845 846
    }

    return(ret);
}

Philip Carns's avatar
Philip Carns committed
847 848 849
int DARSHAN_DECL(fsetpos)(FILE *stream, const fpos_t *pos)
{
    int ret;
850
    struct stdio_file_record_ref *rec_ref;
Philip Carns's avatar
Philip Carns committed
851 852 853 854 855 856 857 858 859 860
    double tm1, tm2;

    MAP_OR_FAIL(fsetpos);

    tm1 = darshan_core_wtime();
    ret = __real_fsetpos(stream, pos);
    tm2 = darshan_core_wtime();

    if(ret >= 0)
    {
861 862 863
        STDIO_PRE_RECORD();
        rec_ref = darshan_lookup_record_ref(stdio_runtime->stream_hash, &stream, sizeof(stream));
        if(rec_ref)
Philip Carns's avatar
Philip Carns committed
864
        {
865
            rec_ref->offset = ftell(stream);
Philip Carns's avatar
Philip Carns committed
866
            DARSHAN_TIMER_INC_NO_OVERLAP(
867 868 869
                rec_ref->file_rec->fcounters[STDIO_F_META_TIME],
                tm1, tm2, rec_ref->last_meta_end);
            rec_ref->file_rec->counters[STDIO_SEEKS] += 1;
Philip Carns's avatar
Philip Carns committed
870
        }
871
        STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
872 873 874 875 876 877 878 879
    }

    return(ret);
}

int DARSHAN_DECL(fsetpos64)(FILE *stream, const fpos_t *pos)
{
    int ret;
880
    struct stdio_file_record_ref *rec_ref;
Philip Carns's avatar
Philip Carns committed
881 882 883 884 885 886 887 888 889 890
    double tm1, tm2;

    MAP_OR_FAIL(fsetpos64);

    tm1 = darshan_core_wtime();
    ret = __real_fsetpos64(stream, pos);
    tm2 = darshan_core_wtime();

    if(ret >= 0)
    {
891 892 893
        STDIO_PRE_RECORD();
        rec_ref = darshan_lookup_record_ref(stdio_runtime->stream_hash, &stream, sizeof(stream));
        if(rec_ref)
Philip Carns's avatar
Philip Carns committed
894
        {
895
            rec_ref->offset = ftell(stream);
Philip Carns's avatar
Philip Carns committed
896
            DARSHAN_TIMER_INC_NO_OVERLAP(
897 898 899
                rec_ref->file_rec->fcounters[STDIO_F_META_TIME],
                tm1, tm2, rec_ref->last_meta_end);
            rec_ref->file_rec->counters[STDIO_SEEKS] += 1;
Philip Carns's avatar
Philip Carns committed
900
        }
901
        STDIO_POST_RECORD();
Philip Carns's avatar
Philip Carns committed
902 903 904 905 906 907
    }

    return(ret);
}


908 909 910 911 912 913 914
/**********************************************************
 * Internal functions for manipulating STDIO module state *
 **********************************************************/

/* initialize internal STDIO module data structures and register with darshan-core */
static void stdio_runtime_initialize()
{
915 916 917 918
    int stdio_buf_size;

    /* try to store default number of records for this module */
    stdio_buf_size = DARSHAN_DEF_MOD_REC_COUNT * sizeof(struct darshan_stdio_file);
919 920 921 922 923 924 925 926

    /* don't do anything if already initialized or instrumenation is disabled */
    if(stdio_runtime || instrumentation_disabled)
        return;

    /* register the stdio module with darshan core */
    darshan_core_register_module(
        DARSHAN_STDIO_MOD,
927 928
        &stdio_shutdown,
        &stdio_buf_size,
929
        &my_rank,
930 931
        &darshan_mem_alignment);

932 933 934 935
    /* return if darshan-core does not provide enough module memory */
    if(stdio_buf_size < sizeof(struct darshan_stdio_file))
    {
        darshan_core_unregister_module(DARSHAN_POSIX_MOD);
936
        return;
937
    }
938 939 940 941

    stdio_runtime = malloc(sizeof(*stdio_runtime));
    if(!stdio_runtime)
    {
942
        darshan_core_unregister_module(DARSHAN_STDIO_MOD);
943 944
        return;
    }
945
    memset(stdio_runtime, 0, sizeof(*stdio_runtime));
946 947
}

948 949 950
/************************************************************************
 * Functions exported by this module for coordinating with darshan-core *
 ************************************************************************/
951

952 953
static void stdio_record_reduction_op(void* infile_v, void* inoutfile_v,
    int *len, MPI_Datatype *datatype)
954
{
955 956 957 958
    struct darshan_stdio_file tmp_file;
    struct darshan_stdio_file *infile = infile_v;
    struct darshan_stdio_file *inoutfile = inoutfile_v;
    int i, j;
959

960
    assert(stdio_runtime);
961

962
    for(i=0; i<*len; i++)
963
    {
964 965 966
        memset(&tmp_file, 0, sizeof(struct darshan_stdio_file));
        tmp_file.base_rec.id = infile->base_rec.id;
        tmp_file.base_rec.rank = -1;
967

968 969 970 971 972 973 974 975 976 977 978 979 980 981
        /* sum */
        for(j=STDIO_OPENS; j<=STDIO_BYTES_READ; j++)
        {
            tmp_file.counters[j] = infile->counters[j] + inoutfile->counters[j];
        }
        
        /* max */
        for(j=STDIO_MAX_BYTE_READ; j<=STDIO_MAX_BYTE_WRITTEN; j++)
        {
            if(infile->counters[j] > inoutfile->counters[j])
                tmp_file.counters[j] = infile->counters[j];
            else
                tmp_file.counters[j] = inoutfile->counters[j];
        }
982

983 984 985 986 987
        /* sum */
        for(j=STDIO_F_META_TIME; j<=STDIO_F_READ_TIME; j++)
        {
            tmp_file.fcounters[j] = infile->fcounters[j] + inoutfile->fcounters[j];
        }
988

989 990 991 992 993 994 995 996 997
        /* min non-zero (if available) value */
        for(j=STDIO_F_OPEN_START_TIMESTAMP; j<=STDIO_F_READ_START_TIMESTAMP; j++)
        {
            if((infile->fcounters[j] < inoutfile->fcounters[j] &&
               infile->fcounters[j] > 0) || inoutfile->fcounters[j] == 0) 
                tmp_file.fcounters[j] = infile->fcounters[j];
            else
                tmp_file.fcounters[j] = inoutfile->fcounters[j];
        }
998

999 1000 1001 1002 1003 1004 1005 1006
        /* max */
        for(j=STDIO_F_OPEN_END_TIMESTAMP; j<=STDIO_F_READ_END_TIMESTAMP; j++)
        {
            if(infile->fcounters[j] > inoutfile->fcounters[j])
                tmp_file.fcounters[j] = infile->fcounters[j];
            else
                tmp_file.fcounters[j] = inoutfile->fcounters[j];
        }
1007

1008 1009 1010 1011
        /* update pointers */
        *inoutfile = tmp_file;
        inoutfile++;
        infile++;
1012 1013 1014 1015 1016
    }

    return;
}

1017
static void stdio_shutdown(
1018 1019 1020 1021 1022 1023
    MPI_Comm mod_comm,
    darshan_record_id *shared_recs,
    int shared_rec_count,
    void **stdio_buf,
    int *stdio_buf_sz)
{
1024 1025
    struct stdio_file_record_ref *rec_ref;
    struct darshan_stdio_file *stdio_rec_buf = *(struct darshan_stdio_file **)stdio_buf;
1026
    int i;
1027 1028
    struct darshan_stdio_file *red_send_buf = NULL;
    struct darshan_stdio_file *red_recv_buf = NULL;
1029 1030
    MPI_Datatype red_type;
    MPI_Op red_op;
1031
    int stdio_rec_count;
1032

1033
    STDIO_LOCK();
1034
    assert(stdio_runtime);
1035
    stdio_rec_count = stdio_runtime->file_rec_count;
1036

1037 1038 1039 1040 1041 1042 1043 1044 1045
    /* if there are globally shared files, do a shared file reduction */
    /* NOTE: the shared file reduction is also skipped if the 
     * DARSHAN_DISABLE_SHARED_REDUCTION environment variable is set.
     */
    if(shared_rec_count && !getenv("DARSHAN_DISABLE_SHARED_REDUCTION"))
    {
        /* necessary initialization of shared records */
        for(i = 0; i < shared_rec_count; i++)
        {
1046 1047 1048
            rec_ref = darshan_lookup_record_ref(stdio_runtime->rec_id_hash,
                &shared_recs[i], sizeof(darshan_record_id));
            assert(rec_ref);
1049

1050
            rec_ref->file_rec->base_rec.rank = -1;
1051 1052 1053 1054 1055 1056
        }

        /* sort the array of files descending by rank so that we get all of the 
         * shared files (marked by rank -1) in a contiguous portion at end 
         * of the array
         */
1057
        darshan_record_sort(stdio_rec_buf, stdio_rec_count, sizeof(struct darshan_stdio_file));
1058 1059

        /* make *send_buf point to the shared files at the end of sorted array */
1060
        red_send_buf = &(stdio_rec_buf[stdio_rec_count-shared_rec_count]);
1061 1062 1063 1064

        /* allocate memory for the reduction output on rank 0 */
        if(my_rank == 0)
        {