From 1e3760b2e78882a0d32f96840a88a6a687227e82 Mon Sep 17 00:00:00 2001 From: John Jenkins Date: Wed, 19 Aug 2015 15:21:57 -0500 Subject: [PATCH] add default workload config reading --- codes/codes-workload.h | 26 +++++++++---- src/workload/codes-workload-method.h | 2 + src/workload/codes-workload.c | 35 ++++++++++++++++++ src/workload/methods/codes-darshan-io-wrkld.c | 24 ++++++++++++ .../methods/codes-dumpi-trace-nw-wrkld.c | 1 + src/workload/methods/codes-iolang-wrkld.c | 33 ++++++++++++++++- .../methods/codes-recorder-io-wrkld.c | 1 + src/workload/methods/test-workload-method.c | 1 + src/workload/scala-trace-data | Bin 260608 -> 0 bytes 9 files changed, 113 insertions(+), 10 deletions(-) delete mode 100644 src/workload/scala-trace-data diff --git a/codes/codes-workload.h b/codes/codes-workload.h index c196e3f..e96c2e7 100644 --- a/codes/codes-workload.h +++ b/codes/codes-workload.h @@ -12,7 +12,9 @@ #ifndef CODES_WORKLOAD_H #define CODES_WORKLOAD_H -#include "ross.h" +#include +#include "configuration.h" + #define MAX_NAME_LENGTH_WKLD 512 typedef struct iolang_params iolang_params; @@ -20,7 +22,6 @@ typedef struct darshan_params darshan_params; typedef struct recorder_params recorder_params; /* struct to hold the actual data from a single MPI event*/ -typedef struct scala_trace_params scala_trace_params; typedef struct dumpi_trace_params dumpi_trace_params; typedef struct checkpoint_wrkld_params checkpoint_wrkld_params; @@ -47,12 +48,6 @@ struct recorder_params int64_t nprocs; }; - -struct scala_trace_params { - char offset_file_name[MAX_NAME_LENGTH_WKLD]; - char nw_wrkld_file_name[MAX_NAME_LENGTH_WKLD]; -}; - struct dumpi_trace_params { char file_name[MAX_NAME_LENGTH_WKLD]; int num_net_traces; @@ -204,6 +199,21 @@ struct codes_workload_op }u; }; +/* read workload configuration from a CODES configuration file and return the + * workload name and parameters, which can then be passed to + * codes_workload_load */ +typedef struct +{ + char const * type; + void * params; +} codes_workload_config_return; + +codes_workload_config_return codes_workload_read_config( + ConfigHandle * handle, + char const * section_name); + +void codes_workload_free_config_return(codes_workload_config_return *c); + /* load and initialize workload of of type "type" with parameters specified by * "params". The rank is the caller's relative rank within the collection * of processes that will participate in this workload. The app_id is the diff --git a/src/workload/codes-workload-method.h b/src/workload/codes-workload-method.h index 975423c..9750175 100644 --- a/src/workload/codes-workload-method.h +++ b/src/workload/codes-workload-method.h @@ -25,6 +25,8 @@ struct codes_workload_method { char *method_name; /* name of the generator */ + void * (*codes_workload_read_config) ( + ConfigHandle *handle, char const * section_name); int (*codes_workload_load)(const char* params, int app_id, int rank); void (*codes_workload_get_next)(int app_id, int rank, struct codes_workload_op *op); int (*codes_workload_get_rank_cnt)(const char* params, int app_id); diff --git a/src/workload/codes-workload.c b/src/workload/codes-workload.c index a8d1d4d..3fec485 100644 --- a/src/workload/codes-workload.c +++ b/src/workload/codes-workload.c @@ -70,6 +70,41 @@ struct rank_queue static struct rank_queue *ranks = NULL; +codes_workload_config_return codes_workload_read_config( + ConfigHandle * handle, + char const * section_name) +{ + char type[MAX_NAME_LENGTH_WKLD]; + codes_workload_config_return r; + r.type = NULL; + r.params = NULL; + + int rc = configuration_get_value(handle, section_name, "type", + NULL, type, MAX_NAME_LENGTH_WKLD); + if (rc <= 0) + return r; + + for (int i = 0; method_array[i] != NULL; i++){ + struct codes_workload_method const * m = method_array[i]; + if (strcmp(m->method_name, type) == 0) { + r.type = m->method_name; + if (m->codes_workload_read_config == NULL) + r.params = NULL; + else + r.params = m->codes_workload_read_config(handle, section_name); + } + } + + return r; +} + +void codes_workload_free_config_return(codes_workload_config_return *c) +{ + free(c->params); + c->type = NULL; + c->params = NULL; +} + int codes_workload_load( const char* type, const char* params, diff --git a/src/workload/methods/codes-darshan-io-wrkld.c b/src/workload/methods/codes-darshan-io-wrkld.c index 3deeff7..4f140db 100644 --- a/src/workload/methods/codes-darshan-io-wrkld.c +++ b/src/workload/methods/codes-darshan-io-wrkld.c @@ -43,6 +43,9 @@ struct rank_io_context struct qhash_head hash_link; }; +static void * darshan_io_workload_read_config( + ConfigHandle * handle, + char const * section_name); /* Darshan workload generator's implementation of the CODES workload API */ static int darshan_io_workload_load(const char *params, int app_id, int rank); static void darshan_io_workload_get_next(int app_id, int rank, struct codes_workload_op *op); @@ -93,6 +96,7 @@ static void file_sanity_check(struct darshan_file *file, struct darshan_job *job struct codes_workload_method darshan_io_workload_method = { .method_name = "darshan_io_workload", + .codes_workload_read_config = darshan_io_workload_read_config, .codes_workload_load = darshan_io_workload_load, .codes_workload_get_next = darshan_io_workload_get_next, .codes_workload_get_rank_cnt = darshan_io_workload_get_rank_cnt, @@ -104,6 +108,26 @@ static int total_rank_cnt = 0; static struct qhash_table *rank_tbl = NULL; static int rank_tbl_pop = 0; +static void * darshan_io_workload_read_config( + ConfigHandle * handle, + char const * section_name) +{ + darshan_params *d = malloc(sizeof(*d)); + assert(d); + d->log_file_path[0] = '\0'; + d->aggregator_cnt = -1; + + int rc = configuration_get_value_relpath(handle, section_name, + "darshan_log_file", NULL, d->log_file_path, + MAX_NAME_LENGTH_WKLD); + assert(rc > 0); + int tmp; + rc = configuration_get_value_int(&config, "workload", + "darshan_aggregator_count", NULL, &tmp); + assert(rc == 0); + d->aggregator_cnt = tmp; + return d; +} /* load the workload generator for this rank, given input params */ static int darshan_io_workload_load(const char *params, int app_id, int rank) { diff --git a/src/workload/methods/codes-dumpi-trace-nw-wrkld.c b/src/workload/methods/codes-dumpi-trace-nw-wrkld.c index 1da14ad..32dfbd0 100644 --- a/src/workload/methods/codes-dumpi-trace-nw-wrkld.c +++ b/src/workload/methods/codes-dumpi-trace-nw-wrkld.c @@ -756,6 +756,7 @@ void dumpi_trace_nw_workload_get_next(int app_id, int rank, struct codes_workloa struct codes_workload_method dumpi_trace_workload_method = { .method_name = "dumpi-trace-workload", + .codes_workload_read_config = NULL, .codes_workload_load = dumpi_trace_nw_workload_load, .codes_workload_get_next = dumpi_trace_nw_workload_get_next, }; diff --git a/src/workload/methods/codes-iolang-wrkld.c b/src/workload/methods/codes-iolang-wrkld.c index 52c31f8..941f59b 100644 --- a/src/workload/methods/codes-iolang-wrkld.c +++ b/src/workload/methods/codes-iolang-wrkld.c @@ -3,6 +3,7 @@ * See COPYRIGHT notice in top-level directory. * */ +#include #include #include "src/iokernellang/CodesIOKernelTypes.h" #include "src/iokernellang/CodesIOKernelParser.h" @@ -20,11 +21,15 @@ /* This file implements the CODES workload API for the I/O kernel language of the BG/P storage model */ +static void * iolang_io_workload_read_config( + ConfigHandle * handle, + char const * section_name); + /* load the workload file */ -int iolang_io_workload_load(const char* params, int app_id, int rank); +static int iolang_io_workload_load(const char* params, int app_id, int rank); /* get next operation */ -void iolang_io_workload_get_next(int app_id, int rank, struct codes_workload_op *op); +static void iolang_io_workload_get_next(int app_id, int rank, struct codes_workload_op *op); /* mapping from bg/p operation enums to CODES workload operations enum */ static int convertTypes(int inst); @@ -39,6 +44,7 @@ int num_ranks = -1; struct codes_workload_method iolang_workload_method = { .method_name = "iolang_workload", + .codes_workload_read_config = iolang_io_workload_read_config, .codes_workload_load = iolang_io_workload_load, .codes_workload_get_next = iolang_io_workload_get_next, }; @@ -54,6 +60,29 @@ struct codes_iolang_wrkld_state_per_rank iolang_workload_info task_info; }; + +static void * iolang_io_workload_read_config( + ConfigHandle * handle, + char const * section_name) +{ + iolang_params *p = malloc(sizeof(*p)); + assert(p); + p->num_cns = -1; + p->use_relpath = 1; + p->io_kernel_meta_path[0] = '\0'; + p->io_kernel_path[0] = '\0'; + + int rc = configuration_get_value_relpath(handle, section_name, + "io_kernel_meta_path", NULL, p->io_kernel_meta_path, + MAX_NAME_LENGTH_WKLD); + assert(rc > 0); + rc = configuration_get_value_int(handle, section_name, "num_ranks", NULL, + &p->num_cns); + if (rc != 0) + p->num_cns = -1; + return p; +} + /* loads the workload file for each simulated MPI rank/ compute node LP */ int iolang_io_workload_load(const char* params, int app_id, int rank) { diff --git a/src/workload/methods/codes-recorder-io-wrkld.c b/src/workload/methods/codes-recorder-io-wrkld.c index e74e20c..8fb5953 100644 --- a/src/workload/methods/codes-recorder-io-wrkld.c +++ b/src/workload/methods/codes-recorder-io-wrkld.c @@ -65,6 +65,7 @@ static int hash_file_compare(void *key, struct qhash_head *link); struct codes_workload_method recorder_io_workload_method = { .method_name = "recorder_io_workload", + .codes_workload_read_config = NULL, .codes_workload_load = recorder_io_workload_load, .codes_workload_get_next = recorder_io_workload_get_next, }; diff --git a/src/workload/methods/test-workload-method.c b/src/workload/methods/test-workload-method.c index de0d9d0..005ab58 100644 --- a/src/workload/methods/test-workload-method.c +++ b/src/workload/methods/test-workload-method.c @@ -34,6 +34,7 @@ struct wkload_stream_state* wkload_streams = NULL; struct codes_workload_method test_workload_method = { .method_name = "test", + .codes_workload_read_config = NULL, .codes_workload_load = test_workload_load, .codes_workload_get_next = test_workload_get_next, }; diff --git a/src/workload/scala-trace-data b/src/workload/scala-trace-data deleted file mode 100644 index 97e7cdb6991929c21d4e38cbe69d600cfbb2ca5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 260608 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 -- 2.26.2