1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5
6WebInspector.TimelineJSProfileProcessor = { };
7
8/**
9 * @param {!WebInspector.TimelineModelImpl} timelineModel
10 * @param {!ProfilerAgent.CPUProfile} jsProfile
11 */
12WebInspector.TimelineJSProfileProcessor.mergeJSProfileIntoTimeline = function(timelineModel, jsProfile)
13{
14    if (!jsProfile.samples)
15        return;
16    var jsProfileModel = new WebInspector.CPUProfileDataModel(jsProfile);
17    var idleNode = jsProfileModel.idleNode;
18    var programNode = jsProfileModel.programNode;
19    var gcNode = jsProfileModel.gcNode;
20
21    /**
22     * @param {!WebInspector.TimelineModel.Record} record
23     */
24    function processRecord(record)
25    {
26        if (record.type() !== WebInspector.TimelineModel.RecordType.FunctionCall &&
27            record.type() !== WebInspector.TimelineModel.RecordType.EvaluateScript)
28            return;
29        var recordStartTime = record.startTime();
30        var recordEndTime = record.endTime();
31        var originalChildren = record.children().splice(0);
32        var childIndex = 0;
33
34        /**
35         * @param {number} depth
36         * @param {!ProfilerAgent.CPUProfileNode} node
37         * @param {number} startTime
38         */
39        function onOpenFrame(depth, node, startTime)
40        {
41            if (node === idleNode || node === programNode || node === gcNode)
42                return;
43            var event = {
44                type: "JSFrame",
45                data: node,
46                startTime: startTime
47            };
48            putOriginalChildrenUpToTime(startTime);
49            record = new WebInspector.TimelineModel.RecordImpl(timelineModel, event, record);
50        }
51
52        /**
53         * @param {number} depth
54         * @param {!ProfilerAgent.CPUProfileNode} node
55         * @param {number} startTime
56         * @param {number} totalTime
57         * @param {number} selfTime
58         */
59        function onCloseFrame(depth, node, startTime, totalTime, selfTime)
60        {
61            if (node === idleNode || node === programNode || node === gcNode)
62                return;
63            record.setEndTime(Math.min(startTime + totalTime, recordEndTime));
64            record._selfTime = record.endTime() - record.startTime();
65            putOriginalChildrenUpToTime(record.endTime());
66            var deoptReason = node.deoptReason;
67            if (deoptReason && deoptReason !== "no reason")
68                record.addWarning(deoptReason);
69            record = record.parent;
70        }
71
72        /**
73         * @param {number} endTime
74         */
75        function putOriginalChildrenUpToTime(endTime)
76        {
77            for (; childIndex < originalChildren.length; ++childIndex)  {
78                var child = originalChildren[childIndex];
79                var midTime = (child.startTime() + child.endTime()) / 2;
80                if (midTime >= endTime)
81                    break;
82                child.parent = record;
83                record.children().push(child);
84            }
85        }
86
87        jsProfileModel.forEachFrame(onOpenFrame, onCloseFrame, recordStartTime, recordEndTime);
88        putOriginalChildrenUpToTime(recordEndTime);
89    }
90
91    timelineModel.forAllRecords(processRecord);
92}
93