diff options
| author | chenzizhan <[email protected]> | 2024-07-12 14:02:33 +0800 |
|---|---|---|
| committer | chenzizhan <[email protected]> | 2024-07-12 14:02:33 +0800 |
| commit | 58e206384b2b8e4afb63284f471a64f3b6fe424a (patch) | |
| tree | ce8ddb0a7ed4d716e4828822e76f45255b92016a /src | |
| parent | 5dc3d8a96bb203abc1ee050cd0c884f2ab989dba (diff) | |
register metric to cube
Diffstat (limited to 'src')
| -rw-r--r-- | src/cube.c | 314 | ||||
| -rw-r--r-- | src/cube.h | 27 | ||||
| -rw-r--r-- | src/exporter/cjson_exporter.c | 11 | ||||
| -rw-r--r-- | src/fieldstat.c | 283 | ||||
| -rw-r--r-- | src/fieldstat_easy.c | 16 |
5 files changed, 342 insertions, 309 deletions
@@ -3,6 +3,7 @@ #include <stdlib.h> #include <assert.h> #include <string.h> +#include <stdarg.h> #include "uthash.h" #define XXH_INLINE_ALL @@ -46,7 +47,8 @@ struct cube { struct spread_sketch *spread_sketch; }; size_t max_n_cell; - + struct metric_manifest_manager *manifest_manager; + struct field *cube_dimensions; size_t n_dimensions; @@ -95,20 +97,20 @@ static void fieldstat_free_tag_array(struct field *fields, size_t n_tags) free(fields); } -void add_cube_to_position(struct cube_manager *instance, struct cube *cube, int id) +void add_cube_to_position(struct cube_manager *pthis, struct cube *cube, int id) { - if (id >= instance->cube_size) { - struct cube **old_cube_arr = instance->cube; - instance->cube = calloc(instance->cube_size * 2, sizeof(struct cube *)); - memcpy(instance->cube, old_cube_arr, sizeof(struct cube *) * instance->cube_size); + if (id >= pthis->cube_size) { + struct cube **old_cube_arr = pthis->cube; + pthis->cube = calloc(pthis->cube_size * 2, sizeof(struct cube *)); + memcpy(pthis->cube, old_cube_arr, sizeof(struct cube *) * pthis->cube_size); free(old_cube_arr); - instance->cube_size *= 2; + pthis->cube_size *= 2; } - instance->cube[id] = cube; + pthis->cube[id] = cube; - if (id >= instance->cube_cnt) { - instance->cube_cnt = id + 1; + if (id >= pthis->cube_cnt) { + pthis->cube_cnt = id + 1; } } @@ -356,12 +358,15 @@ void cube_manager_calibrate(struct cube_manager *pthis, const struct cube_manage { struct cube *node_in_master, *node_in_dest, *tmp; - // exist in self but not in master + HASH_ITER(hh, pthis->hash_table, node_in_dest, tmp) { HASH_FIND(hh, master->hash_table, node_in_dest->key, node_in_dest->key_len, node_in_master); - if (node_in_master == NULL) { + if (node_in_master == NULL) { // exist in self but not in master cube_manager_delete(pthis, node_in_dest); + } else { + metric_manifest_manager_free(node_in_dest->manifest_manager); + node_in_dest->manifest_manager = metric_manifest_manager_copy(node_in_master->manifest_manager); } } @@ -373,6 +378,14 @@ void cube_manager_calibrate(struct cube_manager *pthis, const struct cube_manage cube_manager_add(pthis, cube_fork(node_in_master)); } } + + // for (int i = 0; i < pthis->cube_cnt; i++) { + // if (pthis->cube[i] == NULL) { + // continue; + // } + // metric_manifest_manager_free(pthis->cube[i]->manifest_manager); + // pthis->cube[i]->manifest_manager = metric_manifest_manager_copy(master->cube[i]->manifest_manager); + // } } struct cube_manager *cube_manager_fork(const struct cube_manager *src) @@ -386,10 +399,11 @@ struct cube_manager *cube_manager_fork(const struct cube_manager *src) return pthis; } -void cube_manager_merge(struct cube_manager *dest, const struct cube_manager *src) +int cube_manager_merge(struct cube_manager *dest, const struct cube_manager *src) { struct cube *node = NULL; struct cube *tmp = NULL; + int ret = FS_OK; HASH_ITER(hh, src->hash_table, node, tmp) { struct cube *node_in_dest = NULL; HASH_FIND(hh, dest->hash_table, node->key, node->key_len, node_in_dest); @@ -397,9 +411,14 @@ void cube_manager_merge(struct cube_manager *dest, const struct cube_manager *sr if (node_in_dest == NULL) { cube_manager_add(dest, cube_copy(node)); } else { - cube_merge(node_in_dest, node); + int tmp_ret = cube_merge(node_in_dest, node); + if (tmp_ret != FS_OK) { + ret = tmp_ret; + } } } + + return ret; } void cube_manager_reset(struct cube_manager *pthis) @@ -561,6 +580,7 @@ struct cube *cube_info_new(const struct field *dimensions, size_t n_dimensions, struct cube *cube_new(const struct field *dimensions, size_t n_dimensions, enum sampling_mode mode, size_t max_n_cell) { struct cube *cube = cube_info_new(dimensions, n_dimensions, mode, max_n_cell); + cube->manifest_manager = metric_manifest_manager_new(); switch (mode) { @@ -603,6 +623,7 @@ void cube_free(struct cube *cube) { fieldstat_free_tag_array(cube->cube_dimensions, cube->n_dimensions); free(cube->key); + metric_manifest_manager_free(cube->manifest_manager); free(cube); } @@ -630,8 +651,18 @@ void cube_reset(struct cube *cube) { } } -void cube_set_primary_metric(struct cube *cube, int metric_id) { +int cube_set_primary_metric(struct cube *cube, int metric_id) { + const struct metric_manifest *manifest = metric_manifest_manager_get_by_id(cube->manifest_manager, metric_id); + if (manifest == NULL) { + return FS_ERR_INVALID_METRIC_ID; + } + if (cube->sampling_mode == SAMPLING_MODE_COMPREHENSIVE || + (cube->sampling_mode == SAMPLING_MODE_TOPK && manifest->type != METRIC_TYPE_COUNTER) || + (cube->sampling_mode == SAMPLING_MODE_SPREADSKETCH && manifest->type != METRIC_TYPE_HLL)) { + return FS_ERR_INVALID_PARAM; + } cube->primary_metric_id = metric_id; + return FS_OK; } struct cell *get_cell_in_comprehensive_cube(struct cube *cube, const struct field *dimensions, size_t n_dimension) { @@ -754,10 +785,106 @@ struct cell *get_cell_in_spread_sketch_cube(struct cube *cube, const struct fiel return cell_data; } +union metric_parameter *construct_parameters(enum metric_type type, ...) +{ + union metric_parameter *paras = (union metric_parameter *)malloc(sizeof(union metric_parameter)); + va_list ap; + va_start(ap, type); + switch (type) { + case METRIC_TYPE_COUNTER: + break; + case METRIC_TYPE_HLL: + paras->hll.precision = (char)va_arg(ap, int); + break; + case METRIC_TYPE_HISTOGRAM: + paras->hdr.lowest_trackable_value = va_arg(ap, long long); + paras->hdr.highest_trackable_value = va_arg(ap, long long); + paras->hdr.significant_figures = va_arg(ap, int); + break; + default: + assert(0); + } + va_end(ap); + return paras; +} + +int cube_register_counter(struct cube *cube, const char *metric_name) { + struct metric_manifest *metric = malloc(sizeof(struct metric_manifest)); + metric->name = strdup(metric_name); + metric->parameters = construct_parameters(METRIC_TYPE_COUNTER); + metric->type = METRIC_TYPE_COUNTER; + + int id = metric_manifest_manager_add(cube->manifest_manager, metric); + if (id < 0) { + free(metric->name); + free(metric->parameters); + free(metric); + return FS_ERR_INVALID_KEY; + } -int cube_histogram_record(struct cube *cube, const struct metric_manifest *manifest, const struct field *dimensions, size_t n_dimensions, long long value) { - assert(manifest->type == METRIC_TYPE_HISTOGRAM); - assert(cube->sampling_mode == SAMPLING_MODE_COMPREHENSIVE || (cube->primary_metric_id != manifest->id)); + metric->id = id; + return id; +} + +int cube_register_hll(struct cube *cube,const char *metric_name, unsigned char precision) { + if (precision < 4 || precision > 18) { + return FS_ERR_INVALID_PARAM; + } + + struct metric_manifest *metric = malloc(sizeof(struct metric_manifest)); + metric->name = strdup(metric_name); + metric->parameters = construct_parameters(METRIC_TYPE_HLL, precision); + metric->type = METRIC_TYPE_HLL; + + int id = metric_manifest_manager_add(cube->manifest_manager, metric); + if (id < 0) { + free(metric->name); + free(metric->parameters); + free(metric); + return FS_ERR_INVALID_KEY; + } + + metric->id = id; + return id; +} + +int cube_register_hist(struct cube *cube,const char *metric_name, long long lowest_trackable_value, long long highest_trackable_value, int significant_figures) { + // refer to hdr_histogram.h for the rules of parameters. Just copy them here + if (lowest_trackable_value < 1) { + return FS_ERR_INVALID_PARAM; + } + if (significant_figures < 1 || significant_figures > 5) { + return FS_ERR_INVALID_PARAM; + } + if (lowest_trackable_value * 2 > highest_trackable_value) + { + return FS_ERR_INVALID_PARAM; + } + + struct metric_manifest *metric = malloc(sizeof(struct metric_manifest)); + metric->name = strdup(metric_name); + metric->parameters = construct_parameters(METRIC_TYPE_HISTOGRAM, lowest_trackable_value, highest_trackable_value, significant_figures); + metric->type = METRIC_TYPE_HISTOGRAM; + + int id = metric_manifest_manager_add(cube->manifest_manager, metric); + if (id < 0) { + free(metric->name); + free(metric->parameters); + free(metric); + return FS_ERR_INVALID_KEY; + } + metric->id = id; + + return id; +} + +int cube_histogram_record(struct cube *cube, int metric_id, const struct field *dimensions, size_t n_dimensions, long long value) { + assert(cube->sampling_mode == SAMPLING_MODE_COMPREHENSIVE || (cube->primary_metric_id != metric_id)); + + const struct metric_manifest *manifest = metric_manifest_manager_get_by_id(cube->manifest_manager, metric_id); + if (manifest == NULL || manifest->type != METRIC_TYPE_HISTOGRAM) { + return FS_ERR_INVALID_METRIC_ID; + } struct cell *cell_data = NULL; switch (cube->sampling_mode) { @@ -765,10 +892,10 @@ int cube_histogram_record(struct cube *cube, const struct metric_manifest *manif cell_data = get_cell_in_comprehensive_cube(cube, dimensions, n_dimensions); break;} case SAMPLING_MODE_TOPK: { - cell_data = get_cell_in_topk_cube(cube, dimensions, n_dimensions, 0, manifest->id); + cell_data = get_cell_in_topk_cube(cube, dimensions, n_dimensions, 0, metric_id); break;} case SAMPLING_MODE_SPREADSKETCH: { - cell_data = get_cell_in_spread_sketch_cube(cube, dimensions, n_dimensions, 0, manifest->id); + cell_data = get_cell_in_spread_sketch_cube(cube, dimensions, n_dimensions, 0, metric_id); break;} default: assert(0); @@ -787,12 +914,16 @@ int cube_histogram_record(struct cube *cube, const struct metric_manifest *manif return FS_OK; } -int cube_hll_add(struct cube *cube, const struct metric_manifest *manifest, const struct field *dimensions, size_t n_dimensions, const char *key, size_t key_len) { - assert(manifest->type == METRIC_TYPE_HLL); - assert(cube->sampling_mode != SAMPLING_MODE_TOPK || cube->primary_metric_id != manifest->id); +int cube_hll_add(struct cube *cube, int metric_id, const struct field *dimensions, size_t n_dimensions, const char *key, size_t key_len) { + assert(cube->sampling_mode != SAMPLING_MODE_TOPK || cube->primary_metric_id != metric_id); + + const struct metric_manifest *manifest = metric_manifest_manager_get_by_id(cube->manifest_manager, metric_id); + if (manifest == NULL || manifest->type != METRIC_TYPE_HLL) { + return FS_ERR_INVALID_METRIC_ID; + } uint64_t hash = 0; // just any value, if we do not need to update the primary metric of spread sketch cube, hash value is not used - if (cube->sampling_mode == SAMPLING_MODE_SPREADSKETCH && cube->primary_metric_id == manifest->id) { + if (cube->sampling_mode == SAMPLING_MODE_SPREADSKETCH && cube->primary_metric_id == metric_id) { hash = XXH3_64bits(key, key_len); } struct cell *cell_data = NULL; @@ -801,10 +932,10 @@ int cube_hll_add(struct cube *cube, const struct metric_manifest *manifest, cons cell_data = get_cell_in_comprehensive_cube(cube, dimensions, n_dimensions); break;} case SAMPLING_MODE_TOPK: { - cell_data = get_cell_in_topk_cube(cube, dimensions, n_dimensions, 0, manifest->id); + cell_data = get_cell_in_topk_cube(cube, dimensions, n_dimensions, 0, metric_id); break;} case SAMPLING_MODE_SPREADSKETCH: { - cell_data = get_cell_in_spread_sketch_cube(cube, dimensions, n_dimensions, hash, manifest->id); + cell_data = get_cell_in_spread_sketch_cube(cube, dimensions, n_dimensions, hash, metric_id); break;} default: assert(0); @@ -835,13 +966,16 @@ uint64_t field_array_to_hash(const struct field *field, size_t n_dimensions) { return XXH3_64bits_digest(&state); } -int cube_hll_add_field(struct cube *cube, const struct metric_manifest *manifest, const struct field *dimensions, size_t n_dimensions, const struct field *tags_key, size_t n_tag_key) +int cube_hll_add_field(struct cube *cube, int metric_id, const struct field *dimensions, size_t n_dimensions, const struct field *tags_key, size_t n_tag_key) { - assert(manifest->type == METRIC_TYPE_HLL); - assert(cube->sampling_mode != SAMPLING_MODE_TOPK || (cube->primary_metric_id != manifest->id)); + assert(cube->sampling_mode != SAMPLING_MODE_TOPK || (cube->primary_metric_id != metric_id)); + const struct metric_manifest *manifest = metric_manifest_manager_get_by_id(cube->manifest_manager, metric_id); + if (manifest == NULL || manifest->type != METRIC_TYPE_HLL) { + return FS_ERR_INVALID_METRIC_ID; + } uint64_t hash = 0; // just any value, if we do not need to update the primary metric of spread sketch cube, hash value is not used - if (cube->sampling_mode == SAMPLING_MODE_SPREADSKETCH && cube->primary_metric_id == manifest->id) { + if (cube->sampling_mode == SAMPLING_MODE_SPREADSKETCH && cube->primary_metric_id == metric_id) { hash = field_array_to_hash(tags_key, n_tag_key); } struct cell *cell_data = NULL; @@ -850,10 +984,10 @@ int cube_hll_add_field(struct cube *cube, const struct metric_manifest *manifest cell_data = get_cell_in_comprehensive_cube(cube, dimensions, n_dimensions); break;} case SAMPLING_MODE_TOPK: { - cell_data = get_cell_in_topk_cube(cube, dimensions, n_dimensions, 0, manifest->id); + cell_data = get_cell_in_topk_cube(cube, dimensions, n_dimensions, 0, metric_id); break;} case SAMPLING_MODE_SPREADSKETCH: { - cell_data = get_cell_in_spread_sketch_cube(cube, dimensions, n_dimensions, hash, manifest->id); + cell_data = get_cell_in_spread_sketch_cube(cube, dimensions, n_dimensions, hash, metric_id); break;} default: assert(0); @@ -871,23 +1005,27 @@ int cube_hll_add_field(struct cube *cube, const struct metric_manifest *manifest return FS_OK; } -int cube_counter_incrby(struct cube *cube, const struct metric_manifest *manifest, const struct field *dimensions, size_t n_dimensions, long long increment) { - assert(manifest->type == METRIC_TYPE_COUNTER); +int cube_counter_incrby(struct cube *cube, int metric_id, const struct field *dimensions, size_t n_dimensions, long long increment) { assert(cube->sampling_mode == SAMPLING_MODE_COMPREHENSIVE || - (cube->sampling_mode == SAMPLING_MODE_TOPK && (cube->primary_metric_id != manifest->id || increment >= 0)) || - (cube->sampling_mode == SAMPLING_MODE_SPREADSKETCH && cube->primary_metric_id != manifest->id) + (cube->sampling_mode == SAMPLING_MODE_TOPK && (cube->primary_metric_id != metric_id || increment >= 0)) || + (cube->sampling_mode == SAMPLING_MODE_SPREADSKETCH && cube->primary_metric_id != metric_id) ); + const struct metric_manifest *manifest = metric_manifest_manager_get_by_id(cube->manifest_manager, metric_id); + if (manifest == NULL || manifest->type != METRIC_TYPE_COUNTER) { + return FS_ERR_INVALID_METRIC_ID; + } + struct cell *cell_data = NULL; switch (cube->sampling_mode) { case SAMPLING_MODE_COMPREHENSIVE: { cell_data = get_cell_in_comprehensive_cube(cube, dimensions, n_dimensions); break;} case SAMPLING_MODE_TOPK: { - cell_data = get_cell_in_topk_cube(cube, dimensions, n_dimensions, increment, manifest->id); + cell_data = get_cell_in_topk_cube(cube, dimensions, n_dimensions, increment, metric_id); break;} case SAMPLING_MODE_SPREADSKETCH: { - cell_data = get_cell_in_spread_sketch_cube(cube, dimensions, n_dimensions, 0, manifest->id); + cell_data = get_cell_in_spread_sketch_cube(cube, dimensions, n_dimensions, 0, metric_id); break;} default: assert(0); @@ -904,9 +1042,13 @@ int cube_counter_incrby(struct cube *cube, const struct metric_manifest *manifes return FS_OK; } -int cube_counter_set(struct cube *cube, const struct metric_manifest *manifest, const struct field *dimensions, size_t n_dimensions, long long value) { - assert(manifest->type == METRIC_TYPE_COUNTER); - assert(cube->sampling_mode == SAMPLING_MODE_COMPREHENSIVE || (cube->primary_metric_id != manifest->id)); +int cube_counter_set(struct cube *cube, int metric_id, const struct field *dimensions, size_t n_dimensions, long long value) { + assert(cube->sampling_mode == SAMPLING_MODE_COMPREHENSIVE || (cube->primary_metric_id != metric_id)); + + const struct metric_manifest *manifest = metric_manifest_manager_get_by_id(cube->manifest_manager, metric_id); + if (manifest == NULL || manifest->type != METRIC_TYPE_COUNTER) { + return FS_ERR_INVALID_METRIC_ID; + } struct cell *cell_data = NULL; switch (cube->sampling_mode) { @@ -914,10 +1056,10 @@ int cube_counter_set(struct cube *cube, const struct metric_manifest *manifest, cell_data = get_cell_in_comprehensive_cube(cube, dimensions, n_dimensions); break;} case SAMPLING_MODE_TOPK: { - cell_data = get_cell_in_topk_cube(cube, dimensions, n_dimensions, 0, manifest->id); + cell_data = get_cell_in_topk_cube(cube, dimensions, n_dimensions, 0, metric_id); break;} case SAMPLING_MODE_SPREADSKETCH: { - cell_data = get_cell_in_spread_sketch_cube(cube, dimensions, n_dimensions, 0, manifest->id); + cell_data = get_cell_in_spread_sketch_cube(cube, dimensions, n_dimensions, 0, metric_id); break;} default: assert(0); @@ -953,12 +1095,33 @@ struct cube *cube_copy(const struct cube *cube) break; } + cube_dup->manifest_manager = metric_manifest_manager_copy(cube->manifest_manager); + return cube_dup; } -void cube_merge(struct cube *dest, const struct cube *src) +int cube_merge(struct cube *dest, const struct cube *src) { - assert(dest->sampling_mode == src->sampling_mode); + if (dest->sampling_mode != src->sampling_mode) { + return FS_ERR_INVALID_PARAM; + } + + size_t n_metric_src = 0; + const struct metric_manifest **list_src = metric_manifest_manager_list(src->manifest_manager, &n_metric_src); + size_t n_metric_dst = 0; + const struct metric_manifest **list_dst = metric_manifest_manager_list(dest->manifest_manager, &n_metric_dst); + int len_min = n_metric_src < n_metric_dst ? n_metric_src : n_metric_dst; + for (int i = 0; i < len_min; i++) { + if (list_src[i]->type != list_dst[i]->type) { + return FS_ERR_INVALID_PARAM; + } + if (strcmp(list_src[i]->name, list_dst[i]->name) != 0) { + return FS_ERR_INVALID_PARAM; + } + } + for (int i = n_metric_dst; i < n_metric_src; i++) { + metric_manifest_manager_add(dest->manifest_manager, metric_manifest_copy(list_src[i])); + } switch (dest->sampling_mode) { @@ -975,15 +1138,39 @@ void cube_merge(struct cube *dest, const struct cube *src) assert(0); break; } + + return FS_OK; } struct cube *cube_fork(const struct cube *cube) { - struct cube *ret = cube_new(cube->cube_dimensions, cube->n_dimensions, cube->sampling_mode, cube->max_n_cell); + struct cube *ret = cube_info_new(cube->cube_dimensions, cube->n_dimensions, cube->sampling_mode, cube->max_n_cell); ret->primary_metric_id = cube->primary_metric_id; + ret->manifest_manager = metric_manifest_manager_copy(cube->manifest_manager); + switch (cube->sampling_mode) { + case SAMPLING_MODE_TOPK: + ret->topk = heavy_keeper_new(cube->max_n_cell); + heavy_keeper_set_exdata_schema(ret->topk, exdata_new_i, exdata_free_i, exdata_merge_i, exdata_reset_i, exdata_copy_i); + break; + case SAMPLING_MODE_COMPREHENSIVE: + ret->comprehensive = hash_table_new(cube->max_n_cell); + hash_table_set_exdata_schema(ret->comprehensive, exdata_new_i, exdata_free_i, exdata_merge_i, exdata_reset_i, exdata_copy_i); + break; + case SAMPLING_MODE_SPREADSKETCH: + ret->spread_sketch = spread_sketch_new(cube->max_n_cell); + spread_sketch_set_exdata_schema(ret->spread_sketch, exdata_new_i, exdata_free_i, exdata_merge_i, exdata_reset_i, exdata_copy_i); + break; + default: + assert(0); + break; + } return ret; } +/* -------------------------------------------------------------------------- */ +/* query */ +/* -------------------------------------------------------------------------- */ + struct tmp_sorted_data_spread_sketch_cell { double hll_value; struct cell *data; @@ -1236,6 +1423,37 @@ struct field_list *cube_get_identifier(const struct cube *cube) { return tag_list; } -enum sampling_mode cube_get_sampling_mode(const struct cube *cube) { - return cube->sampling_mode; +const char *cube_get_metric_name(const struct cube *cube, int metric_id) { + const struct metric_manifest *metric = metric_manifest_manager_get_by_id(cube->manifest_manager, metric_id); + if (metric == NULL) { + printf("metric is null\n"); + return NULL; + } + + return metric->name; +} + +enum metric_type cube_get_metric_type(const struct cube *cube, int metric_id) { + const struct metric_manifest *metric = metric_manifest_manager_get_by_id(cube->manifest_manager, metric_id); + if (metric == NULL) { + return (enum metric_type)(-1); + } + + return metric->type; +} + +void cube_get_metrics(const struct cube *cube, int **metric_id_out, size_t *n_metric) +{ + const struct metric_manifest **list = metric_manifest_manager_list(cube->manifest_manager, n_metric); + if (*n_metric == 0) { + *metric_id_out = NULL; + return; + } + + int *tmp_ids = (int *)malloc(sizeof(int) * (*n_metric)); + *metric_id_out = tmp_ids; + + for (int i = 0; i < *n_metric; i++) { + tmp_ids[i] = list[i]->id; + } } @@ -17,15 +17,20 @@ struct cube *cube_new(const struct field *dimensions, size_t n_dimensions, enum void cube_free(struct cube *cube); void cube_reset(struct cube *cube); struct cube *cube_copy(const struct cube *cube); -void cube_merge(struct cube *dest, const struct cube *src); +int cube_merge(struct cube *dest, const struct cube *src); struct cube *cube_fork(const struct cube *cube); // only copy the cube configurations, leave the cells empty -int cube_histogram_record(struct cube *cube, const struct metric_manifest *manifest, const struct field *dimensions, size_t n_dimensions, long long value); -int cube_hll_add(struct cube *cube, const struct metric_manifest *manifest, const struct field *dimensions, size_t n_dimensions, const char *key, size_t key_len); -int cube_hll_add_field(struct cube *cube, const struct metric_manifest *manifest, const struct field *dimensions, size_t n_dimensions, const struct field *tags_key, size_t n_tag_key); -int cube_counter_incrby(struct cube *cube, const struct metric_manifest *manifest, const struct field *dimensions, size_t n_dimensions, long long increment); -int cube_counter_set(struct cube *cube, const struct metric_manifest *manifest, const struct field *dimensions, size_t n_dimensions, long long value); +int cube_register_counter(struct cube *cube, const char *metric_name); +int cube_register_hll(struct cube *cube,const char *metric_name, unsigned char precision); +int cube_register_hist(struct cube *cube,const char *metric_name, long long lowest_trackable_value, long long highest_trackable_value, int significant_figures); +int cube_histogram_record(struct cube *cube, int metric_id, const struct field *dimensions, size_t n_dimensions, long long value); +int cube_hll_add(struct cube *cube, int metric_id, const struct field *dimensions, size_t n_dimensions, const char *key, size_t key_len); +int cube_hll_add_field(struct cube *cube, int metric_id, const struct field *dimensions, size_t n_dimensions, const struct field *tags_key, size_t n_tag_key); +int cube_counter_incrby(struct cube *cube, int metric_id, const struct field *dimensions, size_t n_dimensions, long long increment); +int cube_counter_set(struct cube *cube, int metric_id, const struct field *dimensions, size_t n_dimensions, long long value); + +/* ---------------------------------- query --------------------------------- */ int cube_counter_get(const struct cube *cube, int metric_id, const struct field_list *dimensions, long long *value); int cube_hll_get(const struct cube *cube, int metric_id, const struct field_list *dimensions, double *value); int cube_histogram_value_at_percentile(const struct cube *cube, int metric_id, const struct field_list *dimensions, double percentile, long long *value); @@ -35,10 +40,16 @@ int cube_get_serialization(const struct cube *cube, int metric_id, const struct int cube_get_cell_count(const struct cube *cube); enum sampling_mode cube_get_sampling_mode(const struct cube *cube); void cube_get_cells(const struct cube *cube, struct field_list **tag_list, size_t *n_cell); +void cube_get_metrics(const struct cube *cube, int **metric_id_out, size_t *n_metric); void cube_get_metrics_in_cell(const struct cube *cube, const struct field_list *dimensions, int **metric_id_out, size_t *n_metric_out); -void cube_set_primary_metric(struct cube *cube, int metric_id); +int cube_set_primary_metric(struct cube *cube, int metric_id); struct field_list *cube_get_identifier(const struct cube *cube); +const char *cube_get_metric_name(const struct cube *cube, int metric_id); +enum metric_type cube_get_metric_type(const struct cube *cube, int metric_id); +/* -------------------------------------------------------------------------- */ +/* cube manager */ +/* -------------------------------------------------------------------------- */ struct cube *cube_manager_get_cube_by_id(const struct cube_manager *manager, int cube_id); // the cube will be taken over by the manager, user do not free it. @@ -47,7 +58,7 @@ void cube_manager_delete(struct cube_manager *pthis, struct cube *cube); // the int cube_manager_find(const struct cube_manager *pthis, const struct field *cube_dimensions, size_t n_dimensions); struct cube_manager *cube_manager_new(); void cube_manager_free(struct cube_manager *pthis); -void cube_manager_merge(struct cube_manager *dest, const struct cube_manager *src); +int cube_manager_merge(struct cube_manager *dest, const struct cube_manager *src); void cube_manager_reset(struct cube_manager *pthis); void cube_manager_calibrate(struct cube_manager *pthis, const struct cube_manager *master); diff --git a/src/exporter/cjson_exporter.c b/src/exporter/cjson_exporter.c index 9466f01..3fecf40 100644 --- a/src/exporter/cjson_exporter.c +++ b/src/exporter/cjson_exporter.c @@ -524,16 +524,17 @@ int cell_iter_next(struct cell_iter *iter) { /* -------------------------------------------------------------------------- */ struct export_kv_pair *cell_query_with_iter(const struct cell_iter *iter, int metric_id) { - enum metric_type type = fieldstat_get_metric_type(iter->instance, metric_id); + int cube_id = iter->cube_ids[iter->curr_cube_idx]; + enum metric_type type = fieldstat_get_metric_type(iter->instance, cube_id, metric_id); struct export_kv_pair *ret = NULL; if (type == METRIC_TYPE_COUNTER) { long long value; - int tmp_ret = fieldstat_counter_get(iter->instance, iter->cube_ids[iter->curr_cube_idx], &iter->tag_list[iter->curr_cell_idx], metric_id, &value); + int tmp_ret = fieldstat_counter_get(iter->instance, cube_id, &iter->tag_list[iter->curr_cell_idx], metric_id, &value); if (tmp_ret < 0) { return NULL; } ret = malloc(sizeof(struct export_kv_pair)); - ret->key = strdup(fieldstat_get_metric_name(iter->instance, metric_id)); + ret->key = strdup(fieldstat_get_metric_name(iter->instance, cube_id, metric_id)); ret->type = TAG_INTEGER; ret->value_longlong = value; return ret; @@ -541,12 +542,12 @@ struct export_kv_pair *cell_query_with_iter(const struct cell_iter *iter, int me if (type == METRIC_TYPE_HLL || type == METRIC_TYPE_HISTOGRAM) { char *value; size_t len; - fieldstat_get_serialized_blob(iter->instance, iter->cube_ids[iter->curr_cube_idx], metric_id, &iter->tag_list[iter->curr_cell_idx], &value, &len); + fieldstat_get_serialized_blob(iter->instance, cube_id, metric_id, &iter->tag_list[iter->curr_cell_idx], &value, &len); if (value == NULL) { return NULL; } ret = malloc(sizeof(struct export_kv_pair)); - ret->key = strdup(fieldstat_get_metric_name(iter->instance, metric_id)); + ret->key = strdup(fieldstat_get_metric_name(iter->instance, cube_id, metric_id)); ret->type = TAG_CSTRING; ret->value_str = value; return ret; diff --git a/src/fieldstat.c b/src/fieldstat.c index b847bd5..0e2fb81 100644 --- a/src/fieldstat.c +++ b/src/fieldstat.c @@ -3,7 +3,6 @@ #include <assert.h> #include <stdlib.h> #include <stdio.h> -#include <stdarg.h> #include "cjson/cJSON.h" #include "uthash.h" @@ -11,92 +10,11 @@ #include "fieldstat.h" #include "metrics/metric.h" #include "cube.h" -#include "metric_manifest.h" - struct fieldstat { - struct metric_manifest_manager *manifest_manager; - struct cube_manager *cube_manager; }; -union metric_parameter *construct_parameters(enum metric_type type, ...) -{ - union metric_parameter *paras = (union metric_parameter *)malloc(sizeof(union metric_parameter)); - va_list ap; - va_start(ap, type); - switch (type) { - case METRIC_TYPE_COUNTER: - break; - case METRIC_TYPE_HLL: - paras->hll.precision = (char)va_arg(ap, int); - break; - case METRIC_TYPE_HISTOGRAM: - paras->hdr.lowest_trackable_value = va_arg(ap, long long); - paras->hdr.highest_trackable_value = va_arg(ap, long long); - paras->hdr.significant_figures = va_arg(ap, int); - break; - default: - assert(0); - } - va_end(ap); - return paras; -} - -void tag_array_copy(struct field *tags_dst, const struct field *tags_src, size_t n_field) -{ - for (size_t i = 0; i < n_field; i++) { - tags_dst[i].key = strdup(tags_src[i].key); - tags_dst[i].type = tags_src[i].type; - switch (tags_src[i].type) - { - case TAG_INTEGER: - tags_dst[i].value_longlong = tags_src[i].value_longlong; - break; - case TAG_CSTRING: - tags_dst[i].value_str = strdup(tags_src[i].value_str); - break; - case TAG_DOUBLE: - tags_dst[i].value_double = tags_src[i].value_double; - break; - default: - break; - } - } -} - -bool is_tag_array_same(const struct field *tags1, const struct field *tags2, size_t n_field) -{ - for (size_t i = 0; i < n_field; i++) { - if (tags1[i].type != tags2[i].type) { - return false; - } - if (strcmp(tags1[i].key, tags2[i].key) != 0) { - return false; - } - switch (tags1[i].type) - { - case TAG_INTEGER: - if (tags1[i].value_longlong != tags2[i].value_longlong) { - return false; - } - break; - case TAG_CSTRING: - if (strcmp(tags1[i].value_str, tags2[i].value_str) != 0) { - return false; - } - break; - case TAG_DOUBLE: - if (tags1[i].value_double != tags2[i].value_double) { - return false; - } - break; - default: - break; - } - } - return 0; -} /* -------------------------------------------------------------------------- */ /* fieldstat */ @@ -106,8 +24,6 @@ struct fieldstat *fieldstat_new() { struct fieldstat *instance = calloc(1, sizeof(struct fieldstat)); - instance->manifest_manager = metric_manifest_manager_new(); - instance->cube_manager = cube_manager_new(); return instance; @@ -121,8 +37,6 @@ void fieldstat_free(struct fieldstat *instance) cube_manager_free(instance->cube_manager); - metric_manifest_manager_free(instance->manifest_manager); - free(instance); } @@ -200,96 +114,41 @@ int fieldstat_cube_set_primary_metric(struct fieldstat *instance, int cube_id, i if (cube == NULL) { return FS_ERR_INVALID_CUBE_ID; } - const struct metric_manifest *manifest = metric_manifest_manager_get_by_id(instance->manifest_manager, metric_id); - if (manifest == NULL) { - return FS_ERR_INVALID_METRIC_ID; - } - if (cube_get_sampling_mode(cube) == SAMPLING_MODE_COMPREHENSIVE || - (cube_get_sampling_mode(cube) == SAMPLING_MODE_TOPK && manifest->type != METRIC_TYPE_COUNTER) || - (cube_get_sampling_mode(cube) == SAMPLING_MODE_SPREADSKETCH && manifest->type != METRIC_TYPE_HLL)) { - return FS_ERR_INVALID_PARAM; - } - - cube_set_primary_metric(cube, metric_id); - - return FS_OK; + + return cube_set_primary_metric(cube, metric_id); } /* -------------------------------------------------------------------------- */ /* metric register */ /* -------------------------------------------------------------------------- */ -int fieldstat_register_counter(struct fieldstat *instance, const char *metric_name) -{ - struct metric_manifest *metric = malloc(sizeof(struct metric_manifest)); - metric->name = strdup(metric_name); - metric->parameters = construct_parameters(METRIC_TYPE_COUNTER); - metric->type = METRIC_TYPE_COUNTER; - - int id = metric_manifest_manager_add(instance->manifest_manager, metric); - if (id < 0) { - free(metric->name); - free(metric->parameters); - free(metric); - return FS_ERR_INVALID_KEY; +// cppcheck-suppress [constParameterPointer, unmatchedSuppression] +int fieldstat_register_counter(struct fieldstat *instance, int cube_id, const char *metric_name) +{ + struct cube *cube = cube_manager_get_cube_by_id(instance->cube_manager, cube_id); + if (cube == NULL) { + return FS_ERR_INVALID_CUBE_ID; } - - metric->id = id; - return id; + return cube_register_counter(cube, metric_name); } -int fieldstat_register_hll(struct fieldstat *instance, const char *metric_name, unsigned char precision) +// cppcheck-suppress [constParameterPointer, unmatchedSuppression] +int fieldstat_register_hll(struct fieldstat *instance, int cube_id, const char *metric_name, unsigned char precision) { - if (precision < 4 || precision > 18) { - return FS_ERR_INVALID_PARAM; - } - - struct metric_manifest *metric = malloc(sizeof(struct metric_manifest)); - metric->name = strdup(metric_name); - metric->parameters = construct_parameters(METRIC_TYPE_HLL, precision); - metric->type = METRIC_TYPE_HLL; - - int id = metric_manifest_manager_add(instance->manifest_manager, metric); - if (id < 0) { - free(metric->name); - free(metric->parameters); - free(metric); - return FS_ERR_INVALID_KEY; + struct cube *cube = cube_manager_get_cube_by_id(instance->cube_manager, cube_id); + if (cube == NULL) { + return FS_ERR_INVALID_CUBE_ID; } - - metric->id = id; - return id; + return cube_register_hll(cube, metric_name, precision); } -int fieldstat_register_hist(struct fieldstat *instance, const char *metric_name, long long lowest_trackable_value, long long highest_trackable_value, int significant_figures) +// cppcheck-suppress [constParameterPointer, unmatchedSuppression] +int fieldstat_register_hist(struct fieldstat *instance, int cube_id, const char *metric_name, long long lowest_trackable_value, long long highest_trackable_value, int significant_figures) { - // refer to hdr_histogram.h for the rules of parameters. Just copy them here - if (lowest_trackable_value < 1) { - return FS_ERR_INVALID_PARAM; - } - if (significant_figures < 1 || significant_figures > 5) { - return FS_ERR_INVALID_PARAM; - } - if (lowest_trackable_value * 2 > highest_trackable_value) - { - return FS_ERR_INVALID_PARAM; - } - - - struct metric_manifest *metric = malloc(sizeof(struct metric_manifest)); - metric->name = strdup(metric_name); - metric->parameters = construct_parameters(METRIC_TYPE_HISTOGRAM, lowest_trackable_value, highest_trackable_value, significant_figures); - metric->type = METRIC_TYPE_HISTOGRAM; - - int id = metric_manifest_manager_add(instance->manifest_manager, metric); - if (id < 0) { - free(metric->name); - free(metric->parameters); - free(metric); - return FS_ERR_INVALID_KEY; + struct cube *cube = cube_manager_get_cube_by_id(instance->cube_manager, cube_id); + if (cube == NULL) { + return FS_ERR_INVALID_CUBE_ID; } - metric->id = id; - - return id; + return cube_register_hist(cube, metric_name, lowest_trackable_value, highest_trackable_value, significant_figures); } /* -------------------------------------------------------------------------- */ @@ -303,12 +162,8 @@ int fieldstat_counter_incrby(struct fieldstat *instance, int cube_id, int metric if (cube == NULL) { return FS_ERR_INVALID_CUBE_ID; } - const struct metric_manifest *manifest = metric_manifest_manager_get_by_id(instance->manifest_manager, metric_id); - if (manifest == NULL || manifest->type != METRIC_TYPE_COUNTER) { - return FS_ERR_INVALID_METRIC_ID; - } - - return cube_counter_incrby(cube, manifest, cell_dimensions, n_dimensions, increment); + + return cube_counter_incrby(cube, metric_id, cell_dimensions, n_dimensions, increment); } // cppcheck-suppress [constParameterPointer, unmatchedSuppression] @@ -318,12 +173,8 @@ int fieldstat_counter_set(struct fieldstat *instance, int cube_id, int metric_id if (cube == NULL) { return FS_ERR_INVALID_CUBE_ID; } - const struct metric_manifest *manifest = metric_manifest_manager_get_by_id(instance->manifest_manager, metric_id); - if (manifest == NULL || manifest->type != METRIC_TYPE_COUNTER) { - return FS_ERR_INVALID_METRIC_ID; - } - return cube_counter_set(cube, manifest, cell_dimensions, n_dimensions, value); + return cube_counter_set(cube, metric_id, cell_dimensions, n_dimensions, value); } // cppcheck-suppress [constParameterPointer, unmatchedSuppression] @@ -333,12 +184,8 @@ int fieldstat_hll_add(struct fieldstat *instance, int cube_id, int metric_id, co if (cube == NULL) { return FS_ERR_INVALID_CUBE_ID; } - const struct metric_manifest *manifest = metric_manifest_manager_get_by_id(instance->manifest_manager, metric_id); - if (manifest == NULL || manifest->type != METRIC_TYPE_HLL) { - return FS_ERR_INVALID_METRIC_ID; - } - return cube_hll_add(cube, manifest, cell_dimensions, n_dimensions, key, key_len); + return cube_hll_add(cube, metric_id, cell_dimensions, n_dimensions, key, key_len); } // cppcheck-suppress [constParameterPointer, unmatchedSuppression] @@ -348,12 +195,8 @@ int fieldstat_hll_add_field(struct fieldstat *instance, int cube_id, int metric_ if (cube == NULL) { return FS_ERR_INVALID_CUBE_ID; } - const struct metric_manifest *manifest = metric_manifest_manager_get_by_id(instance->manifest_manager, metric_id); - if (manifest == NULL || manifest->type != METRIC_TYPE_HLL) { - return FS_ERR_INVALID_METRIC_ID; - } - return cube_hll_add_field(cube, manifest, cell_dimensions, n_dimensions, item, item_len); + return cube_hll_add_field(cube, metric_id, cell_dimensions, n_dimensions, item, item_len); } // cppcheck-suppress [constParameterPointer, unmatchedSuppression] @@ -363,12 +206,8 @@ int fieldstat_hist_record(struct fieldstat *instance, int cube_id, int metric_id if (cube == NULL) { return FS_ERR_INVALID_CUBE_ID; } - const struct metric_manifest *manifest = metric_manifest_manager_get_by_id(instance->manifest_manager, metric_id); - if (manifest == NULL || manifest->type != METRIC_TYPE_HISTOGRAM) { - return FS_ERR_INVALID_METRIC_ID; - } - return cube_histogram_record(cube, manifest, cell_dimensions, n_dimensions, value); + return cube_histogram_record(cube, metric_id, cell_dimensions, n_dimensions, value); } int fieldstat_merge(struct fieldstat *instance, const struct fieldstat *src) @@ -377,27 +216,7 @@ int fieldstat_merge(struct fieldstat *instance, const struct fieldstat *src) return FS_ERR_NULL_HANDLER; } - size_t n_metric_src = 0; - const struct metric_manifest **list_src = metric_manifest_manager_list(src->manifest_manager, &n_metric_src); - size_t n_metric_dst = 0; - const struct metric_manifest **list_dst = metric_manifest_manager_list(instance->manifest_manager, &n_metric_dst); - int len_min = n_metric_src < n_metric_dst ? n_metric_src : n_metric_dst; - for (int i = 0; i < len_min; i++) { - if (list_src[i]->type != list_dst[i]->type) { - return FS_ERR_INVALID_PARAM; - } - if (strcmp(list_src[i]->name, list_dst[i]->name) != 0) { - return FS_ERR_INVALID_PARAM; - } - } - for (int i = n_metric_dst; i < n_metric_src; i++) { - metric_manifest_manager_add(instance->manifest_manager, metric_manifest_copy(list_src[i])); - } - - - cube_manager_merge(instance->cube_manager, src->cube_manager); - - return FS_OK; + return cube_manager_merge(instance->cube_manager, src->cube_manager); } struct fieldstat *fieldstat_fork(const struct fieldstat *instance) @@ -408,16 +227,12 @@ struct fieldstat *fieldstat_fork(const struct fieldstat *instance) struct fieldstat *new_instance = calloc(1, sizeof(struct fieldstat)); new_instance->cube_manager = cube_manager_fork(instance->cube_manager); - new_instance->manifest_manager = metric_manifest_manager_copy(instance->manifest_manager); - return new_instance; } int fieldstat_calibrate(const struct fieldstat *master, struct fieldstat *replica) { cube_manager_calibrate(replica->cube_manager, master->cube_manager); - metric_manifest_manager_free(replica->manifest_manager); - replica->manifest_manager = metric_manifest_manager_copy(master->manifest_manager); return FS_OK; } @@ -430,22 +245,6 @@ void fieldstat_get_cubes(const struct fieldstat *instance, int **cube_ids, int * cube_manager_list(instance->cube_manager, cube_ids, n_cube); } -void fieldstat_get_metrics(const struct fieldstat *instance, int **metric_id_out, size_t *n_metric) -{ - const struct metric_manifest **list = metric_manifest_manager_list(instance->manifest_manager, n_metric); - if (*n_metric == 0) { - *metric_id_out = NULL; - return; - } - - int *tmp_ids = (int *)malloc(sizeof(int) * (*n_metric)); - *metric_id_out = tmp_ids; - - for (int i = 0; i < *n_metric; i++) { - tmp_ids[i] = list[i]->id; - } -} - struct field_list *fieldstat_cube_get_tags(const struct fieldstat *instance, int cube_id) { const struct cube *cube = cube_manager_get_cube_by_id(instance->cube_manager, cube_id); @@ -530,24 +329,23 @@ void fieldstat_tag_list_arr_free(struct field_list *tag_list, size_t n_cell) free(tag_list); } -const char *fieldstat_get_metric_name(const struct fieldstat *instance, int metric_id) +const char *fieldstat_get_metric_name(const struct fieldstat *instance, int cube_id, int metric_id) { - const struct metric_manifest *metric = metric_manifest_manager_get_by_id(instance->manifest_manager, metric_id); - if (metric == NULL) { + const struct cube *cube = cube_manager_get_cube_by_id(instance->cube_manager, cube_id); + if (cube == NULL) { + printf("cube is NULL\n"); return NULL; } - - return metric->name; + return cube_get_metric_name(cube, metric_id); } -enum metric_type fieldstat_get_metric_type(const struct fieldstat *instance, int metric_id) +enum metric_type fieldstat_get_metric_type(const struct fieldstat *instance, int cube_id, int metric_id) { - const struct metric_manifest *metric = metric_manifest_manager_get_by_id(instance->manifest_manager, metric_id); - if (metric == NULL) { + const struct cube *cube = cube_manager_get_cube_by_id(instance->cube_manager, cube_id); + if (cube == NULL) { return (enum metric_type)(-1); } - - return metric->type; + return cube_get_metric_type(cube, metric_id); } void fieldstat_cube_get_cells(const struct fieldstat *instance, int cube_id, struct field_list **cell_dimensions, size_t *n_cell) @@ -592,4 +390,9 @@ void fieldstat_get_metric_in_cell(const struct fieldstat *instance, int cube_id, { const struct cube *cube = cube_manager_get_cube_by_id(instance->cube_manager, cube_id); return cube_get_metrics_in_cell(cube, cell_dimensions, metric_id_out, n_metric_out); -}
\ No newline at end of file +} + +void fieldstat_cube_get_metrics(const struct fieldstat *instance, int cube_id, int **metric_id_out, size_t *n_metric) { + const struct cube *cube = cube_manager_get_cube_by_id(instance->cube_manager, cube_id); + cube_get_metrics(cube, metric_id_out, n_metric); +} diff --git a/src/fieldstat_easy.c b/src/fieldstat_easy.c index b5f811c..ef1a921 100644 --- a/src/fieldstat_easy.c +++ b/src/fieldstat_easy.c @@ -192,17 +192,17 @@ int fieldstat_easy_register_counter(struct fieldstat_easy *fse, const char *name pthread_spin_lock(&fse->fsu[i].lock); } - int ret = fieldstat_register_counter(fse->fsu[0].active, name); // try to register + int ret = fieldstat_register_counter(fse->fsu[0].active, 0, name); // try to register if (ret < 0) { for (int i = 0; i < fse->max_thread_num; i++) { pthread_spin_unlock(&fse->fsu[i].lock); } return ret; } - fieldstat_register_counter(fse->fsu[0].read_only, name); + fieldstat_register_counter(fse->fsu[0].read_only, 0, name); for (int i = 1; i < fse->max_thread_num; i++) { - fieldstat_register_counter(fse->fsu[i].active, name); - fieldstat_register_counter(fse->fsu[i].read_only, name); + fieldstat_register_counter(fse->fsu[i].active, 0, name); + fieldstat_register_counter(fse->fsu[i].read_only, 0, name); } for (int i = 0; i < fse->max_thread_num; i++) { @@ -218,17 +218,17 @@ int fieldstat_easy_register_histogram(struct fieldstat_easy *fse, const char *na pthread_spin_lock(&fse->fsu[i].lock); } - int ret = fieldstat_register_hist(fse->fsu[0].active, name, lowest_trackable_value, highest_trackable_value, significant_figures); // try to register + int ret = fieldstat_register_hist(fse->fsu[0].active, 0, name, lowest_trackable_value, highest_trackable_value, significant_figures); // try to register if (ret < 0) { for (int i = 0; i < fse->max_thread_num; i++) { pthread_spin_unlock(&fse->fsu[i].lock); } return ret; } - fieldstat_register_hist(fse->fsu[0].read_only, name, lowest_trackable_value, highest_trackable_value, significant_figures); + fieldstat_register_hist(fse->fsu[0].read_only, 0, name, lowest_trackable_value, highest_trackable_value, significant_figures); for (int i = 1; i < fse->max_thread_num; i++) { - fieldstat_register_hist(fse->fsu[i].active, name, lowest_trackable_value, highest_trackable_value, significant_figures); - fieldstat_register_hist(fse->fsu[i].read_only, name, lowest_trackable_value, highest_trackable_value, significant_figures); + fieldstat_register_hist(fse->fsu[i].active, 0, name, lowest_trackable_value, highest_trackable_value, significant_figures); + fieldstat_register_hist(fse->fsu[i].read_only, 0, name, lowest_trackable_value, highest_trackable_value, significant_figures); } for (int i = 0; i < fse->max_thread_num; i++) { |
