mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Add a sampling profiler and a script to generate profiles for use with Gecko tooling.
This commit is contained in:
parent
db7bb2a510
commit
90f67c11e5
13 changed files with 379 additions and 28 deletions
153
etc/profilicate.py
Normal file
153
etc/profilicate.py
Normal file
|
@ -0,0 +1,153 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2018 The Servo Project Developers. See the COPYRIGHT
|
||||
# file at the top-level directory of this distribution.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
# Script to take raw sample output from Servo sampling profiler and
|
||||
# output a [processed profile]. Based largely on [this script] and
|
||||
# [this documentation].
|
||||
#
|
||||
# [processed profile]: https://github.com/firefox-devtools/profiler/blob/master/docs-developer/processed-profile-format.md
|
||||
# [this script]: https://github.com/firefox-devtools/profiler/blob/master/src/profile-logic/import/linux-perf.js
|
||||
# [this documentation]: https://github.com/firefox-devtools/profiler/blob/master/src/types/profile.js
|
||||
|
||||
from collections import defaultdict
|
||||
import json
|
||||
import sys
|
||||
|
||||
|
||||
class StringTable:
|
||||
def __init__(self):
|
||||
self.table = {}
|
||||
self.idx = 0
|
||||
|
||||
def get(self, s):
|
||||
assert s
|
||||
if s not in self.table:
|
||||
self.table[s] = self.idx
|
||||
self.idx += 1
|
||||
return self.table[s]
|
||||
|
||||
def length(self):
|
||||
return len(self.table.keys())
|
||||
|
||||
def contents(self):
|
||||
return sorted(self.table.keys(), key=self.table.__getitem__)
|
||||
|
||||
|
||||
with open(sys.argv[1]) as f:
|
||||
profile = json.load(f)
|
||||
rate = profile["rate"]
|
||||
samples = profile["data"]
|
||||
startTime = profile["start"]
|
||||
|
||||
frames = {}
|
||||
stacks = {}
|
||||
|
||||
thread_data = defaultdict(list)
|
||||
thread_order = {}
|
||||
for sample in samples:
|
||||
if sample['name']:
|
||||
name = sample['name']
|
||||
else:
|
||||
name = "%s %d %d" % (sample['type'], sample['namespace'], sample['index'])
|
||||
thread_data[name].append((sample['time'], sample['frames']))
|
||||
if name not in thread_order:
|
||||
thread_order[name] = (sample['namespace'], sample['index'])
|
||||
|
||||
tid = 0
|
||||
threads = []
|
||||
for (name, raw_samples) in sorted(thread_data.iteritems(), key=lambda x: thread_order[x[0]]):
|
||||
string_table = StringTable()
|
||||
tid += 1
|
||||
|
||||
stackMap = {}
|
||||
stacks = []
|
||||
frameMap = {}
|
||||
frames = []
|
||||
|
||||
samples = []
|
||||
|
||||
for sample in raw_samples:
|
||||
prefix = None
|
||||
for frame in sample[1]:
|
||||
if not frame['name']:
|
||||
continue
|
||||
if not frame['name'] in frameMap:
|
||||
frameMap[frame['name']] = len(frames)
|
||||
frame_index = string_table.get(frame['name'])
|
||||
frames.append([frame_index])
|
||||
frame = frameMap[frame['name']]
|
||||
|
||||
stack_key = "%d,%d" % (frame, prefix) if prefix else str(frame)
|
||||
if stack_key not in stackMap:
|
||||
stackMap[stack_key] = len(stacks)
|
||||
stacks.append([frame, prefix])
|
||||
stack = stackMap[stack_key]
|
||||
prefix = stack
|
||||
samples.append([stack, sample[0]])
|
||||
|
||||
threads.append({
|
||||
'tid': tid,
|
||||
'name': name,
|
||||
'markers': {
|
||||
'schema': {
|
||||
'name': 0,
|
||||
'time': 1,
|
||||
'data': 2,
|
||||
},
|
||||
'data': [],
|
||||
},
|
||||
'samples': {
|
||||
'schema': {
|
||||
'stack': 0,
|
||||
'time': 1,
|
||||
'responsiveness': 2,
|
||||
'rss': 2,
|
||||
'uss': 4,
|
||||
'frameNumber': 5,
|
||||
},
|
||||
'data': samples,
|
||||
},
|
||||
'frameTable': {
|
||||
'schema': {
|
||||
'location': 0,
|
||||
'implementation': 1,
|
||||
'optimizations': 2,
|
||||
'line': 3,
|
||||
'category': 4,
|
||||
},
|
||||
'data': frames,
|
||||
},
|
||||
'stackTable': {
|
||||
'schema': {
|
||||
'frame': 0,
|
||||
'prefix': 1,
|
||||
},
|
||||
'data': stacks,
|
||||
},
|
||||
'stringTable': string_table.contents(),
|
||||
})
|
||||
|
||||
|
||||
output = {
|
||||
'meta': {
|
||||
'interval': rate,
|
||||
'processType': 0,
|
||||
'product': 'Servo',
|
||||
'stackwalk': 1,
|
||||
'startTime': startTime,
|
||||
'version': 4,
|
||||
'presymbolicated': True,
|
||||
},
|
||||
'libs': [],
|
||||
'threads': threads,
|
||||
}
|
||||
|
||||
print(json.dumps(output))
|
Loading…
Add table
Add a link
Reference in a new issue