Changeset 242073 in webkit


Ignore:
Timestamp:
Feb 25, 2019, 10:36:34 PM (6 years ago)
Author:
Joseph Pecoraro
Message:

Web Inspector: CPU Usage Timeline - Thread Breakdown
https://bugs.webkit.org/show_bug.cgi?id=194788

Reviewed by Devin Rousso.

  • Localizations/en.lproj/localizedStrings.js:
  • UserInterface/Main.html:

New strings and files.

  • UserInterface/Views/Variables.css:

(:root):
New colors for cpu threads / activity breakdown.

  • UserInterface/Models/CPUTimelineRecord.js:

(WI.CPUTimelineRecord.prototype.get workers):
(WI.CPUTimelineRecord):
Distinguish the workers in a CPU timeline record.

  • UserInterface/Views/CPUTimelineOverviewGraph.js:

(WI.CPUTimelineOverviewGraph):
(WI.CPUTimelineOverviewGraph.prototype.layout):

  • UserInterface/Views/CPUTimelineOverviewGraph.css:

(.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect):
(.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.main-thread-usage):
(.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.worker-thread-usage):
(.timeline-overview-graph.cpu > .column-chart > svg > rect):
Stacked column chart for CPU in the overview graph.

  • UserInterface/Views/CPUTimelineView.css:

(.timeline-view.cpu > .content > .overview):
(.timeline-view.cpu > .content > .details > .subtitle.threads):
(.timeline-view.cpu > .content > .overview > .chart):
(.timeline-view.cpu > .content > .overview > .chart > .subtitle):
(.timeline-view.cpu > .content > .overview > .chart > .container):
(.timeline-view.cpu > .content > .overview .samples,):
(.timeline-view.cpu .legend):
(.timeline-view.cpu .legend .row):
(.timeline-view.cpu .legend .row + .row):
(.timeline-view.cpu .legend .swatch):
(.timeline-view.cpu .legend > .row > .swatch.sample-type-idle):
(.timeline-view.cpu .legend > .row > .swatch.sample-type-script):
(.timeline-view.cpu .legend > .row > .swatch.sample-type-style):
(.timeline-view.cpu .legend > .row > .swatch.sample-type-layout):
(.timeline-view.cpu .legend > .row > .swatch.sample-type-paint):
(.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-idle):
(.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-script):
(.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-style):
(.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-layout):
(.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-paint):
(.timeline-view.cpu svg > path):
(.timeline-view.cpu .main-thread svg > path,):
(.timeline-view.cpu .worker-thread svg > path,):
(.timeline-view.cpu .cpu-usage-view.empty):
(.timeline-view.cpu :matches(.line-chart, .stacked-line-chart) .markers):
(.timeline-view.cpu :matches(.line-chart, .stacked-line-chart) .markers > div):
(.timeline-view.cpu :matches(.line-chart, .stacked-line-chart) .markers > div > .label):
(.timeline-view.cpu > .content): Deleted.
(.cpu-usage-view .line-chart > svg > path): Deleted.
(.timeline-view.cpu .legend > .row > .swatch.current): Deleted.

  • UserInterface/Views/CPUTimelineView.js:

(WI.CPUTimelineView):
(WI.CPUTimelineView.displayNameForSampleType):
(WI.CPUTimelineView.prototype.shown):
(WI.CPUTimelineView.prototype.clear.clearUsageView):
(WI.CPUTimelineView.prototype.clear):
(WI.CPUTimelineView.prototype.initialLayout.createChartContainer):
(WI.CPUTimelineView.prototype.initialLayout.appendLegendRow):
(WI.CPUTimelineView.prototype.initialLayout):
(WI.CPUTimelineView.prototype.layout.removeGreaterThan):
(WI.CPUTimelineView.prototype.layout):
(WI.CPUTimelineView.prototype.layout.layoutView):
(WI.CPUTimelineView.prototype.layout.yScale):
(WI.CPUTimelineView.prototype._computeSamplingData.markRecordEntries):
(WI.CPUTimelineView.prototype._computeSamplingData):
(WI.CPUTimelineView.prototype._removeWorkerThreadViews):
(WI.CPUTimelineView.prototype._clearBreakdownLegend):
(WI.CPUTimelineView.prototype.layout.xScale): Deleted.
Line charts and Circle Chart for threads and breakdowns.

  • UserInterface/Views/CPUUsageStackedView.css:

(.cpu-usage-stacked-view):
(.cpu-usage-stacked-view > .details):
(body[dir=ltr] .cpu-usage-stacked-view > .details):
(body[dir=rtl] .cpu-usage-stacked-view > .details):
(.cpu-usage-stacked-view > .details > .name):
(body[dir=rtl] .cpu-usage-stacked-view > .graph):
(.cpu-usage-stacked-view > .graph):
(.cpu-usage-stacked-view > .graph,):

  • UserInterface/Views/CPUUsageStackedView.js:

(WI.CPUUsageStackedView):
(WI.CPUUsageStackedView.prototype.get chart):
(WI.CPUUsageStackedView.prototype.clear):
(WI.CPUUsageStackedView.prototype.updateChart):
(WI.CPUUsageStackedView.prototype._updateDetails):
Same as CPUUsageView except Stacked for the total.

  • UserInterface/Views/CPUUsageView.css:

(.cpu-usage-view):
(.cpu-usage-view > .details):
(.cpu-usage-view > .details > .name):
(.cpu-usage-view > .graph):

  • UserInterface/Views/CPUUsageView.js:

(WI.CPUUsageView):
(WI.CPUUsageView.prototype.get chart):
(WI.CPUUsageView.prototype.clear):
(WI.CPUUsageView.prototype.updateChart):
(WI.CPUUsageView.prototype._updateDetails):
Slight modifications for the new UI.

  • UserInterface/Views/LegacyCPUTimelineView.css:

(.timeline-view.legacy-cpu .cpu-usage-view .line-chart > svg > path):

  • UserInterface/Views/LegacyCPUTimelineView.js:

(WI.LegacyCPUTimelineView.prototype.layout):
Update API calls in the legacy view for minor changes.

  • UserInterface/Views/MemoryCategoryView.css:

(.memory-category-view > .details):
(.memory-category-view > .details > .name):

  • UserInterface/Views/MemoryTimelineOverviewGraph.js:

(WI.MemoryTimelineOverviewGraph.prototype.layout):

  • UserInterface/Views/MemoryTimelineView.css:

(body .timeline-view.memory):
(.timeline-view.memory): Deleted.
Improvements ported from the CPU timeline views.

  • UserInterface/Views/StackedColumnChart.js: Added.

(WI.StackedColumnChart):
(WI.StackedColumnChart.prototype.get size):
(WI.StackedColumnChart.prototype.set size):
(WI.StackedColumnChart.prototype.initializeSections):
(WI.StackedColumnChart.prototype.addColumnSet):
(WI.StackedColumnChart.prototype.clear):
(WI.StackedColumnChart.prototype.layout):
A stacked column chart implementation.

  • UserInterface/Views/View.js:

(WI.View.prototype.removeUnparentedSubview):
Add a way to remove a subview that had its element moved
someplace other than a direct child of our element.

Location:
trunk/Source/WebInspectorUI
Files:
1 added
17 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebInspectorUI/ChangeLog

    r242072 r242073  
     12019-02-25  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: CPU Usage Timeline - Thread Breakdown
     4        https://bugs.webkit.org/show_bug.cgi?id=194788
     5
     6        Reviewed by Devin Rousso.
     7
     8        * Localizations/en.lproj/localizedStrings.js:
     9        * UserInterface/Main.html:
     10        New strings and files.
     11
     12        * UserInterface/Views/Variables.css:
     13        (:root):
     14        New colors for cpu threads / activity breakdown.
     15
     16        * UserInterface/Models/CPUTimelineRecord.js:
     17        (WI.CPUTimelineRecord.prototype.get workers):
     18        (WI.CPUTimelineRecord):
     19        Distinguish the workers in a CPU timeline record.
     20
     21        * UserInterface/Views/CPUTimelineOverviewGraph.js:
     22        (WI.CPUTimelineOverviewGraph):
     23        (WI.CPUTimelineOverviewGraph.prototype.layout):
     24        * UserInterface/Views/CPUTimelineOverviewGraph.css:
     25        (.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect):
     26        (.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.main-thread-usage):
     27        (.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.worker-thread-usage):
     28        (.timeline-overview-graph.cpu > .column-chart > svg > rect):
     29        Stacked column chart for CPU in the overview graph.
     30
     31        * UserInterface/Views/CPUTimelineView.css:
     32        (.timeline-view.cpu > .content > .overview):
     33        (.timeline-view.cpu > .content > .details > .subtitle.threads):
     34        (.timeline-view.cpu > .content > .overview > .chart):
     35        (.timeline-view.cpu > .content > .overview > .chart > .subtitle):
     36        (.timeline-view.cpu > .content > .overview > .chart > .container):
     37        (.timeline-view.cpu > .content > .overview .samples,):
     38        (.timeline-view.cpu .legend):
     39        (.timeline-view.cpu .legend .row):
     40        (.timeline-view.cpu .legend .row + .row):
     41        (.timeline-view.cpu .legend .swatch):
     42        (.timeline-view.cpu .legend > .row > .swatch.sample-type-idle):
     43        (.timeline-view.cpu .legend > .row > .swatch.sample-type-script):
     44        (.timeline-view.cpu .legend > .row > .swatch.sample-type-style):
     45        (.timeline-view.cpu .legend > .row > .swatch.sample-type-layout):
     46        (.timeline-view.cpu .legend > .row > .swatch.sample-type-paint):
     47        (.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-idle):
     48        (.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-script):
     49        (.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-style):
     50        (.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-layout):
     51        (.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-paint):
     52        (.timeline-view.cpu svg > path):
     53        (.timeline-view.cpu .main-thread svg > path,):
     54        (.timeline-view.cpu .worker-thread svg > path,):
     55        (.timeline-view.cpu .cpu-usage-view.empty):
     56        (.timeline-view.cpu :matches(.line-chart, .stacked-line-chart) .markers):
     57        (.timeline-view.cpu :matches(.line-chart, .stacked-line-chart) .markers > div):
     58        (.timeline-view.cpu :matches(.line-chart, .stacked-line-chart) .markers > div > .label):
     59        (.timeline-view.cpu > .content): Deleted.
     60        (.cpu-usage-view .line-chart > svg > path): Deleted.
     61        (.timeline-view.cpu .legend > .row > .swatch.current): Deleted.
     62        * UserInterface/Views/CPUTimelineView.js:
     63        (WI.CPUTimelineView):
     64        (WI.CPUTimelineView.displayNameForSampleType):
     65        (WI.CPUTimelineView.prototype.shown):
     66        (WI.CPUTimelineView.prototype.clear.clearUsageView):
     67        (WI.CPUTimelineView.prototype.clear):
     68        (WI.CPUTimelineView.prototype.initialLayout.createChartContainer):
     69        (WI.CPUTimelineView.prototype.initialLayout.appendLegendRow):
     70        (WI.CPUTimelineView.prototype.initialLayout):
     71        (WI.CPUTimelineView.prototype.layout.removeGreaterThan):
     72        (WI.CPUTimelineView.prototype.layout):
     73        (WI.CPUTimelineView.prototype.layout.layoutView):
     74        (WI.CPUTimelineView.prototype.layout.yScale):
     75        (WI.CPUTimelineView.prototype._computeSamplingData.markRecordEntries):
     76        (WI.CPUTimelineView.prototype._computeSamplingData):
     77        (WI.CPUTimelineView.prototype._removeWorkerThreadViews):
     78        (WI.CPUTimelineView.prototype._clearBreakdownLegend):
     79        (WI.CPUTimelineView.prototype.layout.xScale): Deleted.
     80        Line charts and Circle Chart for threads and breakdowns.
     81
     82        * UserInterface/Views/CPUUsageStackedView.css:
     83        (.cpu-usage-stacked-view):
     84        (.cpu-usage-stacked-view > .details):
     85        (body[dir=ltr] .cpu-usage-stacked-view > .details):
     86        (body[dir=rtl] .cpu-usage-stacked-view > .details):
     87        (.cpu-usage-stacked-view > .details > .name):
     88        (body[dir=rtl] .cpu-usage-stacked-view > .graph):
     89        (.cpu-usage-stacked-view > .graph):
     90        (.cpu-usage-stacked-view > .graph,):
     91        * UserInterface/Views/CPUUsageStackedView.js:
     92        (WI.CPUUsageStackedView):
     93        (WI.CPUUsageStackedView.prototype.get chart):
     94        (WI.CPUUsageStackedView.prototype.clear):
     95        (WI.CPUUsageStackedView.prototype.updateChart):
     96        (WI.CPUUsageStackedView.prototype._updateDetails):
     97        Same as CPUUsageView except Stacked for the total.
     98
     99        * UserInterface/Views/CPUUsageView.css:
     100        (.cpu-usage-view):
     101        (.cpu-usage-view > .details):
     102        (.cpu-usage-view > .details > .name):
     103        (.cpu-usage-view > .graph):
     104        * UserInterface/Views/CPUUsageView.js:
     105        (WI.CPUUsageView):
     106        (WI.CPUUsageView.prototype.get chart):
     107        (WI.CPUUsageView.prototype.clear):
     108        (WI.CPUUsageView.prototype.updateChart):
     109        (WI.CPUUsageView.prototype._updateDetails):
     110        Slight modifications for the new UI.
     111
     112        * UserInterface/Views/LegacyCPUTimelineView.css:
     113        (.timeline-view.legacy-cpu .cpu-usage-view .line-chart > svg > path):
     114        * UserInterface/Views/LegacyCPUTimelineView.js:
     115        (WI.LegacyCPUTimelineView.prototype.layout):
     116        Update API calls in the legacy view for minor changes.
     117
     118        * UserInterface/Views/MemoryCategoryView.css:
     119        (.memory-category-view > .details):
     120        (.memory-category-view > .details > .name):
     121        * UserInterface/Views/MemoryTimelineOverviewGraph.js:
     122        (WI.MemoryTimelineOverviewGraph.prototype.layout):
     123        * UserInterface/Views/MemoryTimelineView.css:
     124        (body .timeline-view.memory):
     125        (.timeline-view.memory): Deleted.
     126        Improvements ported from the CPU timeline views.
     127
     128        * UserInterface/Views/StackedColumnChart.js: Added.
     129        (WI.StackedColumnChart):
     130        (WI.StackedColumnChart.prototype.get size):
     131        (WI.StackedColumnChart.prototype.set size):
     132        (WI.StackedColumnChart.prototype.initializeSections):
     133        (WI.StackedColumnChart.prototype.addColumnSet):
     134        (WI.StackedColumnChart.prototype.clear):
     135        (WI.StackedColumnChart.prototype.layout):
     136        A stacked column chart implementation.
     137
     138        * UserInterface/Views/View.js:
     139        (WI.View.prototype.removeUnparentedSubview):
     140        Add a way to remove a subview that had its `element` moved
     141        someplace other than a direct child of our element.
     142
    11432019-02-25  Joseph Pecoraro  <pecoraro@apple.com>
    2144
  • trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js

    r242049 r242073  
    159159localizedStrings["Breakdown"] = "Breakdown";
    160160localizedStrings["Breakdown of each memory category at the end of the selected time range"] = "Breakdown of each memory category at the end of the selected time range";
     161localizedStrings["Breakdown of time spent on the main thread"] = "Breakdown of time spent on the main thread";
    161162localizedStrings["Breakpoint"] = "Breakpoint";
    162163localizedStrings["Breakpoints"] = "Breakpoints";
     
    600601localizedStrings["MIME Type:"] = "MIME Type:";
    601602localizedStrings["MSE Logging:"] = "MSE Logging:";
     603localizedStrings["Main Thread"] = "Main Thread";
    602604localizedStrings["Manifest URL"] = "Manifest URL";
    603605localizedStrings["Mass"] = "Mass";
     
    689691localizedStrings["Other"] = "Other";
    690692localizedStrings["Other Issue"] = "Other Issue";
     693localizedStrings["Other Threads"] = "Other Threads";
    691694localizedStrings["Other\u2026"] = "Other\u2026";
    692695localizedStrings["Outgoing message"] = "Outgoing message";
     
    956959localizedStrings["Storage"] = "Storage";
    957960localizedStrings["Style Attribute"] = "Style Attribute";
     961localizedStrings["Style Resolution"] = "Style Resolution";
    958962localizedStrings["Style rule"] = "Style rule";
    959963localizedStrings["Styles"] = "Styles";
     
    10011005localizedStrings["This object is referenced by internal objects"] = "This object is referenced by internal objects";
    10021006localizedStrings["This text resource could benefit from compression"] = "This text resource could benefit from compression";
     1007localizedStrings["Threads"] = "Threads";
    10031008localizedStrings["Time"] = "Time";
     1009localizedStrings["Time spent on the main thread"] = "Time spent on the main thread";
    10041010localizedStrings["Time to First Byte"] = "Time to First Byte";
    10051011localizedStrings["Timeline"] = "Timeline";
     
    10171023localizedStrings["Toggle Visibility"] = "Toggle Visibility";
    10181024localizedStrings["Top Functions"] = "Top Functions";
     1025localizedStrings["Total"] = "Total";
    10191026localizedStrings["Total Time"] = "Total Time";
    10201027localizedStrings["Total memory size at the end of the selected time range"] = "Total memory size at the end of the selected time range";
     
    10751082localizedStrings["Waterfall"] = "Waterfall";
    10761083localizedStrings["Web Inspector"] = "Web Inspector";
     1084localizedStrings["WebKit Threads"] = "WebKit Threads";
    10771085localizedStrings["WebRTC"] = "WebRTC";
    10781086localizedStrings["WebRTC Logging:"] = "WebRTC Logging:";
     
    10821090localizedStrings["With Object Properties"] = "With Object Properties";
    10831091localizedStrings["Worker"] = "Worker";
     1092localizedStrings["Worker Thread"] = "Worker Thread";
    10841093localizedStrings["Worker \u2014 %s"] = "Worker \u2014 %s";
    10851094localizedStrings["Working Copy"] = "Working Copy";
  • trunk/Source/WebInspectorUI/UserInterface/Main.html

    r242049 r242073  
    4646    <link rel="stylesheet" href="Views/CPUTimelineOverviewGraph.css">
    4747    <link rel="stylesheet" href="Views/CPUTimelineView.css">
     48    <link rel="stylesheet" href="Views/CPUUsageStackedView.css">
    4849    <link rel="stylesheet" href="Views/CPUUsageView.css">
    4950    <link rel="stylesheet" href="Views/CallFrameIcons.css">
     
    593594    <script src="Views/CPUTimelineOverviewGraph.js"></script>
    594595    <script src="Views/CPUTimelineView.js"></script>
     596    <script src="Views/CPUUsageStackedView.js"></script>
    595597    <script src="Views/CPUUsageView.js"></script>
    596598    <script src="Views/CSSStyleSheetTreeElement.js"></script>
     
    807809    <script src="Views/SVGImageResourceClusterContentView.js"></script>
    808810    <script src="Views/StackTraceView.js"></script>
     811    <script src="Views/StackedColumnChart.js"></script>
    809812    <script src="Views/StackedLineChart.js"></script>
    810813    <script src="Views/StorageSidebarPanel.js"></script>
  • trunk/Source/WebInspectorUI/UserInterface/Models/CPUTimelineRecord.js

    r241739 r242073  
    4444        this._workerThreadUsage = 0;
    4545        this._unknownThreadUsage = 0;
     46        this._workersData = null;
    4647
    4748        for (let thread of threads) {
     
    5354
    5455            if (thread.type === InspectorBackend.domains.CPUProfiler.ThreadInfoType.WebKit) {
    55                 if (thread.targetId)
     56                if (thread.targetId) {
     57                    if (!this._workersData)
     58                        this._workersData = [];
     59                    this._workersData.push(thread);
    5660                    this._workerThreadUsage += thread.usage;
    57                 else
    58                     this._webkitThreadUsage += thread.usage;
     61                    continue;
     62                }
     63
     64                this._webkitThreadUsage += thread.usage;
    5965                continue;
    6066            }
     
    7379    get workerThreadUsage() { return this._workerThreadUsage; }
    7480    get unknownThreadUsage() { return this._unknownThreadUsage; }
     81    get workersData() { return this._workersData; }
    7582};
  • trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineOverviewGraph.css

    r242072 r242073  
    5858}
    5959
     60body[dir=rtl] .timeline-overview-graph.cpu > .stacked-column-chart {
     61    transform: scaleX(-1);
     62}
     63
     64.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect {
     65    stroke: var(--cpu-stroke-color);
     66    fill: var(--cpu-fill-color);
     67}
     68
     69.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.main-thread-usage {
     70    fill: var(--cpu-main-thread-fill-color);
     71}
     72
     73.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.worker-thread-usage {
     74    fill: var(--cpu-worker-thread-fill-color);
     75}
     76
     77/* LegacyCPUTimeline */
     78.timeline-overview-graph.cpu > .column-chart > svg > rect {
     79    stroke: var(--cpu-stroke-color);
     80    fill: var(--cpu-main-thread-fill-color);
     81}
     82
    6083body[dir=rtl] .timeline-overview-graph.cpu > .column-chart {
    6184    transform: scaleX(-1);
    6285}
    63 
    64 .timeline-overview-graph.cpu > .column-chart > svg > rect {
    65     stroke: var(--cpu-stroke-color);
    66     fill: var(--cpu-fill-color);
    67 }
  • trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineOverviewGraph.js

    r240872 r242073  
    3939
    4040        let size = new WI.Size(0, this.height);
    41         this._chart = new WI.ColumnChart(size);
     41        if (WI.settings.experimentalEnableCPUUsageEnhancements.value) {
     42            this._chart = new WI.StackedColumnChart(size);
     43            this._chart.initializeSections(["main-thread-usage", "worker-thread-usage", "total-usage"]);
     44        } else
     45            this._chart = new WI.ColumnChart(size);
    4246        this.addSubview(this._chart);
    4347        this.element.appendChild(this._chart.element);
     
    115119        for (let record of visibleRecords) {
    116120            let w = intervalWidth;
    117             let h = Math.max(minimumDisplayHeight, yScale(record.usage));
     121            let h3 = Math.max(minimumDisplayHeight, yScale(record.usage));
    118122            let x = xScale(record.startTime - (samplingRatePerSecond / 2));
    119             let y = height - h;
    120             this._chart.addColumn(x, y, w, h);
     123            if (WI.settings.experimentalEnableCPUUsageEnhancements.value) {
     124                let h1 = Math.max(minimumDisplayHeight, yScale(record.mainThreadUsage));
     125                let h2 = Math.max(minimumDisplayHeight, yScale(record.mainThreadUsage + record.workerThreadUsage));
     126                this._chart.addColumnSet(x, height, w, [h1, h2, h3]);
     127            } else
     128                this._chart.addColumn(x, height - h3, w, h3);
    121129        }
    122 
    123         this._chart.updateLayout();
    124130    }
    125131
  • trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.css

    r240763 r242073  
    2828}
    2929
    30 .timeline-view.cpu > .content {
    31     margin-top: 10px;
     30.timeline-view.cpu > .content > .overview {
     31    display: flex;
     32    justify-content: center;
     33    margin-bottom: 10px;
     34    padding: 10px;
     35    border-bottom: 1px solid var(--border-color);
    3236}
    3337
     
    6468}
    6569
    66 .cpu-usage-view .line-chart > svg > path {
     70.timeline-view.cpu > .content > .details > .subtitle.threads {
     71    position: relative;
     72    z-index: calc(var(--timeline-marker-z-index) + 1);
     73    padding-top: 10px;
     74    background-color: var(--background-color-content);
     75}
     76
     77.timeline-view.cpu > .content > .overview > .chart {
     78    width: 420px;
     79    text-align: center;
     80}
     81
     82.timeline-view.cpu > .content > .overview > .chart > .subtitle {
     83    margin-bottom: 1em;
     84}
     85
     86.timeline-view.cpu > .content > .overview > .chart > .container {
     87    display: flex;
     88    justify-content: center;
     89}
     90
     91.timeline-view.cpu > .content > .overview .samples,
     92.timeline-view.cpu > .content > .overview .legend .size {
     93    margin: auto;
     94    color: var(--text-color-secondary);
     95}
     96
     97.timeline-view.cpu .legend {
     98    -webkit-padding-start: 20px;
     99    text-align: start;
     100}
     101
     102.timeline-view.cpu .legend .row {
     103    display: flex;
     104}
     105
     106.timeline-view.cpu .legend .row + .row {
     107    margin-top: 4px;
     108}
     109
     110.timeline-view.cpu .legend .swatch {
     111    width: 1em;
     112    height: 1em;
     113    margin-top: 1px;
     114    -webkit-margin-end: 8px;
     115}
     116
     117.timeline-view.cpu .legend > .row > .swatch.sample-type-idle {
     118    border: 1px solid var(--cpu-idle-stroke-color);
     119    background-color: var(--cpu-idle-fill-color);
     120}
     121
     122.timeline-view.cpu .legend > .row > .swatch.sample-type-script {
     123    border: 1px solid var(--cpu-script-stroke-color);
     124    background-color: var(--cpu-script-fill-color);
     125}
     126
     127.timeline-view.cpu .legend > .row > .swatch.sample-type-style {
     128    border: 1px solid var(--cpu-style-stroke-color);
     129    background-color: var(--cpu-style-fill-color);
     130}
     131
     132.timeline-view.cpu .legend > .row > .swatch.sample-type-layout {
     133    border: 1px solid var(--cpu-layout-stroke-color);
     134    background-color: var(--cpu-layout-fill-color);
     135}
     136
     137.timeline-view.cpu .legend > .row > .swatch.sample-type-paint {
     138    border: 1px solid var(--cpu-paint-stroke-color);
     139    background-color: var(--cpu-paint-fill-color);
     140}
     141
     142.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-idle {
     143    stroke: var(--cpu-idle-stroke-color);
     144    fill: var(--cpu-idle-fill-color);
     145}
     146
     147.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-script {
     148    stroke: var(--cpu-script-stroke-color);
     149    fill: var(--cpu-script-fill-color);
     150}
     151
     152.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-style {
     153    stroke: var(--cpu-style-stroke-color);
     154    fill: var(--cpu-style-fill-color);
     155}
     156
     157.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-layout {
     158    stroke: var(--cpu-layout-stroke-color);
     159    fill: var(--cpu-layout-fill-color);
     160}
     161
     162.timeline-view.cpu .circle-chart > svg > path.segment.sample-type-paint {
     163    stroke: var(--cpu-paint-stroke-color);
     164    fill: var(--cpu-paint-fill-color);
     165}
     166
     167.timeline-view.cpu svg > path {
    67168    stroke: var(--cpu-stroke-color);
    68169    fill: var(--cpu-fill-color);
    69170}
    70171
    71 .timeline-view.cpu .legend > .row > .swatch.current {
    72     border: 1px solid var(--cpu-max-comparison-stroke-color);
    73     background: var(--cpu-max-comparison-fill-color);
    74 }
     172.timeline-view.cpu .main-thread svg > path,
     173.timeline-view.cpu svg > path.main-thread-usage {
     174    fill: var(--cpu-main-thread-fill-color);
     175}
     176
     177.timeline-view.cpu .worker-thread svg > path,
     178.timeline-view.cpu svg > path.worker-thread-usage {
     179    fill: var(--cpu-worker-thread-fill-color);
     180}
     181
     182.timeline-view.cpu .cpu-usage-view.empty {
     183    display: none;
     184}
     185
     186.timeline-view.cpu :matches(.line-chart, .stacked-line-chart) .markers {
     187    position: absolute;
     188    top: 0;
     189    left: 0;
     190    right: 0;
     191    bottom: 0;
     192    pointer-events: none;
     193}
     194
     195.timeline-view.cpu :matches(.line-chart, .stacked-line-chart) .markers > div {
     196    position: absolute;
     197    z-index: 10;
     198    width: 100%;
     199    height: 1px;
     200    background-color: hsla(0, 0%, var(--foreground-lightness), 0.07);
     201}
     202
     203body[dir=ltr] .timeline-view.cpu :matches(.line-chart, .stacked-line-chart) .markers > div {
     204    text-align: end;
     205}
     206
     207body[dir=rtl] .timeline-view.cpu :matches(.line-chart, .stacked-line-chart) .markers > div {
     208    transform: scaleX(-1);
     209}
     210
     211.timeline-view.cpu :matches(.line-chart, .stacked-line-chart) .markers > div > .label {
     212    padding: 2px;
     213    font-size: 8px;
     214    color: var(--text-color-secondary);
     215    background-color: var(--background-color-content);
     216}
  • trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.js

    r241301 r242073  
    3636        this.element.classList.add("cpu");
    3737
     38        timeline.addEventListener(WI.Timeline.Event.RecordAdded, this._cpuTimelineRecordAdded, this);
     39    }
     40
     41    // Static
     42
     43    static displayNameForSampleType(type)
     44    {
     45        switch (type) {
     46        case WI.CPUTimelineView.SampleType.Script:
     47            return WI.UIString("Script");
     48        case WI.CPUTimelineView.SampleType.Layout:
     49            return WI.UIString("Layout");
     50        case WI.CPUTimelineView.SampleType.Paint:
     51            return WI.UIString("Paint");
     52        case WI.CPUTimelineView.SampleType.Style:
     53            return WI.UIString("Style Resolution");
     54        }
     55        console.error("Unknown sample type", type);
     56    }
     57
     58    static get cpuUsageViewHeight() { return 150; }
     59    static get threadCPUUsageViewHeight() { return 65; }
     60
     61    // Public
     62
     63    shown()
     64    {
     65        super.shown();
     66
     67        if (this._timelineRuler)
     68            this._timelineRuler.updateLayout(WI.View.LayoutReason.Resize);
     69    }
     70
     71    closed()
     72    {
     73        console.assert(this.representedObject instanceof WI.Timeline);
     74        this.representedObject.removeEventListener(null, null, this);
     75    }
     76
     77    reset()
     78    {
     79        super.reset();
     80
     81        this.clear();
     82    }
     83
     84    clear()
     85    {
     86        if (!this.didInitialLayout)
     87            return;
     88
     89        this._breakdownChart.clear();
     90        this._breakdownChart.needsLayout();
     91        this._clearBreakdownLegend();
     92
     93        function clearUsageView(view) {
     94            view.clear();
     95
     96            let markersElement = view.chart.element.querySelector(".markers");
     97            if (markersElement)
     98                markersElement.remove();
     99        }
     100
     101        clearUsageView(this._cpuUsageView);
     102        clearUsageView(this._mainThreadUsageView);
     103        clearUsageView(this._webkitThreadUsageView);
     104        clearUsageView(this._unknownThreadUsageView);
     105
     106        this._removeWorkerThreadViews();
     107    }
     108
     109    get scrollableElements()
     110    {
     111        return [this.element];
     112    }
     113
     114    // Protected
     115
     116    get showsFilterBar() { return false; }
     117
     118    initialLayout()
     119    {
     120        this.element.style.setProperty("--cpu-usage-stacked-view-height", CPUTimelineView.cpuUsageViewHeight + "px");
     121        this.element.style.setProperty("--cpu-usage-view-height", CPUTimelineView.threadCPUUsageViewHeight + "px");
     122
    38123        let contentElement = this.element.appendChild(document.createElement("div"));
    39124        contentElement.classList.add("content");
    40125
    41         // FIXME: Overview with charts.
     126        let overviewElement = contentElement.appendChild(document.createElement("div"));
     127        overviewElement.classList.add("overview");
     128
     129        function createChartContainer(parentElement, subtitle, tooltip) {
     130            let chartElement = parentElement.appendChild(document.createElement("div"));
     131            chartElement.classList.add("chart");
     132
     133            let chartSubtitleElement = chartElement.appendChild(document.createElement("div"));
     134            chartSubtitleElement.classList.add("subtitle");
     135            chartSubtitleElement.textContent = subtitle;
     136            chartSubtitleElement.title = tooltip;
     137
     138            let chartFlexContainerElement = chartElement.appendChild(document.createElement("div"));
     139            chartFlexContainerElement.classList.add("container");
     140            return chartFlexContainerElement;
     141        }
     142
     143        function appendLegendRow(legendElement, sampleType) {
     144            let rowElement = legendElement.appendChild(document.createElement("div"));
     145            rowElement.classList.add("row");
     146
     147            let swatchElement = rowElement.appendChild(document.createElement("div"));
     148            swatchElement.classList.add("swatch", sampleType);
     149
     150            let valueContainer = rowElement.appendChild(document.createElement("div"));
     151            valueContainer.classList.add("value");
     152
     153            let labelElement = valueContainer.appendChild(document.createElement("div"));
     154            labelElement.classList.add("label");
     155            labelElement.textContent = WI.CPUTimelineView.displayNameForSampleType(sampleType);
     156
     157            let sizeElement = valueContainer.appendChild(document.createElement("div"));
     158            sizeElement.classList.add("size");
     159
     160            return sizeElement;
     161        }
     162
     163        let breakdownChartContainerElement = createChartContainer(overviewElement, WI.UIString("Main Thread"), WI.UIString("Breakdown of time spent on the main thread"));
     164        this._breakdownChart = new WI.CircleChart({size: 120, innerRadiusRatio: 0.5});
     165        this._breakdownChart.segments = Object.values(WI.CPUTimelineView.SampleType);
     166        this.addSubview(this._breakdownChart);
     167        breakdownChartContainerElement.appendChild(this._breakdownChart.element);
     168
     169        this._breakdownLegendElement = breakdownChartContainerElement.appendChild(document.createElement("div"));
     170        this._breakdownLegendElement.classList.add("legend");
     171
     172        this._breakdownLegendScriptElement = appendLegendRow(this._breakdownLegendElement, WI.CPUTimelineView.SampleType.Script);
     173        this._breakdownLegendLayoutElement = appendLegendRow(this._breakdownLegendElement, WI.CPUTimelineView.SampleType.Layout);
     174        this._breakdownLegendPaintElement = appendLegendRow(this._breakdownLegendElement, WI.CPUTimelineView.SampleType.Paint);
     175        this._breakdownLegendStyleElement = appendLegendRow(this._breakdownLegendElement, WI.CPUTimelineView.SampleType.Style);
    42176
    43177        let detailsContainerElement = this._detailsContainerElement = contentElement.appendChild(document.createElement("div"));
     
    45179
    46180        this._timelineRuler = new WI.TimelineRuler;
     181        this._timelineRuler.zeroTime = this.zeroTime;
     182        this._timelineRuler.startTime = this.startTime;
     183        this._timelineRuler.endTime = this.endTime;
     184
    47185        this.addSubview(this._timelineRuler);
    48186        detailsContainerElement.appendChild(this._timelineRuler.element);
     187
     188        // Cause the TimelineRuler to layout now so we will have some of its
     189        // important properties initialized for our layout.
     190        this._timelineRuler.updateLayout(WI.View.LayoutReason.Resize);
    49191
    50192        let detailsSubtitleElement = detailsContainerElement.appendChild(document.createElement("div"));
     
    52194        detailsSubtitleElement.textContent = WI.UIString("CPU Usage");
    53195
    54         this._cpuUsageView = new WI.CPUUsageView;
     196        this._cpuUsageView = new WI.CPUUsageStackedView(WI.UIString("Total"));
    55197        this.addSubview(this._cpuUsageView);
    56198        this._detailsContainerElement.appendChild(this._cpuUsageView.element);
    57199
    58         timeline.addEventListener(WI.Timeline.Event.RecordAdded, this._cpuTimelineRecordAdded, this);
    59     }
    60 
    61     // Public
    62 
    63     shown()
    64     {
    65         super.shown();
    66 
    67         this._timelineRuler.updateLayout(WI.View.LayoutReason.Resize);
    68     }
    69 
    70     closed()
    71     {
    72         console.assert(this.representedObject instanceof WI.Timeline);
    73         this.representedObject.removeEventListener(null, null, this);
    74     }
    75 
    76     reset()
    77     {
    78         super.reset();
    79 
    80         this.clear();
    81     }
    82 
    83     clear()
    84     {
    85         this._cpuUsageView.clear();
    86     }
    87 
    88     get scrollableElements()
    89     {
    90         return [this.element];
    91     }
    92 
    93     // Protected
    94 
    95     get showsFilterBar() { return false; }
     200        let threadsSubtitleElement = detailsContainerElement.appendChild(document.createElement("div"));
     201        threadsSubtitleElement.classList.add("subtitle", "threads");
     202        threadsSubtitleElement.textContent = WI.UIString("Threads");
     203
     204        this._mainThreadUsageView = new WI.CPUUsageView(WI.UIString("Main Thread"));
     205        this._mainThreadUsageView.element.classList.add("main-thread");
     206        this.addSubview(this._mainThreadUsageView);
     207        this._detailsContainerElement.appendChild(this._mainThreadUsageView.element);
     208
     209        this._webkitThreadUsageView = new WI.CPUUsageView(WI.UIString("WebKit Threads"));
     210        this._webkitThreadUsageView.element.classList.add("non-main-thread");
     211        this.addSubview(this._webkitThreadUsageView);
     212        this._detailsContainerElement.appendChild(this._webkitThreadUsageView.element);
     213
     214        this._unknownThreadUsageView = new WI.CPUUsageView(WI.UIString("Other Threads"));
     215        this._unknownThreadUsageView.element.classList.add("non-main-thread");
     216        this.addSubview(this._unknownThreadUsageView);
     217        this._detailsContainerElement.appendChild(this._unknownThreadUsageView.element);
     218
     219        this._workerViews = [];
     220    }
    96221
    97222    layout()
     
    105230        this._timelineRuler.endTime = this.endTime;
    106231
    107         const cpuUsageViewHeight = 75; // Keep this in sync with .cpu-usage-view
     232        let secondsPerPixel = this._timelineRuler.secondsPerPixel;
     233        if (!secondsPerPixel)
     234            return;
    108235
    109236        let graphStartTime = this.startTime;
    110237        let graphEndTime = this.endTime;
    111         let secondsPerPixel = this._timelineRuler.secondsPerPixel;
    112238        let visibleEndTime = Math.min(this.endTime, this.currentTime);
    113239
    114240        let discontinuities = this._recording.discontinuitiesInTimeRange(graphStartTime, visibleEndTime);
     241        let originalDiscontinuities = discontinuities.slice();
    115242
    116243        // Don't include the record before the graph start if the graph start is within a gap.
     
    122249        }
    123250
    124         // Update total usage chart with the last record's data.
    125         let lastRecord = visibleRecords.lastValue;
    126 
    127         // FIXME: Left chart.
    128         // FIXME: Right chart.
     251        let samplingData = this._computeSamplingData(graphStartTime, visibleEndTime);
     252        let nonIdleSamplesCount = samplingData.samples.length - samplingData.samplesIdle;
     253        if (!nonIdleSamplesCount) {
     254            this._breakdownChart.clear();
     255            this._breakdownChart.needsLayout();
     256            this._clearBreakdownLegend();
     257        } else {
     258            let percentScript = samplingData.samplesScript / nonIdleSamplesCount;
     259            let percentLayout = samplingData.samplesLayout / nonIdleSamplesCount;
     260            let percentPaint = samplingData.samplesPaint / nonIdleSamplesCount;
     261            let percentStyle = samplingData.samplesStyle / nonIdleSamplesCount;
     262
     263            this._breakdownLegendScriptElement.textContent = `${Number.percentageString(percentScript)} (${samplingData.samplesScript})`;
     264            this._breakdownLegendLayoutElement.textContent = `${Number.percentageString(percentLayout)} (${samplingData.samplesLayout})`;
     265            this._breakdownLegendPaintElement.textContent = `${Number.percentageString(percentPaint)} (${samplingData.samplesPaint})`;
     266            this._breakdownLegendStyleElement.textContent = `${Number.percentageString(percentStyle)} (${samplingData.samplesStyle})`;
     267
     268            this._breakdownChart.values = [percentScript * 100, percentLayout * 100, percentPaint * 100, percentStyle * 100];
     269            this._breakdownChart.needsLayout();
     270
     271            let centerElement = this._breakdownChart.centerElement;
     272            let samplesElement = centerElement.firstChild;
     273            if (!samplesElement) {
     274                samplesElement = centerElement.appendChild(document.createElement("div"));
     275                samplesElement.classList.add("samples");
     276                samplesElement.title = WI.UIString("Time spent on the main thread");
     277            }
     278
     279            let millisecondsStringNoDecimal = WI.UIString("%.0fms").format(nonIdleSamplesCount);
     280            samplesElement.textContent = millisecondsStringNoDecimal;
     281        }
    129282
    130283        let dataPoints = [];
     284        let workersDataMap = new Map;
     285
    131286        let max = -Infinity;
     287        let mainThreadMax = -Infinity;
     288        let webkitThreadMax = -Infinity;
     289        let unknownThreadMax = -Infinity;
     290
    132291        let min = Infinity;
     292        let mainThreadMin = Infinity;
     293        let webkitThreadMin = Infinity;
     294        let unknownThreadMin = Infinity;
     295
    133296        let average = 0;
     297        let mainThreadAverage = 0;
     298        let webkitThreadAverage = 0;
     299        let unknownThreadAverage = 0;
    134300
    135301        for (let record of visibleRecords) {
    136302            let time = record.startTime;
    137             let usage = record.usage;
     303            let {usage, mainThreadUsage, workerThreadUsage, webkitThreadUsage, unknownThreadUsage} = record;
    138304
    139305            if (discontinuities.length && discontinuities[0].endTime < time) {
     
    142308                while (discontinuities.length && discontinuities[0].endTime < time)
    143309                    endDiscontinuity = discontinuities.shift();
    144                 dataPoints.push({time: startDiscontinuity.startTime, size: 0});
    145                 dataPoints.push({time: endDiscontinuity.endTime, size: 0});
    146                 dataPoints.push({time: endDiscontinuity.endTime, size: usage});
    147             }
    148 
    149             dataPoints.push({time, size: usage});
     310
     311                if (dataPoints.length) {
     312                    let previousDataPoint = dataPoints.lastValue;
     313                    dataPoints.push({
     314                        time: startDiscontinuity.startTime,
     315                        mainThreadUsage: previousDataPoint.mainThreadUsage,
     316                        workerThreadUsage: previousDataPoint.workerThreadUsage,
     317                        webkitThreadUsage: previousDataPoint.webkitThreadUsage,
     318                        unknownThreadUsage: previousDataPoint.unknownThreadUsage,
     319                        usage: previousDataPoint.usage,
     320                    });
     321                }
     322
     323                dataPoints.push({time: startDiscontinuity.startTime, mainThreadUsage: 0, workerThreadUsage: 0, webkitThreadUsage: 0, unknownThreadUsage: 0, usage: 0});
     324                dataPoints.push({time: endDiscontinuity.endTime, mainThreadUsage: 0, workerThreadUsage: 0, webkitThreadUsage: 0, unknownThreadUsage: 0, usage: 0});
     325                dataPoints.push({time: endDiscontinuity.endTime, mainThreadUsage, workerThreadUsage, webkitThreadUsage, unknownThreadUsage, usage});
     326            }
     327
     328            dataPoints.push({time, mainThreadUsage, workerThreadUsage, webkitThreadUsage, unknownThreadUsage, usage});
     329
    150330            max = Math.max(max, usage);
     331            mainThreadMax = Math.max(mainThreadMax, mainThreadUsage);
     332            webkitThreadMax = Math.max(webkitThreadMax, webkitThreadUsage);
     333            unknownThreadMax = Math.max(unknownThreadMax, unknownThreadUsage);
     334
    151335            min = Math.min(min, usage);
     336            mainThreadMin = Math.min(mainThreadMin, mainThreadUsage);
     337            webkitThreadMin = Math.min(webkitThreadMin, webkitThreadUsage);
     338            unknownThreadMin = Math.min(unknownThreadMin, unknownThreadUsage);
     339
    152340            average += usage;
     341            mainThreadAverage += mainThreadUsage;
     342            webkitThreadAverage += webkitThreadUsage;
     343            unknownThreadAverage += unknownThreadUsage;
     344
     345            if (record.workersData && record.workersData.length) {
     346                for (let {targetId, usage} of record.workersData) {
     347                    let workerData = workersDataMap.get(targetId);
     348                    if (!workerData) {
     349                        workerData = {
     350                            discontinuities: originalDiscontinuities.slice(),
     351                            recordsCount: 0,
     352                            dataPoints: [],
     353                            min: Infinity,
     354                            max: -Infinity,
     355                            average: 0
     356                        };
     357
     358                        while (workerData.discontinuities.length && workerData.discontinuities[0].endTime <= graphStartTime)
     359                            workerData.discontinuities.shift();
     360                        workerData.dataPoints.push({time: graphStartTime, usage: 0});
     361                        workerData.dataPoints.push({time, usage: 0});
     362                        workersDataMap.set(targetId, workerData);
     363                    }
     364
     365                    if (workerData.discontinuities.length && workerData.discontinuities[0].endTime < time) {
     366                        let startDiscontinuity = workerData.discontinuities.shift();
     367                        let endDiscontinuity = startDiscontinuity;
     368                        while (workerData.discontinuities.length && workerData.discontinuities[0].endTime < time)
     369                            endDiscontinuity = workerData.discontinuities.shift();
     370                        if (workerData.dataPoints.length) {
     371                            let previousDataPoint = workerData.dataPoints.lastValue;
     372                            workerData.dataPoints.push({time: startDiscontinuity.startTime, usage: previousDataPoint.usage});
     373                        }
     374                        workerData.dataPoints.push({time: startDiscontinuity.startTime, usage: 0});
     375                        workerData.dataPoints.push({time: endDiscontinuity.endTime, usage: 0});
     376                        workerData.dataPoints.push({time: endDiscontinuity.endTime, usage});
     377                    }
     378
     379                    workerData.dataPoints.push({time, usage});
     380                    workerData.recordsCount += 1;
     381                    workerData.max = Math.max(workerData.max, usage);
     382                    workerData.min = Math.min(workerData.min, usage);
     383                    workerData.average += usage;
     384                }
     385            }
    153386        }
    154387
    155388        average /= visibleRecords.length;
     389        mainThreadAverage /= visibleRecords.length;
     390        webkitThreadAverage /= visibleRecords.length;
     391        unknownThreadAverage /= visibleRecords.length;
     392
     393        for (let [workerId, workerData] of workersDataMap)
     394            workerData.average = workerData.average / workerData.recordsCount;
    156395
    157396        // If the graph end time is inside a gap, the last data point should
     
    160399            visibleEndTime = discontinuities[0].startTime;
    161400
    162         function layoutView(view, {dataPoints, min, max, average}) {
     401        function removeGreaterThan(arr, max) {
     402            return arr.filter((x) => x <= max);
     403        }
     404
     405        function markerValuesForMaxValue(max) {
     406            if (max < 1)
     407                return [0.5];
     408            if (max < 7)
     409                return removeGreaterThan([1, 3, 5], max);
     410            if (max < 12.5)
     411                return removeGreaterThan([5, 10], max);
     412            if (max < 20)
     413                return removeGreaterThan([5, 10, 15], max);
     414            if (max < 30)
     415                return removeGreaterThan([10, 20, 30], max);
     416            if (max < 50)
     417                return removeGreaterThan([15, 30, 45], max);
     418            if (max < 100)
     419                return removeGreaterThan([25, 50, 75], max);
     420            if (max < 200)
     421                return removeGreaterThan([50, 100, 150], max);
     422            if (max >= 200) {
     423                let hundreds = Math.floor(max / 100);
     424                let even = (hundreds % 2) === 0;
     425                if (even) {
     426                    let top = hundreds * 100;
     427                    let bottom = top / 2;
     428                    return [bottom, top];
     429                }
     430                let top = hundreds * 100;
     431                let bottom = 100;
     432                let mid = (top + bottom) / 2;
     433                return [bottom, mid, top];
     434            }
     435        }
     436
     437        // Layout all graphs to the same time scale. The maximum value is
     438        // the maximum total CPU usage across all threads.
     439        let layoutMax = max;
     440
     441        function layoutView(view, property, graphHeight, {dataPoints, min, max, average}) {
    163442            if (min === Infinity)
    164443                min = 0;
    165444            if (max === -Infinity)
    166445                max = 0;
    167 
    168             // Zoom in to the top of each graph to accentuate small changes.
    169             let graphMin = min * 0.95;
    170             let graphMax = (max * 1.05) - graphMin;
     446            if (layoutMax === -Infinity)
     447                layoutMax = 0;
     448
     449            let isAllThreadsGraph = property === null;
     450
     451            let graphMax = layoutMax * 1.05;
    171452
    172453            function xScale(time) {
     
    174455            }
    175456
    176             let size = new WI.Size(xScale(graphEndTime), cpuUsageViewHeight);
     457            let size = new WI.Size(xScale(graphEndTime), graphHeight);
    177458
    178459            function yScale(value) {
    179                 return size.height - (((value - graphMin) / graphMax) * size.height);
    180             }
    181 
    182             view.updateChart(dataPoints, size, visibleEndTime, min, max, average, xScale, yScale);
    183         }
    184 
    185         layoutView(this._cpuUsageView, {dataPoints, min, max, average});
     460                return size.height - ((value / graphMax) * size.height);
     461            }
     462
     463            view.updateChart(dataPoints, size, visibleEndTime, min, max, average, xScale, yScale, property);
     464
     465            let markersElement = view.chart.element.querySelector(".markers");
     466            if (!markersElement) {
     467                markersElement = view.chart.element.appendChild(document.createElement("div"));
     468                markersElement.className = "markers";
     469            }
     470            markersElement.removeChildren();
     471
     472            let markerValues;
     473            if (isAllThreadsGraph)
     474                markerValues = markerValuesForMaxValue(max);
     475            else {
     476                const minimumMarkerTextHeight = 17;
     477                let percentPerPixel = 1 / (graphHeight / layoutMax);
     478                if (layoutMax < 5) {
     479                    let minimumDisplayablePercentByTwo = Math.ceil((minimumMarkerTextHeight * percentPerPixel) / 2) * 2;
     480                    markerValues = [Math.max(minimumDisplayablePercentByTwo, Math.floor(max))];
     481                } else {
     482                    let minimumDisplayablePercentByFive = Math.ceil((minimumMarkerTextHeight * percentPerPixel) / 5) * 5;
     483                    markerValues = [Math.max(minimumDisplayablePercentByFive, Math.floor(max))];
     484                }
     485            }
     486
     487            for (let value of markerValues) {
     488                let marginTop = yScale(value);
     489
     490                let markerElement = markersElement.appendChild(document.createElement("div"));
     491                markerElement.style.marginTop = marginTop.toFixed(2) + "px";
     492
     493                let labelElement = markerElement.appendChild(document.createElement("span"));
     494                labelElement.classList.add("label");
     495                const precision = 0;
     496                labelElement.innerText = Number.percentageString(value / 100, precision);
     497            }
     498        }
     499
     500        layoutView(this._cpuUsageView, null, CPUTimelineView.cpuUsageViewHeight, {dataPoints, min, max, average});
     501        layoutView(this._mainThreadUsageView, "mainThreadUsage", CPUTimelineView.threadCPUUsageViewHeight, {dataPoints, min: mainThreadMin, max: mainThreadMax, average: mainThreadAverage});
     502        layoutView(this._webkitThreadUsageView, "webkitThreadUsage", CPUTimelineView.threadCPUUsageViewHeight, {dataPoints, min: webkitThreadMin, max: webkitThreadMax, average: webkitThreadAverage});
     503        layoutView(this._unknownThreadUsageView, "unknownThreadUsage", CPUTimelineView.threadCPUUsageViewHeight, {dataPoints, min: unknownThreadMin, max: unknownThreadMax, average: unknownThreadAverage});
     504
     505        this._removeWorkerThreadViews();
     506
     507        for (let [workerId, workerData] of workersDataMap) {
     508            let worker = WI.targetManager.targetForIdentifier(workerId);
     509            let displayName = worker ? worker.displayName : WI.UIString("Worker Thread");
     510            let workerView = new WI.CPUUsageView(displayName);
     511            workerView.element.classList.add("worker-thread");
     512            this.addSubview(workerView);
     513            this._detailsContainerElement.insertBefore(workerView.element, this._webkitThreadUsageView.element);
     514            this._workerViews.push(workerView);
     515
     516            layoutView(workerView, "usage", CPUTimelineView.threadCPUUsageViewHeight, {dataPoints: workerData.dataPoints, min: workerData.min, max: workerData.max, average: workerData.average});
     517        }
    186518    }
    187519
    188520    // Private
     521
     522    _computeSamplingData(startTime, endTime)
     523    {
     524        // Compute per-millisecond samples of what the main thread was doing.
     525        // We construct an array for every millisecond between the start and end time
     526        // and mark each millisecond with the best representation of the work that
     527        // was being done at that time. We start by populating the samples with
     528        // all of the script periods and then override with layout and rendering
     529        // samples. This means a forced layout would be counted as a layout:
     530        //
     531        // Initial:        [ ------, ------, ------, ------, ------ ]
     532        // Script Samples: [ ------, Script, Script, Script, ------ ]
     533        // Layout Samples: [ ------, Script, Layout, Script, ------ ]
     534        //
     535        // The undefined samples are considered Idle, but in actuality WebKit
     536        // may have been doing some work (such as hit testing / inspector protocol)
     537        // that is not included it in generic Timeline data. This just works with
     538        // with the data available to the frontend and is quite accurate for most
     539        // Main Thread activity.
     540
     541        const includeRecordBeforeStart = true;
     542
     543        let scriptTimeline = this._recording.timelineForRecordType(WI.TimelineRecord.Type.Script);
     544        let scriptRecords = scriptTimeline ? scriptTimeline.recordsInTimeRange(startTime, endTime, includeRecordBeforeStart) : [];
     545        scriptRecords = scriptRecords.filter((record) => {
     546            switch (record.eventType) {
     547            case WI.ScriptTimelineRecord.EventType.ScriptEvaluated:
     548            case WI.ScriptTimelineRecord.EventType.APIScriptEvaluated:
     549            case WI.ScriptTimelineRecord.EventType.ObserverCallback:
     550            case WI.ScriptTimelineRecord.EventType.EventDispatched:
     551            case WI.ScriptTimelineRecord.EventType.MicrotaskDispatched:
     552            case WI.ScriptTimelineRecord.EventType.TimerFired:
     553            case WI.ScriptTimelineRecord.EventType.AnimationFrameFired:
     554                // These event types define script entry/exits.
     555                return true;
     556
     557            case WI.ScriptTimelineRecord.EventType.AnimationFrameRequested:
     558            case WI.ScriptTimelineRecord.EventType.AnimationFrameCanceled:
     559            case WI.ScriptTimelineRecord.EventType.TimerInstalled:
     560            case WI.ScriptTimelineRecord.EventType.TimerRemoved:
     561            case WI.ScriptTimelineRecord.EventType.ProbeSampleRecorded:
     562            case WI.ScriptTimelineRecord.EventType.ConsoleProfileRecorded:
     563            case WI.ScriptTimelineRecord.EventType.GarbageCollected:
     564                // These event types have no time range, or are contained by the others.
     565                return false;
     566
     567            default:
     568                console.error("Unhandled ScriptTimelineRecord.EventType", record.eventType);
     569                return false;
     570            }
     571        });
     572
     573        let layoutTimeline = this._recording.timelineForRecordType(WI.TimelineRecord.Type.Layout);
     574        let layoutRecords = layoutTimeline ? layoutTimeline.recordsInTimeRange(startTime, endTime, includeRecordBeforeStart) : [];
     575        layoutRecords = layoutRecords.filter((record) => {
     576            switch (record.eventType) {
     577            case WI.LayoutTimelineRecord.EventType.RecalculateStyles:
     578            case WI.LayoutTimelineRecord.EventType.ForcedLayout:
     579            case WI.LayoutTimelineRecord.EventType.Layout:
     580            case WI.LayoutTimelineRecord.EventType.Paint:
     581            case WI.LayoutTimelineRecord.EventType.Composite:
     582                // These event types define layout and rendering entry/exits.
     583                return true;
     584
     585            case WI.LayoutTimelineRecord.EventType.InvalidateStyles:
     586            case WI.LayoutTimelineRecord.EventType.InvalidateLayout:
     587                // These event types have no time range.
     588                return false;
     589
     590            default:
     591                console.error("Unhandled LayoutTimelineRecord.EventType", record.eventType);
     592                return false;
     593            }
     594        });
     595
     596        let millisecondStartTime = Math.round(startTime * 1000);
     597        let millisecondEndTime = Math.round(endTime * 1000);
     598        let millisecondDuration = millisecondEndTime - millisecondStartTime;
     599
     600        let samples = new Array(millisecondDuration);
     601
     602        function markRecordEntries(records, callback) {
     603            for (let record of records) {
     604                let recordStart = Math.round(record.startTime * 1000);
     605                let recordEnd = Math.round(record.endTime * 1000);
     606                if (recordStart > millisecondEndTime)
     607                    continue;
     608                if (recordEnd < millisecondStartTime)
     609                    continue;
     610
     611                let offset = recordStart - millisecondStartTime;
     612                recordStart = Math.max(recordStart, millisecondStartTime);
     613                recordEnd = Math.min(recordEnd, millisecondEndTime);
     614
     615                let value = callback(record);
     616                for (let t = recordStart; t <= recordEnd; ++t)
     617                    samples[t - millisecondStartTime] = value;
     618            }
     619        }
     620
     621        markRecordEntries(scriptRecords, (record) => {
     622            return WI.CPUTimelineView.SampleType.Script;
     623        });
     624
     625        markRecordEntries(layoutRecords, (record) => {
     626            switch (record.eventType) {
     627            case WI.LayoutTimelineRecord.EventType.RecalculateStyles:
     628                return WI.CPUTimelineView.SampleType.Style;
     629            case WI.LayoutTimelineRecord.EventType.ForcedLayout:
     630            case WI.LayoutTimelineRecord.EventType.Layout:
     631                return WI.CPUTimelineView.SampleType.Layout;
     632            case WI.LayoutTimelineRecord.EventType.Paint:
     633            case WI.LayoutTimelineRecord.EventType.Composite:
     634                return WI.CPUTimelineView.SampleType.Paint;
     635            }
     636        });
     637
     638        let samplesIdle = 0;
     639        let samplesScript = 0;
     640        let samplesLayout = 0;
     641        let samplesPaint = 0;
     642        let samplesStyle = 0;
     643        for (let i = 0; i < samples.length; ++i) {
     644            switch (samples[i]) {
     645            case undefined:
     646                samplesIdle++;
     647                break;
     648            case WI.CPUTimelineView.SampleType.Script:
     649                samplesScript++;
     650                break;
     651            case WI.CPUTimelineView.SampleType.Layout:
     652                samplesLayout++;
     653                break;
     654            case WI.CPUTimelineView.SampleType.Paint:
     655                samplesPaint++;
     656                break;
     657            case WI.CPUTimelineView.SampleType.Style:
     658                samplesStyle++;
     659                break;
     660            }
     661        }
     662
     663        return {
     664            samples,
     665            samplesIdle,
     666            samplesScript,
     667            samplesLayout,
     668            samplesPaint,
     669            samplesStyle,
     670        };
     671    }
     672
     673    _removeWorkerThreadViews()
     674    {
     675        if (!this._workerViews.length)
     676            return;
     677
     678        for (let view of this._workerViews)
     679            this.removeSubview(view);
     680
     681        this._workerViews = [];
     682    }
     683
     684    _clearBreakdownLegend()
     685    {
     686        this._breakdownLegendScriptElement.textContent = emDash;
     687        this._breakdownLegendLayoutElement.textContent = emDash;
     688        this._breakdownLegendPaintElement.textContent = emDash;
     689        this._breakdownLegendStyleElement.textContent = emDash;
     690
     691        this._breakdownChart.centerElement.removeChildren();
     692    }
    189693
    190694    _cpuTimelineRecordAdded(event)
     
    197701    }
    198702};
     703
     704// NOTE: UI follows this order.
     705WI.CPUTimelineView.SampleType = {
     706    Script: "sample-type-script",
     707    Layout: "sample-type-layout",
     708    Paint: "sample-type-paint",
     709    Style: "sample-type-style",
     710};
  • trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageStackedView.css

    r242072 r242073  
    2424 */
    2525
    26 .cpu-usage-view {
     26.cpu-usage-stacked-view {
    2727    display: flex;
    2828    width: 100%;
    29     height: 76px; /* Keep this in sync with cpuUsageViewHeight + 1 (for border-bottom) */
     29    height: calc(var(--cpu-usage-stacked-view-height) + 1px); /* +1 for border-bottom */
    3030    border-bottom: 1px solid var(--border-color);
    3131}
    3232
    33 .cpu-usage-view > .details {
     33.cpu-usage-stacked-view > .details {
    3434    flex-shrink: 0;
    3535    width: 150px;
    3636    padding-top: 10px;
     37    -webkit-padding-start: 15px;
    3738    font-family: -webkit-system-font, sans-serif;
    3839    font-size: 12px;
    3940    color: var(--text-color-secondary);
    40     -webkit-padding-start: 15px;
    41 
    42     --cpu-usage-view-details-border-end: 1px solid var(--border-color);
     41    overflow: hidden;
     42    text-overflow: ellipsis;
     43    -webkit-border-end: 1px solid var(--border-color);
    4344}
    4445
    45 body[dir=ltr] .cpu-usage-view > .details {
    46     border-right: var(--cpu-usage-view-details-border-end);
     46.cpu-usage-stacked-view > .details > .name {
     47    color: var(--text-color);
     48    white-space: nowrap;
    4749}
    4850
    49 body[dir=rtl] .cpu-usage-view > .details {
    50     border-left: var(--cpu-usage-view-details-border-end);
    51 }
    52 
    53 body[dir=rtl] .cpu-usage-view > .graph {
     51body[dir=rtl] .cpu-usage-stacked-view > .graph {
    5452    transform: scaleX(-1);
    5553}
    5654
    57 .cpu-usage-view > .graph,
    58 .cpu-usage-view > .graph > .line-chart,
    59 .cpu-usage-view > .graph > .line-chart > svg {
     55.cpu-usage-stacked-view > .graph {
     56    position: relative;
     57}
     58
     59.cpu-usage-stacked-view > .graph,
     60.cpu-usage-stacked-view > .graph > .stacked-line-chart,
     61.cpu-usage-stacked-view > .graph > .stacked-line-chart > svg {
    6062    width: 100%;
    6163    height: 100%;
  • trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageStackedView.js

    r242072 r242073  
    2424 */
    2525
    26 WI.CPUUsageView = class CPUUsageView extends WI.View
     26WI.CPUUsageStackedView = class CPUUsageStackedView extends WI.View
    2727{
    28     constructor()
     28    constructor(displayName)
    2929    {
    3030        super();
    3131
    32         this.element.classList.add("cpu-usage-view");
     32        this.element.classList.add("cpu-usage-stacked-view");
    3333
    3434        this._detailsElement = this.element.appendChild(document.createElement("div"));
    3535        this._detailsElement.classList.add("details");
    3636
     37        let detailsNameElement = this._detailsElement.appendChild(document.createElement("span"));
     38        detailsNameElement.classList.add("name");
     39        detailsNameElement.textContent = displayName;
     40
     41        this._detailsElement.appendChild(document.createElement("br"));
    3742        this._detailsAverageElement = this._detailsElement.appendChild(document.createElement("span"));
    3843        this._detailsElement.appendChild(document.createElement("br"));
     
    4550        this._graphElement.classList.add("graph");
    4651
    47         this._chart = new WI.LineChart;
     52        this._chart = new WI.StackedLineChart;
     53        this._chart.initializeSections(["main-thread-usage", "worker-thread-usage", "total-usage"]);
    4854        this.addSubview(this._chart);
    4955        this._graphElement.appendChild(this._chart.element);
     
    5157
    5258    // Public
     59
     60    get chart() { return this._chart; }
    5361
    5462    clear()
     
    6068
    6169        this._chart.clear();
     70        this._chart.needsLayout();
    6271    }
    6372
     
    8594        // Extend the first data point to the start so it doesn't look like we originate at zero size.
    8695        let firstX = 0;
    87         let firstY = yScale(dataPoints[0].size);
    88         this._chart.addPoint(firstX, firstY);
     96        let firstY1 = yScale(dataPoints[0].mainThreadUsage);
     97        let firstY2 = yScale(dataPoints[0].mainThreadUsage + dataPoints[0].workerThreadUsage);
     98        let firstY3 = yScale(dataPoints[0].usage);
     99        this._chart.addPointSet(firstX, [firstY1, firstY2, firstY3]);
    89100
    90101        // Points for data points.
    91102        for (let dataPoint of dataPoints) {
    92103            let x = xScale(dataPoint.time);
    93             let y = yScale(dataPoint.size);
    94             this._chart.addPoint(x, y);
     104            let y1 = yScale(dataPoint.mainThreadUsage);
     105            let y2 = yScale(dataPoint.mainThreadUsage + dataPoint.workerThreadUsage);
     106            let y3 = yScale(dataPoint.usage)
     107            this._chart.addPointSet(x, [y1, y2, y3]);
    95108        }
    96109
     
    98111        let lastDataPoint = dataPoints.lastValue;
    99112        let lastX = Math.floor(xScale(visibleEndTime));
    100         let lastY = yScale(lastDataPoint.size);
    101         this._chart.addPoint(lastX, lastY);
     113        let lastY1 = yScale(lastDataPoint.mainThreadUsage);
     114        let lastY2 = yScale(lastDataPoint.mainThreadUsage + lastDataPoint.workerThreadUsage);
     115        let lastY3 = yScale(lastDataPoint.usage);
     116        this._chart.addPointSet(lastX, [lastY1, lastY2, lastY3]);
    102117    }
    103118
  • trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageView.css

    r240763 r242073  
    2727    display: flex;
    2828    width: 100%;
    29     height: 76px; /* Keep this in sync with cpuUsageViewHeight + 1 (for border-bottom) */
     29    height: calc(var(--cpu-usage-view-height) + 1px); /* +1 for border-bottom */
    3030    border-bottom: 1px solid var(--border-color);
    3131}
     
    3535    width: 150px;
    3636    padding-top: 10px;
     37    -webkit-padding-start: 15px;
    3738    font-family: -webkit-system-font, sans-serif;
    3839    font-size: 12px;
    3940    color: var(--text-color-secondary);
    40     -webkit-padding-start: 15px;
    41 
    42     --cpu-usage-view-details-border-end: 1px solid var(--border-color);
     41    overflow: hidden;
     42    text-overflow: ellipsis;
     43    -webkit-border-end: 1px solid var(--border-color);
    4344}
    4445
    45 body[dir=ltr] .cpu-usage-view > .details {
    46     border-right: var(--cpu-usage-view-details-border-end);
    47 }
    48 
    49 body[dir=rtl] .cpu-usage-view > .details {
    50     border-left: var(--cpu-usage-view-details-border-end);
     46.cpu-usage-view > .details > .name {
     47    color: var(--text-color);
     48    white-space: nowrap;
    5149}
    5250
    5351body[dir=rtl] .cpu-usage-view > .graph {
    5452    transform: scaleX(-1);
     53}
     54
     55.cpu-usage-view > .graph {
     56    position: relative;
    5557}
    5658
  • trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageView.js

    r240763 r242073  
    2626WI.CPUUsageView = class CPUUsageView extends WI.View
    2727{
    28     constructor()
     28    constructor(displayName)
    2929    {
    3030        super();
     
    3535        this._detailsElement.classList.add("details");
    3636
     37        if (displayName) {
     38            let detailsNameElement = this._detailsElement.appendChild(document.createElement("span"));
     39            detailsNameElement.classList.add("name");
     40            detailsNameElement.textContent = displayName;
     41            this._detailsElement.appendChild(document.createElement("br"));
     42        }
     43
    3744        this._detailsAverageElement = this._detailsElement.appendChild(document.createElement("span"));
    3845        this._detailsElement.appendChild(document.createElement("br"));
    3946        this._detailsMaxElement = this._detailsElement.appendChild(document.createElement("span"));
    40         this._detailsElement.appendChild(document.createElement("br"));
    41         this._detailsMinElement = this._detailsElement.appendChild(document.createElement("span"));
    4247        this._updateDetails(NaN, NaN);
    4348
     
    5257    // Public
    5358
     59    get chart() { return this._chart; }
     60
    5461    clear()
    5562    {
    5663        this._cachedAverageSize = undefined;
    57         this._cachedMinSize = undefined;
    5864        this._cachedMaxSize = undefined;
    5965        this._updateDetails(NaN, NaN);
     
    6268    }
    6369
    64     updateChart(dataPoints, size, visibleEndTime, min, max, average, xScale, yScale)
     70    updateChart(dataPoints, size, visibleEndTime, min, max, average, xScale, yScale, property)
    6571    {
    6672        console.assert(size instanceof WI.Size);
     
    6975        console.assert(min <= max);
    7076        console.assert(min <= average && average <= max);
     77        console.assert(property, "CPUUsageView needs a property of the dataPoints to graph");
    7178
    7279        this._updateDetails(min, max, average);
     
    8592        // Extend the first data point to the start so it doesn't look like we originate at zero size.
    8693        let firstX = 0;
    87         let firstY = yScale(dataPoints[0].size);
     94        let firstY = yScale(dataPoints[0][property]);
    8895        this._chart.addPoint(firstX, firstY);
    8996
     
    9198        for (let dataPoint of dataPoints) {
    9299            let x = xScale(dataPoint.time);
    93             let y = yScale(dataPoint.size);
     100            let y = yScale(dataPoint[property]);
    94101            this._chart.addPoint(x, y);
    95102        }
     
    98105        let lastDataPoint = dataPoints.lastValue;
    99106        let lastX = Math.floor(xScale(visibleEndTime));
    100         let lastY = yScale(lastDataPoint.size);
     107        let lastY = yScale(lastDataPoint[property]);
    101108        this._chart.addPoint(lastX, lastY);
    102109    }
     
    106113    _updateDetails(minSize, maxSize, averageSize)
    107114    {
    108         if (this._cachedMinSize === minSize && this._cachedMaxSize === maxSize && this._cachedAverageSize === averageSize)
     115        if (this._cachedMaxSize === maxSize && this._cachedAverageSize === averageSize)
    109116            return;
    110117
    111118        this._cachedAverageSize = averageSize;
    112         this._cachedMinSize = minSize;
    113119        this._cachedMaxSize = maxSize;
    114120
    115         this._detailsAverageElement.textContent = WI.UIString("Average: %s").format(Number.isFinite(maxSize) ? Number.percentageString(averageSize / 100) : emDash);
     121        this._detailsAverageElement.hidden = !Number.isFinite(averageSize);
     122        this._detailsMaxElement.hidden = !Number.isFinite(maxSize);
     123
     124        this._detailsAverageElement.textContent = WI.UIString("Average: %s").format(Number.isFinite(averageSize) ? Number.percentageString(averageSize / 100) : emDash);
    116125        this._detailsMaxElement.textContent = WI.UIString("Highest: %s").format(Number.isFinite(maxSize) ? Number.percentageString(maxSize / 100) : emDash);
    117         this._detailsMinElement.textContent = WI.UIString("Lowest: %s").format(Number.isFinite(minSize) ? Number.percentageString(minSize / 100) : emDash);
    118126    }
    119127};
  • trunk/Source/WebInspectorUI/UserInterface/Views/LegacyCPUTimelineView.css

    r241325 r242073  
    6666.timeline-view.legacy-cpu .cpu-usage-view .line-chart > svg > path {
    6767    stroke: var(--cpu-stroke-color);
    68     fill: var(--cpu-fill-color);
     68    fill: var(--cpu-main-thread-fill-color);
    6969}
  • trunk/Source/WebInspectorUI/UserInterface/Views/LegacyCPUTimelineView.js

    r241325 r242073  
    5858    }
    5959
     60    // Static
     61
     62    static get cpuUsageViewHeight() { return 150; }
     63
    6064    // Public
    6165
     
    9599
    96100    get showsFilterBar() { return false; }
     101
     102    initialLayout()
     103    {
     104        this.element.style.setProperty("--cpu-usage-view-height", LegacyCPUTimelineView.cpuUsageViewHeight + "px");
     105    }
    97106
    98107    layout()
     
    105114        this._timelineRuler.startTime = this.startTime;
    106115        this._timelineRuler.endTime = this.endTime;
    107 
    108         const cpuUsageViewHeight = 75; // Keep this in sync with .legacy-cpu-usage-view
    109116
    110117        let graphStartTime = this.startTime;
     
    169176            }
    170177
    171             let size = new WI.Size(xScale(graphEndTime), cpuUsageViewHeight);
     178            let size = new WI.Size(xScale(graphEndTime), LegacyCPUTimelineView.cpuUsageViewHeight);
    172179
    173180            function yScale(value) {
     
    175182            }
    176183
    177             view.updateChart(dataPoints, size, visibleEndTime, min, max, average, xScale, yScale);
     184            view.updateChart(dataPoints, size, visibleEndTime, min, max, average, xScale, yScale, "size");
    178185        }
    179186
  • trunk/Source/WebInspectorUI/UserInterface/Views/MemoryCategoryView.css

    r240763 r242073  
    3535    width: 150px;
    3636    padding-top: 10px;
     37    -webkit-padding-start: 15px;
    3738    font-family: -webkit-system-font, sans-serif;
    3839    font-size: 12px;
    3940    color: var(--text-color-secondary);
    40     -webkit-padding-start: 15px;
    41 
    42     --memory-category-view-details-border-end: 1px solid var(--border-color);
    43 }
    44 
    45 body[dir=ltr] .memory-category-view > .details {
    46     border-right: var(--memory-category-view-details-border-end);
    47 }
    48 
    49 body[dir=rtl] .memory-category-view > .details {
    50     border-left: var(--memory-category-view-details-border-end);
     41    overflow: hidden;
     42    text-overflow: ellipsis;
     43    -webkit-border-end: 1px solid var(--border-color);
    5144}
    5245
    5346.memory-category-view > .details > .name {
    5447    color: var(--text-color);
     48    white-space: nowrap;
    5549}
    56 
    5750
    5851body[dir=rtl] .memory-category-view > .graph {
  • trunk/Source/WebInspectorUI/UserInterface/Views/MemoryTimelineOverviewGraph.js

    r240871 r242073  
    211211            }
    212212        }
    213 
    214         this._chart.updateLayout();
    215213    }
    216214
  • trunk/Source/WebInspectorUI/UserInterface/Views/MemoryTimelineView.css

    r240763 r242073  
    2424 */
    2525
    26 .timeline-view.memory {
     26body .timeline-view.memory {
    2727    overflow: scroll;
    2828}
  • trunk/Source/WebInspectorUI/UserInterface/Views/Variables.css

    r242072 r242073  
    130130
    131131    --cpu-stroke-color: hsl(118, 33%, 42%);
    132     --cpu-fill-color: hsl(118, 43%, 55%);
     132    --cpu-fill-color: hsl(81, 80%, 50%);
     133    --cpu-main-thread-fill-color: hsl(118, 43%, 55%);
     134    --cpu-worker-thread-fill-color: hsl(45, 94.75%, 55%);
     135
     136    --cpu-idle-fill-color: hsl(220, 10%, 75%);
     137    --cpu-idle-stroke-color: hsl(220, 10%, 55%);
     138    --cpu-script-fill-color: hsl(269, 65%, 75%);
     139    --cpu-script-stroke-color: hsl(269, 33%, 50%);
     140    --cpu-style-fill-color: hsl(22, 60%, 70%);
     141    --cpu-style-stroke-color: hsl(22, 40%, 50%);
     142    --cpu-layout-fill-color: hsl(0, 65%, 75%);
     143    --cpu-layout-stroke-color: hsl(0, 54%, 50%);
     144    --cpu-paint-fill-color: hsl(76, 49%, 75%);
     145    --cpu-paint-stroke-color: hsl(79, 45%, 50%);
    133146
    134147    --network-header-color: hsl(204, 52%, 55%);
  • trunk/Source/WebInspectorUI/UserInterface/Views/View.js

    r237720 r242073  
    118118    {
    119119        console.assert(view instanceof WI.View);
    120         console.assert(view.element.parentNode === this._element, "Subview DOM element must be a child of the parent view element.");
     120        console.assert(this._element.contains(view.element), "Subview DOM element must be a child of the parent view element.");
    121121
    122122        let index = this._subviews.lastIndexOf(view);
Note: See TracChangeset for help on using the changeset viewer.