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
 */