codes-recorder-io-wrkld.c 11.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Copyright (C) 2013 University of Chicago.
 * See COPYRIGHT notice in top-level directory.
 *
 */

/* Recorder workload generator that plugs into the general CODES workload
 * generator API. This generator consumes a set of input files of Recorder I/O
 * traces and passes these traces to the underlying simulator.
 */
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/stat.h>
#include <dirent.h>

#include "ross.h"
#include "codes/codes-workload.h"
20
#include "src/workload/codes-workload-method.h"
21
#include "codes/quickhash.h"
22
#include "codes/jenkins-hash.h"
23

24
#define RECORDER_NEGLIGIBLE_DELAY .00001
25 26 27

#define RANK_HASH_TABLE_SIZE 397

28
struct recorder_io_op
29 30
{
    double start_time;
31
    double end_time;
32
    struct codes_workload_op codes_op;
33 34
};

35 36 37 38 39 40 41
struct file_entry
{
    uint64_t file_id;
    int fd;
    struct qhash_head hash_link;
};

42 43 44 45
/* structure for storing all context needed to retrieve traces for this rank */
struct rank_traces_context
{
    int rank;
46
    double last_op_time;
47

48
    struct recorder_io_op trace_ops[2048]; /* TODO: this should be extendable */
49 50
    int trace_list_ndx;
    int trace_list_max;
51

52
    /* hash table link to next rank (if any) */
53
    struct qhash_head hash_link;
54 55 56 57 58 59 60 61
};

/* CODES workload API functions for workloads generated from recorder traces*/
static int recorder_io_workload_load(const char *params, int rank);
static void recorder_io_workload_get_next(int rank, struct codes_workload_op *op);

/* helper functions for recorder workload CODES API */
static int hash_rank_compare(void *key, struct qhash_head *link);
62
static int hash_file_compare(void *key, struct qhash_head *link);
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77

/* workload method name and function pointers for the CODES workload API */
struct codes_workload_method recorder_io_workload_method =
{
    .method_name = "recorder_io_workload",
    .codes_workload_load = recorder_io_workload_load,
    .codes_workload_get_next = recorder_io_workload_get_next,
};

static struct qhash_table *rank_tbl = NULL;
static int rank_tbl_pop = 0;

/* load the workload generator for this rank, given input params */
static int recorder_io_workload_load(const char *params, int rank)
{
78
    recorder_params *r_params = (recorder_params *) params;
Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
79
    struct rank_traces_context *newv = NULL;
80 81 82
    struct qhash_table *file_id_tbl = NULL;
    struct qhash_head *link = NULL;
    struct file_entry *file;
83

84
    int64_t nprocs = r_params->nprocs;
85
    char *trace_dir = r_params->trace_dir_path;
86 87 88 89
    if(!trace_dir)
        return -1;

    /* allocate a new trace context for this rank */
Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
90 91
    newv = (struct rank_traces_context*)malloc(sizeof(*newv));
    if(!newv)
92 93
        return -1;

Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
94 95 96
    newv->rank = rank;
    newv->trace_list_ndx = 0;
    newv->trace_list_max = 0;
97

98
#if 0
99 100 101 102 103 104 105
    DIR *dirp;
    struct dirent *entry;
    dirp = opendir(trace_dir);
    while((entry = readdir(dirp)) != NULL) {
        if(entry->d_type == DT_REG)
            nprocs++;
    }
106
    closedir(dirp);
107
#endif
108

109
    char trace_file_name[1024] = {'\0'};
110 111 112 113 114 115
    sprintf(trace_file_name, "%s/log.%d", trace_dir, rank);

    FILE *trace_file = fopen(trace_file_name, "r");
    if(trace_file == NULL)
        return -1;

116
    char *line = NULL;
117 118
    size_t len;
    ssize_t ret_value;
119
    char function_name[128] = {'\0'};
120 121
    double wkld_start_time = 0.0;
    double io_start_time = 0.0;
122 123
    while((ret_value = getline(&line, &len, trace_file)) != -1) {
        struct recorder_io_op r_op;
124
        char *token = strtok(line, ", \n");
125
        int fd;
126

127
        if (strcmp(token, "BARRIER") && strcmp(token, "0"))
128
        {
129 130 131 132
            if (wkld_start_time == 0.0)
                wkld_start_time = atof(token);

            r_op.start_time = atof(token) - wkld_start_time;
133 134
            token = strtok(NULL, ", ");
        }
135 136 137
        strcpy(function_name, token);

        if(!strcmp(function_name, "open") || !strcmp(function_name, "open64")) {
138
            char *filename = NULL;
139
            char *open_flags = NULL;
140

141
            filename = strtok(NULL, ", (");
142 143 144 145 146 147 148 149 150 151
            open_flags = strtok(NULL, ", )");

            if (!(atoi(open_flags) & O_CREAT))
            {
                r_op.codes_op.op_type = CODES_WK_BARRIER;
                r_op.end_time = r_op.start_time;

                r_op.codes_op.u.barrier.count = nprocs;
                r_op.codes_op.u.barrier.root = 0;

Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
152 153
                newv->trace_ops[newv->trace_list_ndx++] = r_op;
                if (newv->trace_list_ndx == 2048) break;
154
            }
155 156

            token = strtok(NULL, ", )");
157
            token = strtok(NULL, ", ");
158
            fd = atoi(token);
159 160

            token = strtok(NULL, ", \n");
161
            r_op.end_time = r_op.start_time + atof(token);
162 163 164 165 166 167

            if (!file_id_tbl)
            {
                file_id_tbl = qhash_init(hash_file_compare, quickhash_32bit_hash, 11);
                if (!file_id_tbl)
                {
Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
168
                    free(newv);
169 170 171 172
                    return -1;
                }
            }

Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
173
            file = (struct file_entry*)malloc(sizeof(struct file_entry));
174 175
            if (!file)
            {
Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
176
                free(newv);
177 178 179
                return -1;
            }
            
180
            uint32_t h1 = 0x00000000, h2 = 0xFFFFFFFF;
181 182 183
            bj_hashlittle2(filename, strlen(filename), &h1, &h2);
            file->file_id = h1 + (((uint64_t)h2)<<32);
            file->fd = fd;
184
            r_op.codes_op.op_type = CODES_WK_OPEN;
185
            r_op.codes_op.u.open.file_id = file->file_id;
186
            r_op.codes_op.u.open.create_flag = atoi(open_flags) & O_CREAT;
187 188

            qhash_add(file_id_tbl, &fd, &(file->hash_link));
189 190 191
        }
        else if(!strcmp(function_name, "close")) {
            r_op.codes_op.op_type = CODES_WK_CLOSE;
192

193
            token = strtok(NULL, ", ()");
194
            fd = atoi(token);
195 196 197

            token = strtok(NULL, ", ");
            token = strtok(NULL, ", \n");
198
            r_op.end_time = r_op.start_time + atof(token);
199 200 201 202

            link = qhash_search(file_id_tbl, &fd);
            if (!link)
            {
Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
203
                free(newv);
204 205 206 207 208 209 210 211
                return -1;
            }

            file = qhash_entry(link, struct file_entry, hash_link);
            r_op.codes_op.u.close.file_id = file->file_id;

            qhash_del(link);
            free(file);
212 213 214
        }
        else if(!strcmp(function_name, "read") || !strcmp(function_name, "read64")) {
            r_op.codes_op.op_type = CODES_WK_READ;
215

216
            token = strtok(NULL, ", (");
217
            fd = atoi(token);
218

219 220
            // Throw out the buffer
            token = strtok(NULL, ", ");
221

222 223
            token = strtok(NULL, ", )");
            r_op.codes_op.u.read.size = atol(token);
224

225 226
            token = strtok(NULL, ", )");
            r_op.codes_op.u.read.offset = atol(token);
227 228 229

            token = strtok(NULL, ", ");
            token = strtok(NULL, ", \n");
230 231 232 233 234 235 236 237 238

            if (io_start_time == 0.0)
            {
                r_op.end_time = r_op.start_time + atof(token);
            }
            else
            {
                r_op.start_time = r_op.end_time = io_start_time;
            }
239 240 241 242

            link = qhash_search(file_id_tbl, &fd);
            if (!link)
            {
Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
243
                free(newv);
244 245 246 247 248
                return -1;
            }

            file = qhash_entry(link, struct file_entry, hash_link);
            r_op.codes_op.u.read.file_id = file->file_id;
249 250 251
        }
        else if(!strcmp(function_name, "write") || !strcmp(function_name, "write64")) {
            r_op.codes_op.op_type = CODES_WK_WRITE;
252

253
            token = strtok(NULL, ", (");
254
            fd = atoi(token);
255

256 257
            // Throw out the buffer
            token = strtok(NULL, ", ");
258

259 260
            token = strtok(NULL, ", )");
            r_op.codes_op.u.write.size = atol(token);
261

262 263
            token = strtok(NULL, ", )");
            r_op.codes_op.u.write.offset = atol(token);
264 265 266

            token = strtok(NULL, ", ");
            token = strtok(NULL, ", \n");
267 268 269 270 271 272 273 274 275

            if (io_start_time == 0.0)
            {
                r_op.end_time = r_op.start_time + atof(token);
            }
            else
            {
                r_op.start_time = r_op.end_time = io_start_time;
            }
276 277 278 279

            link = qhash_search(file_id_tbl, &fd);
            if (!link)
            {
Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
280
                free(newv);
281 282 283 284 285
                return -1;
            }

            file = qhash_entry(link, struct file_entry, hash_link);
            r_op.codes_op.u.write.file_id = file->file_id;
286
        }
287 288 289
        else if(!strcmp(function_name, "BARRIER")) {
            r_op.start_time = r_op.end_time = io_start_time;
            
290 291 292
            r_op.codes_op.op_type = CODES_WK_BARRIER;
            r_op.codes_op.u.barrier.count = nprocs;
            r_op.codes_op.u.barrier.root = 0;
293 294 295
        }
        else if(!strcmp(function_name, "0")) {
            token = strtok (NULL, ", \n");
Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
296
            newv->trace_ops[newv->trace_list_ndx-1].end_time += atof(token);
297 298 299

            io_start_time = 0.0;
            continue;
300 301
        }
        else{
302 303 304 305
            if (!strcmp(function_name, "MPI_File_write_at_all") ||
                !strcmp(function_name, "MPI_File_read_at_all")) {
                io_start_time = r_op.start_time;
            }
306
            continue;
307 308
        }

Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
309 310
        newv->trace_ops[newv->trace_list_ndx++] = r_op;
        if (newv->trace_list_ndx == 2048) break;
311
    }
312

313
    fclose(trace_file);
314
    qhash_finalize(file_id_tbl);
315 316 317

    /* reset ndx to 0 and set max to event count */
    /* now we can read all events by counting through array from 0 - max */
Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
318 319 320
    newv->trace_list_max = newv->trace_list_ndx;
    newv->trace_list_ndx = 0;
    newv->last_op_time = 0.0;
321 322 323 324 325 326

    /* initialize the hash table of rank contexts, if it has not been initialized */
    if (!rank_tbl) {
        rank_tbl = qhash_init(hash_rank_compare, quickhash_32bit_hash, RANK_HASH_TABLE_SIZE);

        if (!rank_tbl) {
Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
327
            free(newv);
328 329 330 331 332
            return -1;
        }
    }

    /* add this rank context to the hash table */
Elsa Gonsiorowski (Uranus)'s avatar
Elsa Gonsiorowski (Uranus) committed
333
    qhash_add(rank_tbl, &(newv->rank), &(newv->hash_link));
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
    rank_tbl_pop++;

    return 0;
}

/* pull the next trace (independent or collective) for this rank from its trace context */
static void recorder_io_workload_get_next(int rank, struct codes_workload_op *op)
{
    struct qhash_head *hash_link = NULL;
    struct rank_traces_context *tmp = NULL;

    /* Find event context for this rank in the rank hash table */
    hash_link = qhash_search(rank_tbl, &rank);

    /* terminate the workload if there is no valid rank context */
    if(!hash_link) {
350

351 352 353 354 355 356 357
        op->op_type = CODES_WK_END;
        return;
    }

    tmp = qhash_entry(hash_link, struct rank_traces_context, hash_link);
    assert(tmp->rank == rank);

358
    if(tmp->trace_list_ndx == tmp->trace_list_max) {
359 360 361 362
        /* no more events -- just end the workload */
        op->op_type = CODES_WK_END;
        qhash_del(hash_link);
        free(tmp);
363

364 365
        rank_tbl_pop--;
        if(!rank_tbl_pop)
366
        {
367
            qhash_finalize(rank_tbl);
368 369
            rank_tbl = NULL;
        }
370 371
    }
    else {
372 373 374 375 376 377 378 379 380 381 382 383 384 385
        struct recorder_io_op *next_r_op = &(tmp->trace_ops[tmp->trace_list_ndx]);

        if ((next_r_op->start_time - tmp->last_op_time) <= RECORDER_NEGLIGIBLE_DELAY) {
            *op = next_r_op->codes_op;

            tmp->trace_list_ndx++;
            tmp->last_op_time = next_r_op->end_time;
        }
        else {
            op->op_type = CODES_WK_DELAY;
            op->u.delay.seconds = next_r_op->start_time - tmp->last_op_time;

            tmp->last_op_time = next_r_op->start_time;
        }
386 387 388 389 390 391 392 393 394 395
    }

    return;
}

static int hash_rank_compare(void *key, struct qhash_head *link)
{
    int *in_rank = (int *)key;
    struct rank_traces_context *tmp;

396
    tmp = qhash_entry(link, struct rank_traces_context, hash_link);
397 398 399 400 401 402
    if (tmp->rank == *in_rank)
        return 1;

    return 0;
}

403 404 405 406 407 408 409 410 411 412 413
static int hash_file_compare(void *key, struct qhash_head *link)
{
    int *in_file = (int *)key;
    struct file_entry *tmp;

    tmp = qhash_entry(link, struct file_entry, hash_link);
    if (tmp->fd == *in_file)
        return 1;

    return 0;
}
414 415 416 417 418 419 420 421 422

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