darshan-dxt.c 35.7 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
/*
 * 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>
Shane Snyder's avatar
Shane Snyder committed
27
#include <regex.h>
28
29
30
31
32

#include "utlist.h"
#include "uthash.h"
#include "darshan.h"
#include "darshan-dynamic.h"
Shane Snyder's avatar
Shane Snyder committed
33
#include "darshan-dxt.h"
34
35
36
37
38

#ifndef HAVE_OFF64_T
typedef int64_t off64_t;
#endif

39
/* maximum amount of memory to use for storing DXT records */
40
41
42
43
44
#ifdef __DARSHAN_MOD_MEM_MAX
#define DXT_IO_TRACE_MEM_MAX (__DARSHAN_MOD_MEM_MAX * 1024 * 1024)
#else
#define DXT_IO_TRACE_MEM_MAX (4 * 1024 * 1024) /* 4 MiB default */
#endif
45

46
47
48
/* initial size of read/write trace buffer (in number of segments) */
/* NOTE: when this size is exceeded, the buffer size is doubled */
#define IO_TRACE_BUF_SIZE       64
49

50
51
52
53
54
55
56
57
58
59
60
61
/* XXX: dirty hack -- If DXT runs out of memory to store trace data in,
 * we should set a flag so that log parsers know that the log has
 * incomplete data. This functionality is typically handled automatically
 * when registering records with Darshan, but DXT modules don't
 * register records and manage their own memory. Since DXT modules request
 * 0 memory when registering themselves, any attempt to register a record
 * will result in setting the partial flag for the module, which is
 * exactly what we do here.
 */
#define SET_DXT_MOD_PARTIAL_FLAG(mod_id) \
    darshan_core_register_record(0, NULL, mod_id, 1, NULL);

62
63
64
/* 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
65
66
67
 * assists with the instrumenting of specific statistics in the file record.
 *
 * NOTE: we use the 'darshan_record_ref' interface (in darshan-common) to
68
 * associate different types of handles with this dxt_file_record_ref struct.
69
70
71
 * 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
72
 * only be a single Darshan record identifier that indexes a dxt_file_record_ref,
73
74
 * there could be multiple open file descriptors that index it.
 */
75
struct dxt_file_record_ref
76
{
77
    struct dxt_file_record *file_rec;
78

79
80
    int64_t write_available_buf;
    int64_t read_available_buf;
81
82
83

    segment_info *write_traces;
    segment_info *read_traces;
84
85

    char trace_enabled;
86
87
};

88
89
/* The dxt_runtime structure maintains necessary state for storing
 * DXT file records and for coordinating with darshan-core at
90
91
 * shutdown time.
 */
92
struct dxt_posix_runtime
93
94
95
{
    void *rec_id_hash;
    int file_rec_count;
Shane Snyder's avatar
Shane Snyder committed
96
97
    char *record_buf;
    int record_buf_size;
98
99
};

100
struct dxt_mpiio_runtime
101
102
103
{
    void *rec_id_hash;
    int file_rec_count;
Shane Snyder's avatar
Shane Snyder committed
104
105
    char *record_buf;
    int record_buf_size;
106
107
};

Shane Snyder's avatar
Shane Snyder committed
108
109
110
111
112
113
114
enum dxt_trigger_type
{
    DXT_FILE_TRIGGER,
    DXT_RANK_TRIGGER,
    DXT_SMALL_IO_TRIGGER,
    DXT_UNALIGNED_IO_TRIGGER
};
115

Shane Snyder's avatar
Shane Snyder committed
116
117
118
119
struct dxt_trigger_info
{
    int type;
    union {
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
        struct
        {
            regex_t regex;
        } file;
        struct
        {
            regex_t regex;
        } rank;
        struct
        {
            double thresh_pct;
        } small_io;
        struct
        {
            double thresh_pct;
        } unaligned_io;
Shane Snyder's avatar
Shane Snyder committed
136
137
138
139
140
141
142
143
    } u;
};

/* internal helper routines */
static int dxt_should_trace_rank(
    int rank);
static int dxt_should_trace_file(
    darshan_record_id rec_id);
144
145
146
147
148
149
static void check_wr_trace_buf(
    struct dxt_file_record_ref *rec_ref);
static void check_rd_trace_buf(
    struct dxt_file_record_ref *rec_ref);
static struct dxt_file_record_ref *dxt_posix_track_new_file_record(
    darshan_record_id rec_id);
150
151
static struct dxt_file_record_ref *dxt_mpiio_track_new_file_record(
    darshan_record_id rec_id);
152
static void dxt_posix_cleanup_runtime(
153
    void);
154
static void dxt_mpiio_cleanup_runtime(
155
156
    void);

Shane Snyder's avatar
Shane Snyder committed
157
/* DXT shutdown routines for darshan-core */
158
static void dxt_posix_shutdown(
159
    void **dxt_buf, int *dxt_buf_sz);
160
static void dxt_mpiio_shutdown(
161
    void **dxt_buf, int *dxt_buf_sz);
162

163
164
static struct dxt_posix_runtime *dxt_posix_runtime = NULL;
static struct dxt_mpiio_runtime *dxt_mpiio_runtime = NULL;
165
static pthread_mutex_t dxt_runtime_mutex =
166
167
            PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;

168
static int dxt_my_rank = -1;
169
170
static int dxt_total_mem = DXT_IO_TRACE_MEM_MAX;
static int dxt_mem_remaining = 0;
171

Shane Snyder's avatar
Shane Snyder committed
172
173
174
175
176
177
178
179
#define MAX_DXT_TRIGGERS 20
static int num_dxt_triggers = 0;
static struct dxt_trigger_info dxt_triggers[MAX_DXT_TRIGGERS];
static int dxt_use_file_triggers = 0;
static int dxt_use_rank_triggers = 0;
static int dxt_use_dynamic_triggers = 0;
static int dxt_trace_all = 0;

180
181
#define DXT_LOCK() pthread_mutex_lock(&dxt_runtime_mutex)
#define DXT_UNLOCK() pthread_mutex_unlock(&dxt_runtime_mutex)
182

Shane Snyder's avatar
Shane Snyder committed
183
184
185
/************************************************************
 *  DXT routines exposed to Darshan core and other modules  *
 ************************************************************/
186

Shane Snyder's avatar
Shane Snyder committed
187
188
void dxt_load_trigger_conf(
    char *trigger_conf_path)
189
{
Shane Snyder's avatar
Shane Snyder committed
190
191
192
193
194
195
    FILE *fp;
    char *line = NULL;
    size_t len = 0;
    char *tok;
    struct dxt_trigger_info *next_trigger;
    int ret;
196

Shane Snyder's avatar
Shane Snyder committed
197
198
199
200
201
202
203
    fp = fopen(trigger_conf_path, "r");
    if(!fp)
    {
        darshan_core_fprintf(stderr, "darshan library warning: "\
            "unable to open DXT trigger config at path %s\n", trigger_conf_path);
        return;
    }
204

Shane Snyder's avatar
Shane Snyder committed
205
206
207
208
209
    while(getline(&line, &len, fp) != -1)
    {
        /* remove newline if present */
        if(line[strlen(line) - 1] == '\n')
            line[strlen(line) - 1] = '\0';
210

Shane Snyder's avatar
Shane Snyder committed
211
        next_trigger = &dxt_triggers[num_dxt_triggers];
212

Shane Snyder's avatar
Shane Snyder committed
213
214
215
        /* extract trigger type and parameters */
        tok = strtok(line, " \t");
        if(strcmp(tok, "FILE") == 0)
216
        {
Shane Snyder's avatar
Shane Snyder committed
217
218
            next_trigger->type = DXT_FILE_TRIGGER;
            tok += strlen(tok) + 1;
219
            ret = regcomp(&next_trigger->u.file.regex, tok, REG_EXTENDED);
Shane Snyder's avatar
Shane Snyder committed
220
221
222
223
224
225
226
227
228
229
230
231
            if(ret)
            {
                darshan_core_fprintf(stderr, "darshan library warning: "\
                    "unable to compile DXT trigger regex from %s\n", line);
                continue;
            }
            dxt_use_file_triggers = 1;
        }
        else if(strcmp(tok, "RANK") == 0)
        {
            next_trigger->type = DXT_RANK_TRIGGER;
            tok += strlen(tok) + 1;
232
            ret = regcomp(&next_trigger->u.rank.regex, tok, REG_EXTENDED);
Shane Snyder's avatar
Shane Snyder committed
233
234
235
236
237
238
239
240
241
242
243
244
            if(ret)
            {
                darshan_core_fprintf(stderr, "darshan library warning: "\
                    "unable to compile DXT trigger regex from %s\n", line);
                continue;
            }
            dxt_use_rank_triggers= 1;
        }
        else if(strcmp(tok, "SMALL_IO") == 0)
        {
            next_trigger->type = DXT_SMALL_IO_TRIGGER;
            tok += strlen(tok) + 1;
245
            next_trigger->u.small_io.thresh_pct = atof(tok);
Shane Snyder's avatar
Shane Snyder committed
246
247
248
249
250
251
            dxt_use_dynamic_triggers= 1;
        }
        else if(strcmp(tok, "UNALIGNED_IO") == 0)
        {
            next_trigger->type = DXT_UNALIGNED_IO_TRIGGER;
            tok += strlen(tok) + 1;
252
            next_trigger->u.unaligned_io.thresh_pct = atof(tok);
Shane Snyder's avatar
Shane Snyder committed
253
            dxt_use_dynamic_triggers= 1;
254
        }
Shane Snyder's avatar
Shane Snyder committed
255
256
257
258
259
260
261
        else
        {
            darshan_core_fprintf(stderr, "darshan library warning: "\
                "unknown DXT trigger (%s) found in %s\n", tok, trigger_conf_path);
            continue;
        }
        ++num_dxt_triggers;
262
    }
Shane Snyder's avatar
Shane Snyder committed
263
264
265
266

    fclose(fp);
    free(line);
    return;
267
268
}

269
/* initialize internal DXT module data structures and register with darshan-core */
Shane Snyder's avatar
Shane Snyder committed
270
void dxt_posix_runtime_initialize()
271
{
Shane Snyder's avatar
Shane Snyder committed
272
273
274
275
276
    /* DXT modules request 0 memory -- buffers will be managed internally by DXT
     * and passed back to darshan-core at shutdown time to allow DXT more control
     * over realloc'ing module memory as needed.
     */
    int dxt_psx_buf_size = 0;
277
278
279
280
281
282
    darshan_module_funcs mod_funcs = {
#ifdef HAVE_MPI
    .mod_redux_func = NULL,
#endif
    .mod_shutdown_func = &dxt_posix_shutdown
    };
283

Shane Snyder's avatar
Shane Snyder committed
284
285
286
287
288
    /* determine whether tracing should be generally disabled/enabled */
    if(getenv("DXT_ENABLE_IO_TRACE"))
        dxt_trace_all = 1;
    else if(getenv("DXT_DISABLE_IO_TRACE"))
        return;
289

Shane Snyder's avatar
Shane Snyder committed
290
291
292
    /* register the DXT module with darshan core */
    darshan_core_register_module(
        DXT_POSIX_MOD,
293
        mod_funcs,
Shane Snyder's avatar
Shane Snyder committed
294
295
296
        &dxt_psx_buf_size,
        &dxt_my_rank,
        NULL);
297

Shane Snyder's avatar
Shane Snyder committed
298
299
300
301
302
303
    /* return if darshan-core allocates an unexpected amount of memory */
    if(dxt_psx_buf_size != 0)
    {
        darshan_core_unregister_module(DXT_POSIX_MOD);
        return;
    }
304

Shane Snyder's avatar
Shane Snyder committed
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
    /* determine whether we should avoid tracing on this rank */
    if(!dxt_should_trace_rank(dxt_my_rank))
    {
        if(!dxt_trace_all && !dxt_use_file_triggers && !dxt_use_dynamic_triggers)
        {
            /* nothing to trace, just back out */
            darshan_core_unregister_module(DXT_POSIX_MOD);
            return;
        }
    }
    else
    {
        dxt_trace_all = 1; /* trace everything */
    }

    DXT_LOCK();
    dxt_posix_runtime = malloc(sizeof(*dxt_posix_runtime));
    if(!dxt_posix_runtime)
    {
        darshan_core_unregister_module(DXT_POSIX_MOD);
325
        DXT_UNLOCK();
Shane Snyder's avatar
Shane Snyder committed
326
327
328
329
330
        return;
    }
    memset(dxt_posix_runtime, 0, sizeof(*dxt_posix_runtime));
    dxt_mem_remaining = dxt_total_mem;
    DXT_UNLOCK();
331

Shane Snyder's avatar
Shane Snyder committed
332
333
334
335
336
337
338
339
340
341
    return;
}

void dxt_mpiio_runtime_initialize()
{
    /* DXT modules request 0 memory -- buffers will be managed internally by DXT
     * and passed back to darshan-core at shutdown time to allow DXT more control
     * over realloc'ing module memory as needed.
     */
    int dxt_mpiio_buf_size = 0;
342
343
344
345
346
347
    darshan_module_funcs mod_funcs = {
#ifdef HAVE_MPI
    .mod_redux_func = NULL,
#endif
    .mod_shutdown_func = &dxt_mpiio_shutdown
    };
Shane Snyder's avatar
Shane Snyder committed
348
349
350
351
352
353
354
355
356
357

    /* determine whether tracing should be generally disabled/enabled */
    if(getenv("DXT_ENABLE_IO_TRACE"))
        dxt_trace_all = 1;
    else if(getenv("DXT_DISABLE_IO_TRACE"))
        return;

    /* register the DXT module with darshan core */
    darshan_core_register_module(
        DXT_MPIIO_MOD,
358
        mod_funcs,
Shane Snyder's avatar
Shane Snyder committed
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
        &dxt_mpiio_buf_size,
        &dxt_my_rank,
        NULL);

    /* return if darshan-core allocates an unexpected amount of memory */
    if(dxt_mpiio_buf_size != 0)
    {
        darshan_core_unregister_module(DXT_MPIIO_MOD);
        return;
    }

    /* determine whether we should avoid tracing on this rank */
    if(!dxt_should_trace_rank(dxt_my_rank))
    {
        if(!dxt_trace_all && !dxt_use_file_triggers && !dxt_use_dynamic_triggers)
374
        {
Shane Snyder's avatar
Shane Snyder committed
375
376
377
            /* nothing to trace, just back out */
            darshan_core_unregister_module(DXT_MPIIO_MOD);
            return;
378
        }
379
    }
Shane Snyder's avatar
Shane Snyder committed
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
    else
    {
        dxt_trace_all = 1; /* trace everything */
    }

    DXT_LOCK();
    dxt_mpiio_runtime = malloc(sizeof(*dxt_mpiio_runtime));
    if(!dxt_mpiio_runtime)
    {
        darshan_core_unregister_module(DXT_MPIIO_MOD);
        DXT_UNLOCK();
        return;
    }
    memset(dxt_mpiio_runtime, 0, sizeof(*dxt_mpiio_runtime));
    dxt_mem_remaining = dxt_total_mem; /* XXX is this right? better with memory */
    DXT_UNLOCK();

    return;
398
399
}

400
401
void dxt_posix_write(darshan_record_id rec_id, int64_t offset,
        int64_t length, double start_time, double end_time)
402
{
403
404
    struct dxt_file_record_ref* rec_ref = NULL;
    struct dxt_file_record *file_rec;
405
    int should_trace_file;
406

407
408
    DXT_LOCK();

409
    if(!dxt_posix_runtime)
410
411
    {
        DXT_UNLOCK();
Shane Snyder's avatar
Shane Snyder committed
412
        return;
413
    }
414

415
416
417
418
    rec_ref = darshan_lookup_record_ref(dxt_posix_runtime->rec_id_hash,
        &rec_id, sizeof(darshan_record_id));
    if(!rec_ref)
    {
419
420
421
422
423
424
425
426
        /* check whether we should actually trace */
        should_trace_file = dxt_should_trace_file(rec_id);
        if(!should_trace_file && !dxt_trace_all && !dxt_use_dynamic_triggers)
        {
            DXT_UNLOCK();
            return;
        }

427
428
        /* track new dxt file record */
        rec_ref = dxt_posix_track_new_file_record(rec_id);
429
430
431
432
433
        if(!rec_ref)
        {
            DXT_UNLOCK();
            return;
        }
434
435
        if(should_trace_file)
            rec_ref->trace_enabled = 1;
436
437
    }

438
439
440
    file_rec = rec_ref->file_rec;
    check_wr_trace_buf(rec_ref);
    if(file_rec->write_count == rec_ref->write_available_buf)
441
442
443
    {
        /* no more memory for i/o segments ... back out */
        SET_DXT_MOD_PARTIAL_FLAG(DXT_POSIX_MOD);
444
        DXT_UNLOCK();
445
446
        return;
    }
447

448
449
450
451
    rec_ref->write_traces[file_rec->write_count].offset = offset;
    rec_ref->write_traces[file_rec->write_count].length = length;
    rec_ref->write_traces[file_rec->write_count].start_time = start_time;
    rec_ref->write_traces[file_rec->write_count].end_time = end_time;
452
    file_rec->write_count += 1;
453
454

    DXT_UNLOCK();
455
456
}

457
458
void dxt_posix_read(darshan_record_id rec_id, int64_t offset,
        int64_t length, double start_time, double end_time)
459
{
460
461
    struct dxt_file_record_ref* rec_ref = NULL;
    struct dxt_file_record *file_rec;
462
    int should_trace_file;
463

464
465
    DXT_LOCK();

466
    if(!dxt_posix_runtime)
467
468
    {
        DXT_UNLOCK();
Shane Snyder's avatar
Shane Snyder committed
469
        return;
470
    }
471
472
473

    rec_ref = darshan_lookup_record_ref(dxt_posix_runtime->rec_id_hash,
                &rec_id, sizeof(darshan_record_id));
474
475
476
477
478
479
480
481
482
483
    if (!rec_ref)
    {
        /* check whether we should actually trace */
        should_trace_file = dxt_should_trace_file(rec_id);
        if(!should_trace_file && !dxt_trace_all && !dxt_use_dynamic_triggers)
        {
            DXT_UNLOCK();
            return;
        }

484
485
        /* track new dxt file record */
        rec_ref = dxt_posix_track_new_file_record(rec_id);
486
487
488
489
490
        if(!rec_ref)
        {
            DXT_UNLOCK();
            return;
        }
491
492
        if(should_trace_file)
            rec_ref->trace_enabled = 1;
493
494
495
    }

    file_rec = rec_ref->file_rec;
496
497
    check_rd_trace_buf(rec_ref);
    if(file_rec->read_count == rec_ref->read_available_buf)
498
499
500
    {
        /* no more memory for i/o segments ... back out */
        SET_DXT_MOD_PARTIAL_FLAG(DXT_POSIX_MOD);
501
        DXT_UNLOCK();
502
503
        return;
    }
504

505
506
507
508
    rec_ref->read_traces[file_rec->read_count].offset = offset;
    rec_ref->read_traces[file_rec->read_count].length = length;
    rec_ref->read_traces[file_rec->read_count].start_time = start_time;
    rec_ref->read_traces[file_rec->read_count].end_time = end_time;
509
    file_rec->read_count += 1;
510
511

    DXT_UNLOCK();
512
513
}

514
515
void dxt_mpiio_write(darshan_record_id rec_id, int64_t offset,
        int64_t length, double start_time, double end_time)
516
{
517
518
    struct dxt_file_record_ref* rec_ref = NULL;
    struct dxt_file_record *file_rec;
519
    int should_trace_file;
520

521
522
    DXT_LOCK();

523
    if(!dxt_mpiio_runtime)
524
525
    {
        DXT_UNLOCK();
Shane Snyder's avatar
Shane Snyder committed
526
        return;
527
    }
528

529
530
531
532
    rec_ref = darshan_lookup_record_ref(dxt_mpiio_runtime->rec_id_hash,
                &rec_id, sizeof(darshan_record_id));
    if(!rec_ref)
    {
533
534
535
536
537
538
539
540
        /* check whether we should actually trace */
        should_trace_file = dxt_should_trace_file(rec_id);
        if(!should_trace_file && !dxt_trace_all && !dxt_use_dynamic_triggers)
        {
            DXT_UNLOCK();
            return;
        }

541
542
        /* track new dxt file record */
        rec_ref = dxt_mpiio_track_new_file_record(rec_id);
543
544
545
546
547
        if(!rec_ref)
        {
            DXT_UNLOCK();
            return;
        }
548
549
        if(should_trace_file)
            rec_ref->trace_enabled = 1;
550
551
    }

552
553
554
    file_rec = rec_ref->file_rec;
    check_wr_trace_buf(rec_ref);
    if(file_rec->write_count == rec_ref->write_available_buf)
555
556
557
    {
        /* no more memory for i/o segments ... back out */
        SET_DXT_MOD_PARTIAL_FLAG(DXT_MPIIO_MOD);
558
        DXT_UNLOCK();
559
560
        return;
    }
561

562
    rec_ref->write_traces[file_rec->write_count].length = length;
563
    rec_ref->write_traces[file_rec->write_count].offset = offset;
564
565
    rec_ref->write_traces[file_rec->write_count].start_time = start_time;
    rec_ref->write_traces[file_rec->write_count].end_time = end_time;
566
    file_rec->write_count += 1;
567
568

    DXT_UNLOCK();
569
570
}

571
572
void dxt_mpiio_read(darshan_record_id rec_id, int64_t offset,
        int64_t length, double start_time, double end_time)
573
{
574
575
    struct dxt_file_record_ref* rec_ref = NULL;
    struct dxt_file_record *file_rec;
576
    int should_trace_file;
577

578
579
    DXT_LOCK();

580
    if(!dxt_mpiio_runtime)
581
582
    {
        DXT_UNLOCK();
Shane Snyder's avatar
Shane Snyder committed
583
        return;
584
    }
585

586
587
588
589
    rec_ref = darshan_lookup_record_ref(dxt_mpiio_runtime->rec_id_hash,
                &rec_id, sizeof(darshan_record_id));
    if(!rec_ref)
    {
590
591
592
593
594
595
596
597
        /* check whether we should actually trace */
        should_trace_file = dxt_should_trace_file(rec_id);
        if(!should_trace_file && !dxt_trace_all && !dxt_use_dynamic_triggers)
        {
            DXT_UNLOCK();
            return;
        }

598
599
        /* track new dxt file record */
        rec_ref = dxt_mpiio_track_new_file_record(rec_id);
600
601
602
603
604
        if(!rec_ref)
        {
            DXT_UNLOCK();
            return;
        }
605
606
        if(should_trace_file)
            rec_ref->trace_enabled = 1;
607
608
    }

609
610
611
    file_rec = rec_ref->file_rec;
    check_rd_trace_buf(rec_ref);
    if(file_rec->read_count == rec_ref->read_available_buf)
612
613
614
    {
        /* no more memory for i/o segments ... back out */
        SET_DXT_MOD_PARTIAL_FLAG(DXT_MPIIO_MOD);
615
        DXT_UNLOCK();
616
617
        return;
    }
618

619
    rec_ref->read_traces[file_rec->read_count].length = length;
620
    rec_ref->read_traces[file_rec->read_count].offset = offset;
621
622
    rec_ref->read_traces[file_rec->read_count].start_time = start_time;
    rec_ref->read_traces[file_rec->read_count].end_time = end_time;
623
    file_rec->read_count += 1;
624
625
626
627
628
629

    DXT_UNLOCK();
}

static void dxt_posix_filter_dynamic_traces_iterator(void *rec_ref_p, void *user_ptr)
{
630
    struct dxt_file_record_ref *psx_rec_ref, *mpiio_rec_ref;
631
632
    struct darshan_posix_file *(*rec_id_to_psx_file)(darshan_record_id);
    struct darshan_posix_file *psx_file;
633
634
635
636
637
638
    int i;
    int should_keep = 0;

    psx_rec_ref = (struct dxt_file_record_ref *)rec_ref_p;
    if(psx_rec_ref->trace_enabled)
        return; /* we're already tracing this file */
639
640

    rec_id_to_psx_file = (struct darshan_posix_file *(*)(darshan_record_id))user_ptr;
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
    psx_file = rec_id_to_psx_file(psx_rec_ref->file_rec->base_rec.id);

    /* analyze dynamic triggers to determine whether we should keep the record */
    for(i = 0; i < num_dxt_triggers; i++)
    {
        switch(dxt_triggers[i].type)
        {
            case DXT_SMALL_IO_TRIGGER:
            {
                int total_ops = psx_file->counters[POSIX_WRITES] +
                    psx_file->counters[POSIX_READS];
                int small_ops = psx_file->counters[POSIX_SIZE_WRITE_0_100] +
                    psx_file->counters[POSIX_SIZE_WRITE_100_1K] + 
                    psx_file->counters[POSIX_SIZE_WRITE_1K_10K] +
                    psx_file->counters[POSIX_SIZE_READ_0_100] +
                    psx_file->counters[POSIX_SIZE_READ_100_1K] + 
                    psx_file->counters[POSIX_SIZE_READ_1K_10K];
                double small_pct = (small_ops / (double)(total_ops));
                if(small_pct > dxt_triggers[i].u.small_io.thresh_pct)
                    should_keep = 1;
                break;
            }
            case DXT_UNALIGNED_IO_TRIGGER:
            {
                int total_ops = psx_file->counters[POSIX_WRITES] +
                    psx_file->counters[POSIX_READS];
                int unaligned_ops = psx_file->counters[POSIX_FILE_NOT_ALIGNED];
                double unaligned_pct = (unaligned_ops / (double)(total_ops));
                if(unaligned_pct > dxt_triggers[i].u.unaligned_io.thresh_pct)
                    should_keep = 1;
                break;
            }
            default:
                continue;
        }
        if(should_keep)
            break;
    }

    /* drop the record if no dynamic trace triggers occurred */
    if(!should_keep)
    {
683
        if(dxt_mpiio_runtime && dxt_mpiio_runtime->rec_id_hash)
684
        {
685
686
687
688
689
690
691
692
693
694
            /* first check the MPI-IO traces to see if we should drop there */
            mpiio_rec_ref = darshan_delete_record_ref(&dxt_mpiio_runtime->rec_id_hash,
                &psx_file->base_rec.id, sizeof(darshan_record_id));
            if(mpiio_rec_ref)
            {
                free(mpiio_rec_ref->write_traces);
                free(mpiio_rec_ref->read_traces);
                free(mpiio_rec_ref->file_rec);
                free(mpiio_rec_ref);
            }
695
696
        }

697
        if(dxt_posix_runtime && dxt_posix_runtime->rec_id_hash)
698
        {
699
700
701
702
703
704
705
706
707
708
            /* then delete the POSIX trace records */
            psx_rec_ref = darshan_delete_record_ref(&dxt_posix_runtime->rec_id_hash,
                &psx_file->base_rec.id, sizeof(darshan_record_id));
            if(psx_rec_ref)
            {
                free(psx_rec_ref->write_traces);
                free(psx_rec_ref->read_traces);
                free(psx_rec_ref->file_rec);
                free(psx_rec_ref);
            }
709
710
        }
    }
711
712
713
714
715
716
717

    return;
}

void dxt_posix_filter_dynamic_traces(
    struct darshan_posix_file *(*rec_id_to_psx_file)(darshan_record_id))
{
718
719
720
721
722
723
724
    DXT_LOCK();

    if(!dxt_posix_runtime || !dxt_use_dynamic_triggers || dxt_trace_all)
    {
        DXT_UNLOCK();
        return;
    }
725
726
727
728
729
730
731

    darshan_iter_record_refs(dxt_posix_runtime->rec_id_hash,
        dxt_posix_filter_dynamic_traces_iterator, rec_id_to_psx_file);

    DXT_UNLOCK();

    return;
732
733
}

Shane Snyder's avatar
Shane Snyder committed
734
735
736
/***********************************
 *  internal DXT helper routines   *
 ***********************************/
737

Shane Snyder's avatar
Shane Snyder committed
738
static int dxt_should_trace_rank(int my_rank)
739
{
Shane Snyder's avatar
Shane Snyder committed
740
741
    int i;
    char rank_str[16] = {0};
742

Shane Snyder's avatar
Shane Snyder committed
743
    sprintf(rank_str, "%d", my_rank);
744

Shane Snyder's avatar
Shane Snyder committed
745
746
    if(!dxt_use_rank_triggers)
        return(0);
747

Shane Snyder's avatar
Shane Snyder committed
748
    for(i = 0; i < num_dxt_triggers; i++)
749
    {
Shane Snyder's avatar
Shane Snyder committed
750
        if((dxt_triggers[i].type == DXT_RANK_TRIGGER) &&
751
           (regexec(&dxt_triggers[i].u.rank.regex, rank_str, 0, NULL, 0) == 0))
Shane Snyder's avatar
Shane Snyder committed
752
            return(1);
753
754
    }

Shane Snyder's avatar
Shane Snyder committed
755
756
757
758
759
760
761
762
763
764
765
766
767
    return(0);
}

static int dxt_should_trace_file(darshan_record_id rec_id)
{
    char *rec_name;
    int i;

    if(!dxt_use_file_triggers)
        return(0);

    rec_name  = darshan_core_lookup_record_name(rec_id);
    if(rec_name)
768
    {
Shane Snyder's avatar
Shane Snyder committed
769
770
        /* compare file name against cached triggers to see if we should trace */
        for(i = 0; i < num_dxt_triggers; i++)
771
        {
Shane Snyder's avatar
Shane Snyder committed
772
            if((dxt_triggers[i].type == DXT_FILE_TRIGGER) &&
773
               (regexec(&dxt_triggers[i].u.file.regex, rec_name, 0, NULL, 0) == 0))
Shane Snyder's avatar
Shane Snyder committed
774
                return(1);
775
776
777
        }
    }

Shane Snyder's avatar
Shane Snyder committed
778
    return(0);
779
780
}

Shane Snyder's avatar
Shane Snyder committed
781
static void check_wr_trace_buf(struct dxt_file_record_ref *rec_ref)
782
{
Shane Snyder's avatar
Shane Snyder committed
783
    struct dxt_file_record *file_rec = rec_ref->file_rec;
784

Shane Snyder's avatar
Shane Snyder committed
785
786
    int write_count = file_rec->write_count;
    int write_available_buf = rec_ref->write_available_buf;
787

Shane Snyder's avatar
Shane Snyder committed
788
789
790
791
792
793
    if (write_count >= write_available_buf) {
        int write_count_inc;
        if(write_available_buf == 0)
            write_count_inc = IO_TRACE_BUF_SIZE;
        else
            write_count_inc = write_available_buf;
794

Shane Snyder's avatar
Shane Snyder committed
795
796
797
798
799
        DXT_LOCK();
        if((write_count_inc * sizeof(segment_info)) > dxt_mem_remaining)
            write_count_inc = dxt_mem_remaining / sizeof(segment_info);

        dxt_mem_remaining -= (write_count_inc * sizeof(segment_info));
800
        DXT_UNLOCK();
801

Shane Snyder's avatar
Shane Snyder committed
802
        if(write_count_inc > 0)
803
        {
Shane Snyder's avatar
Shane Snyder committed
804
805
806
807
808
809
            write_available_buf += write_count_inc;
            rec_ref->write_traces =
                (segment_info *)realloc(rec_ref->write_traces,
                        write_available_buf * sizeof(segment_info));

            rec_ref->write_available_buf = write_available_buf;
810
811
        }
    }
Shane Snyder's avatar
Shane Snyder committed
812
}
813

Shane Snyder's avatar
Shane Snyder committed
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
static void check_rd_trace_buf(struct dxt_file_record_ref *rec_ref)
{
    struct dxt_file_record *file_rec = rec_ref->file_rec;

    int read_count = file_rec->read_count;
    int read_available_buf = rec_ref->read_available_buf;

    if (read_count >= read_available_buf) {
        int read_count_inc;
        if(read_available_buf == 0)
            read_count_inc = IO_TRACE_BUF_SIZE;
        else
            read_count_inc = read_available_buf;

        DXT_LOCK();
        if((read_count_inc * sizeof(segment_info)) > dxt_mem_remaining)
            read_count_inc = dxt_mem_remaining / sizeof(segment_info);

        dxt_mem_remaining -= (read_count_inc * sizeof(segment_info));
        DXT_UNLOCK();

        if(read_count_inc > 0)
        {
            read_available_buf += read_count_inc;
            rec_ref->read_traces =
                (segment_info *)realloc(rec_ref->read_traces,
                        read_available_buf * sizeof(segment_info));
            
            rec_ref->read_available_buf = read_available_buf;
        }
    }
845
846
}

847
848
static struct dxt_file_record_ref *dxt_posix_track_new_file_record(
    darshan_record_id rec_id)
849
{
850
851
    struct dxt_file_record_ref *rec_ref = NULL;
    struct dxt_file_record *file_rec = NULL;
852
853
    int ret;

854
855
856
857
    /* check if we have enough room for a new DXT record */
    DXT_LOCK();
    if(dxt_mem_remaining < sizeof(struct dxt_file_record))
    {
858
        SET_DXT_MOD_PARTIAL_FLAG(DXT_POSIX_MOD);
859
860
861
862
        DXT_UNLOCK();
        return(NULL);
    }

863
864
    rec_ref = malloc(sizeof(*rec_ref));
    if(!rec_ref)
865
866
867
868
    {
        DXT_UNLOCK();
        return(NULL);
    }
869
870
    memset(rec_ref, 0, sizeof(*rec_ref));

871
872
873
874
875
876
877
878
879
    file_rec = malloc(sizeof(*file_rec));
    if(!file_rec)
    {
        free(rec_ref);
        DXT_UNLOCK();
        return(NULL);
    }
    memset(file_rec, 0, sizeof(*file_rec));

880
    /* add a reference to this file record based on record id */
881
    ret = darshan_add_record_ref(&(dxt_posix_runtime->rec_id_hash), &rec_id,
882
883
884
            sizeof(darshan_record_id), rec_ref);
    if(ret == 0)
    {
885
        free(file_rec);
886
        free(rec_ref);
887
888
        DXT_UNLOCK();
        return(NULL);
889
890
    }

891
892
    dxt_mem_remaining -= sizeof(struct dxt_file_record);
    DXT_UNLOCK();
893

894
    /* initialize record and record reference fields */
895
    file_rec->base_rec.id = rec_id;
896
    file_rec->base_rec.rank = dxt_my_rank;
Cong Xu's avatar
Cong Xu committed
897
    gethostname(file_rec->hostname, HOSTNAME_SIZE);
898
899

    rec_ref->file_rec = file_rec;
900
    dxt_posix_runtime->file_rec_count++;
901
902

    return(rec_ref);
903
904
}

905
906
static struct dxt_file_record_ref *dxt_mpiio_track_new_file_record(
    darshan_record_id rec_id)
907
{
908
909
    struct dxt_file_record *file_rec = NULL;
    struct dxt_file_record_ref *rec_ref = NULL;
910
911
    int ret;

912
913
914
915
    /* check if we have enough room for a new DXT record */
    DXT_LOCK();
    if(dxt_mem_remaining < sizeof(struct dxt_file_record))
    {
916
        SET_DXT_MOD_PARTIAL_FLAG(DXT_MPIIO_MOD);
917
918
919
920
        DXT_UNLOCK();
        return(NULL);
    }

921
922
    rec_ref = malloc(sizeof(*rec_ref));
    if(!rec_ref)
Shane Snyder's avatar
Shane Snyder committed
923

924
925
926
927
    {
        DXT_UNLOCK();
        return(NULL);
    }
928
929
    memset(rec_ref, 0, sizeof(*rec_ref));

930
931
932
933
934
935
936
937
938
    file_rec = malloc(sizeof(*file_rec));
    if(!file_rec)
    {
        free(rec_ref);
        DXT_UNLOCK();
        return(NULL);
    }
    memset(file_rec, 0, sizeof(*file_rec));

939
    /* add a reference to this file record based on record id */
940
    ret = darshan_add_record_ref(&(dxt_mpiio_runtime->rec_id_hash), &rec_id,
941
942
943
            sizeof(darshan_record_id), rec_ref);
    if(ret == 0)
    {
944
        free(file_rec);
945
        free(rec_ref);
946
        DXT_UNLOCK();
Shane Snyder's avatar
Shane Snyder committed
947
        return(NULL);
948
949
    }

950
951
    dxt_mem_remaining -= sizeof(struct dxt_file_record);
    DXT_UNLOCK();
952

953
    /* initialize record and record reference fields */
954
    file_rec->base_rec.id = rec_id;
955
    file_rec->base_rec.rank = dxt_my_rank;
Cong Xu's avatar
Cong Xu committed
956
    gethostname(file_rec->hostname, HOSTNAME_SIZE);
957
958

    rec_ref->file_rec = file_rec;
959
    dxt_mpiio_runtime->file_rec_count++;
960

961
    return(rec_ref);
962
963
}

964
static void dxt_free_record_data(void *rec_ref_p, void *user_ptr)
965
{
966
    struct dxt_file_record_ref *dxt_rec_ref = (struct dxt_file_record_ref *)rec_ref_p;
967

968
969
    free(dxt_rec_ref->write_traces);
    free(dxt_rec_ref->read_traces);
Shane Snyder's avatar
Shane Snyder committed
970
    free(dxt_rec_ref->file_rec);
971
972
}

973
static void dxt_posix_cleanup_runtime()
974
{
975
976
    darshan_iter_record_refs(dxt_posix_runtime->rec_id_hash,
        dxt_free_record_data, NULL);
977
    darshan_clear_record_refs(&(dxt_posix_runtime->rec_id_hash), 1);
978

979
980
    free(dxt_posix_runtime);
    dxt_posix_runtime = NULL;
981
982
983
984

    return;
}

985
static void dxt_mpiio_cleanup_runtime()
986
{
987
988
    darshan_iter_record_refs(dxt_mpiio_runtime->rec_id_hash,
        dxt_free_record_data, NULL);
989
    darshan_clear_record_refs(&(dxt_mpiio_runtime->rec_id_hash), 1);
990

991
992
    free(dxt_mpiio_runtime);
    dxt_mpiio_runtime = NULL;
993
994
995
996
997
998
999
1000

    return;
}

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

1001
static void dxt_serialize_posix_records(void *rec_ref_p, void *user_ptr)
1002
{
Shane Snyder's avatar
Shane Snyder committed
1003
    struct dxt_file_record_ref *rec_ref = (struct dxt_file_record_ref *)rec_ref_p;
1004
    struct dxt_file_record *file_rec;
1005
1006
1007
    int64_t record_size = 0;
    int64_t record_write_count = 0;
    int64_t record_read_count = 0;
Shane Snyder's avatar
Shane Snyder committed
1008
    void *tmp_buf_ptr;
1009

Shane Snyder's avatar
Shane Snyder committed
1010
1011
1012
    assert(rec_ref);
    file_rec = rec_ref->file_rec;
    assert(file_rec);
1013

Shane Snyder's avatar
Shane Snyder committed
1014
1015
1016
1017
    record_write_count = file_rec->write_count;
    record_read_count = file_rec->read_count;
    if (record_write_count == 0 && record_read_count == 0)
        return;
1018

Shane Snyder's avatar
Shane Snyder committed
1019
1020
    /*
     * Buffer format:
1021
     * dxt_file_record + write_traces + read_traces
Shane Snyder's avatar
Shane Snyder committed
1022
1023
1024
     */
    record_size = sizeof(struct dxt_file_record) +
            (record_write_count + record_read_count) * sizeof(segment_info);
1025

Shane Snyder's avatar
Shane Snyder committed
1026
1027
    tmp_buf_ptr = (void *)(dxt_posix_runtime->record_buf +
        dxt_posix_runtime->record_buf_size);
1028

Shane Snyder's avatar
Shane Snyder committed
1029
1030
1031
    /*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));
1032

Shane Snyder's avatar
Shane Snyder committed
1033
    /*Copy write record */
1034
    memcpy(tmp_buf_ptr, (void *)(rec_ref->write_traces),
Shane Snyder's avatar
Shane Snyder committed
1035
1036
1037
            record_write_count * sizeof(segment_info));
    tmp_buf_ptr = (void *)(tmp_buf_ptr +
                record_write_count * sizeof(segment_info));
1038

Shane Snyder's avatar
Shane Snyder committed
1039
    /*Copy read record */
1040
    memcpy(tmp_buf_ptr, (void *)(rec_ref->read_traces),
Shane Snyder's avatar
Shane Snyder committed
1041
1042
1043
            record_read_count * sizeof(segment_info));
    tmp_buf_ptr = (void *)(tmp_buf_ptr +
                record_read_count * sizeof(segment_info));
1044

Shane Snyder's avatar
Shane Snyder committed
1045
    dxt_posix_runtime->record_buf_size += record_size;
1046

Shane Snyder's avatar
Shane Snyder committed
1047
1048
#if 0
    int i;
Cong Xu's avatar
Cong Xu committed
1049
1050
    int64_t rank;
    char *hostname;
Shane Snyder's avatar
Shane Snyder committed
1051
1052
1053
1054
    int64_t offset;
    int64_t length;
    double start_time;
    double end_time;
1055

Cong Xu's avatar
Cong Xu committed
1056
1057
1058
1059
1060
    rank = file_rec->base_rec.rank;
    hostname = file_rec->hostname;

    printf("X_POSIX, record_id: %" PRIu64 "\n", rec_ref->file_rec->base_rec.id);
    printf("X_POSIX, write_count is: %d read_count is: %d\n",
Shane Snyder's avatar
Shane Snyder committed
1061
                file_rec->write_count, file_rec->read_count);
Cong Xu's avatar
Cong Xu committed
1062
    printf("X_POSIX, rank: %d hostname: %s\n", rank, hostname);
1063

Shane Snyder's avatar
Shane Snyder committed
1064
    for (i = 0; i < file_rec->write_count; i++) {
1065
1066
1067
1068
        offset = rec_ref->write_traces[i].offset;
        length = rec_ref->write_traces[i].length;
        start_time = rec_ref->write_traces[i].start_time;
        end_time = rec_ref->write_traces[i].end_time;
1069

Cong Xu's avatar
Cong Xu committed
1070
        printf("X_POSIX, rank %d writes segment %lld [offset: %lld length: %lld start_time: %fs end_time: %fs]\n", rank, i, offset, length, start_time, end_time);
Shane Snyder's avatar
Shane Snyder committed
1071
    }
1072

Shane Snyder's avatar
Shane Snyder committed
1073
    for (i = 0; i < file_rec->read_count; i++) {
1074
1075
1076
1077
        offset = rec_ref->read_traces[i].offset;
        length = rec_ref->read_traces[i].length;
        start_time = rec_ref->read_traces[i].start_time;
        end_time = rec_ref->read_traces[i].end_time;
1078

Cong Xu's avatar
Cong Xu committed
1079
        printf("X_POSIX, rank %d reads segment %lld [offset: %lld length: %lld start_time: %fs end_time: %fs]\n", rank, i, offset, length, start_time, end_time);
Shane Snyder's avatar
Shane Snyder committed
1080
1081
1082
    }
#endif
}
1083

Shane Snyder's avatar
Shane Snyder committed
1084
1085
1086
1087
1088
static void dxt_posix_shutdown(
    void **dxt_posix_buf,
    int *dxt_posix_buf_sz)
{
    assert(dxt_posix_runtime);
1089

Shane Snyder's avatar
Shane Snyder committed
1090
1091
    *dxt_posix_buf_sz = 0;

1092
    dxt_posix_runtime->record_buf = malloc(dxt_total_mem);
Shane Snyder's avatar
Shane Snyder committed
1093
1094
    if(!(dxt_posix_runtime->record_buf))
        return;
1095
    memset(dxt_posix_runtime->record_buf, 0, dxt_total_mem);
Shane Snyder's avatar
Shane Snyder committed
1096
1097
1098
    dxt_posix_runtime->record_buf_size = 0;

    /* iterate all dxt posix records and serialize them to the output buffer */
1099
1100
    darshan_iter_record_refs(dxt_posix_runtime->rec_id_hash,
        dxt_serialize_posix_records, NULL);
Shane Snyder's avatar
Shane Snyder committed
1101
1102
1103
1104

    /* set output */
    *dxt_posix_buf = dxt_posix_runtime->record_buf;
    *dxt_posix_buf_sz = dxt_posix_runtime->record_buf_size;
1105
1106

    /* shutdown internal structures used for instrumenting */
1107
    dxt_posix_cleanup_runtime();
1108
1109
1110
1111

    return;
}

1112
static void dxt_serialize_mpiio_records(void *rec_ref_p, void *user_ptr)
1113
{
Shane Snyder's avatar
Shane Snyder committed
1114
    struct dxt_file_record_ref *rec_ref = (struct dxt_file_record_ref *)rec_ref_p;
1115
    struct dxt_file_record *file_rec;
1116
1117
1118
    int64_t record_size = 0;
    int64_t record_write_count = 0;
    int64_t record_read_count = 0;
Shane Snyder's avatar
Shane Snyder committed
1119
    void *tmp_buf_ptr;
1120

Shane Snyder's avatar
Shane Snyder committed
1121
1122
1123
    assert(rec_ref);
    file_rec = rec_ref->file_rec;
    assert(file_rec);
1124

Shane Snyder's avatar
Shane Snyder committed
1125
1126
1127
1128
    record_write_count = file_rec->write_count;
    record_read_count = file_rec->read_count;
    if (record_write_count == 0 && record_read_count == 0)
        return;
1129

Shane Snyder's avatar
Shane Snyder committed
1130
1131
    /*
     * Buffer format:
1132
     * dxt_file_record + write_traces + read_traces
Shane Snyder's avatar
Shane Snyder committed
1133
1134
1135
     */
    record_size = sizeof(struct dxt_file_record) +
            (record_write_count + record_read_count) * sizeof(segment_info);
1136

Shane Snyder's avatar
Shane Snyder committed
1137
1138
    tmp_buf_ptr = (void *)(dxt_mpiio_runtime->record_buf +
        dxt_mpiio_runtime->record_buf_size);
1139

Shane Snyder's avatar
Shane Snyder committed
1140
1141
1142
    /*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));
1143

Shane Snyder's avatar
Shane Snyder committed
1144
    /*Copy write record */
1145
    memcpy(tmp_buf_ptr, (void *)(rec_ref->write_traces),