stardis-green

Post-processing of green functions
git clone git://git.meso-star.fr/stardis-green.git
Log | Files | Refs | README | LICENSE

commit b6c3be90ff1308480635a97ab68f5aba5ee9d530
parent 1aded4de6c6a195a613d39a1f6b23f5a6ee70c1b
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Fri, 16 Oct 2020 15:13:17 +0200

BugFix: race condition in logging

Diffstat:
Msrc/green-compute.c | 193+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 159 insertions(+), 34 deletions(-)

diff --git a/src/green-compute.c b/src/green-compute.c @@ -22,12 +22,77 @@ #include <rsys/cstr.h> #include <rsys/logger.h> #include <rsys/text_reader.h> +#include <rsys/dynamic_array.h> #include <math.h> #include <string.h> #include <ctype.h> #include <omp.h> +enum log_record_type { + RECORD_INVALID = BIT(0), + RECORD_UNKNOWN = BIT(1), + RECORD_UNUSED = BIT(2), + RECORD_DEFAULT = BIT(3), + RECORD_TYPES_UNDEF__ = BIT(4) +}; + +struct log_record { + enum log_record_type type; + struct str name; + const char* keep_line; + double default_value; +}; + +static FINLINE void +log_record_init + (struct mem_allocator* allocator, + struct log_record* data) +{ + data->type = RECORD_TYPES_UNDEF__; + data->keep_line = NULL; + data->default_value = INF; + str_init(allocator, &data->name); +} + +static FINLINE res_T +log_record_copy + (struct log_record* dst, + struct log_record const* src) +{ + dst->type = src->type; + dst->keep_line = src->keep_line; + dst->default_value = src->default_value; + return str_copy(&dst->name, &src->name); +} + + +static FINLINE res_T +log_record_copy_and_release + (struct log_record* dst, + struct log_record* src) +{ + dst->type = src->type; + dst->keep_line = src->keep_line; + dst->default_value = src->default_value; + return str_copy_and_release(&dst->name, &src->name); +} + +static FINLINE void +log_record_release + (struct log_record* data) +{ + str_release(&data->name); +} + +#define DARRAY_NAME logs +#define DARRAY_DATA struct log_record +#define DARRAY_FUNCTOR_INIT log_record_init +#define DARRAY_FUNCTOR_COPY log_record_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE log_record_copy_and_release +#define DARRAY_FUNCTOR_RELEASE log_record_release +#include <rsys/dynamic_array.h> + void check_green_table_variables_use (struct green* green) @@ -270,33 +335,87 @@ green_compute_1 *STD = (V > 0) ? sqrt(V / (double)green->counts.ok_count) : 0; } +void do_log + (const char* file_name, + struct green* green, + struct darray_logs* logs) +{ + size_t i; + enum log_type log_type = LOG_WARNING; + ASSERT(file_name && green && logs); + + if(darray_logs_size_get(logs) == 0) return; + + FOR_EACH(i, 0, darray_logs_size_get(logs)) { + struct log_record* record = darray_logs_data_get(logs) + i; + if(record->type & (RECORD_INVALID | RECORD_UNKNOWN)) { + log_type = LOG_ERROR; + break; + } + } + logger_print(green->logger, log_type, "In file '%s':\n", file_name); + FOR_EACH(i, 0, darray_logs_size_get(logs)) { + struct log_record* record = darray_logs_data_get(logs) + i; + switch (record->type) { + case RECORD_INVALID: + logger_print(green->logger, LOG_ERROR, + "In line '%s':\n\tInvalid data (missing name)\n", + record->keep_line); + break; + case RECORD_UNKNOWN: + logger_print(green->logger, LOG_ERROR, + "In line '%s':\n\tUnknown variable name: '%s'\n", + record->keep_line, str_cget(&record->name)); + break; + case RECORD_UNUSED: + logger_print(green->logger, LOG_WARNING, + "In line '%s':\n\tAttempt to change unused variable '%s'.\n", + record->keep_line, str_cget(&record->name)); + break; + case RECORD_DEFAULT: + logger_print(green->logger, LOG_WARNING, + "In line '%s':\n\tChange variable '%s' to its default value %g.\n", + record->keep_line, str_cget(&record->name), record->default_value); + break; + default: + FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n"); + } + } +} + static res_T parse_line (const char* file_name, const int64_t idx, struct green* green, - struct applied_settings_elt* settings) + struct applied_settings_elt* settings, + struct darray_logs* logs) { res_T res = RES_OK; - int name_count = 0; + int name_count; struct str name; char* tk = NULL; char* tok_ctx = NULL; - const struct str* keep_line = darray_str_cdata_get(&green->settings) + idx; + const struct str* keep_line; struct str line; - int unused = 0, same = 0; - ASSERT(file_name && green); + keep_line = darray_str_cdata_get(&green->settings) + idx; str_init(green->allocator, &line); str_init(green->allocator, &name); ERR(str_set(&line, str_cget(keep_line))); /* At least one name=value, no name without value */ - for(;;) { + for(name_count = 0; ; name_count++) { struct variable_data* vd; + struct log_record record; double prev; + + if(res != RES_OK) goto error; + + record.keep_line = str_cget(keep_line); /* Just in case */ + tk = strtok_r(name_count ? NULL : str_get(&line), "=", &tok_ctx); if(tk) { char* c; @@ -311,52 +430,54 @@ parse_line if(!tk) { if(name_count == 0) { /* At least 1 name */ - logger_print(green->logger, LOG_ERROR, - "Invalid data (missing name)\n"); + record.type = RECORD_INVALID; + str_init(green->allocator, &record.name); res = RES_BAD_ARG; - goto error; + goto push_record; } else break; } ERR(str_set(&name, tk)); CHK_TOK(strtok_r(NULL, " \t", &tok_ctx), "value"); vd = htable_variable_ptr_find(&green->variable_ptrs, &name); - if(!vd || !vd->used) { - /* Name should exist */ - if(!vd) { - logger_print(green->logger, LOG_ERROR, - "Invalid variable name: '%s'\n", - str_cget(&name)); - res = RES_BAD_ARG; - goto error; - } - logger_print(green->logger, LOG_WARNING, - "Attempt to change unused variable '%s'.\n", str_cget(&name)); - unused = 1; + if(!vd) { + record.type = RECORD_UNKNOWN; + str_init(green->allocator, &record.name); + ERR(str_copy(&record.name, &name)); + res = RES_BAD_ARG; + goto push_record; } + if(!vd->used) { + record.type = RECORD_UNUSED; + str_init(green->allocator, &record.name); + ERR(str_copy(&record.name, &name)); + goto push_record; + } + /* Variable exists and is used in Green function: check if really changed */ prev = ((double*)settings)[vd->idx]; ERR(cstr_to_double(tk, ((double*)settings) + vd->idx)); if(prev == ((double*)settings)[vd->idx]) { - logger_print(green->logger, LOG_WARNING, - "Change variable '%s' to its default value %g.\n", - str_cget(&name), prev); - same = 1; + record.type = RECORD_DEFAULT; + str_init(green->allocator, &record.name); + ERR(str_copy(&record.name, &name)); + record.default_value = prev; + goto push_record; + } + continue; +push_record: + #pragma omp critical + { + res_T tmp_res = darray_logs_push_back(logs, &record); + str_release(&record.name); + if(res == RES_OK) res = tmp_res; } - name_count++; } - if(unused || same) - logger_print(green->logger, LOG_WARNING, - "In file '%s':\n\t%s\n", - file_name, str_cget(keep_line)); end: str_release(&line); str_release(&name); return res; error: - logger_print(green->logger, LOG_ERROR, - "Invalid line in file '%s':\n", file_name); - logger_print(green->logger, LOG_ERROR, "%s\n", str_cget(keep_line)); goto end; } @@ -369,6 +490,7 @@ green_compute size_t sz; int64_t i; struct applied_settings_elt** settings = NULL; + struct darray_logs logs; ASSERT(green && in_name); sz = darray_str_size_get(&green->settings); @@ -379,6 +501,7 @@ green_compute res = RES_MEM_ERR; goto error; } + darray_logs_init(green->allocator, &logs); omp_set_num_threads((int)green->nthreads); #pragma omp parallel for schedule(static) @@ -401,7 +524,7 @@ green_compute /* Apply settings */ applied_settings_set_defaults(green, settings[t]); - tmp_res = parse_line(in_name, i, green, settings[t]); + tmp_res = parse_line(in_name, i, green, settings[t], &logs); if(tmp_res != RES_OK) { res = tmp_res; continue; @@ -412,10 +535,12 @@ green_compute if(res != RES_OK) goto error; exit: + do_log(in_name, green, &logs); if(settings) { FOR_EACH(i, 0, green->nthreads) MEM_RM(green->allocator, settings[i]); MEM_RM(green->allocator, settings); } + darray_logs_release(&logs); return res; error: goto exit;