codes-iomock-wrkld.c 7.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*
 * Copyright (C) 2013 University of Chicago.
 * See COPYRIGHT notice in top-level directory.
 *
 */

#include <assert.h>
#include <ross.h>
#include <codes/codes-workload.h>
#include <codes/quickhash.h>
#include <codes/quicklist.h>
Jonathan Jenkins's avatar
Jonathan Jenkins committed
12
#include <codes/codes.h>
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74

#define DEFAULT_HASH_TBL_SIZE 1024

struct app_params
{
    iomock_params params;
    int app_id;
    struct qlist_head ql;
};

struct rank_state
{
    int rank;
    int app_id;
    int reqs_processed;
    int has_opened;
    int has_closed;
    struct app_params *params;
    struct qhash_head hash_link;
};

// globals
// hold all of the ranks using this workload
static struct qhash_table *rank_tbl = NULL;
static int num_qhash_entries = 0;

// hold application configurations
static struct qlist_head app_params_list = QLIST_HEAD_INIT(app_params_list);

// check parameter sets for equality
static int params_eq(iomock_params const * a, iomock_params const * b)
{
    return (a->file_id == b->file_id &&
            a->use_uniq_file_ids == b->use_uniq_file_ids &&
            a->is_write == b->is_write &&
            a->num_requests == b->num_requests &&
            a->request_size == b->request_size);
}

// comparison function for hash table
static int rank_tbl_compare(void * key, struct qhash_head * link)
{
    struct rank_state *a = key;
    struct rank_state *b = qhash_entry(link, struct rank_state, hash_link);
    if (a->rank == b->rank && a->app_id == b->app_id)
        return 1;
    else
        return 0;
}

// calculate file id depending on config
static uint64_t get_file_id(iomock_params const * p, int rank)
{
    return p->file_id + (p->use_uniq_file_ids ? rank : 0);
}

static void * iomock_workload_read_config(
        ConfigHandle * handle,
        char const * section_name,
        char const * annotation,
        int num_ranks)
{
Jonathan Jenkins's avatar
Jonathan Jenkins committed
75
    (void)num_ranks; // not needed for this workload
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 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 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
    iomock_params *p = malloc(sizeof(*p));
    assert(p);

    // defaults
    p->file_id = 0;
    p->is_write = 1;
    p->use_uniq_file_ids = 0;
    p->rank_table_size = 0;

    char req_type[CONFIGURATION_MAX_NAME] = "";

    int rc;

    // required
    rc = configuration_get_value_int(handle, section_name, "mock_num_requests",
            annotation, &p->num_requests);
    if (rc || p->num_requests < 0)
        tw_error(TW_LOC,
                "mock workload: expected non-negative integer for "
                "\"mock_num_requests\"");
    rc = configuration_get_value_int(handle, section_name, "mock_request_size",
            annotation, &p->request_size);
    if (rc || p->request_size < 0)
        tw_error(TW_LOC,
                "mock workload: expected positive integer for "
                "\"mock_request_size\"");

    // optionals
    rc = configuration_get_value(handle, section_name, "mock_request_type",
            annotation, req_type, CONFIGURATION_MAX_NAME);
    if (rc > 0) {
        if (strcmp(req_type, "write") == 0)
            p->is_write = 1;
        else if (strcmp(req_type, "read") == 0)
            p->is_write = 0;
        else
            tw_error(TW_LOC,
                    "mock workload: expected \"read\" or \"write\" for "
                    "mock_request_type, got %s\n", req_type);
    }

    long int file_id;
    rc = configuration_get_value_longint(handle, section_name, "mock_file_id",
            annotation, &file_id);
    if (!rc)
        p->file_id = file_id;

    configuration_get_value_int(handle, section_name,
            "mock_use_unique_file_ids", annotation, &p->use_uniq_file_ids);

    rc = configuration_get_value_int(handle, section_name,
            "mock_rank_table_size", annotation, &p->rank_table_size);
    if (!rc && p->rank_table_size < 0)
        tw_error(TW_LOC, "mock_rank_table_size expected to be positive\n");

    return p;
}

/* load the workload file */
static int iomock_workload_load(const char* params, int app_id, int rank)
{
    iomock_params const * p = (iomock_params const *) params;

    // search for and append if needed into the global params table
    struct qlist_head *ent;
    struct app_params *ap;
    qlist_for_each(ent, &app_params_list) {
        ap = qlist_entry(ent, struct app_params, ql);
        if (app_id == ap->app_id) {
            if (params_eq(&ap->params, p))
                break;
            else
                tw_error(TW_LOC, "app %d: rank %d passed in a different config",
                        app_id, rank);
        }
    }
    if (ent == &app_params_list) {
        ap = malloc(sizeof(*ap));
        assert(ap);
        ap->params = *p;
        ap->app_id = app_id;
        qlist_add_tail(&ap->ql, &app_params_list);
    }


    if (rank_tbl == NULL) {
        rank_tbl = qhash_init(rank_tbl_compare, quickhash_64bit_hash,
                p->rank_table_size ? p->rank_table_size : DEFAULT_HASH_TBL_SIZE);
        assert(rank_tbl);
    }

    struct rank_state *rs = malloc(sizeof(*rs));
    assert(rs);
    rs->rank = rank;
    rs->app_id = app_id;
    rs->has_opened = 0;
    rs->has_closed = 0;
    rs->reqs_processed = 0;
    rs->params = ap;

    qhash_add(rank_tbl, rs, &rs->hash_link);
    num_qhash_entries++;

    return 0;
}

static void iomock_workload_get_next(
        int app_id,
        int rank,
        struct codes_workload_op *op)
{
    struct rank_state cmp = { .rank = rank, .app_id = app_id };

    struct qhash_head *hash_link = qhash_search(rank_tbl, &cmp);
    if (hash_link == NULL)
        tw_error(TW_LOC, "mock workload: unable to find app-rank context for "
                "app %d, rank %d", app_id, rank);

    struct rank_state * rs =
        qhash_entry(hash_link, struct rank_state, hash_link);
    iomock_params const * p = &rs->params->params;

    if (!rs->has_opened) {
        op->op_type = CODES_WK_OPEN;
        op->u.open.create_flag = 1;
        op->u.open.file_id = get_file_id(p, rank);
        rs->has_opened = 1;
    }
    else if (rs->reqs_processed == p->num_requests) {
        if (!rs->has_closed) {
            op->op_type = CODES_WK_CLOSE;
            op->u.close.file_id = get_file_id(p, rank);
            rs->has_closed = 1;
        }
        else {
            op->op_type = CODES_WK_END;
            // cleanup
            qhash_del(hash_link);
            num_qhash_entries--;
            if (num_qhash_entries == 0) {
                qhash_finalize(rank_tbl);
                rank_tbl = NULL;
            }
        }
    }
    else {
        if (p->is_write) {
            op->op_type = CODES_WK_WRITE;
            op->u.write.file_id = get_file_id(p, rank);
            op->u.write.size = p->request_size;
            op->u.write.offset =
                (uint64_t)p->request_size * (uint64_t)rs->reqs_processed;
        }
        else {
            op->op_type = CODES_WK_READ;
            op->u.read.file_id = get_file_id(p, rank);
            op->u.read.size = p->request_size;
            op->u.read.offset =
                (uint64_t)p->request_size * (uint64_t)rs->reqs_processed;
        }
        rs->reqs_processed++;
    }
    return;
}

struct codes_workload_method iomock_workload_method =
{
    .method_name = "iomock_workload",
    .codes_workload_read_config = iomock_workload_read_config,
    .codes_workload_load = iomock_workload_load,
    .codes_workload_get_next = iomock_workload_get_next,
    .codes_workload_get_rank_cnt = NULL
};

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