darshan-diff.c 15.8 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
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "uthash-1.9.2/src/uthash.h"

#define DEF_MOD_BUF_SIZE 1024 /* 1 KiB is enough for all current mod records ... */

/* XXX: this structure is a temporary hack to get at the rank for each module's record */
struct darshan_base_rec
{
    darshan_record_id f_id;
    int64_t rank;
};

struct darshan_mod_record_ref
{
    int rank;
    char mod_dat[DEF_MOD_BUF_SIZE];
    struct darshan_mod_record_ref *prev;
    struct darshan_mod_record_ref *next;
};
32

33
34
35
36
37
38
struct darshan_file_record_ref
{
    darshan_record_id rec_id;
    struct darshan_mod_record_ref *mod_recs[DARSHAN_MAX_MODS];
    UT_hash_handle hlink;
};
39

40
41
static int darshan_build_global_record_hash(
    darshan_fd fd, struct darshan_file_record_ref **rec_hash);
42

43
static void print_str_diff(char *prefix, char *arg1, char *arg2)
44
45
46
{
    printf("- %s %s\n", prefix, arg1);
    printf("+ %s %s\n", prefix, arg2);
47
    return;
48
}
49
50

static void print_int64_diff(char *prefix, int64_t arg1, int64_t arg2)
51
{
Philip Carns's avatar
Philip Carns committed
52
53
    printf("- %s %" PRId64 "\n", prefix, arg1);
    printf("+ %s %" PRId64 "\n", prefix, arg2);
54
    return;
55
56
}

57
int main(int argc, char *argv[])
58
{
59
    char *logfile1, *logfile2;
60
61
    darshan_fd file1, file2;
    struct darshan_job job1, job2;
62
    char exe1[4096], exe2[4096];
63
64
65
66
67
68
69
70
71
72
    struct darshan_record_ref *name_hash1 = NULL, *name_hash2 = NULL;
    struct darshan_record_ref *name_ref1, *name_ref2;
    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_rec *base_rec1, *base_rec2;
    char *file_name1, *file_name2;
    int i;
    int ret;
73

74
    if(argc != 3)
75
    {
76
        fprintf(stderr, "Usage: darshan-diff <logfile1> <logfile2>\n");
77
78
79
        return(-1);
    }

80
81
82
83
84
85
86
    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);
87
88
        return(-1);
    }
89
90
91
92
93
94

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

98
99
100
    /* get job data for each log file */
    ret = darshan_log_getjob(file1, &job1);
    if(ret < 0)
101
    {
102
        darshan_log_close(file1);
103
104
        darshan_log_close(file2);
        fprintf(stderr, "Error: unable to read job info for darshan log file %s.\n", logfile1);
105
106
        return(-1);
    }
107
108
109

    ret = darshan_log_getjob(file2, &job2);
    if(ret < 0)
110
    {
111
        darshan_log_close(file1);
112
        darshan_log_close(file2);
113
        fprintf(stderr, "Error: unable to read job info for darshan log file %s.\n", logfile2);
114
115
116
        return(-1);
    }

117
118
119
    /* get exe string for each log file */
    ret = darshan_log_getexe(file1, exe1);
    if(ret < 0)
120
    {
121
        darshan_log_close(file1);
122
123
        darshan_log_close(file2);
        fprintf(stderr, "Error: unable to read exe for darshan log file %s.\n", logfile1);
124
125
        return(-1);
    }
126
127
128

    ret = darshan_log_getexe(file2, exe2);
    if(ret < 0)
129
    {
130
        darshan_log_close(file1);
131
        darshan_log_close(file2);
132
        fprintf(stderr, "Error: unable to read exe for darshan log file %s.\n", logfile2);
133
134
135
        return(-1);
    }

136
137
138
    /* print diff of exe and job data */
    if (strcmp(exe1, exe2))
        print_str_diff("# exe: ", exe1, exe2);
139
140

    if (job1.uid != job2.uid)
141
        print_int64_diff("# uid:", job1.uid, job2.uid);
142
    if (job1.start_time != job2.start_time)
143
144
145
146
147
        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);
148
    if ((job1.end_time-job1.start_time) != (job2.end_time - job2.start_time))
149
150
        print_int64_diff("# run time:",
                (int64_t)(job1.end_time - job1.start_time + 1),
151
152
                (int64_t)(job2.end_time - job2.start_time + 1));

153
154
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
    /* get hash of record ids to file names for each log */
    ret = darshan_log_gethash(file1, &name_hash1);
    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);
    }

    ret = darshan_log_gethash(file2, &name_hash2);
    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++)
        {
            /* 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;
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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297

            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_rec *)mod_buf1;
                base_rec2 = (struct darshan_base_rec *)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)
                {
                    HASH_FIND(hlink, name_hash1, &(base_rec1->f_id),
                        sizeof(darshan_record_id), name_ref1);
                    assert(name_ref1);
                    file_name1 = name_ref1->rec.name;
                }
                if(mod_buf2)
                {
                    HASH_FIND(hlink, name_hash2, &(base_rec2->f_id),
                        sizeof(darshan_record_id), name_ref2);
                    assert(name_ref2);
                    file_name2 = name_ref2->rec.name;
                }

                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;
                    }
                    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;
                    }
                    free(mod_rec2);
                }
298
299
300
            }
        }

301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
        HASH_DELETE(hlink, rec_hash1, rec_ref1);
        free(rec_ref1);
        if(rec_ref2)
        {
            HASH_DELETE(hlink, rec_hash2, rec_ref2);
            free(rec_ref2);
        }
    }

    /* 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)
    {
        printf("\n");

        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_rec *)mod_rec2->mod_dat;
323

324
325
326
327
                HASH_FIND(hlink, name_hash2, &(base_rec2->f_id),
                    sizeof(darshan_record_id), name_ref2);
                assert(name_ref2);
                file_name2 = name_ref2->rec.name;
328

329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
                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;
                }
                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);
        free(name_ref1->rec.name);
        free(name_ref1);
    }
    HASH_ITER(hlink, name_hash2, name_ref2, name_ref1)
    {
        HASH_DELETE(hlink, name_hash2, name_ref2);
        free(name_ref2->rec.name);
        free(name_ref2);
    }
362

363
364
    darshan_log_close(file1);
    darshan_log_close(file2);
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410

    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;
    darshan_record_id tmp_rec_id;
    struct darshan_base_rec *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++)
    {
        while(1)
        {
            if(!mod_logutils[i]) break;

            mod_rec = malloc(sizeof(struct darshan_mod_record_ref));
            assert(mod_rec);
            memset(mod_rec, 0, sizeof(struct darshan_mod_record_ref));

            ret = mod_logutils[i]->log_get_record(fd, mod_rec->mod_dat, &tmp_rec_id);
            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_rec *)mod_rec->mod_dat;
                mod_rec->rank = base_rec->rank;

                HASH_FIND(hlink, *rec_hash, &tmp_rec_id, sizeof(darshan_record_id), file_rec);
411
                if(!file_rec)
412
                {
413
414
                    /* there is no entry in the global hash table of darshan records
                     * for this log file, so create one and add it.
415
                     */
416
417
418
419
420
421
422
423
424
425
426
427
428
                    file_rec = malloc(sizeof(struct darshan_file_record_ref));
                    assert(file_rec);

                    memset(file_rec, 0, sizeof(struct darshan_file_record_ref));
                    file_rec->rec_id = tmp_rec_id;
                    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 */
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

                    /* 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
                {
465
466
                    /* there are currently no records for this module, so just
                     * initialize a new linked list
467
468
469
470
471
472
473
474
                     */
                    mod_rec->prev = mod_rec->next = mod_rec;
                    file_rec->mod_recs[i] = mod_rec;
                }
            }
        }
    }

475
476
477
478
479
480
481
482
483
484
485
    return(0);
}

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