aboutsummaryrefslogtreecommitdiffstats
path: root/etc
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2019-03-22 13:15:50 -0400
committerJosh Matthews <josh@joshmatthews.net>2019-03-26 16:35:08 -0400
commit90f67c11e5de39341b8b212a022ce997f9382eb3 (patch)
tree391e8643504f957e26d6abaf1eee62eba3f52513 /etc
parentdb7bb2a5101ea6042654b59b3b81725e2da65891 (diff)
downloadservo-90f67c11e5de39341b8b212a022ce997f9382eb3.tar.gz
servo-90f67c11e5de39341b8b212a022ce997f9382eb3.zip
Add a sampling profiler and a script to generate profiles for use with Gecko tooling.
Diffstat (limited to 'etc')
-rw-r--r--etc/profilicate.py153
1 files changed, 153 insertions, 0 deletions
diff --git a/etc/profilicate.py b/etc/profilicate.py
new file mode 100644
index 00000000000..44c734aef99
--- /dev/null
+++ b/etc/profilicate.py
@@ -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))