darshan-logutils.c 10.3 KB
Newer Older
1 2 3 4 5
/*
 *  (C) 2009 by Argonne National Laboratory.
 *      See COPYRIGHT in top-level directory.
 */

6
#define _GNU_SOURCE
7
#include "darshan-util-config.h"
8 9
#include <stdio.h>
#include <string.h>
10
#include <assert.h>
11
#include <stdlib.h>
12
#include <unistd.h>
13
#include <inttypes.h>
14 15 16
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
17
#include <errno.h>
18

19 20 21 22 23
#include <zlib.h>
#ifdef HAVE_LIBBZ2
#include <bzlib.h>
#endif

24 25
#include "darshan-logutils.h"

26 27
struct darshan_fd_s
{
28
    int pf;
29 30 31
    int64_t pos;
    char mode[2];
    int swap_flag;
32
    char version[8];
33
    char* name;
34 35 36 37 38
    int mod_count;
    int64_t job_off;
    int64_t rec_off;
    int64_t mod_off;
    int64_t end_off;
39 40
};

41 42 43
static int darshan_log_seek(darshan_fd fd, off_t offset);
static int darshan_log_read(darshan_fd fd, void *buf, int len);
static int darshan_log_write(darshan_fd fd, void *buf, int len);
44

45 46 47 48 49 50 51

/* darshan_log_open()
 *
 * open a darshan log file for reading/writing
 *
 * returns 0 on success, -1 on failure
 */
52
darshan_fd darshan_log_open(const char *name, const char *mode)
53
{
54
    int o_flags;
55

56 57 58
    /* we only allows "w" or "r" modes, nothing fancy */
    assert(strlen(mode) == 1);
    assert(mode[0] == 'r' || mode[0] == 'w');
59 60 61 62
    if(mode[0] == 'r')
        o_flags = O_RDONLY;
    else
        o_flags = O_WRONLY;
63

64 65 66 67 68
    darshan_fd tmp_fd = malloc(sizeof(*tmp_fd));
    if(!tmp_fd)
        return(NULL);
    memset(tmp_fd, 0, sizeof(*tmp_fd));

69 70
    /* TODO: why is mode needed??? */
    /* TODO: why is name needed??? */
71 72 73 74 75 76 77 78 79
    tmp_fd->mode[0] = mode[0];
    tmp_fd->mode[1] = mode[1];
    tmp_fd->name  = strdup(name);
    if(!tmp_fd->name)
    {
        free(tmp_fd);
        return(NULL);
    }

80 81
    tmp_fd->pf = open(name, o_flags);
    if(tmp_fd->pf < 0)
82
    {
83
        free(tmp_fd->name);
84
        free(tmp_fd);
85
        return(NULL);
86
    }
87 88

    return(tmp_fd);
89 90
}

91 92 93 94 95 96 97 98
/* darshan_log_getheader()
 *
 * read the header of the darshan log and set internal data structures
 * NOTE: this function must be called before reading other portions of the log
 *
 * returns 0 on success, -1 on failure
 */
int darshan_log_getheader(darshan_fd fd, struct darshan_header *header)
99
{
100 101
    struct stat sbuf;
    int64_t ndx_buf[2];
102
    int ret;
103

104
    ret = darshan_log_seek(fd, 0);
105
    if(ret < 0)
106 107
    {
        fprintf(stderr, "Error: unable to seek in darshan log file.\n");
108
        return(ret);
109
    }
110

111
    /* read header from log file */
112
    ret = darshan_log_read(fd, header, sizeof(*header));
113
    if(ret < sizeof(*header))
114
    {
115
        fprintf(stderr, "Error: invalid darshan log file (failed to read header).\n");
116 117 118
        return(-1);
    }

119 120
    /* save the version string */
    strncpy(fd->version, header->version_string, 8);
121 122

    if(header->magic_nr == CP_MAGIC_NR)
123
    {
124
        /* no byte swapping needed, this file is in host format already */
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
        fd->swap_flag = 0;
    }
    else
    {
        /* try byte swapping */
        DARSHAN_BSWAP64(&header->magic_nr);
        if(header->magic_nr == CP_MAGIC_NR)
        {
            fd->swap_flag = 1;
        }
        else
        {
            /* otherwise this file is just broken */
            fprintf(stderr, "Error: bad magic number in darshan log file.\n");
            return(-1);
        }
141 142
    }

143 144 145
    /* read index map from log file */
    ret = darshan_log_read(fd, ndx_buf, (2*sizeof(int64_t)));
    if(ret < (2 * sizeof(int64_t)))
146
    {
147 148
        fprintf(stderr, "Error: invalid darshan log file (failed to read header indexes).\n");
        return(-1);
149 150
    }

151 152 153 154 155 156 157 158 159 160
    /* fill index info into darshan file descriptor */
    fd->job_off = sizeof(struct darshan_header) + (2 * sizeof(int64_t)); /* TODO: */
    fd->rec_off = ndx_buf[0];
    fd->mod_off = ndx_buf[1];

    /* use stat to get log file size -- used to help index the log */
    fstat(fd->pf, &sbuf);
    fd->end_off = sbuf.st_size;

    return(0);
161
}
162

163
/* darshan_log_getjob()
164 165
 *
 * read job level metadata from the darshan log file
166
 *
167
 * returns 0 on success, -1 on failure
168
 */
169
int darshan_log_getjob(darshan_fd fd, struct darshan_job *job)
170
{
171
    int ret;
172

173
    ret = darshan_log_seek(fd, fd->job_off);
174
    if(ret < 0)
175
    {
176 177
        fprintf(stderr, "Error: unable to seek in darshan log file.\n");
        return(ret);
178 179
    }

180
    /* read the job data from the log file */
181
    ret = darshan_log_read(fd, job, sizeof(*job));
182
    if(ret < sizeof(*job))
183
    {
184
        fprintf(stderr, "Error: invalid darshan log file (failed to read job data).\n");
185 186 187
        return(-1);
    }

188
    if(fd->swap_flag)
189
    {
190 191 192 193 194 195
        /* swap bytes if necessary */
        DARSHAN_BSWAP64(&job->uid);
        DARSHAN_BSWAP64(&job->start_time);
        DARSHAN_BSWAP64(&job->end_time);
        DARSHAN_BSWAP64(&job->nprocs);
        DARSHAN_BSWAP64(&job->jobid);
196 197 198 199 200
    }

    return(0);
}

201 202 203 204 205 206 207
/* darshan_log_getjob()
 *
 * read job level metadata from the darshan log file
 *
 * returns 0 on success, -1 on failure
 */
int darshan_log_getmap(darshan_fd fd, struct darshan_record_ref **map)
208
{
209 210 211 212 213 214 215
    int map_size;
    unsigned char *map_buf;
    unsigned char *buf_ptr;
    darshan_record_id *rec_id_ptr;
    uint32_t *path_len_ptr;
    char *path_ptr;
    struct darshan_record_ref *ref;
216 217
    int ret;

218
    ret = darshan_log_seek(fd, fd->rec_off);
219
    if(ret < 0)
220 221
    {
        fprintf(stderr, "Error: unable to seek in darshan log file.\n");
222
        return(ret);
223
    }
224

225
    /* allocate a buffer to store the (serialized) darshan record map */
226 227 228
    map_size = fd->mod_off - fd->rec_off;
    map_buf = malloc(map_size);
    if(!map_buf)
229 230
        return(-1);

231
    /* read the record map from the log file */
232 233
    ret = darshan_log_read(fd, map_buf, map_size);
    if(ret < map_size)
234
    {
235
        fprintf(stderr, "Error: invalid darshan log file (failed to read record map).\n");
236
        free(map_buf);
237
        return(-1);
238 239
    }

240 241
    buf_ptr = map_buf;
    while(buf_ptr < (map_buf + map_size))
242
    {
243
        /* get pointers for each field of this darshan record */
244 245 246
        /* NOTE: darshan record map serialization method: 
         *          ... darshan_record_id | (uint32_t) path_len | path ...
         */
247 248 249 250 251 252 253 254 255
        rec_id_ptr = (darshan_record_id *)buf_ptr;
        buf_ptr += sizeof(darshan_record_id);
        path_len_ptr = (uint32_t *)buf_ptr;
        buf_ptr += sizeof(uint32_t);
        path_ptr = (char *)buf_ptr;
        buf_ptr += *path_len_ptr;

        ref = malloc(sizeof(*ref));
        if(!ref)
256
        {
257 258
            free(map_buf);
            return(-1);
259
        }
260 261
        ref->rec.name = malloc(*path_len_ptr + 1);
        if(!ref->rec.name)
262
        {
263 264 265
            free(map_buf);
            free(ref);
            return(-1);
266 267
        }

268
        if(fd->swap_flag)
269
        {
270 271 272
            /* we need to sort out endianness issues before deserializing */
            DARSHAN_BSWAP64(rec_id_ptr);
            DARSHAN_BSWAP32(path_len_ptr);
273 274
        }

275 276 277 278
        /* set the fields for this record */
        ref->rec.id = *rec_id_ptr;
        memcpy(ref->rec.name, path_ptr, *path_len_ptr);
        ref->rec.name[*path_len_ptr] = '\0';
279

280 281
        /* add this record to the hash */
        HASH_ADD(hlink, *map, rec.id, sizeof(darshan_record_id), ref);
282 283
    }

284
    free(map_buf);
285

286
    return(0);
287
}
288

289 290
/* TODO: hardcoded for posix -- what can we do generally?
 *       different function for each module and a way to map to this function?
291
 */
292
int darshan_log_getfile(darshan_fd fd, struct darshan_posix_file *file)
293 294 295 296
{
    int ret;
    const char* err_string;
    int i;
297

298
    if(fd->pos < fd->mod_off)
299
    {
300
        ret = darshan_log_seek(fd, fd->mod_off);
301
        if(ret < 0)
302 303
        {
            fprintf(stderr, "Error: unable to seek in darshan log file.\n");
304
            return(ret);
305
        }
306
    }
307 308 309 310

    /* reset file record, so that diff compares against a zero'd out record
     * if file is missing
     */
311
    memset(file, 0, sizeof(*file));
312

313
    ret = darshan_log_read(fd, file, sizeof(*file));
314 315 316 317 318 319
    if(ret == sizeof(*file))
    {
        /* got exactly one, correct size record */
        if(fd->swap_flag)
        {
            /* swap bytes if necessary */
320
            DARSHAN_BSWAP64(&file->f_id);
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
            DARSHAN_BSWAP64(&file->rank);
            for(i=0; i<CP_NUM_INDICES; i++)
                DARSHAN_BSWAP64(&file->counters[i]);
            for(i=0; i<CP_F_NUM_INDICES; i++)
                DARSHAN_BSWAP64(&file->fcounters[i]);
        }
        return(1);
    }


    if(ret > 0)
    {
        /* got a short read */
        fprintf(stderr, "Error: invalid file record (too small)\n");
        return(-1);
    }

338
    if(ret == 0)
339 340 341 342 343 344
    {
        /* hit end of file */
        return(0);
    }

    /* all other errors */
345
    err_string = strerror(errno);
346 347 348 349
    fprintf(stderr, "Error: %s\n", err_string);
    return(-1);
}

350 351
#if 0
int darshan_log_getexe(darshan_fd fd, char *buf)
Philip Carns's avatar
Philip Carns committed
352 353
{
    int ret;
354
    char* newline;
Philip Carns's avatar
Philip Carns committed
355

356 357 358
    ret = darshan_log_seek(fd, fd->job_struct_size);
    if(ret < 0)
        return(ret);
Philip Carns's avatar
Philip Carns committed
359

360 361
    ret = darshan_log_read(fd, buf, (fd->COMPAT_CP_EXE_LEN + 1));
    if (ret < (fd->COMPAT_CP_EXE_LEN + 1))
Philip Carns's avatar
Philip Carns committed
362
    {
363
        perror("darshan_log_read");
Philip Carns's avatar
Philip Carns committed
364 365 366
        return(-1);
    }

367 368 369 370 371 372 373
    /* this call is only supposed to return the exe string, but starting in
     * log format 1.23 there could be a table of mount entry information
     * after the exe.  Look for newline character and truncate there.
     */
    newline = strchr(buf, '\n');
    if(newline)
        *newline = '\0';
374

375
    return (0);
376
}
377
#endif
378

379 380 381 382 383 384 385
/* darshan_log_close()
 *
 * close an open darshan file descriptor
 *
 * returns 0 on success, -1 on failure
 */
void darshan_log_close(darshan_fd fd)
386
{
387 388
    if(fd->pf)
        close(fd->pf);
389

390 391
    free(fd->name);
    free(fd);
392 393
}

394
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
395

396 397 398 399 400 401
/* return amount written on success, -1 on failure.
 */
static int darshan_log_write(darshan_fd fd, void* buf, int len)
{
    int ret;

402
    if(fd->pf)
403
    {
404
        ret = write(fd->pf, buf, len);
405 406 407 408 409 410 411 412
        if(ret > 0)
            fd->pos += ret;
        return(ret);
    }

    return(-1);
}

413 414 415 416 417 418
/* return amount read on success, 0 on EOF, -1 on failure.
 */
static int darshan_log_read(darshan_fd fd, void* buf, int len)
{
    int ret;

419
    if(fd->pf)
420
    {
421
        ret = read(fd->pf, buf, len);
422 423 424 425 426 427 428 429 430 431
        if(ret > 0)
            fd->pos += ret;
        return(ret);
    }

    return(-1);
}

/* return 0 on successful seek to offset, -1 on failure.
 */
432
static int darshan_log_seek(darshan_fd fd, off_t offset)
433
{
434 435
    off_t ret_off;

436 437 438
    if(fd->pos == offset)
        return(0);

439 440
    ret_off = lseek(fd->pf, offset, SEEK_SET);
    if(ret_off == offset)
441
    {
442
        fd->pos = offset;
443 444 445 446 447
        return(0);
    }

    return(-1);
}