diff --git a/lib/igt_stats.c b/lib/igt_stats.c
index 1103a7b..d757fc6 100644
--- a/lib/igt_stats.c
+++ b/lib/igt_stats.c
@@ -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;
+}
diff --git a/lib/igt_stats.h b/lib/igt_stats.h
index d6eb48f..46b7019 100644
--- a/lib/igt_stats.h
+++ b/lib/igt_stats.h
@@ -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__ */
diff --git a/lib/tests/igt_stats.c b/lib/tests/igt_stats.c
index 12778e2..480321f 100644
--- a/lib/tests/igt_stats.c
+++ b/lib/tests/igt_stats.c
@@ -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();
 }
