From c98de7ed1514d51f463e1b4f1508b6a466b05718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Tue, 16 May 2023 11:18:43 -0400 Subject: [PATCH] Show the precise CPU usage information in the tooltip instead of the smoothed values --- .../shared/thread/ActivityGraphFills.js | 21 ++++++--- .../components/SampleTooltipContents.test.js | 46 +++++++++++++++---- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/components/shared/thread/ActivityGraphFills.js b/src/components/shared/thread/ActivityGraphFills.js index 82e52a2acc..69bed6dce7 100644 --- a/src/components/shared/thread/ActivityGraphFills.js +++ b/src/components/shared/thread/ActivityGraphFills.js @@ -114,7 +114,7 @@ export function computeActivityGraphFills( mutableFills ); - const upperGraphEdge = activityGraphFills.run(); + const { averageCPUPerPixel, upperGraphEdge } = activityGraphFills.run(); // We're done mutating the fills' Float32Array buffers. const fills = mutableFills; @@ -123,6 +123,7 @@ export function computeActivityGraphFills( fillsQuerier: new ActivityFillGraphQuerier( renderedComponentSettings, fills, + averageCPUPerPixel, upperGraphEdge ), }; @@ -152,11 +153,18 @@ export class ActivityGraphFillComputer { * Run the computation to compute a list of the fills that need to be drawn for the * ThreadActivityGraph. */ - run(): Float32Array { + run(): {| + +averageCPUPerPixel: Float32Array, + +upperGraphEdge: Float32Array, + |} { // First go through each sample, and set the buffers that contain the percentage // that a category contributes to a given place in the X axis of the chart. this._accumulateSampleCategories(); + // First get the average CPU in each pixel, and then accumulate the upper edge + // of the graph after applying the blur. + const averageCPUPerPixel = this._accumulateUpperEdge().slice(); + // Smooth the graphs by applying a 1D gaussian blur to the per-pixel // contribution of each fill. for (const fill of this.mutableFills) { @@ -165,7 +173,7 @@ export class ActivityGraphFillComputer { const upperGraphEdge = this._accumulateUpperEdge(); - return upperGraphEdge; + return { averageCPUPerPixel, upperGraphEdge }; } /** @@ -383,15 +391,18 @@ export class ActivityGraphFillComputer { export class ActivityFillGraphQuerier { renderedComponentSettings: RenderedComponentSettings; fills: CategoryFill[]; + averageCPUPerPixel: Float32Array; upperGraphEdge: Float32Array; constructor( renderedComponentSettings: RenderedComponentSettings, fills: CategoryFill[], + averageCPUPerPixel: Float32Array, upperGraphEdge: Float32Array ) { this.renderedComponentSettings = renderedComponentSettings; this.fills = fills; + this.averageCPUPerPixel = averageCPUPerPixel; this.upperGraphEdge = upperGraphEdge; } @@ -485,9 +496,7 @@ export class ActivityFillGraphQuerier { return null; } - // This is the height of the graph and it directly corresponds to the average - // CPU usage number. - const cpuRatio = this.upperGraphEdge[deviceX]; + const cpuRatio = this.averageCPUPerPixel[deviceX]; // Get the time range of the contributed samples to the average CPU usage value. let timeRange = 0; diff --git a/src/test/components/SampleTooltipContents.test.js b/src/test/components/SampleTooltipContents.test.js index 99f408dfd3..916bfa990f 100644 --- a/src/test/components/SampleTooltipContents.test.js +++ b/src/test/components/SampleTooltipContents.test.js @@ -40,22 +40,38 @@ const GRAPH_WIDTH = Math.floor(PIXELS_PER_SAMPLE * SAMPLE_COUNT); const GRAPH_HEIGHT = 10; function getSamplesPixelPosition( sampleIndex: IndexIntoSamplesTable, - samplePosition: 'before' | 'after' = 'before' + samplePosition: 'before' | 'after' | 'on-top' = 'before' ): CssPixels { const quarterSample = PIXELS_PER_SAMPLE / 4; // Compute the pixel position of either first or the second part of the sample. // "sampleIndex * PIXELS_PER_SAMPLE" corresponds to the center of the sample, // we need to +/- quarter sample to find these places in the sample: // - // before after - // 50% CPU 100% CPU - // v v + // on-top + // 100% CPU + // | + // before | after + // 50% CPU | 100% CPU + // v v v // +--------------------+--------------------+--------------------+ // | | //////////| | // +--------------------+////////////////////+--------------------+ - const beforeOrAfter = - samplePosition === 'before' ? -quarterSample : +quarterSample; - return sampleIndex * PIXELS_PER_SAMPLE + beforeOrAfter; + let sampleOffset; + switch (samplePosition) { + case 'before': + sampleOffset = -quarterSample; + break; + case 'after': + sampleOffset = +quarterSample; + break; + case 'on-top': + sampleOffset = 0; + break; + + default: + break; + } + return sampleIndex * PIXELS_PER_SAMPLE + sampleOffset; } describe('SampleTooltipContents', function () { @@ -85,7 +101,7 @@ describe('SampleTooltipContents', function () { function setup( profile: Profile, hoveredSampleIndex: number, - hoveredSamplePosition: 'before' | 'after' = 'before' + hoveredSamplePosition: 'before' | 'after' | 'on-top' = 'before' ) { const store = storeWithProfile(profile); const threadsKey = 0; @@ -312,4 +328,18 @@ describe('SampleTooltipContents', function () { const cpuUsage = ensureExists(screen.getByText(/CPU/).nextElementSibling); expect(cpuUsage).toHaveTextContent('45% (average over 1.0ms)'); }); + + it('renders the CPU usage properly in the areas where blur is applied', () => { + const profile = getProfileWithCPU([null, 400, 580, 1000], 'µs'); + + // Let's check the second threadCPUDelta value. This should show the + // We are hovering on top of the sample which should use 580µs. Since the + // max value is 1000µs, the CPU usage should be 58%. + const hoveredSampleIndex = 1; + // Hovering on top of the sample. + setup(profile, hoveredSampleIndex, 'on-top'); + + const cpuUsage = ensureExists(screen.getByText(/CPU/).nextElementSibling); + expect(cpuUsage).toHaveTextContent('58% (average over 1.0ms)'); + }); });