darshan-dxt.c 24.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
/*
 * Copyright (C) 2016 Intel Corporation.
 * See COPYRIGHT notice in top-level directory.
 *
 */

#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 "utlist.h"
#include "uthash.h"
#include "darshan.h"
#include "darshan-dynamic.h"

#ifndef HAVE_OFF64_T
typedef int64_t off64_t;
#endif

#ifdef DARSHAN_LUSTRE
#include <lustre/lustre_user.h>
#endif

#define IO_TRACE_BUF_SIZE       1024

43
struct dxt_record_ref_tracker
44 45 46 47 48
{
    void *rec_ref_p;
    UT_hash_handle hlink;
};

49 50 51
/* The dxt_file_record_ref structure maintains necessary runtime metadata
 * for the DXT file record (dxt_file_record structure, defined in
 * darshan-dxt-log-format.h) pointed to by 'file_rec'. This metadata
52 53 54
 * assists with the instrumenting of specific statistics in the file record.
 *
 * NOTE: we use the 'darshan_record_ref' interface (in darshan-common) to
55
 * associate different types of handles with this dxt_file_record_ref struct.
56 57 58
 * This allows us to index this struct (and the underlying file record) by using
 * either the corresponding Darshan record identifier (derived from the filename)
 * or by a generated file descriptor, for instance. Note that, while there should
59
 * only be a single Darshan record identifier that indexes a dxt_file_record_ref,
60 61
 * there could be multiple open file descriptors that index it.
 */
62
struct dxt_file_record_ref
63
{
64
    struct dxt_file_record *file_rec;
65 66
    int64_t write_available_buf;
    int64_t read_available_buf;
67 68 69
    int fs_type; /* same as darshan_fs_info->fs_type */
};

70 71
/* The dxt_runtime structure maintains necessary state for storing
 * DXT file records and for coordinating with darshan-core at
72 73
 * shutdown time.
 */
74
struct dxt_posix_runtime
75 76 77 78 79 80
{
    void *rec_id_hash;
    void *fd_hash;
    int file_rec_count;
};

81
struct dxt_mpiio_runtime
82 83 84 85 86 87
{
    void *rec_id_hash;
    void *fh_hash;
    int file_rec_count;
};

88
void dxt_posix_runtime_initialize(
89
    void);
90
void dxt_mpiio_runtime_initialize(
91
    void);
92
void dxt_posix_track_new_file_record(
93
    darshan_record_id rec_id, const char *path);
94
void dxt_mpiio_track_new_file_record(
95
    darshan_record_id rec_id, const char *path);
96 97
void dxt_posix_add_record_ref(darshan_record_id rec_id, int fd);
void dxt_mpiio_add_record_ref(darshan_record_id rec_id, MPI_File fh);
98
#if 0
99 100
static void dxt_instrument_fs_data(
    darshan_record_id rec_id, int fs_type, struct dxt_file_record *file_rec);
101
#endif
102
static void dxt_posix_cleanup_runtime(
103
    void);
104
static void dxt_mpiio_cleanup_runtime(
105 106
    void);

107
static void dxt_posix_shutdown(
108
    MPI_Comm mod_comm, darshan_record_id *shared_recs,
109 110
    int shared_rec_count, void **dxt_buf, int *dxt_buf_sz);
static void dxt_mpiio_shutdown(
111
    MPI_Comm mod_comm, darshan_record_id *shared_recs,
112
    int shared_rec_count, void **dxt_buf, int *dxt_buf_sz);
113 114 115 116 117 118


#ifdef DARSHAN_LUSTRE
/* XXX modules don't expose an API for other modules, so use extern to get
 * Lustre instrumentation function
 */
119 120
extern void dxt_get_lustre_stripe_info(
    darshan_record_id rec_id, struct dxt_file_record *file_rec);
121 122
#endif

123 124 125
static struct dxt_posix_runtime *dxt_posix_runtime = NULL;
static struct dxt_mpiio_runtime *dxt_mpiio_runtime = NULL;
static pthread_mutex_t dxt_posix_runtime_mutex =
126
            PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
127
static pthread_mutex_t dxt_mpiio_runtime_mutex =
128 129 130 131 132 133 134
            PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;

static int posix_my_rank = -1;
static int mpiio_my_rank = -1;
static int instrumentation_disabled = 0;
static int darshan_mem_alignment = 1;

135 136
#define DXT_POSIX_LOCK() pthread_mutex_lock(&dxt_posix_runtime_mutex)
#define DXT_POSIX_UNLOCK() pthread_mutex_unlock(&dxt_posix_runtime_mutex)
137

138 139
#define DXT_MPIIO_LOCK() pthread_mutex_lock(&dxt_mpiio_runtime_mutex)
#define DXT_MPIIO_UNLOCK() pthread_mutex_unlock(&dxt_mpiio_runtime_mutex)
140 141 142


/**********************************************************
143
 *      Wrappers for DXT I/O functions of interest      *
144 145
 **********************************************************/

146
void check_io_trace_buf(struct dxt_file_record_ref *rec_ref)
147
{
148
    struct dxt_file_record *file_rec = rec_ref->file_rec;
149

150
    int write_count = file_rec->write_count;
151
    int write_available_buf = rec_ref->write_available_buf;
152 153 154 155 156 157 158 159

    if (write_count >= write_available_buf) {
        write_available_buf += IO_TRACE_BUF_SIZE;

        file_rec->write_traces =
            (segment_info *)realloc(file_rec->write_traces,
                    write_available_buf * sizeof(segment_info));

160
        rec_ref->write_available_buf = write_available_buf;
161 162 163
    }

    int read_count = file_rec->read_count;
164
    int read_available_buf = rec_ref->read_available_buf;
165 166 167 168 169 170 171 172

    if (read_count >= read_available_buf) {
        read_available_buf += IO_TRACE_BUF_SIZE;

        file_rec->read_traces =
            (segment_info *)realloc(file_rec->read_traces,
                    read_available_buf * sizeof(segment_info));

173
        rec_ref->read_available_buf = read_available_buf;
174 175 176
    }
}

177
void dxt_posix_write(int fd, int64_t offset, int64_t length,
178 179
        double start_time, double end_time)
{
180 181
    struct dxt_file_record_ref* rec_ref = NULL;
    struct dxt_file_record *file_rec;
182

183
    rec_ref = darshan_lookup_record_ref(dxt_posix_runtime->fd_hash,
184 185
                &fd, sizeof(int));
    if (!rec_ref) {
186
        fprintf(stderr, "Error: dxt_posix_write unable to find rec_ref.\n");
187 188 189 190
        return;
    }

    file_rec = rec_ref->file_rec;
191
    if (dxt_posix_runtime) {
192
        check_io_trace_buf(rec_ref);
193 194 195 196 197 198 199 200 201
    }

    file_rec->write_traces[file_rec->write_count].offset = offset;
    file_rec->write_traces[file_rec->write_count].length = length;
    file_rec->write_traces[file_rec->write_count].start_time = start_time;
    file_rec->write_traces[file_rec->write_count].end_time = end_time;
    file_rec->write_count += 1;
}

202
void dxt_posix_read(int fd, int64_t offset, int64_t length,
203 204
        double start_time, double end_time)
{
205 206
    struct dxt_file_record_ref* rec_ref = NULL;
    struct dxt_file_record *file_rec;
207

208
    rec_ref = darshan_lookup_record_ref(dxt_posix_runtime->fd_hash,
209 210
                &fd, sizeof(int));
    if (!rec_ref) {
211
        fprintf(stderr, "Error: dxt_posix_read unable to find rec_ref.\n");
212 213 214 215
        return;
    }

    file_rec = rec_ref->file_rec;
216
    if (dxt_posix_runtime) {
217
        check_io_trace_buf(rec_ref);
218 219 220 221 222 223 224 225 226
    }

    file_rec->read_traces[file_rec->read_count].offset = offset;
    file_rec->read_traces[file_rec->read_count].length = length;
    file_rec->read_traces[file_rec->read_count].start_time = start_time;
    file_rec->read_traces[file_rec->read_count].end_time = end_time;
    file_rec->read_count += 1;
}

227
void dxt_mpiio_write(MPI_File fh, int64_t length,
228 229
        double start_time, double end_time)
{
230 231
    struct dxt_file_record_ref* rec_ref = NULL;
    struct dxt_file_record *file_rec;
232

233
    rec_ref = darshan_lookup_record_ref(dxt_mpiio_runtime->fh_hash,
234 235
                &fh, sizeof(MPI_File));
    if (!rec_ref) {
236
        fprintf(stderr, "Error: dxt_mpiio_write unable to find rec_ref.\n");
237 238 239 240
        return;
    }

    file_rec = rec_ref->file_rec;
241
    if (dxt_mpiio_runtime) {
242
        check_io_trace_buf(rec_ref);
243 244 245 246 247 248 249 250
    }

    file_rec->write_traces[file_rec->write_count].length = length;
    file_rec->write_traces[file_rec->write_count].start_time = start_time;
    file_rec->write_traces[file_rec->write_count].end_time = end_time;
    file_rec->write_count += 1;
}

251
void dxt_mpiio_read(MPI_File fh, int64_t length,
252 253
        double start_time, double end_time)
{
254 255
    struct dxt_file_record_ref* rec_ref = NULL;
    struct dxt_file_record *file_rec;
256

257
    rec_ref = darshan_lookup_record_ref(dxt_mpiio_runtime->fh_hash,
258 259
                &fh, sizeof(MPI_File));
    if (!rec_ref) {
260
        fprintf(stderr, "Error: dxt_mpiio_read unable to find rec_ref.\n");
261 262 263 264
        return;
    }

    file_rec = rec_ref->file_rec;
265
    if (dxt_mpiio_runtime) {
266
        check_io_trace_buf(rec_ref);
267 268 269 270 271 272 273 274 275 276
    }

    file_rec->read_traces[file_rec->read_count].length = length;
    file_rec->read_traces[file_rec->read_count].start_time = start_time;
    file_rec->read_traces[file_rec->read_count].end_time = end_time;
    file_rec->read_count += 1;
}


/**********************************************************
277
 * Internal functions for manipulating DXT module state *
278 279
 **********************************************************/

280 281
/* initialize internal DXT module data structures and register with darshan-core */
void dxt_posix_runtime_initialize()
282 283 284 285
{
    int psx_buf_size;

    /* try and store a default number of records for this module */
286
    psx_buf_size = DARSHAN_DEF_MOD_REC_COUNT * sizeof(struct dxt_file_record);
287

288
    /* register the DXT module with darshan core */
289
    darshan_core_register_module(
290 291
        DXT_POSIX_MOD,
        &dxt_posix_shutdown,
292 293 294 295 296
        &psx_buf_size,
        &posix_my_rank,
        &darshan_mem_alignment);

    /* return if darshan-core does not provide enough module memory */
297
    if(psx_buf_size < sizeof(struct dxt_file_record))
298
    {
299
        darshan_core_unregister_module(DXT_POSIX_MOD);
300 301 302
        return;
    }

303 304
    dxt_posix_runtime = malloc(sizeof(*dxt_posix_runtime));
    if(!dxt_posix_runtime)
305
    {
306
        darshan_core_unregister_module(DXT_POSIX_MOD);
307 308
        return;
    }
309
    memset(dxt_posix_runtime, 0, sizeof(*dxt_posix_runtime));
310 311 312 313

    return;
}

314
void dxt_mpiio_runtime_initialize()
315 316 317 318
{
    int psx_buf_size;

    /* try and store a default number of records for this module */
319
    psx_buf_size = DARSHAN_DEF_MOD_REC_COUNT * sizeof(struct dxt_file_record);
320

321
    /* register the DXT module with darshan core */
322
    darshan_core_register_module(
323 324
        DXT_MPIIO_MOD,
        &dxt_mpiio_shutdown,
325 326 327 328 329
        &psx_buf_size,
        &mpiio_my_rank,
        &darshan_mem_alignment);

    /* return if darshan-core does not provide enough module memory */
330
    if(psx_buf_size < sizeof(struct dxt_file_record))
331
    {
332
        darshan_core_unregister_module(DXT_MPIIO_MOD);
333 334 335
        return;
    }

336 337
    dxt_mpiio_runtime = malloc(sizeof(*dxt_mpiio_runtime));
    if(!dxt_mpiio_runtime)
338
    {
339
        darshan_core_unregister_module(DXT_MPIIO_MOD);
340 341
        return;
    }
342
    memset(dxt_mpiio_runtime, 0, sizeof(*dxt_mpiio_runtime));
343 344 345 346

    return;
}

347
void dxt_posix_track_new_file_record(
348 349
    darshan_record_id rec_id, const char *path)
{
350 351
    struct dxt_file_record_ref *rec_ref = NULL;
    struct dxt_file_record *file_rec = NULL;
352 353 354 355 356 357 358 359 360
    struct darshan_fs_info fs_info;
    int ret;

    rec_ref = malloc(sizeof(*rec_ref));
    if(!rec_ref)
        return;
    memset(rec_ref, 0, sizeof(*rec_ref));

    /* add a reference to this file record based on record id */
361
    ret = darshan_add_record_ref(&(dxt_posix_runtime->rec_id_hash), &rec_id,
362 363 364 365 366 367 368 369 370 371 372 373 374
            sizeof(darshan_record_id), rec_ref);
    if(ret == 0)
    {
        free(rec_ref);
        return;
    }

    /* register the actual file record with darshan-core so it is persisted
     * in the log file
     */
    file_rec = darshan_core_register_record(
            rec_id,
            path,
375 376
            DXT_POSIX_MOD,
            sizeof(struct dxt_file_record),
377 378 379 380
            &fs_info);

    if(!file_rec)
    {
381
        darshan_delete_record_ref(&(dxt_posix_runtime->rec_id_hash),
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
                &rec_id, sizeof(darshan_record_id));
        free(rec_ref);
        return;
    }

    /*
     * Registering this file record was successful, so initialize
     * some fields */
    file_rec->base_rec.id = rec_id;
    file_rec->base_rec.rank = posix_my_rank;

    file_rec->write_count = 0;
    file_rec->write_traces = malloc(IO_TRACE_BUF_SIZE *
            sizeof(segment_info));

    file_rec->read_count = 0;
    file_rec->read_traces = malloc(IO_TRACE_BUF_SIZE *
            sizeof(segment_info));

    rec_ref->file_rec = file_rec;
402 403
    rec_ref->write_available_buf = IO_TRACE_BUF_SIZE;
    rec_ref->read_available_buf = IO_TRACE_BUF_SIZE;
404 405
    rec_ref->fs_type = fs_info.fs_type;

406
    dxt_posix_runtime->file_rec_count++;
407 408
}

409
void dxt_mpiio_track_new_file_record(
410 411
    darshan_record_id rec_id, const char *path)
{
412 413
    struct dxt_file_record *file_rec = NULL;
    struct dxt_file_record_ref *rec_ref = NULL;
414 415 416 417 418 419 420 421 422
    struct darshan_fs_info fs_info;
    int ret;

    rec_ref = malloc(sizeof(*rec_ref));
    if(!rec_ref)
        return;
    memset(rec_ref, 0, sizeof(*rec_ref));

    /* add a reference to this file record based on record id */
423
    ret = darshan_add_record_ref(&(dxt_mpiio_runtime->rec_id_hash), &rec_id,
424 425 426 427 428 429 430 431 432 433 434 435 436
            sizeof(darshan_record_id), rec_ref);
    if(ret == 0)
    {
        free(rec_ref);
        return;
    }

    /* register the actual file record with darshan-core so it is persisted
     * in the log file
     */
    file_rec = darshan_core_register_record(
            rec_id,
            path,
437 438
            DXT_MPIIO_MOD,
            sizeof(struct dxt_file_record),
439 440 441 442
            &fs_info);

    if(!file_rec)
    {
443
        darshan_delete_record_ref(&(dxt_mpiio_runtime->rec_id_hash),
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
                &rec_id, sizeof(darshan_record_id));
        free(rec_ref);
        return;
    }

    /* registering this file record was successful, so initialize
     * some fields
     */
    file_rec->base_rec.id = rec_id;
    file_rec->base_rec.rank = mpiio_my_rank;

    file_rec->write_count = 0;
    file_rec->write_traces = malloc(IO_TRACE_BUF_SIZE *
            sizeof(segment_info));

    file_rec->read_count = 0;
    file_rec->read_traces = malloc(IO_TRACE_BUF_SIZE *
            sizeof(segment_info));

    rec_ref->file_rec = file_rec;
464 465
    rec_ref->write_available_buf = IO_TRACE_BUF_SIZE;
    rec_ref->read_available_buf = IO_TRACE_BUF_SIZE;
466 467
    rec_ref->fs_type = fs_info.fs_type;

468
    dxt_mpiio_runtime->file_rec_count++;
469 470
}

471
void dxt_posix_add_record_ref(darshan_record_id rec_id, int fd)
472
{
473 474
    struct dxt_file_record_ref *rec_ref = NULL;
    struct dxt_file_record *file_rec;
475 476
    int i;

477
    rec_ref = darshan_lookup_record_ref(dxt_posix_runtime->rec_id_hash, &rec_id,
478 479 480
                sizeof(darshan_record_id));
    assert(rec_ref);

481
    darshan_add_record_ref(&(dxt_posix_runtime->fd_hash), &fd,
482 483
            sizeof(int), rec_ref);

484
#if 0
485 486
    /* get Lustre stripe information */
    file_rec = rec_ref->file_rec;
487
    dxt_instrument_fs_data(rec_id, rec_ref->fs_type, file_rec);
488
#endif
489 490
}

491
void dxt_mpiio_add_record_ref(darshan_record_id rec_id, MPI_File fh)
492
{
493
    struct dxt_file_record_ref *rec_ref = NULL;
494

495
    rec_ref = darshan_lookup_record_ref(dxt_mpiio_runtime->rec_id_hash, &rec_id,
496 497 498
                sizeof(darshan_record_id));
    assert(rec_ref);

499
    darshan_add_record_ref(&(dxt_mpiio_runtime->fh_hash), &fh,
500 501 502
            sizeof(MPI_File), rec_ref);
}

503
#if 0
504 505
static void dxt_instrument_fs_data(
        darshan_record_id rec_id, int fs_type, struct dxt_file_record *file_rec)
506 507 508 509 510
{
#ifdef DARSHAN_LUSTRE
    /* allow lustre to generate a record if we configured with lustre support */
    if(fs_type == LL_SUPER_MAGIC)
    {
511
        dxt_get_lustre_stripe_info(rec_id, file_rec);
512 513 514 515 516
        return;
    }
#endif
    return;
}
517
#endif
518

519
void dxt_clear_record_refs(void **hash_head_p, int free_flag)
520
{
521 522 523 524 525
    struct dxt_record_ref_tracker *ref_tracker, *tmp;
    struct dxt_record_ref_tracker *ref_tracker_head =
        *(struct dxt_record_ref_tracker **)hash_head_p;
    struct dxt_file_record_ref *rec_ref;
    struct dxt_file_record *file_rec;
526

527
#if 0    
528 529 530 531 532
    /* iterate the hash table and remove/free all reference trackers */
    HASH_ITER(hlink, ref_tracker_head, ref_tracker, tmp)
    {
        HASH_DELETE(hlink, ref_tracker_head, ref_tracker);
        if (free_flag) {
533
            rec_ref = (struct dxt_file_record_ref *)ref_tracker->rec_ref_p;
534 535 536 537 538 539 540 541 542 543 544 545 546
            file_rec = rec_ref->file_rec;

            if (file_rec->write_traces)
                free(file_rec->write_traces);

            if (file_rec->read_traces)
                free(file_rec->read_traces);

            free(rec_ref);
        }
        free(ref_tracker);
    }
    *hash_head_p = ref_tracker_head;
547
#endif
548 549 550 551

    return;
}

552
static void dxt_posix_cleanup_runtime()
553
{
554 555
    dxt_clear_record_refs(&(dxt_posix_runtime->fd_hash), 0);
    dxt_clear_record_refs(&(dxt_posix_runtime->rec_id_hash), 1);
556

557 558
    free(dxt_posix_runtime);
    dxt_posix_runtime = NULL;
559 560 561 562

    return;
}

563
static void dxt_mpiio_cleanup_runtime()
564
{
565 566
    dxt_clear_record_refs(&(dxt_mpiio_runtime->fh_hash), 0);
    dxt_clear_record_refs(&(dxt_mpiio_runtime->rec_id_hash), 1);
567

568 569
    free(dxt_mpiio_runtime);
    dxt_mpiio_runtime = NULL;
570 571 572 573 574 575 576 577 578

    return;
}


/********************************************************************************
 * shutdown function exported by this module for coordinating with darshan-core *
 ********************************************************************************/

579
static void dxt_posix_shutdown(
580 581 582
    MPI_Comm mod_comm,
    darshan_record_id *shared_recs,
    int shared_rec_count,
583 584
    void **dxt_posix_buf,
    int *dxt_posix_buf_sz)
585
{
586 587
    struct dxt_file_record_ref *rec_ref;
    struct dxt_file_record *file_rec;
588 589 590 591 592 593 594 595 596 597 598
    int i, idx;

    int64_t offset;
    int64_t length;
    int64_t rank;
    double start_time;
    double end_time;

    int64_t record_size = 0;
    int64_t record_write_count = 0;
    int64_t record_read_count = 0;
599
    void *tmp_buf_ptr = *dxt_posix_buf;
600

601
    assert(dxt_posix_runtime);
602

603 604 605 606 607
    DXT_POSIX_LOCK();
    int dxt_rec_count = dxt_posix_runtime->file_rec_count;
    struct dxt_record_ref_tracker *ref_tracker, *tmp;
    struct dxt_record_ref_tracker *ref_tracker_head =
        (struct dxt_record_ref_tracker *)(dxt_posix_runtime->rec_id_hash);
608

609
    *dxt_posix_buf_sz = 0;
610 611

    HASH_ITER(hlink, ref_tracker_head, ref_tracker, tmp) {
612
        rec_ref = (struct dxt_file_record_ref *)ref_tracker->rec_ref_p;
613 614 615 616 617 618 619 620 621 622 623 624
        assert(rec_ref);

        file_rec = rec_ref->file_rec;

        record_write_count = file_rec->write_count;
        record_read_count = file_rec->read_count;

        if (record_write_count == 0 && record_read_count == 0)
            continue;

        /*
         * Buffer format:
625
         * dxt_file_record + ost_ids + write_traces + read_traces
626
         */
627
        record_size = sizeof(struct dxt_file_record) +
628 629
                (record_write_count + record_read_count) * sizeof(segment_info);

630 631
        if (*dxt_posix_buf_sz == 0) {
            *dxt_posix_buf = (void *)malloc(record_size);
632
        } else {
633 634
            *dxt_posix_buf = (void *)realloc((*dxt_posix_buf),
                            *dxt_posix_buf_sz + record_size);
635
        }
636
        tmp_buf_ptr = (void *)(*dxt_posix_buf) + *dxt_posix_buf_sz;
637

638 639 640
        /*Copy struct dxt_file_record */
        memcpy(tmp_buf_ptr, (void *)file_rec, sizeof(struct dxt_file_record));
        tmp_buf_ptr = ((void *)tmp_buf_ptr) + sizeof(struct dxt_file_record);
641 642 643 644 645 646 647 648 649 650 651 652 653

        /*Copy write record */
        memcpy(tmp_buf_ptr, (void *)(file_rec->write_traces),
                record_write_count * sizeof(segment_info));
        tmp_buf_ptr = ((void *)tmp_buf_ptr) +
                    record_write_count * sizeof(segment_info);

        /*Copy read record */
        memcpy(tmp_buf_ptr, (void *)(file_rec->read_traces),
                record_read_count * sizeof(segment_info));
        tmp_buf_ptr = ((char *)tmp_buf_ptr) +
                    record_read_count * sizeof(segment_info);

654
        *dxt_posix_buf_sz += record_size;
655 656

#if 0
657 658
        printf("DXT, record_id: %" PRIu64 "\n", rec_ref->file_rec->base_rec.id);
        printf("DXT, write_count is: %d read_count is: %d\n",
659
                    file_rec->write_count, file_rec->read_count);
660 661 662 663 664 665 666 667

        for (i = 0; i < file_rec->write_count; i++) {
            rank = file_rec->base_rec.rank;
            offset = file_rec->write_traces[i].offset;
            length = file_rec->write_traces[i].length;
            start_time = file_rec->write_traces[i].start_time;
            end_time = file_rec->write_traces[i].end_time;

668
            printf("DXT, rank %d writes segment %lld [offset: %lld length: %lld start_time: %fs end_time: %fs]\n", rank, i, offset, length, start_time, end_time);
669 670 671 672 673 674 675 676 677
        }

        for (i = 0; i < file_rec->read_count; i++) {
            rank = file_rec->base_rec.rank;
            offset = file_rec->read_traces[i].offset;
            length = file_rec->read_traces[i].length;
            start_time = file_rec->read_traces[i].start_time;
            end_time = file_rec->read_traces[i].end_time;

678
            printf("DXT, rank %d reads segment %lld [offset: %lld length: %lld start_time: %fs end_time: %fs]\n", rank, i, offset, length, start_time, end_time);
679 680 681 682 683
        }
#endif
    }

    /* shutdown internal structures used for instrumenting */
684
    dxt_posix_cleanup_runtime();
685 686 687 688

    /* disable further instrumentation */
    instrumentation_disabled = 1;

689
    DXT_POSIX_UNLOCK();
690 691 692 693

    return;
}

694
static void dxt_mpiio_shutdown(
695 696 697
    MPI_Comm mod_comm,
    darshan_record_id *shared_recs,
    int shared_rec_count,
698 699
    void **dxt_mpiio_buf,
    int *dxt_mpiio_buf_sz)
700
{
701 702
    struct dxt_file_record_ref *rec_ref;
    struct dxt_file_record *file_rec;
703 704 705 706 707 708 709 710 711 712 713
    int i, idx;

    int64_t offset;
    int64_t length;
    int64_t rank;
    double start_time;
    double end_time;

    int64_t record_size = 0;
    int64_t record_write_count = 0;
    int64_t record_read_count = 0;
714
    void *tmp_buf_ptr = *dxt_mpiio_buf;
715

716
    assert(dxt_mpiio_runtime);
717

718 719 720 721 722
    DXT_MPIIO_LOCK();
    int dxt_rec_count = dxt_mpiio_runtime->file_rec_count;
    struct dxt_record_ref_tracker *ref_tracker, *tmp;
    struct dxt_record_ref_tracker *ref_tracker_head =
        (struct dxt_record_ref_tracker *)(dxt_mpiio_runtime->rec_id_hash);
723

724
    *dxt_mpiio_buf_sz = 0;
725 726

    HASH_ITER(hlink, ref_tracker_head, ref_tracker, tmp) {
727
        rec_ref = (struct dxt_file_record_ref *)ref_tracker->rec_ref_p;
728 729 730 731 732 733 734 735 736 737 738
        assert(rec_ref);

        file_rec = rec_ref->file_rec;

        record_write_count = file_rec->write_count;
        record_read_count = file_rec->read_count;
        if (record_write_count == 0 && record_read_count == 0)
            continue;

        /*
         * Buffer format:
739
         * dxt_file_record + ost_ids + write_traces + read_traces
740
         */
741
        record_size = sizeof(struct dxt_file_record) +
742 743
                (record_write_count + record_read_count) * sizeof(segment_info);

744 745
        if (*dxt_mpiio_buf_sz == 0) {
            *dxt_mpiio_buf = (void *)malloc(record_size);
746
        } else {
747 748
            *dxt_mpiio_buf = (void *)realloc((*dxt_mpiio_buf),
                            *dxt_mpiio_buf_sz + record_size);
749
        }
750
        tmp_buf_ptr = (void *)(*dxt_mpiio_buf) + *dxt_mpiio_buf_sz;
751

752 753 754
        /*Copy struct dxt_file_record */
        memcpy(tmp_buf_ptr, (void *)file_rec, sizeof(struct dxt_file_record));
        tmp_buf_ptr = ((void *)tmp_buf_ptr) + sizeof(struct dxt_file_record);
755 756 757 758 759 760 761 762 763 764 765 766 767

        /*Copy write record */
        memcpy(tmp_buf_ptr, (void *)(file_rec->write_traces),
                record_write_count * sizeof(segment_info));
        tmp_buf_ptr = ((void *)tmp_buf_ptr) +
                    record_write_count * sizeof(segment_info);

        /*Copy read record */
        memcpy(tmp_buf_ptr, (void *)(file_rec->read_traces),
                record_read_count * sizeof(segment_info));
        tmp_buf_ptr = ((char *)tmp_buf_ptr) +
                    record_read_count * sizeof(segment_info);

768
        *dxt_mpiio_buf_sz += record_size;
769 770 771

#if 0
        printf("Cong, record_id: %" PRIu64 "\n", rec_ref->file_rec->base_rec.id);
772
        printf("DXT, file_rec->write_count is: %d\n",
773 774 775 776 777 778 779 780 781
                    file_rec->write_count);

        for (i = 0; i < file_rec->write_count; i++) {
            rank = file_rec->base_rec.rank;
            offset = file_rec->write_traces[i].offset;
            length = file_rec->write_traces[i].length;
            start_time = file_rec->write_traces[i].start_time;
            end_time = file_rec->write_traces[i].end_time;

782
            printf("DXT, rank %d writes segment %lld [offset: %lld length: %lld start_time: %fs end_time: %fs]\n", rank, i, offset, length, start_time, end_time);
783 784 785 786 787 788 789 790 791
        }

        for (i = 0; i < file_rec->read_count; i++) {
            rank = file_rec->base_rec.rank;
            offset = file_rec->read_traces[i].offset;
            length = file_rec->read_traces[i].length;
            start_time = file_rec->read_traces[i].start_time;
            end_time = file_rec->read_traces[i].end_time;

792
            printf("DXT, rank %d reads segment %lld [offset: %lld length: %lld start_time: %fs end_time: %fs]\n", rank, i, offset, length, start_time, end_time);
793 794 795 796 797
        }
#endif
    }

    /* shutdown internal structures used for instrumenting */
798
    dxt_mpiio_cleanup_runtime();
799 800 801 802

    /* disable further instrumentation */
    instrumentation_disabled = 1;

803
    DXT_MPIIO_UNLOCK();
804 805 806 807 808 809 810 811 812 813 814 815

    return;
}

/*
 * Local variables:
 *  c-indent-level: 4
 *  c-basic-offset: 4
 * End:
 *
 * vim: ts=8 sts=4 sw=4 expandtab
 */