Changeset 242300 in webkit
- Timestamp:
- Mar 1, 2019 5:18:13 PM (5 years ago)
- Location:
- trunk/Source/WebInspectorUI
- Files:
-
- 2 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebInspectorUI/ChangeLog
r242296 r242300 1 2019-03-01 Joseph Pecoraro <pecoraro@apple.com> 2 3 Web Inspector: CPU Usage - Energy Impact Section 4 https://bugs.webkit.org/show_bug.cgi?id=195151 5 6 Reviewed by Devin Rousso. 7 8 * Localizations/en.lproj/localizedStrings.js: 9 * UserInterface/Main.html: 10 New strings and resources. 11 12 * UserInterface/Views/CPUTimelineView.css: 13 (.timeline-view.cpu > .content .subtitle > .info): 14 (@media (prefers-color-scheme: dark)): 15 (.energy-info-popover-content): 16 (.timeline-view.cpu > .content > .overview > .divider): 17 (body[dir=ltr] .timeline-view.cpu > .content > .overview > .divider): 18 (body[dir=rtl] .timeline-view.cpu > .content > .overview > .divider): 19 (.timeline-view.cpu :matches(.area-chart, .stacked-area-chart) svg > path): 20 (.timeline-view.cpu .gauge-chart:not(.empty) > svg > path.low): 21 (.timeline-view.cpu .gauge-chart:not(.empty) > svg > path.medium): 22 (.timeline-view.cpu .gauge-chart:not(.empty) > svg > path.high): 23 (.timeline-view.cpu .gauge-chart:not(.empty) > svg > polygon.needle): 24 (.timeline-view.cpu .energy): 25 (.timeline-view.cpu .energy .energy-impact): 26 (.timeline-view.cpu .energy .energy-impact.low): 27 (.timeline-view.cpu .energy .energy-impact.medium): 28 (.timeline-view.cpu .energy .energy-impact.high): 29 (.timeline-view.cpu .energy .energy-impact-number): 30 Styling the chart and text for the different energy impact levels. 31 32 * UserInterface/Views/CPUTimelineView.js: 33 (WI.CPUTimelineView.prototype.get lowEnergyValue): 34 (WI.CPUTimelineView.prototype.get highEnergyValue): 35 (WI.CPUTimelineView.prototype.initialLayout): 36 (WI.CPUTimelineView.prototype.layout): 37 (WI.CPUTimelineView.prototype._layoutEnergyChart.mapWithBias): 38 (WI.CPUTimelineView.prototype._layoutEnergyChart.valuesForGauge): 39 (WI.CPUTimelineView.prototype._layoutEnergyChart): 40 (WI.CPUTimelineView.prototype._clearEnergyImpactText): 41 New gauge chart and associated popover. 42 We do a bit of biasing of the data for each of the sections 43 in the gauge chart. Each section biases toward the cap of the 44 section so that: 45 - we encourage lower power usage (sub 3%) 46 - the gauge needle quickly moves past the low value of a range 47 48 * UserInterface/Views/GaugeChart.css: Added. 49 (.gauge-chart): 50 (body[dir=rtl] .gauge-chart): 51 (.gauge-chart > svg > path,): 52 (.gauge-chart > svg > polygon.needle): 53 (.gauge-chart.empty > svg > polygon.needle): 54 (@media (prefers-color-scheme: dark)): 55 * UserInterface/Views/GaugeChart.js: Added. 56 (WI.GaugeChart.prototype.get size): 57 (WI.GaugeChart.prototype.get segments): 58 (WI.GaugeChart.prototype.get value): 59 (WI.GaugeChart.prototype.set value): 60 (WI.GaugeChart.prototype.clear): 61 (WI.GaugeChart.prototype.initialLayout): 62 (WI.GaugeChart.prototype.layout): 63 (WI.GaugeChart.prototype._validateSegments): 64 (WI.GaugeChart.prototype._createSegmentPathData): 65 GaugeChart with variable number of sections and a 66 current value needle. It has a bit of customization 67 when drawing the arc at the start of each segment. 68 69 * UserInterface/Views/Variables.css: 70 (:root): 71 (@media (prefers-color-scheme: dark)): 72 New CPU colors for the different energy impact levels. 73 1 74 2019-03-01 Nikita Vasilyev <nvasilyev@apple.com> 2 75 -
trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
r242080 r242300 142 142 localizedStrings["Automatically continue after evaluating"] = "Automatically continue after evaluating"; 143 143 localizedStrings["Available Style Sheets"] = "Available Style Sheets"; 144 localizedStrings["Average CPU: %s"] = "Average CPU: %s"; 144 145 localizedStrings["Average Time"] = "Average Time"; 145 146 localizedStrings["Average: %s"] = "Average: %s"; … … 339 340 localizedStrings["Duplicate property"] = "Duplicate property"; 340 341 localizedStrings["Duration"] = "Duration"; 342 localizedStrings["Duration: %s"] = "Duration: %s"; 341 343 localizedStrings["Dynamically calculated for the parent element"] = "Dynamically calculated for the parent element"; 342 344 localizedStrings["Dynamically calculated for the selected element"] = "Dynamically calculated for the selected element"; … … 394 396 localizedStrings["Encoded"] = "Encoded"; 395 397 localizedStrings["Encoding"] = "Encoding"; 398 localizedStrings["Energy Impact"] = "Energy Impact"; 396 399 localizedStrings["Ensure aria-hidden=\u0022%s\u0022 is not used."] = "Ensure aria-hidden=\u0022%s\u0022 is not used."; 397 400 localizedStrings["Ensure that \u0022%s\u0022 is spelled correctly."] = "Ensure that \u0022%s\u0022 is spelled correctly."; … … 414 417 localizedStrings["Errors"] = "Errors"; 415 418 localizedStrings["Errors:"] = "Errors:"; 419 localizedStrings["Estimated energy impact."] = "Estimated energy impact."; 416 420 localizedStrings["Eval Code"] = "Eval Code"; 417 421 localizedStrings["Evaluate JavaScript"] = "Evaluate JavaScript"; … … 714 718 /* The number of tests that passed expressed as a percentage, followed by a literal %. */ 715 719 localizedStrings["Percentage (of audits)"] = "%s%%"; 720 localizedStrings["Periods of high CPU utilization will rapidly drain battery. Strive to keep idle pages under %s average CPU utilization."] = "Periods of high CPU utilization will rapidly drain battery. Strive to keep idle pages under %s average CPU utilization."; 716 721 localizedStrings["Ping"] = "Ping"; 717 722 localizedStrings["Ping Frame"] = "Ping Frame"; … … 884 889 localizedStrings["Shadow Content (%s)"] = "Shadow Content (%s)"; 885 890 localizedStrings["Shared Focus"] = "Shared Focus"; 891 localizedStrings["Short"] = "Short"; 886 892 localizedStrings["Shortest property path to %s"] = "Shortest property path to %s"; 887 893 localizedStrings["Show %d More"] = "Show %d More"; … … 989 995 localizedStrings["The page's content has changed"] = "The page's content has changed"; 990 996 localizedStrings["The resource was requested insecurely."] = "The resource was requested insecurely."; 997 localizedStrings["There is an incurred energy penalty each time the page enters script. This commonly happens with timers, event handlers, and observers."] = "There is an incurred energy penalty each time the page enters script. This commonly happens with timers, event handlers, and observers."; 991 998 localizedStrings["These are all of the different test result levels."] = "These are all of the different test result levels."; 992 999 localizedStrings["These are all of the different types of data that can be returned with the test result."] = "These are all of the different types of data that can be returned with the test result."; … … 1021 1028 localizedStrings["Timestamp \u2014 %s"] = "Timestamp \u2014 %s"; 1022 1029 localizedStrings["Timing"] = "Timing"; 1030 localizedStrings["To improve CPU utilization reduce or batch workloads when the page is not visible or during times when the page is not being interacted with."] = "To improve CPU utilization reduce or batch workloads when the page is not visible or during times when the page is not being interacted with."; 1023 1031 localizedStrings["Toggle Classes"] = "Toggle Classes"; 1024 1032 localizedStrings["Toggle Visibility"] = "Toggle Visibility"; … … 1070 1078 localizedStrings["Vertex"] = "Vertex"; 1071 1079 localizedStrings["Vertex Shader"] = "Vertex Shader"; 1080 localizedStrings["Very High"] = "Very High"; 1072 1081 localizedStrings["View Image"] = "View Image"; 1073 1082 localizedStrings["View Recording"] = "View Recording"; -
trunk/Source/WebInspectorUI/UserInterface/Main.html
r242104 r242300 107 107 <link rel="stylesheet" href="Views/FontResourceContentView.css"> 108 108 <link rel="stylesheet" href="Views/FormattedValue.css"> 109 <link rel="stylesheet" href="Views/GaugeChart.css"> 109 110 <link rel="stylesheet" href="Views/GeneralStyleDetailsSidebarPanel.css"> 110 111 <link rel="stylesheet" href="Views/GoToLineDialog.css"> … … 673 674 <script src="Views/FrameDOMTreeContentView.js"></script> 674 675 <script src="Views/FrameTreeElement.js"></script> 676 <script src="Views/GaugeChart.js"></script> 675 677 <script src="Views/GeneralTreeElementPathComponent.js"></script> 676 678 <script src="Views/GenericResourceContentView.js"></script> -
trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.css
r242242 r242300 41 41 } 42 42 43 .timeline-view.cpu > .content .subtitle > .info { 44 display: inline-block; 45 width: 15px; 46 height: 15px; 47 -webkit-margin-start: 7px; 48 color: white; 49 font-size: 12px; 50 background-color: darkgray; 51 border-radius: 50%; 52 } 53 54 .energy-info-popover-content { 55 width: 275px; 56 padding: 0 5px; 57 -webkit-hyphens: auto; 58 } 59 43 60 .timeline-view.cpu > .content > .details { 44 61 position: relative; … … 90 107 } 91 108 109 .timeline-view.cpu > .content > .overview > .divider { 110 margin: 0 5px; 111 112 --cpu-timeline-view-overview-divider-border-end: 1px solid var(--border-color); 113 } 114 115 body[dir=ltr] .timeline-view.cpu > .content > .overview > .divider { 116 border-right: var(--cpu-timeline-view-overview-divider-border-end); 117 } 118 119 body[dir=rtl] .timeline-view.cpu > .content > .overview > .divider { 120 border-left: var(--cpu-timeline-view-overview-divider-border-end); 121 } 122 92 123 .timeline-view.cpu > .content > .overview .samples, 93 124 .timeline-view.cpu > .content > .overview .legend .size { … … 166 197 } 167 198 168 .timeline-view.cpu svg > path {199 .timeline-view.cpu :matches(.area-chart, .stacked-area-chart) svg > path { 169 200 stroke: var(--cpu-stroke-color); 170 201 fill: var(--cpu-fill-color); … … 240 271 fill: var(--cpu-paint-fill-color); 241 272 } 273 274 .timeline-view.cpu .gauge-chart .low { 275 --gauge-chart-path-fill-color: var(--cpu-low-color); 276 --gauge-chart-path-stroke-color: var(--cpu-low-color); 277 } 278 279 .timeline-view.cpu .gauge-chart .medium { 280 --gauge-chart-path-fill-color: var(--cpu-medium-color); 281 --gauge-chart-path-stroke-color: var(--cpu-medium-color); 282 } 283 284 .timeline-view.cpu .gauge-chart .high { 285 --gauge-chart-path-fill-color: var(--cpu-high-color); 286 --gauge-chart-path-stroke-color: var(--cpu-high-color); 287 } 288 289 .timeline-view.cpu .gauge-chart { 290 --gauge-chart-needle-fill-color: hsla(0, 0%, 36%, 0.85); 291 --gauge-chart-needle-stroke-color: hsla(0, 0%, 36%, 0.85); 292 } 293 294 .timeline-view.cpu .energy { 295 color: hsla(0, 0%, var(--foreground-lightness), 0.85); 296 } 297 298 .timeline-view.cpu .energy .energy-impact { 299 min-width: 140px; 300 margin-top: 15px; 301 font-size: 3em; 302 color: var(--text-color-secondary); 303 } 304 305 .timeline-view.cpu .energy .energy-impact.low { 306 color: var(--cpu-low-color); 307 } 308 309 .timeline-view.cpu .energy .energy-impact.medium { 310 color: var(--cpu-medium-color); 311 } 312 313 .timeline-view.cpu .energy .energy-impact.high { 314 color: var(--cpu-high-color); 315 } 316 317 .timeline-view.cpu .energy .energy-impact-number { 318 font-size: 14px; 319 } 320 321 @media (prefers-color-scheme: dark) { 322 .timeline-view.cpu > .content .subtitle > .info { 323 background-color: gray; 324 } 325 326 .timeline-view.cpu .gauge-chart:not(.empty) > svg > polygon.needle { 327 fill: hsla(0, 0%, var(--foreground-lightness), 0.85); 328 stroke: hsla(0, 0%, var(--foreground-lightness), 0.85); 329 } 330 } -
trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.js
r242243 r242300 60 60 static get indicatorViewHeight() { return 15; } 61 61 62 static get lowEnergyThreshold() { return 3; } 63 static get mediumEnergyThreshold() { return 50; } 64 static get highEnergyThreshold() { return 150; } 65 62 66 // Public 63 67 … … 91 95 this._breakdownChart.needsLayout(); 92 96 this._clearBreakdownLegend(); 97 98 this._energyChart.clear(); 99 this._energyChart.needsLayout(); 100 this._clearEnergyImpactText(); 93 101 94 102 function clearUsageView(view) { … … 178 186 this._breakdownLegendPaintElement = appendLegendRow(this._breakdownLegendElement, WI.CPUTimelineView.SampleType.Paint); 179 187 this._breakdownLegendStyleElement = appendLegendRow(this._breakdownLegendElement, WI.CPUTimelineView.SampleType.Style); 188 189 let dividerElement = overviewElement.appendChild(document.createElement("div")); 190 dividerElement.classList.add("divider"); 191 192 let energyTooltip = WI.UIString("Estimated energy impact.") 193 let energyContainerElement = createChartContainer(overviewElement, WI.UIString("Energy Impact"), energyTooltip); 194 energyContainerElement.classList.add("energy"); 195 196 let energyChartElement = energyContainerElement.parentElement; 197 let energySubtitleElement = energyChartElement.firstChild; 198 let energyInfoElement = energySubtitleElement.appendChild(document.createElement("span")); 199 energyInfoElement.className = "info"; 200 energyInfoElement.textContent = "?"; 201 202 this._energyInfoPopover = null; 203 this._energyInfoPopoverContentElement = null; 204 energyInfoElement.addEventListener("click", (event) => { 205 if (!this._energyInfoPopover) 206 this._energyInfoPopover = new WI.Popover; 207 208 if (!this._energyInfoPopoverContentElement) { 209 this._energyInfoPopoverContentElement = document.createElement("div"); 210 this._energyInfoPopoverContentElement.className = "energy-info-popover-content"; 211 212 const precision = 0; 213 let lowPercent = Number.percentageString(CPUTimelineView.lowEnergyThreshold / 100, precision); 214 215 let p1 = this._energyInfoPopoverContentElement.appendChild(document.createElement("p")); 216 p1.textContent = WI.UIString("Periods of high CPU utilization will rapidly drain battery. Strive to keep idle pages under %s average CPU utilization.").format(lowPercent); 217 218 let p2 = this._energyInfoPopoverContentElement.appendChild(document.createElement("p")); 219 p2.textContent = WI.UIString("There is an incurred energy penalty each time the page enters script. This commonly happens with timers, event handlers, and observers."); 220 221 let p3 = this._energyInfoPopoverContentElement.appendChild(document.createElement("p")); 222 p3.textContent = WI.UIString("To improve CPU utilization reduce or batch workloads when the page is not visible or during times when the page is not being interacted with."); 223 } 224 225 let isRTL = WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL; 226 let preferredEdges = isRTL ? [WI.RectEdge.MAX_Y, WI.RectEdge.MIN_X] : [WI.RectEdge.MAX_Y, WI.RectEdge.MAX_X]; 227 let calculateTargetFrame = () => WI.Rect.rectFromClientRect(energyInfoElement.getBoundingClientRect()).pad(3); 228 229 this._energyInfoPopover.presentNewContentWithFrame(this._energyInfoPopoverContentElement, calculateTargetFrame(), preferredEdges); 230 this._energyInfoPopover.windowResizeHandler = () => { 231 this._energyInfoPopover.present(calculateTargetFrame(), preferredEdges); 232 }; 233 }); 234 235 this._energyChart = new WI.GaugeChart({ 236 height: 110, 237 strokeWidth: 20, 238 segments: [ 239 {className: "low", limit: 10}, 240 {className: "medium", limit: 80}, 241 {className: "high", limit: 100}, 242 ] 243 }); 244 this.addSubview(this._energyChart); 245 energyContainerElement.appendChild(this._energyChart.element); 246 247 let energyTextContainerElement = energyContainerElement.appendChild(document.createElement("div")); 248 249 this._energyImpactLabelElement = energyTextContainerElement.appendChild(document.createElement("div")); 250 this._energyImpactLabelElement.className = "energy-impact"; 251 252 this._energyImpactNumberElement = energyTextContainerElement.appendChild(document.createElement("div")); 253 this._energyImpactNumberElement.className = "energy-impact-number"; 254 255 this._energyImpactDurationElement = energyTextContainerElement.appendChild(document.createElement("div")); 256 this._energyImpactDurationElement.className = "energy-impact-number"; 180 257 181 258 let detailsContainerElement = contentElement.appendChild(document.createElement("div")); … … 256 333 let graphEndTime = this.endTime; 257 334 let visibleEndTime = Math.min(this.endTime, this.currentTime); 335 let visibleDuration = visibleEndTime - graphStartTime; 258 336 259 337 let discontinuities = this._recording.discontinuitiesInTimeRange(graphStartTime, visibleEndTime); … … 561 639 let size = new WI.Size(graphWidth, CPUTimelineView.indicatorViewHeight); 562 640 this._mainThreadWorkIndicatorView.updateChart(samplingData.samples, size, visibleEndTime, xScaleIndicatorRange); 641 642 this._layoutEnergyChart(average, visibleDuration); 563 643 } 564 644 565 645 // Private 646 647 _layoutEnergyChart(average, visibleDuration) 648 { 649 // The lower the bias value [0..1], the more it increases the skew towards rangeHigh. 650 function mapWithBias(value, rangeLow, rangeHigh, outputRangeLow, outputRangeHigh, bias) { 651 console.assert(value >= rangeLow && value <= rangeHigh, "value was not in range.", value); 652 let percentInRange = (value - rangeLow) / (rangeHigh - rangeLow); 653 let skewedPercent = Math.pow(percentInRange, bias); 654 let valueInOutputRange = (skewedPercent * (outputRangeHigh - outputRangeLow)) + outputRangeLow; 655 return valueInOutputRange; 656 } 657 658 this._clearEnergyImpactText(); 659 660 if (average === 0) { 661 // Zero. (0% CPU, mapped to 0) 662 this._energyImpactLabelElement.textContent = WI.UIString("Low"); 663 this._energyImpactLabelElement.classList.add("low"); 664 this._energyChart.value = 0; 665 } else if (average <= CPUTimelineView.lowEnergyThreshold) { 666 // Low. (<=3% CPU, mapped to 0-10) 667 this._energyImpactLabelElement.textContent = WI.UIString("Low"); 668 this._energyImpactLabelElement.classList.add("low"); 669 this._energyChart.value = mapWithBias(average, 0, CPUTimelineView.lowEnergyThreshold, 0, 10, 0.85); 670 } else if (average <= CPUTimelineView. mediumEnergyThreshold) { 671 // Medium (3%-90% CPU, mapped to 10-80) 672 this._energyImpactLabelElement.textContent = WI.UIString("Medium"); 673 this._energyImpactLabelElement.classList.add("medium"); 674 this._energyChart.value = mapWithBias(average, CPUTimelineView.lowEnergyThreshold, CPUTimelineView.mediumEnergyThreshold, 10, 80, 0.6); 675 } else if (average < CPUTimelineView. highEnergyThreshold) { 676 // High. (50-150% CPU, mapped to 80-100) 677 this._energyImpactLabelElement.textContent = WI.UIString("High"); 678 this._energyImpactLabelElement.classList.add("high"); 679 this._energyChart.value = mapWithBias(average, CPUTimelineView.mediumEnergyThreshold, CPUTimelineView.highEnergyThreshold, 80, 100, 0.9); 680 } else { 681 // Very High. (>150% CPU, mapped to 100) 682 this._energyImpactLabelElement.textContent = WI.UIString("Very High"); 683 this._energyImpactLabelElement.classList.add("high"); 684 this._energyChart.value = 100; 685 } 686 687 this._energyChart.needsLayout(); 688 689 this._energyImpactNumberElement.textContent = WI.UIString("Average CPU: %s").format(Number.percentageString(average / 100)); 690 691 if (visibleDuration < 5) 692 this._energyImpactDurationElement.textContent = WI.UIString("Duration: %s").format(WI.UIString("Short")); 693 else { 694 let durationDisplayString = Math.floor(visibleDuration) + "s"; 695 this._energyImpactDurationElement.textContent = WI.UIString("Duration: %s").format(durationDisplayString); 696 } 697 } 566 698 567 699 _computeSamplingData(startTime, endTime) … … 725 857 726 858 this._workerViews = []; 859 } 860 861 _clearEnergyImpactText() 862 { 863 this._energyImpactLabelElement.classList.remove("low", "medium", "high"); 864 this._energyImpactLabelElement.textContent = emDash; 865 this._energyImpactNumberElement.textContent = ""; 866 this._energyImpactDurationElement.textContent = ""; 727 867 } 728 868 -
trunk/Source/WebInspectorUI/UserInterface/Views/ChartDetailsSectionRow.js
r223308 r242300 313 313 "M", x1, y1, // Starting position. 314 314 "A", r1, r1, 0, largeArcFlag, 1, x2, y2, // Draw outer arc. 315 "L", x3, y3, // Connect outer and inn ner arcs.315 "L", x3, y3, // Connect outer and inner arcs. 316 316 "A", r2, r2, 0, largeArcFlag, 0, x4, y4, // Draw inner arc. 317 317 "Z" // Close path. -
trunk/Source/WebInspectorUI/UserInterface/Views/CircleChart.js
r240870 r242300 202 202 "M", x1, y1, // Starting position. 203 203 "A", r1, r1, 0, largeArcFlag, 1, x2, y2, // Draw outer arc. 204 "L", x3, y3, // Connect outer and inn ner arcs.204 "L", x3, y3, // Connect outer and inner arcs. 205 205 "A", r2, r2, 0, largeArcFlag, 0, x4, y4, // Draw inner arc. 206 206 "Z" // Close path. -
trunk/Source/WebInspectorUI/UserInterface/Views/Variables.css
r242228 r242300 143 143 --cpu-paint-stroke-color: hsl(79, 45%, 50%); 144 144 145 --cpu-low-color: hsl(110, 52%, 56%); 146 --cpu-medium-color: hsl(46, 91%, 62%); 147 --cpu-high-color: hsl(6, 79%, 57%); 148 145 149 --network-header-color: hsl(204, 52%, 55%); 146 150 --network-system-color: hsl(79, 32%, 50%); … … 285 289 --network-error-color: hsl(0, 54%, 55%); 286 290 291 --cpu-low-color: hsl(110, 52%, 56%); 292 --cpu-medium-color: hsl(46, 91%, 62%); 293 --cpu-high-color: hsl(6, 79%, 57%); 294 287 295 --even-zebra-stripe-row-background-color: var(--background-color); 288 296 --odd-zebra-stripe-row-background-color: var(--background-color-secondary);
Note: See TracChangeset
for help on using the changeset viewer.