Merge "Add the ability to pick the number of buckets in the histogram." into androidx-main
diff --git a/development/plot-benchmarks/src/lib/Chart.svelte b/development/plot-benchmarks/src/lib/Chart.svelte
index 9a224e2..de2616e 100644
--- a/development/plot-benchmarks/src/lib/Chart.svelte
+++ b/development/plot-benchmarks/src/lib/Chart.svelte
@@ -1,16 +1,18 @@
<script lang="ts">
import type { ChartType, LegendItem } from "chart.js";
import { Chart } from "chart.js/auto";
- import { onMount } from "svelte";
+ import { createEventDispatcher, onMount } from "svelte";
import { writable, type Writable } from "svelte/store";
import type { Data } from "../types/chart.js";
import { LegendPlugin } from "../plugins.js";
import Legend from "./Legend.svelte";
import { saveToClipboard as save } from "../clipboard.js";
+ import type { Controls, ControlsEvent } from "../types/events.js";
export let data: Data;
export let chartType: ChartType = "line";
export let isExperimental: boolean = false;
+ export let showHistogramControls: boolean = false;
$: {
if ($chart) {
@@ -20,7 +22,9 @@
}
// State
+ let controlsDispatcher = createEventDispatcher<ControlsEvent>();
let element: HTMLCanvasElement;
+ let buckets: Writable<number> = writable(100);
let chart: Writable<Chart | null> = writable(null);
let items: Writable<LegendItem[] | null> = writable(null);
@@ -56,6 +60,18 @@
await save($chart);
}
}
+
+ function onHistogramChanged(event: Event) {
+ const element = event.target as EventTarget & HTMLInputElement;
+ const oldValue = $buckets;
+ $buckets = parseInt(element.value, 10);
+ if (oldValue != $buckets) {
+ let controls: Controls = {
+ buckets: $buckets,
+ };
+ controlsDispatcher("controls", controls);
+ }
+ }
</script>
<article>
@@ -69,6 +85,24 @@
</button>
</div>
<canvas class="chart" bind:this={element} />
+ {#if showHistogramControls}
+ <div class="controls">
+ <label for="buckets">
+ Histogram
+ <input
+ type="range"
+ data-tooltip={$buckets}
+ data-placement="right"
+ min="10"
+ max="250"
+ value={$buckets}
+ id="buckets"
+ name="buckets"
+ on:change={onHistogramChanged}
+ />
+ </label>
+ </div>
+ {/if}
{#if isExperimental}
<footer class="slim">
<section class="experimental">
@@ -92,19 +126,20 @@
flex-direction: row;
justify-content: flex-end;
}
-
.toolbar .btn {
width: auto;
height: auto;
border: none;
padding: 5px;
}
-
+ .controls {
+ margin-top: 20px;
+ width: 100%;
+ }
.slim {
margin-bottom: 0px;
padding: 0;
}
-
.experimental {
display: flex;
flex-direction: row;
diff --git a/development/plot-benchmarks/src/lib/Session.svelte b/development/plot-benchmarks/src/lib/Session.svelte
index e70f88c..a099cf8 100644
--- a/development/plot-benchmarks/src/lib/Session.svelte
+++ b/development/plot-benchmarks/src/lib/Session.svelte
@@ -1,29 +1,33 @@
<script lang="ts">
+ import type { Remote } from "comlink";
import { createEventDispatcher } from "svelte";
import {
+ derived,
writable,
type Readable,
type Writable,
- derived,
} from "svelte/store";
import { readBenchmarks } from "../files.js";
- import { ChartDataTransforms } from "../transforms/data-transforms.js";
+ import {
+ ChartDataTransforms,
+ type Mapper,
+ } from "../transforms/data-transforms.js";
import { Transforms } from "../transforms/metric-transforms.js";
- import { STANDARD_MAPPER } from "../transforms/standard-mappers.js";
import type { Data, Series } from "../types/chart.js";
import type { Metrics } from "../types/data.js";
import type {
- FileMetadataEvent,
+ Controls,
DatasetSelection,
- StatInfo,
+ FileMetadataEvent,
MetricSelection,
+ StatInfo,
} from "../types/events.js";
import type { FileMetadata } from "../types/files.js";
+ import type { StatService } from "../workers/service.js";
import { Session, type IndexedWrapper } from "../wrappers/session.js";
import Chart from "./Chart.svelte";
import Group from "./Group.svelte";
- import type { StatService } from "../workers/service.js";
- import type { Remote } from "comlink";
+ import { buildMapper } from "../transforms/standard-mappers.js";
export let fileEntries: FileMetadata[];
export let service: Remote<StatService>;
@@ -31,14 +35,17 @@
// State
let eventDispatcher = createEventDispatcher<FileMetadataEvent>();
let session: Session;
+ let mapper: Mapper<number>;
let metrics: Metrics<number>;
let series: Series[];
let chartData: Data;
let classGroups: Record<string, IndexedWrapper[]>;
+ let showHistogramControls: boolean;
let size: number;
let activeSeries: Promise<Series[]>;
// Stores
+ let buckets: Writable<number> = writable(100);
let activeDragDrop: Writable<boolean> = writable(false);
let suppressed: Writable<Set<string>> = writable(new Set());
let suppressedMetrics: Writable<Set<string>> = writable(new Set());
@@ -97,11 +104,18 @@
}
};
+ let controlsHandler = function (event: CustomEvent<Controls>) {
+ const controls: Controls = event.detail;
+ $buckets = controls.buckets;
+ };
+
$: {
session = new Session(fileEntries);
+ mapper = buildMapper($buckets);
metrics = Transforms.buildMetrics(session, $suppressed, $suppressedMetrics);
+ showHistogramControls = metrics.sampled && metrics.sampled.length > 0;
activeSeries = service.pSeries(metrics, $active);
- series = ChartDataTransforms.mapToSeries(metrics, STANDARD_MAPPER);
+ series = ChartDataTransforms.mapToSeries(metrics, mapper);
chartData = ChartDataTransforms.mapToDataset(series);
classGroups = session.classGroups;
size = session.fileNames.size;
@@ -183,7 +197,11 @@
</article>
{#if series.length > 0}
- <Chart data={chartData} />
+ <Chart
+ data={chartData}
+ {showHistogramControls}
+ on:controls={controlsHandler}
+ />
{/if}
{#await activeSeries}
diff --git a/development/plot-benchmarks/src/transforms/data-transforms.ts b/development/plot-benchmarks/src/transforms/data-transforms.ts
index c176da9..41ef149 100644
--- a/development/plot-benchmarks/src/transforms/data-transforms.ts
+++ b/development/plot-benchmarks/src/transforms/data-transforms.ts
@@ -18,8 +18,9 @@
const series: Series[] = [];
const standard = metrics.standard;
const sampled = metrics.sampled;
- // Builds ranges for distribution
+ // Builds ranges for distribution.
const ranges = mapper.sampledRanges(metrics);
+ // Builds series.
if (standard) {
for (let i = 0; i < standard.length; i += 1) {
const metric = standard[i];
diff --git a/development/plot-benchmarks/src/transforms/standard-mappers.ts b/development/plot-benchmarks/src/transforms/standard-mappers.ts
index 11baf19..9db0cd1 100644
--- a/development/plot-benchmarks/src/transforms/standard-mappers.ts
+++ b/development/plot-benchmarks/src/transforms/standard-mappers.ts
@@ -37,14 +37,14 @@
return ranges;
}
-function sampledMapper(metric: Metric<number[]>, range: Range | null): Series[] {
+function sampledMapper(metric: Metric<number[]>, buckets: number, range: Range | null): Series[] {
const series: Series[] = [];
const data: Record<string, ChartData<number[]>> = metric.data;
const entries = Object.entries(data);
for (let i = 0; i < entries.length; i += 1) {
const [source, chartData] = entries[i];
const label = labelFor(metric, source);
- const [points, _, __] = histogramPoints(chartData.values, /* buckets */ undefined, /* target */ undefined, range);
+ const [points, _, __] = histogramPoints(chartData.values, buckets, /* target */ undefined, range);
series.push({
label: label,
type: "line",
@@ -194,11 +194,32 @@
}
/**
- * The standard mapper.
+ * The Standard Mapper.
*/
-export const STANDARD_MAPPER: Mapper = {
- rangeLabel: rangeLabel,
- standard: standardMapper,
- sampled: sampledMapper,
- sampledRanges: sampledRanges
-};
+class StandardMapper {
+ constructor(private buckets: number) {
+ // Does nothing.
+ }
+ // Delegate
+ rangeLabel(metric: Metric<unknown>): string {
+ return rangeLabel(metric);
+ }
+ standard(metric: Metric<number>): Series[] {
+ return standardMapper(metric);
+ }
+ sampled(metric: Metric<number[]>, range: Range | null): Series[] {
+ return sampledMapper(metric, this.buckets, range);
+ }
+ sampledRanges(metrics: Metrics<number>): Record<string, Range> {
+ return sampledRanges(metrics);
+ }
+}
+
+/**
+ * Builds a Standard mapper.
+ * @param buckets are the number of buckets in the histogram to use.
+ * @return an instance of `Mapper`.
+ */
+export function buildMapper(buckets: number): Mapper<number> {
+ return new StandardMapper(buckets);
+}
diff --git a/development/plot-benchmarks/src/types/chart.ts b/development/plot-benchmarks/src/types/chart.ts
index 0d77b63..e90f8d2 100644
--- a/development/plot-benchmarks/src/types/chart.ts
+++ b/development/plot-benchmarks/src/types/chart.ts
@@ -20,7 +20,7 @@
export interface Series {
label: string;
type: ChartType;
- data: Array<Point>;
+ data: Point[];
// Additional series options
// For e.g. https://www.chartjs.org/docs/latest/charts/line.html
options: object;
diff --git a/development/plot-benchmarks/src/types/events.ts b/development/plot-benchmarks/src/types/events.ts
index 72890d4..f98f9ed 100644
--- a/development/plot-benchmarks/src/types/events.ts
+++ b/development/plot-benchmarks/src/types/events.ts
@@ -31,3 +31,11 @@
export interface StatEvent {
info: StatInfo[];
}
+
+export interface ControlsEvent {
+ controls: Controls;
+}
+
+export interface Controls {
+ buckets: number;
+}
diff --git a/development/plot-benchmarks/src/workers/service.ts b/development/plot-benchmarks/src/workers/service.ts
index 90ff9a5..33c52f2 100644
--- a/development/plot-benchmarks/src/workers/service.ts
+++ b/development/plot-benchmarks/src/workers/service.ts
@@ -27,7 +27,7 @@
continue;
}
const [delta, distribution] = this.buildDistribution(reference, target);
- const [points, pPlots, p] = histogramPoints([distribution], 100, delta);
+ const [points, pPlots, p] = histogramPoints([distribution], /* buckets */ 100, /* target */ delta);
series.push({
label: `${name} { ${metric.label} } - Likelihood`,
type: "line",
@@ -67,7 +67,7 @@
continue;
}
const [delta, distribution] = this.buildStandardDistribution(reference, target);
- const [points, pPlots, p] = histogramPoints([distribution], 100, delta);
+ const [points, pPlots, p] = histogramPoints([distribution], /* buckets */ 100, /* target */ delta);
series.push({
label: `${name} { ${metric.label} } - Likelihood`,
type: "line",