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

7
#include <stdio.h>
8
9
10
11
12
#include <stdlib.h>
#include <inttypes.h>
#include <sys/types.h>
#include <assert.h>

13
#include "darshan-logutils.h"
14
15
16
17
18
#include "uthash-1.9.2/src/uthash.h"

struct darshan_mod_record_ref
{
    int rank;
19
    char *mod_dat;
20
21
22
23
24
25
26
27
28
29
    struct darshan_mod_record_ref *prev;
    struct darshan_mod_record_ref *next;
};

struct darshan_file_record_ref
{
    darshan_record_id rec_id;
    struct darshan_mod_record_ref *mod_recs[DARSHAN_MAX_MODS];
    UT_hash_handle hlink;
};
30

31
32
static int darshan_build_global_record_hash(
    darshan_fd fd, struct darshan_file_record_ref **rec_hash);
33

34
static void print_str_diff(char *prefix, char *arg1, char *arg2)
35
36
37
{
    printf("- %s %s\n", prefix, arg1);
    printf("+ %s %s\n", prefix, arg2);
38
    return;
39
}
40
41

static void print_int64_diff(char *prefix, int64_t arg1, int64_t arg2)
42
{
Philip Carns's avatar
Philip Carns committed
43
44
    printf("- %s %" PRId64 "\n", prefix, arg1);
    printf("+ %s %" PRId64 "\n", prefix, arg2);
45
    return;
46
47
}

48
int main(int argc, char *argv[])
49
{
50
    char *logfile1, *logfile2;
51
52
    darshan_fd file1, file2;
    struct darshan_job job1, job2;
53
    char exe1[4096], exe2[4096];
54
55
    struct darshan_name_record_ref *name_hash1 = NULL, *name_hash2 = NULL;
    struct darshan_name_record_ref *name_ref1, *name_ref2;
56
57
58
59
60
61
62
63
    struct darshan_file_record_ref *rec_hash1 = NULL, *rec_hash2 = NULL;
    struct darshan_file_record_ref *rec_ref1, *rec_ref2, *rec_tmp;
    struct darshan_mod_record_ref *mod_rec1, *mod_rec2;
    void *mod_buf1, *mod_buf2;
    struct darshan_base_record *base_rec1, *base_rec2;
    char *file_name1, *file_name2;
    int i;
    int ret;
64

65
    if(argc != 3)
66
    {
67
        fprintf(stderr, "Usage: darshan-diff <logfile1> <logfile2>\n");
68
69
70
        return(-1);
    }

71
72
73
74
75
76
77
    logfile1 = argv[1];
    logfile2 = argv[2];

    file1 = darshan_log_open(logfile1);
    if(!file1)
    {
        fprintf(stderr, "Error: unable to open darshan log file %s.\n", logfile1);
78
79
        return(-1);
    }
80
81
82
83
84
85

    file2 = darshan_log_open(logfile2);
    if(!file2)
    {
        darshan_log_close(file1);
        fprintf(stderr, "Error: unable to open darshan log file %s.\n", logfile2);
86
87
88
        return(-1);
    }

89
    /* get job data for each log file */
90
    ret = darshan_log_get_job(file1, &job1);
91
    if(ret < 0)
92
    {
93
        darshan_log_close(file1);
94
95
        darshan_log_close(file2);
        fprintf(stderr, "Error: unable to read job info for darshan log file %s.\n", logfile1);
96
97
        return(-1);
    }
98

99
    ret = darshan_log_get_job(file2, &job2);
100
    if(ret < 0)
101
    {
102
        darshan_log_close(file1);
103
        darshan_log_close(file2);
104
        fprintf(stderr, "Error: unable to read job info for darshan log file %s.\n", logfile2);
105
106
107
        return(-1);
    }

108
    /* get exe string for each log file */
109
    ret = darshan_log_get_exe(file1, exe1);
110
    if(ret < 0)
111
    {
112
        darshan_log_close(file1);
113
114
        darshan_log_close(file2);
        fprintf(stderr, "Error: unable to read exe for darshan log file %s.\n", logfile1);
115
116
        return(-1);
    }
117

118
    ret = darshan_log_get_exe(file2, exe2);
119
    if(ret < 0)
120
    {
121
        darshan_log_close(file1);
122
        darshan_log_close(file2);
123
        fprintf(stderr, "Error: unable to read exe for darshan log file %s.\n", logfile2);
124
125
126
        return(-1);
    }

127
128
129
    /* print diff of exe and job data */
    if (strcmp(exe1, exe2))
        print_str_diff("# exe: ", exe1, exe2);
130
131

    if (job1.uid != job2.uid)
132
        print_int64_diff("# uid:", job1.uid, job2.uid);
133
    if (job1.start_time != job2.start_time)
134
135
136
137
138
        print_int64_diff("# start_time:", job1.start_time, job2.start_time);
    if (job1.end_time != job2.end_time)
        print_int64_diff("# end_time:", job1.end_time, job2.end_time);
    if (job1.nprocs != job2.nprocs)
        print_int64_diff("# nprocs:", job1.nprocs, job2.nprocs);
139
    if ((job1.end_time-job1.start_time) != (job2.end_time - job2.start_time))
140
141
        print_int64_diff("# run time:",
                (int64_t)(job1.end_time - job1.start_time + 1),
142
143
                (int64_t)(job2.end_time - job2.start_time + 1));

144
    /* get hash of record ids to file names for each log */
145
    ret = darshan_log_get_namehash(file1, &name_hash1);
146
147
148
149
150
151
152
153
    if(ret < 0)
    {
        darshan_log_close(file1);
        darshan_log_close(file2);
        fprintf(stderr, "Error: unable to read record hash for darshan log file %s.\n", logfile1);
        return(-1);
    }

154
    ret = darshan_log_get_namehash(file2, &name_hash2);
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    if(ret < 0)
    {
        darshan_log_close(file1);
        darshan_log_close(file2);
        fprintf(stderr, "Error: unable to read record hash for darshan log file %s.\n", logfile2);
        return(-1);
    }

    /* build hash tables of all records opened by all modules for each darshan log file */
    ret = darshan_build_global_record_hash(file1, &rec_hash1);
    if(ret < 0)
    {
        fprintf(stderr, "Error: unable to build record hash for darshan log file %s.\n", logfile1);
        darshan_log_close(file1);
        darshan_log_close(file2);
        return(-1);
    }

    ret = darshan_build_global_record_hash(file2, &rec_hash2);
    if(ret < 0)
    {
        fprintf(stderr, "Error: unable to build record hash for darshan log file %s.\n", logfile2);
        darshan_log_close(file1);
        darshan_log_close(file2);
        return(-1);
    }

    /* iterate records for the first log file and correlate/diff with records from
     * the second log file
     */
    HASH_ITER(hlink, rec_hash1, rec_ref1, rec_tmp)
    {
        printf("\n");

        /* search hash2 for this record */
        HASH_FIND(hlink, rec_hash2, &(rec_ref1->rec_id), sizeof(darshan_record_id), rec_ref2);

        for(i = 0; i < DARSHAN_MAX_MODS; i++)
        {
194
195
196
197
            /* skip the DXT modules -- we won't be diff'ing traces */
            if(i == DXT_POSIX_MOD || i == DXT_MPIIO_MOD)
                continue;

198
199
200
201
202
203
204
205
            /* TODO: skip modules that don't have the same format version, for now */
            if(rec_ref1->mod_recs[i] && rec_ref2 && rec_ref2->mod_recs[i] &&
                (file1->mod_ver[i] != file2->mod_ver[i]))
            {
                fprintf(stderr, "Warning: skipping %s module data due to incompatible"
                    "version numbers (file1=%d, file2=%d).\n",
                    darshan_module_names[i], file1->mod_ver[i], file2->mod_ver[i]);
                continue;
206
            }
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247

            while(1)
            {
                mod_rec1 = rec_ref1->mod_recs[i];
                if(rec_ref2)
                    mod_rec2 = rec_ref2->mod_recs[i];
                else
                    mod_rec2 = NULL;

                if(mod_rec1 == NULL)
                    mod_buf1 = NULL;
                else
                    mod_buf1 = mod_rec1->mod_dat;
                if(mod_rec2 == NULL)
                    mod_buf2 = NULL;
                else
                    mod_buf2 = mod_rec2->mod_dat;

                base_rec1 = (struct darshan_base_record *)mod_buf1;
                base_rec2 = (struct darshan_base_record *)mod_buf2;
                if(!base_rec1 && !base_rec2)
                {
                    /* break out if there are no more records for this module */
                    break;
                }
                else if(base_rec1 && base_rec2)
                {
                    /* make sure if we have module records for this darshan record
                     * from both log files, that we are performing the diff rank-by-rank
                     * (i.e., we diff rank 1 records together, rank 2 records together,
                     * and so on)
                     */
                    if(base_rec1->rank < base_rec2->rank)
                        mod_buf2 = NULL;
                    else if(base_rec1->rank > base_rec2->rank)
                        mod_buf1 = NULL;
                }

                /* get corresponding file name for each record */
                if(mod_buf1)
                {
Shane Snyder's avatar
Shane Snyder committed
248
                    HASH_FIND(hlink, name_hash1, &(base_rec1->id),
249
250
                        sizeof(darshan_record_id), name_ref1);
                    assert(name_ref1);
251
                    file_name1 = name_ref1->name_record->name;
252
253
254
                }
                if(mod_buf2)
                {
Shane Snyder's avatar
Shane Snyder committed
255
                    HASH_FIND(hlink, name_hash2, &(base_rec2->id),
256
257
                        sizeof(darshan_record_id), name_ref2);
                    assert(name_ref2);
258
                    file_name2 = name_ref2->name_record->name;
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
                }

                mod_logutils[i]->log_print_diff(mod_buf1, file_name1, mod_buf2, file_name2);

                /* remove records which we have diffed already */
                if(mod_buf1)
                {
                    if(mod_rec1->next == mod_rec1)
                    {
                        rec_ref1->mod_recs[i] = NULL;
                    }
                    else
                    {
                        mod_rec1->prev->next = mod_rec1->next;
                        mod_rec1->next->prev = mod_rec1->prev;
                        rec_ref1->mod_recs[i] = mod_rec1->next;
                    }
276
                    free(mod_rec1->mod_dat);
277
278
279
280
281
282
283
284
285
286
287
288
289
290
                    free(mod_rec1);
                }
                if(mod_buf2)
                {
                    if(mod_rec2->next == mod_rec2)
                    {
                        rec_ref2->mod_recs[i] = NULL;
                    }
                    else
                    {
                        mod_rec2->prev->next = mod_rec2->next;
                        mod_rec2->next->prev = mod_rec2->prev;
                        rec_ref2->mod_recs[i] = mod_rec2->next;
                    }
291
                    free(mod_rec2->mod_dat);
292
293
                    free(mod_rec2);
                }
294
295
296
            }
        }

297
298
299
300
301
302
303
304
        HASH_DELETE(hlink, rec_hash1, rec_ref1);
        free(rec_ref1);
        if(rec_ref2)
        {
            HASH_DELETE(hlink, rec_hash2, rec_ref2);
            free(rec_ref2);
        }
    }
305

306
307
308
309
310
311
312
313
314
315
316
317
    /* iterate any remaning records from the 2nd log file and print the diff output --
     * NOTE: that these records do not have corresponding records in the first log file
     */
    HASH_ITER(hlink, rec_hash2, rec_ref2, rec_tmp)
    {
        for(i = 0; i < DARSHAN_MAX_MODS; i++)
        {
            while(rec_ref2->mod_recs[i])
            {
                mod_rec2 = rec_ref2->mod_recs[i];
                base_rec2 = (struct darshan_base_record *)mod_rec2->mod_dat;

Shane Snyder's avatar
Shane Snyder committed
318
                HASH_FIND(hlink, name_hash2, &(base_rec2->id),
319
320
                    sizeof(darshan_record_id), name_ref2);
                assert(name_ref2);
321
                file_name2 = name_ref2->name_record->name;
322

323
324
325
326
327
328
329
330
331
332
333
334
335
                mod_logutils[i]->log_print_diff(NULL, NULL, mod_rec2->mod_dat, file_name2);
                
                /* remove the record we just diffed */
                if(mod_rec2->next == mod_rec2)
                {
                    rec_ref2->mod_recs[i] = NULL;
                }
                else
                {
                    mod_rec2->prev->next = mod_rec2->next;
                    mod_rec2->next->prev = mod_rec2->prev;
                    rec_ref2->mod_recs[i] = mod_rec2->next;
                }
336
                free(mod_rec2->mod_dat);
337
338
339
340
341
342
343
344
345
346
347
                free(mod_rec2);
            }
        }

        HASH_DELETE(hlink, rec_hash2, rec_ref2);
        free(rec_ref2);
    }

    HASH_ITER(hlink, name_hash1, name_ref1, name_ref2)
    {
        HASH_DELETE(hlink, name_hash1, name_ref1);
348
        free(name_ref1->name_record);
349
350
351
352
353
        free(name_ref1);
    }
    HASH_ITER(hlink, name_hash2, name_ref2, name_ref1)
    {
        HASH_DELETE(hlink, name_hash2, name_ref2);
354
        free(name_ref2->name_record);
355
356
        free(name_ref2);
    }
357

358
359
    darshan_log_close(file1);
    darshan_log_close(file2);
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377

    return(0);
}

static int darshan_build_global_record_hash(
    darshan_fd fd, struct darshan_file_record_ref **rec_hash)
{
    struct darshan_mod_record_ref *mod_rec;
    struct darshan_file_record_ref *file_rec;
    struct darshan_base_record *base_rec;
    int i;
    int ret;

    /* iterate over all modules in each log file, adding records to the
     * appropriate hash table
     */
    for(i = 0; i < DARSHAN_MAX_MODS; i++)
    {
378
        if(!mod_logutils[i]) continue;
379

380
381
382
383
384
385
        while(1)
        {
            mod_rec = malloc(sizeof(struct darshan_mod_record_ref));
            assert(mod_rec);
            memset(mod_rec, 0, sizeof(struct darshan_mod_record_ref));

386
            ret = mod_logutils[i]->log_get_record(fd, (void **)&(mod_rec->mod_dat));
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
            if(ret < 0)
            {
                fprintf(stderr, "Error: unable to read module %s data from log file.\n",
                    darshan_module_names[i]);
                free(mod_rec);
                return(-1);
            }
            else if(ret == 0)
            {
                free(mod_rec);
                break;
            }
            else
            {
                base_rec = (struct darshan_base_record *)mod_rec->mod_dat;
                mod_rec->rank = base_rec->rank;

404
                HASH_FIND(hlink, *rec_hash, &(base_rec->id), sizeof(darshan_record_id), file_rec);
405
406
407
408
409
410
411
412
413
                if(!file_rec)
                {
                    /* there is no entry in the global hash table of darshan records
                     * for this log file, so create one and add it.
                     */
                    file_rec = malloc(sizeof(struct darshan_file_record_ref));
                    assert(file_rec);

                    memset(file_rec, 0, sizeof(struct darshan_file_record_ref));
414
                    file_rec->rec_id = base_rec->id;
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
                    HASH_ADD(hlink, *rec_hash, rec_id, sizeof(darshan_record_id), file_rec);

                }

                /* add new record into the linked list of this module's records */
                if(file_rec->mod_recs[i])
                {
                    /* there is already an initialized linked list for this module */

                    /* we start at the end of the list and work backwards to insert this
                     * record (the list is sorted according to increasing ranks, and in
                     * general, darshan log records are sorted according to increasing
                     * ranks, as well)
                     */
                    struct darshan_mod_record_ref *tmp_mod_rec = file_rec->mod_recs[i]->prev;
                    while(1)
                    {
                        if(mod_rec->rank > tmp_mod_rec->rank)
                        {
                            /* insert new module record after this record */
                            mod_rec->prev = tmp_mod_rec;
                            mod_rec->next = tmp_mod_rec->next;
                            tmp_mod_rec->next->prev = mod_rec;
                            tmp_mod_rec->next = mod_rec;
                            break;
                        }
                        else if(mod_rec->rank < tmp_mod_rec->rank)
                        {
                            /* insert new module record before this record */
                            mod_rec->prev = tmp_mod_rec->prev;
                            mod_rec->next = tmp_mod_rec;
                            tmp_mod_rec->prev->next = mod_rec;
                            tmp_mod_rec->prev = mod_rec;
                            if(file_rec->mod_recs[i] == mod_rec->next)
                                file_rec->mod_recs[i] = mod_rec;
                            break;
                        }

                        tmp_mod_rec = tmp_mod_rec->prev;
                        assert(tmp_mod_rec != file_rec->mod_recs[i]);
                    }
                }
                else
                {
                    /* there are currently no records for this module, so just
                     * initialize a new linked list
                     */
                    mod_rec->prev = mod_rec->next = mod_rec;
                    file_rec->mod_recs[i] = mod_rec;
                }
            }
        }
    }

469
470
471
472
473
474
475
476
477
478
479
    return(0);
}

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