diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2015-07-19 15:01:42 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2015-07-19 15:30:23 +0100 |
commit | 8506cdcaa59ba90fcccda762d9307528d9f4c5c7 (patch) | |
tree | d5c679c4418fdf37b475d1779461b7dd98fb8130 | |
parent | fdefdd48f61b39d2af825ccdba11fafcaf58031a (diff) |
lib: Allow storing floating point values in igt_stats
We don't always have precise integers with which to store, so allow
degrading to double precision floating point based on available input.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | lib/igt_stats.c | 99 | ||||
-rw-r--r-- | lib/igt_stats.h | 15 |
2 files changed, 91 insertions, 23 deletions
diff --git a/lib/igt_stats.c b/lib/igt_stats.c index 70650ec7..55dea0c2 100644 --- a/lib/igt_stats.c +++ b/lib/igt_stats.c @@ -31,6 +31,9 @@ #define U64_MAX ((uint64_t)~0ULL) +#define sorted_value(stats, i) (stats->is_float ? stats->sorted_f[i] : stats->sorted_u64[i]) +#define unsorted_value(stats, i) (stats->is_float ? stats->values_f[i] : stats->values_u64[i]) + /** * SECTION:igt_stats * @short_description: Tools for statistical analysis @@ -84,14 +87,14 @@ static void igt_stats_ensure_capacity(igt_stats_t *stats, return; new_capacity = get_new_capacity(new_n_values); - stats->values = realloc(stats->values, - sizeof(*stats->values) * new_capacity); - igt_assert(stats->values); + stats->values_u64 = realloc(stats->values_u64, + sizeof(*stats->values_u64) * new_capacity); + igt_assert(stats->values_u64); stats->capacity = new_capacity; - free(stats->sorted); - stats->sorted = NULL; + free(stats->sorted_u64); + stats->sorted_u64 = NULL; } /** @@ -130,6 +133,8 @@ void igt_stats_init_with_size(igt_stats_t *stats, unsigned int capacity) stats->min = U64_MAX; stats->max = 0; + stats->range[0] = HUGE_VAL; + stats->range[1] = -HUGE_VAL; } /** @@ -140,8 +145,8 @@ void igt_stats_init_with_size(igt_stats_t *stats, unsigned int capacity) */ void igt_stats_fini(igt_stats_t *stats) { - free(stats->values); - free(stats->sorted); + free(stats->values_u64); + free(stats->sorted_u64); } @@ -202,9 +207,14 @@ void igt_stats_set_population(igt_stats_t *stats, bool full_population) */ void igt_stats_push(igt_stats_t *stats, uint64_t value) { + if (stats->is_float) { + igt_stats_push_float(stats, value); + return; + } + igt_stats_ensure_capacity(stats, 1); - stats->values[stats->n_values++] = value; + stats->values_u64[stats->n_values++] = value; stats->mean_variance_valid = false; stats->sorted_array_valid = false; @@ -216,6 +226,38 @@ void igt_stats_push(igt_stats_t *stats, uint64_t value) } /** + * igt_stats_push: + * @stats: An #igt_stats_t instance + * @value: An floating point + * + * Adds a new value to the @stats dataset and converts the igt_stats from + * an integer collection to a floating point one. + */ +void igt_stats_push_float(igt_stats_t *stats, double value) +{ + igt_stats_ensure_capacity(stats, 1); + + if (!stats->is_float) { + int n; + + for (n = 0; n < stats->n_values; n++) + stats->values_f[n] = stats->values_u64[n]; + + stats->is_float = true; + } + + stats->values_f[stats->n_values++] = value; + + stats->mean_variance_valid = false; + stats->sorted_array_valid = false; + + if (value < stats->range[0]) + stats->range[0] = value; + if (value > stats->range[1]) + stats->range[1] = value; +} + +/** * igt_stats_push_array: * @stats: An #igt_stats_t instance * @values: (array length=n_values): A pointer to an array of data points @@ -242,6 +284,7 @@ void igt_stats_push_array(igt_stats_t *stats, */ uint64_t igt_stats_get_min(igt_stats_t *stats) { + igt_assert(!stats->is_float); return stats->min; } @@ -253,6 +296,7 @@ uint64_t igt_stats_get_min(igt_stats_t *stats) */ uint64_t igt_stats_get_max(igt_stats_t *stats) { + igt_assert(!stats->is_float); return stats->max; } @@ -283,26 +327,39 @@ static int cmp_u64(const void *pa, const void *pb) return 0; } +static int cmp_f(const void *pa, const void *pb) +{ + const double *a = pa, *b = pb; + + if (*a < *b) + return -1; + if (*a > *b) + return 1; + return 0; +} + static void igt_stats_ensure_sorted_values(igt_stats_t *stats) { if (stats->sorted_array_valid) return; - if (!stats->sorted) { + if (!stats->sorted_u64) { /* * igt_stats_ensure_capacity() will free ->sorted when the * capacity increases, which also correspond to an invalidation * of the sorted array. We'll then reallocate it here on * demand. */ - stats->sorted = calloc(stats->capacity, sizeof(*stats->values)); - igt_assert(stats->sorted); + stats->sorted_u64 = calloc(stats->capacity, + sizeof(*stats->values_u64)); + igt_assert(stats->sorted_u64); } - memcpy(stats->sorted, stats->values, - sizeof(*stats->values) * stats->n_values); + memcpy(stats->sorted_u64, stats->values_u64, + sizeof(*stats->values_u64) * stats->n_values); - qsort(stats->sorted, stats->n_values, sizeof(*stats->values), cmp_u64); + qsort(stats->sorted_u64, stats->n_values, sizeof(*stats->values_u64), + stats->is_float ? cmp_f : cmp_u64); stats->sorted_array_valid = true; } @@ -326,7 +383,7 @@ igt_stats_get_median_internal(igt_stats_t *stats, if (n_values % 2 == 1) { /* median is the value in the middle (actual datum) */ mid = start + n_values / 2; - median = stats->sorted[mid]; + median = sorted_value(stats, mid); /* the two halves contain the median value */ if (lower_end) @@ -342,7 +399,7 @@ igt_stats_get_median_internal(igt_stats_t *stats, * values. */ mid = start + n_values / 2 - 1; - median = (stats->sorted[mid] + stats->sorted[mid + 1]) / 2.; + median = (sorted_value(stats, mid) + sorted_value(stats, mid+1))/2.; if (lower_end) *lower_end = mid + 1; @@ -439,10 +496,10 @@ static void igt_stats_knuth_mean_variance(igt_stats_t *stats) return; for (i = 0; i < stats->n_values; i++) { - double delta = stats->values[i] - mean; + double delta = unsorted_value(stats, i) - mean; mean += delta / (i + 1); - m2 += delta * (stats->values[i] - mean); + m2 += delta * (unsorted_value(stats, i) - mean); } stats->mean = mean; @@ -518,7 +575,7 @@ double igt_stats_get_iqm(igt_stats_t *stats) mean = 0; for (i = 0; i <= q3 - q1; i++) - mean += (stats->sorted[q1 + i] - mean) / (i + 1); + mean += (sorted_value(stats, q1 + i) - mean) / (i + 1); if (stats->n_values % 4) { double rem = .5 * (stats->n_values % 4) / 4; @@ -526,8 +583,8 @@ double igt_stats_get_iqm(igt_stats_t *stats) q1 = (stats->n_values) / 4; q3 = (3 * stats->n_values + 3) / 4; - mean += rem * (stats->sorted[q1] - mean) / i++; - mean += rem * (stats->sorted[q3] - mean) / i++; + mean += rem * (sorted_value(stats, q1) - mean) / i++; + mean += rem * (sorted_value(stats, q3) - mean) / i++; } return mean; diff --git a/lib/igt_stats.h b/lib/igt_stats.h index 554ab158..0dc065f4 100644 --- a/lib/igt_stats.h +++ b/lib/igt_stats.h @@ -34,17 +34,27 @@ * @n_values: The number of pushed values */ typedef struct { - uint64_t *values; + union { + uint64_t *values_u64; + double *values_f; + }; unsigned int n_values; + unsigned int is_float : 1; /*< private >*/ unsigned int capacity; unsigned int is_population : 1; unsigned int mean_variance_valid : 1; unsigned int sorted_array_valid : 1; + uint64_t min, max; + double range[2]; double mean, variance; - uint64_t *sorted; + + union { + uint64_t *sorted_u64; + double *sorted_f; + }; } igt_stats_t; void igt_stats_init(igt_stats_t *stats); @@ -53,6 +63,7 @@ void igt_stats_fini(igt_stats_t *stats); bool igt_stats_is_population(igt_stats_t *stats); void igt_stats_set_population(igt_stats_t *stats, bool full_population); void igt_stats_push(igt_stats_t *stats, uint64_t value); +void igt_stats_push_float(igt_stats_t *stats, double value); void igt_stats_push_array(igt_stats_t *stats, const uint64_t *values, unsigned int n_values); uint64_t igt_stats_get_min(igt_stats_t *stats); |