@@ -639,3 +639,108 @@ double igt_stats_get_trimean(igt_stats_t *stats)
igt_stats_get_quartiles(stats, &q1, &q2, &q3);
return (q1 + 2*q2 + q3) / 4;
}
+
+/**
+ * igt_histogram_init:
+ * @hist: An #igt_histogram_t instance
+ * @stats: Input data
+ *
+ * Initializes an igt_histogram_t object. Use igt_histogram_fini() when finished
+ * with it.
+ */
+void igt_histogram_init(igt_histogram_t *hist, igt_stats_t *stats)
+{
+ memset(hist, 0, sizeof(*hist));
+ hist->stats = stats;
+ hist->n_bins = 10;
+}
+
+/**
+ * igt_histogram_fini:
+ * @hist: An #igt_histogram_t instance
+ *
+ * Frees resources allocated during the life time of @hist.
+ */
+void igt_histogram_fini(igt_histogram_t *hist)
+{
+ free(hist->frequencies);
+}
+
+/* XXX: we should probably use an automatic binning algorithm */
+
+/**
+ * igt_histogram_set_n_bins:
+ * @hist: An #igt_histogram_t instance
+ * @n_bins: Number of bins
+ *
+ * Set how many bins should be use to classify the input data.
+ *
+ * The default is 10.
+ */
+void igt_histogram_set_n_bins(igt_histogram_t *hist, unsigned int n_bins)
+{
+ if (hist->n_bins == n_bins)
+ return;
+
+ hist->n_bins = n_bins;
+ free(hist->frequencies);
+ hist->frequencies = NULL;
+}
+
+/**
+ * igt_histogram_set_density:
+ * @hist: An #igt_histogram_t instance
+ * @density: The new density setting
+ *
+ * Whether the histogram should represent a density distribution (integral over
+ * the range of the input data is 1) or simply contain the number of data
+ * points in each bin.
+ *
+ * By default density is #false.
+ *
+ */
+void igt_histogram_set_density(igt_histogram_t *hist, bool density)
+{
+ if (hist->compute_density == density)
+ return;
+
+ hist->compute_density = density;
+ free(hist->frequencies);
+ hist->frequencies = NULL;
+}
+
+double *igt_histogram_get_frequencies(igt_histogram_t *hist)
+{
+ igt_stats_t *stats = hist->stats;
+ unsigned int i;
+ uint64_t min, max;
+ double bin_length;
+
+ /*
+ * XXX: we could cache frequencies with a way to know if stats has
+ * changed since the last time.
+ */
+ free(hist->frequencies);
+ hist->frequencies = calloc(hist->n_bins, sizeof(double));
+
+ min = igt_stats_get_min(stats);
+ max = igt_stats_get_max(stats);
+ bin_length = (max - min) / (double)hist->n_bins;
+
+ for (i = 0; i < stats->n_values; i++) {
+ unsigned int bin;
+
+ bin = (stats->values[i] - min) / bin_length;
+ if (bin >= hist->n_bins)
+ bin--;
+ hist->frequencies[bin]++;
+ }
+
+ if (!hist->compute_density)
+ return hist->frequencies;
+
+ for (i = 0; i < hist->n_bins; i++)
+ hist->frequencies[i] /= stats->n_values;
+
+ return hist->frequencies;
+}
@@ -73,4 +73,27 @@ double igt_stats_get_median(igt_stats_t *stats);
double igt_stats_get_variance(igt_stats_t *stats);
double igt_stats_get_std_deviation(igt_stats_t *stats);
+/**
+ * igt_histogram_t:
+ *
+ * An histogram will split the input data containted in an #igt_stats_t object
+ * in a number of bins and, depending on the density property, either:
+ * - Compute the number of data points in each bin,
+ * - Normalize the data such as the histogram represents a density function,
+ * the integral over the range is 1.
+ */
+typedef struct {
+ /*< private >*/
+ igt_stats_t *stats;
+ unsigned int n_bins;
+ double *frequencies;
+ bool compute_density;
+} igt_histogram_t;
+
+void igt_histogram_init(igt_histogram_t *hist, igt_stats_t *stats);
+void igt_histogram_fini(igt_histogram_t *hist);
+void igt_histogram_set_n_bins(igt_histogram_t *hist, unsigned int n_bins);
+void igt_histogram_set_density(igt_histogram_t *hist, bool density);
+double *igt_histogram_get_frequencies(igt_histogram_t *hist);
+
#endif /* __IGT_STATS_H__ */
@@ -227,6 +227,29 @@ static void test_reallocation(void)
igt_stats_fini(&stats);
}
+static void test_histogram(void)
+{
+ static const uint64_t s1[] = { 10, 12, 14, 16, 87, 53, 90, 72 };
+ igt_stats_t stats;
+ igt_histogram_t hist;
+ double *freqs;
+
+ igt_stats_init_from_array(&stats, s1, ARRAY_SIZE(s1));
+ igt_histogram_init(&hist, &stats);
+ igt_histogram_set_n_bins(&hist, 2);
+
+ freqs = igt_histogram_get_frequencies(&hist);
+ igt_assert_eq_double(freqs[0], 4);
+ igt_assert_eq_double(freqs[1], 4);
+
+ igt_histogram_set_density(&hist, true);
+ freqs = igt_histogram_get_frequencies(&hist);
+ igt_assert_eq_double(freqs[0], 0.5);
+ igt_assert_eq_double(freqs[1], 0.5);
+
+ igt_histogram_fini(&hist);
+}
+
igt_simple_main
{
test_init_zero();
@@ -239,4 +262,5 @@ igt_simple_main
test_invalidate_mean();
test_std_deviation();
test_reallocation();
+ test_histogram();
}
Histograms are a great way to have a look at a dataset to understand how the values are distributed. Signed-off-by: Damien Lespiau <damien.lespiau@intel.com> --- lib/igt_stats.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/igt_stats.h | 23 +++++++++++ lib/tests/igt_stats.c | 24 ++++++++++++ 3 files changed, 152 insertions(+)