Modern IDB: Add -private.html variants of crypto/subtle IndexedDB tests.
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / MemoryTimelineOverviewGraph.js
1 /*
2  * Copyright (C) 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WebInspector.MemoryTimelineOverviewGraph = class MemoryTimelineOverviewGraph extends WebInspector.TimelineOverviewGraph
27 {
28     constructor(timeline, timelineOverview)
29     {
30         super(timelineOverview);
31
32         this.element.classList.add("memory");
33
34         console.assert(timeline instanceof WebInspector.MemoryTimeline);
35
36         this._memoryTimeline = timeline;
37         this._memoryTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._memoryTimelineRecordAdded, this);
38         this._memoryTimeline.addEventListener(WebInspector.MemoryTimeline.Event.MemoryPressureEventAdded, this._memoryTimelineMemoryPressureEventAdded, this)
39
40         this._didInitializeCategories = false;
41
42         let size = new WebInspector.Size(0, this.height);
43         this._chart = new WebInspector.StackedLineChart(size);
44         this.element.appendChild(this._chart.element);
45
46         this._legendElement = this.element.appendChild(document.createElement("div"));
47         this._legendElement.classList.add("legend");
48
49         this._memoryPressureMarkersContainerElement = this.element.appendChild(document.createElement("div"));
50         this._memoryPressureMarkersContainerElement.classList.add("memory-pressure-markers-container");
51         this._memoryPressureMarkerElements = [];
52
53         this.reset();
54     }
55
56     // Protected
57
58     get height()
59     {
60         return 108;
61     }
62
63     reset()
64     {
65         super.reset();
66
67         this._maxSize = 0;
68         this._cachedMaxSize = undefined;
69
70         this._updateLegend();
71         this._chart.clear();
72         this._chart.needsLayout();
73
74         this._memoryPressureMarkersContainerElement.removeChildren();
75         this._memoryPressureMarkerElements = [];
76     }
77
78     layout()
79     {
80         if (!this.visible)
81             return;
82
83         this._updateLegend();
84         this._chart.clear();
85
86         if (!this._didInitializeCategories)
87             return;
88
89         let graphWidth = this.timelineOverview.scrollContainerWidth;
90         if (isNaN(graphWidth))
91             return;
92
93         if (this._chart.size.width !== graphWidth || this._chart.size.height !== this.height)
94             this._chart.size = new WebInspector.Size(graphWidth, this.height);
95
96         let graphStartTime = this.startTime;
97         let graphEndTime = this.endTime;
98         let graphCurrentTime = this.currentTime;
99         let visibleEndTime = Math.min(this.endTime, this.currentTime);
100
101         let secondsPerPixel = this.timelineOverview.secondsPerPixel;
102         let maxCapacity = this._maxSize * 1.05; // Add 5% for padding.
103
104         function xScale(time) {
105             return (time - graphStartTime) / secondsPerPixel;
106         }
107
108         let height = this.height;
109         function yScale(size) {
110             return height - ((size / maxCapacity) * height);
111         }
112
113         let visibleMemoryPressureEventMarkers = this._visibleMemoryPressureEvents(graphStartTime, visibleEndTime);
114
115         // Reuse existing marker elements.
116         for (let i = 0; i < visibleMemoryPressureEventMarkers.length; ++i) {
117             let markerElement = this._memoryPressureMarkerElements[i];
118             if (!markerElement) {
119                 markerElement = this._memoryPressureMarkersContainerElement.appendChild(document.createElement("div"));
120                 markerElement.classList.add("memory-pressure-event");
121                 this._memoryPressureMarkerElements[i] = markerElement;
122             }
123
124             let memoryPressureEvent = visibleMemoryPressureEventMarkers[i];
125             markerElement.style.left = xScale(memoryPressureEvent.timestamp) + "px";
126         }
127
128         // Remove excess marker elements.
129         let excess = this._memoryPressureMarkerElements.length - visibleMemoryPressureEventMarkers.length;
130         if (excess) {
131             let elementsToRemove = this._memoryPressureMarkerElements.splice(visibleMemoryPressureEventMarkers.length);
132             for (let element of elementsToRemove)
133                 element.remove();
134         }
135
136         let visibleRecords = this._visibleRecords(graphStartTime, visibleEndTime);
137         if (!visibleRecords.length)
138             return;
139
140         function pointSetForRecord(record) {
141             let size = 0;
142             let ys = [];
143             for (let i = 0; i < record.categories.length; ++i) {
144                 size += record.categories[i].size;
145                 ys[i] = yScale(size);
146             }
147             return ys;
148         }
149
150         // Extend the first record to the start so it doesn't look like we originate at zero size.
151         if (visibleRecords[0] === this._memoryTimeline.records[0])
152             this._chart.addPointSet(0, pointSetForRecord(visibleRecords[0]));
153
154         // Points for visible records.
155         for (let record of visibleRecords) {
156             let x = xScale(record.startTime);
157             this._chart.addPointSet(x, pointSetForRecord(record));
158         }
159
160         // Extend the last value to current / end time.
161         let lastRecord = visibleRecords.lastValue;
162         let x = Math.floor(xScale(visibleEndTime));
163         this._chart.addPointSet(x, pointSetForRecord(lastRecord));
164
165         this._chart.updateLayout();
166     }
167
168     // Private
169
170     _updateLegend()
171     {
172         if (this._cachedMaxSize === this._maxSize)
173             return;
174
175         this._cachedMaxSize = this._maxSize;
176
177         if (!this._maxSize) {
178             this._legendElement.hidden = true;
179             this._legendElement.textContent = "";
180         } else {
181             this._legendElement.hidden = false;
182             this._legendElement.textContent = WebInspector.UIString("Maximum Size: %s").format(Number.bytesToString(this._maxSize));
183         }
184     }
185
186     _visibleMemoryPressureEvents(startTime, endTime)
187     {
188         let events = this._memoryTimeline.memoryPressureEvents;
189         if (!events.length)
190             return [];
191
192         let lowerIndex = events.lowerBound(startTime, (time, event) => time - event.timestamp);
193         let upperIndex = events.upperBound(endTime, (time, event) => time - event.timestamp);
194         return events.slice(lowerIndex, upperIndex);
195     }
196
197     _visibleRecords(startTime, endTime)
198     {
199         let records = this._memoryTimeline.records;
200         let lowerIndex = records.lowerBound(startTime, (time, record) => time - record.timestamp);
201         let upperIndex = records.upperBound(endTime, (time, record) => time - record.timestamp);
202
203         // Include the record right before the start time in case it extends into this range.
204         if (lowerIndex > 0)
205             lowerIndex--;
206         // FIXME: <https://webkit.org/b/153759> Web Inspector: Memory Timelines should better extend to future data
207         // if (upperIndex !== records.length)
208         //     upperIndex++;
209
210         return records.slice(lowerIndex, upperIndex);
211     }
212
213     _memoryTimelineRecordAdded(event)
214     {
215         let memoryTimelineRecord = event.data.record;
216
217         this._maxSize = Math.max(this._maxSize, memoryTimelineRecord.totalSize);
218
219         if (!this._didInitializeCategories) {
220             this._didInitializeCategories = true;
221             let types = [];
222             for (let category of memoryTimelineRecord.categories)
223                 types.push(category.type);
224             this._chart.initializeSections(types);
225         }
226
227         this.needsLayout();
228     }
229
230     _memoryTimelineMemoryPressureEventAdded(event)
231     {
232         this.needsLayout();
233     }
234 };