зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1473334 - run the webaudio benchmark in raptor instead of AWFY. r=rwood
port the webaudio benchmark from arewefastyet.com to in-tree raptor. Differential Revision: https://phabricator.services.mozilla.com/D2224 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
87baa69fc6
Коммит
04f65a0f76
|
@ -75,6 +75,16 @@ raptor-firefox-motionmark-animometer:
|
||||||
extra-options:
|
extra-options:
|
||||||
- --test=raptor-motionmark-animometer
|
- --test=raptor-motionmark-animometer
|
||||||
|
|
||||||
|
raptor-firefox-webaudio:
|
||||||
|
description: "Raptor Firefox WebAudio benchmark"
|
||||||
|
try-name: raptor-firefox-webaudio
|
||||||
|
treeherder-symbol: Rap(wa)
|
||||||
|
run-on-projects: ['try', 'mozilla-central']
|
||||||
|
max-run-time: 1800
|
||||||
|
mozharness:
|
||||||
|
extra-options:
|
||||||
|
- --test=raptor-webaudio
|
||||||
|
|
||||||
raptor-chrome-tp6:
|
raptor-chrome-tp6:
|
||||||
description: "Raptor Chrome tp6"
|
description: "Raptor Chrome tp6"
|
||||||
try-name: raptor-chrome-tp6
|
try-name: raptor-chrome-tp6
|
||||||
|
@ -132,3 +142,14 @@ raptor-chrome-motionmark-animometer:
|
||||||
extra-options:
|
extra-options:
|
||||||
- --test=raptor-motionmark-animometer
|
- --test=raptor-motionmark-animometer
|
||||||
- --app=chrome
|
- --app=chrome
|
||||||
|
|
||||||
|
raptor-chrome-webaudio:
|
||||||
|
description: "Raptor Chrome WebAudio benchmark"
|
||||||
|
try-name: raptor-chrome-webaudio
|
||||||
|
treeherder-symbol: Rap-C(wa)
|
||||||
|
run-on-projects: ['try', 'mozilla-central']
|
||||||
|
max-run-time: 1800
|
||||||
|
mozharness:
|
||||||
|
extra-options:
|
||||||
|
- --test=raptor-webaudio
|
||||||
|
- --app=chrome
|
||||||
|
|
|
@ -86,9 +86,11 @@ raptor:
|
||||||
- raptor-firefox-stylebench
|
- raptor-firefox-stylebench
|
||||||
- raptor-firefox-motionmark-htmlsuite
|
- raptor-firefox-motionmark-htmlsuite
|
||||||
- raptor-firefox-motionmark-animometer
|
- raptor-firefox-motionmark-animometer
|
||||||
|
- raptor-firefox-webaudio
|
||||||
- raptor-chrome-tp6
|
- raptor-chrome-tp6
|
||||||
- raptor-chrome-speedometer
|
- raptor-chrome-speedometer
|
||||||
- raptor-chrome-stylebench
|
- raptor-chrome-stylebench
|
||||||
|
- raptor-chrome-webaudio
|
||||||
|
|
||||||
awsy:
|
awsy:
|
||||||
- awsy
|
- awsy
|
||||||
|
|
|
@ -91,6 +91,8 @@ class Output(object):
|
||||||
subtests, vals = self.parseSpeedometerOutput(test)
|
subtests, vals = self.parseSpeedometerOutput(test)
|
||||||
elif 'motionmark' in test.measurements:
|
elif 'motionmark' in test.measurements:
|
||||||
subtests, vals = self.parseMotionmarkOutput(test)
|
subtests, vals = self.parseMotionmarkOutput(test)
|
||||||
|
elif 'webaudio' in test.measurements:
|
||||||
|
subtests, vals = self.parseWebaudioOutput(test)
|
||||||
suite['subtests'] = subtests
|
suite['subtests'] = subtests
|
||||||
else:
|
else:
|
||||||
LOG.error("output.summarize received unsupported test results type")
|
LOG.error("output.summarize received unsupported test results type")
|
||||||
|
@ -145,6 +147,54 @@ class Output(object):
|
||||||
|
|
||||||
return subtests, vals
|
return subtests, vals
|
||||||
|
|
||||||
|
def parseWebaudioOutput(self, test):
|
||||||
|
# each benchmark 'index' becomes a subtest; each pagecycle / iteration
|
||||||
|
# of the test has multiple values per index/subtest
|
||||||
|
|
||||||
|
# this is the format we receive the results in from the benchmark
|
||||||
|
# i.e. this is ONE pagecycle of speedometer:
|
||||||
|
|
||||||
|
# {u'name': u'raptor-webaudio-firefox', u'type': u'benchmark', u'measurements':
|
||||||
|
# {u'webaudio': [[u'[{"name":"Empty testcase","duration":26,"buffer":{}},{"name"
|
||||||
|
# :"Simple gain test without resampling","duration":66,"buffer":{}},{"name":"Simple
|
||||||
|
# gain test without resampling (Stereo)","duration":71,"buffer":{}},{"name":"Simple
|
||||||
|
# gain test without resampling (Stereo and positional)","duration":67,"buffer":{}},
|
||||||
|
# {"name":"Simple gain test","duration":41,"buffer":{}},{"name":"Simple gain test
|
||||||
|
# (Stereo)","duration":59,"buffer":{}},{"name":"Simple gain test (Stereo and positional)",
|
||||||
|
# "duration":68,"buffer":{}},{"name":"Upmix without resampling (Mono -> Stereo)",
|
||||||
|
# "duration":53,"buffer":{}},{"name":"Downmix without resampling (Mono -> Stereo)",
|
||||||
|
# "duration":44,"buffer":{}},{"name":"Simple mixing (same buffer)",
|
||||||
|
# "duration":288,"buffer":{}}
|
||||||
|
|
||||||
|
_subtests = {}
|
||||||
|
data = test.measurements['webaudio']
|
||||||
|
for page_cycle in data:
|
||||||
|
data = json.loads(page_cycle[0])
|
||||||
|
for item in data:
|
||||||
|
# for each pagecycle, build a list of subtests and append all related replicates
|
||||||
|
sub = item['name']
|
||||||
|
replicates = [item['duration']]
|
||||||
|
if sub not in _subtests.keys():
|
||||||
|
# subtest not added yet, first pagecycle, so add new one
|
||||||
|
_subtests[sub] = {'unit': test.unit,
|
||||||
|
'alertThreshold': float(test.alert_threshold),
|
||||||
|
'lowerIsBetter': test.lower_is_better,
|
||||||
|
'name': sub,
|
||||||
|
'replicates': []}
|
||||||
|
_subtests[sub]['replicates'].extend([round(x, 3) for x in replicates])
|
||||||
|
|
||||||
|
vals = []
|
||||||
|
subtests = []
|
||||||
|
names = _subtests.keys()
|
||||||
|
names.sort(reverse=True)
|
||||||
|
for name in names:
|
||||||
|
_subtests[name]['value'] = filter.median(_subtests[name]['replicates'])
|
||||||
|
subtests.append(_subtests[name])
|
||||||
|
vals.append([_subtests[name]['value'], name])
|
||||||
|
|
||||||
|
print subtests
|
||||||
|
return subtests, vals
|
||||||
|
|
||||||
def parseMotionmarkOutput(self, test):
|
def parseMotionmarkOutput(self, test):
|
||||||
# for motionmark we want the frameLength:average value for each test
|
# for motionmark we want the frameLength:average value for each test
|
||||||
|
|
||||||
|
@ -266,6 +316,14 @@ class Output(object):
|
||||||
results = [i for i, j in val_list if j == 'geomean']
|
results = [i for i, j in val_list if j == 'geomean']
|
||||||
return filter.mean(results)
|
return filter.mean(results)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def webaudio_score(cls, val_list):
|
||||||
|
"""
|
||||||
|
webaudio_score: self reported as 'Geometric Mean'
|
||||||
|
"""
|
||||||
|
results = [i for i, j in val_list if j == 'Geometric Mean']
|
||||||
|
return filter.mean(results)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def stylebench_score(cls, val_list):
|
def stylebench_score(cls, val_list):
|
||||||
"""
|
"""
|
||||||
|
@ -294,6 +352,8 @@ class Output(object):
|
||||||
return self.speedometer_score(vals)
|
return self.speedometer_score(vals)
|
||||||
elif testname.startswith('raptor-stylebench'):
|
elif testname.startswith('raptor-stylebench'):
|
||||||
return self.stylebench_score(vals)
|
return self.stylebench_score(vals)
|
||||||
|
elif testname.startswith('raptor-webaudio'):
|
||||||
|
return self.webaudio_score(vals)
|
||||||
elif len(vals) > 1:
|
elif len(vals) > 1:
|
||||||
return filter.geometric_mean([i for i, j in vals])
|
return filter.geometric_mean([i for i, j in vals])
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -4,3 +4,4 @@
|
||||||
[include:tests/raptor-stylebench.ini]
|
[include:tests/raptor-stylebench.ini]
|
||||||
[include:tests/raptor-motionmark-htmlsuite.ini]
|
[include:tests/raptor-motionmark-htmlsuite.ini]
|
||||||
[include:tests/raptor-motionmark-animometer.ini]
|
[include:tests/raptor-motionmark-animometer.ini]
|
||||||
|
[include:tests/raptor-webaudio.ini]
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
# speedometer benchmark for firefox and chrome
|
||||||
|
|
||||||
|
[DEFAULT]
|
||||||
|
type = benchmark
|
||||||
|
test_url = http://localhost:<port>/webaudio/index.html?raptor
|
||||||
|
page_cycles = 5
|
||||||
|
page_timeout = 180000
|
||||||
|
unit = score
|
||||||
|
lower_is_better = true
|
||||||
|
alert_threshold = 2.0
|
||||||
|
|
||||||
|
[raptor-webaudio-firefox]
|
||||||
|
apps = firefox
|
||||||
|
|
||||||
|
[raptor-webaudio-chrome]
|
||||||
|
apps = chrome
|
|
@ -23,6 +23,7 @@
|
||||||
{
|
{
|
||||||
"matches": ["*://*/Speedometer/index.html*",
|
"matches": ["*://*/Speedometer/index.html*",
|
||||||
"*://*/StyleBench/*",
|
"*://*/StyleBench/*",
|
||||||
|
"*://*/webaudio/*",
|
||||||
"*://*/MotionMark/*"],
|
"*://*/MotionMark/*"],
|
||||||
"js": ["benchmark-relay.js"]
|
"js": ["benchmark-relay.js"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# webaudio-benchmark
|
||||||
|
|
||||||
|
## Run
|
||||||
|
|
||||||
|
Just open `index.html`. Time are in milliseconds, lower is better.
|
||||||
|
|
||||||
|
## Adding new benchmarks
|
||||||
|
|
||||||
|
Look into `benchmarks.js`, it's pretty straightforward.
|
||||||
|
|
||||||
|
## Grafana dashboard
|
||||||
|
|
||||||
|
When adding new benchmarks, run `node generate-grafana-dashboard.js`, this
|
||||||
|
should overwrite `webaudio.json` so that the new benchmarks are registered in
|
||||||
|
grafana.
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MPL 2.0
|
|
@ -0,0 +1 @@
|
||||||
|
0.2
|
|
@ -0,0 +1,371 @@
|
||||||
|
if (typeof(window) == "undefined") {
|
||||||
|
benchmarks = []
|
||||||
|
registerTestFile = function() {}
|
||||||
|
registerTestCase = function(o) { return benchmarks.push(o.name); }
|
||||||
|
}
|
||||||
|
|
||||||
|
registerTestFile("think-mono-48000.wav");
|
||||||
|
registerTestFile("think-mono-44100.wav");
|
||||||
|
registerTestFile("think-mono-38000.wav");
|
||||||
|
registerTestFile("think-stereo-48000.wav");
|
||||||
|
registerTestFile("think-stereo-44100.wav");
|
||||||
|
registerTestFile("think-stereo-38000.wav");
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function () {
|
||||||
|
var oac = new OfflineAudioContext(1, 120 * samplerate, samplerate);
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Empty testcase"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function () {
|
||||||
|
var oac = new OfflineAudioContext(1, 120 * samplerate, samplerate);
|
||||||
|
var source0 = oac.createBufferSource();
|
||||||
|
source0.buffer = getSpecificFile({rate: oac.samplerate, channels:1});
|
||||||
|
source0.loop = true;
|
||||||
|
source0.connect(oac.destination);
|
||||||
|
source0.start(0);
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Simple gain test without resampling"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function() {
|
||||||
|
var oac = new OfflineAudioContext(2, 120 * samplerate, samplerate);
|
||||||
|
var source0 = oac.createBufferSource();
|
||||||
|
source0.buffer = getSpecificFile({rate: oac.samplerate, channels:2});
|
||||||
|
source0.loop = true;
|
||||||
|
source0.connect(oac.destination);
|
||||||
|
source0.start(0);
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Simple gain test without resampling (Stereo)"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function () {
|
||||||
|
var oac = new OfflineAudioContext(2, 120 * samplerate, samplerate);
|
||||||
|
var source0 = oac.createBufferSource();
|
||||||
|
var panner = oac.createPanner();
|
||||||
|
source0.buffer = getSpecificFile({rate: oac.samplerate, channels:2});
|
||||||
|
source0.loop = true;
|
||||||
|
panner.setPosition(1, 2, 3);
|
||||||
|
panner.setOrientation(10, 10, 10);
|
||||||
|
source0.connect(panner);
|
||||||
|
panner.connect(oac.destination);
|
||||||
|
source0.start(0);
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Simple gain test without resampling (Stereo and positional)"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function() {
|
||||||
|
var oac = new OfflineAudioContext(1, 120 * samplerate, samplerate);
|
||||||
|
var source0 = oac.createBufferSource();
|
||||||
|
source0.buffer = getSpecificFile({rate: 38000, channels:1});
|
||||||
|
source0.loop = true;
|
||||||
|
source0.connect(oac.destination);
|
||||||
|
source0.start(0);
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Simple gain test"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function() {
|
||||||
|
var oac = new OfflineAudioContext(2, 120 * samplerate, samplerate);
|
||||||
|
var source0 = oac.createBufferSource();
|
||||||
|
source0.buffer = getSpecificFile({rate: 38000, channels:2});
|
||||||
|
source0.loop = true;
|
||||||
|
source0.connect(oac.destination);
|
||||||
|
source0.start(0);
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Simple gain test (Stereo)"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function() {
|
||||||
|
var oac = new OfflineAudioContext(2, 120 * samplerate, samplerate);
|
||||||
|
var source0 = oac.createBufferSource();
|
||||||
|
var panner = oac.createPanner();
|
||||||
|
source0.buffer = getSpecificFile({rate: 38000, channels:2});
|
||||||
|
source0.loop = true;
|
||||||
|
panner.setPosition(1, 2, 3);
|
||||||
|
panner.setOrientation(10, 10, 10);
|
||||||
|
source0.connect(panner);
|
||||||
|
panner.connect(oac.destination);
|
||||||
|
source0.start(0);
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Simple gain test (Stereo and positional)"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function() {
|
||||||
|
var oac = new OfflineAudioContext(2, 120 * samplerate, samplerate);
|
||||||
|
var source0 = oac.createBufferSource();
|
||||||
|
source0.buffer = getSpecificFile({rate: oac.samplerate, channels:1});
|
||||||
|
source0.loop = true;
|
||||||
|
source0.connect(oac.destination);
|
||||||
|
source0.start(0);
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Upmix without resampling (Mono -> Stereo)"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function() {
|
||||||
|
var oac = new OfflineAudioContext(1, 120 * samplerate, samplerate);
|
||||||
|
var source0 = oac.createBufferSource();
|
||||||
|
source0.buffer = getSpecificFile({rate: oac.samplerate, channels:2});
|
||||||
|
source0.loop = true;
|
||||||
|
source0.connect(oac.destination);
|
||||||
|
source0.start(0);
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Downmix without resampling (Mono -> Stereo)"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function() {
|
||||||
|
var oac = new OfflineAudioContext(2, 30 * samplerate, samplerate);
|
||||||
|
for (var i = 0; i < 100; i++) {
|
||||||
|
var source0 = oac.createBufferSource();
|
||||||
|
source0.buffer = getSpecificFile({rate: 38000, channels:1});
|
||||||
|
source0.loop = true;
|
||||||
|
source0.connect(oac.destination);
|
||||||
|
source0.start(0);
|
||||||
|
}
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Simple mixing (same buffer)"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function() {
|
||||||
|
var oac = new OfflineAudioContext(2, 30 * samplerate, samplerate);
|
||||||
|
var reference = getSpecificFile({rate: 38000, channels:1}).getChannelData(0);
|
||||||
|
for (var i = 0; i < 100; i++) {
|
||||||
|
var source0 = oac.createBufferSource();
|
||||||
|
// copy the buffer into the a new one, so we know the implementation is not
|
||||||
|
// sharing them.
|
||||||
|
var b = oac.createBuffer(1, reference.length, 38000);
|
||||||
|
var data = b.getChannelData(0);
|
||||||
|
for (var j = 0; j < b.length; j++) {
|
||||||
|
data[i] = reference[i];
|
||||||
|
}
|
||||||
|
source0.buffer = b;
|
||||||
|
source0.loop = true;
|
||||||
|
source0.connect(oac.destination);
|
||||||
|
source0.start(0);
|
||||||
|
}
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Simple mixing (different buffers)"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function() {
|
||||||
|
var oac = new OfflineAudioContext(2, 300 * samplerate, samplerate);
|
||||||
|
var gain = oac.createGain();
|
||||||
|
gain.gain.value = -1;
|
||||||
|
gain.connect(oac.destination);
|
||||||
|
var gainsi = [];
|
||||||
|
for (var i = 0; i < 4; i++) {
|
||||||
|
var gaini = oac.createGain();
|
||||||
|
gaini.gain.value = 0.25;
|
||||||
|
gaini.connect(gain);
|
||||||
|
gainsi[i] = gaini
|
||||||
|
}
|
||||||
|
for (var j = 0; j < 2; j++) {
|
||||||
|
var sourcej = oac.createBufferSource();
|
||||||
|
sourcej.buffer = getSpecificFile({rate: 38000, channels:1});
|
||||||
|
sourcej.loop = true;
|
||||||
|
sourcej.start(0);
|
||||||
|
for (var i = 0; i < 4; i++) {
|
||||||
|
var gainij = oac.createGain();
|
||||||
|
gainij.gain.value = 0.5;
|
||||||
|
gainij.connect(gainsi[i]);
|
||||||
|
sourcej.connect(gainij);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Simple mixing with gains"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function() {
|
||||||
|
var oac = new OfflineAudioContext(1, 30 * samplerate, samplerate);
|
||||||
|
var i,l;
|
||||||
|
var decay = 10;
|
||||||
|
var duration = 4;
|
||||||
|
var len = samplerate * duration;
|
||||||
|
var buffer = ac.createBuffer(2, len, oac.sampleRate)
|
||||||
|
var iL = buffer.getChannelData(0)
|
||||||
|
var iR = buffer.getChannelData(1)
|
||||||
|
// Simple exp decay loop
|
||||||
|
for(i=0,l=buffer.length;i<l;i++) {
|
||||||
|
iL[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / len, decay);
|
||||||
|
iR[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / len, decay);
|
||||||
|
}
|
||||||
|
var convolver = oac.createConvolver();
|
||||||
|
convolver.buffer = buffer;
|
||||||
|
convolver.connect(oac.destination);
|
||||||
|
|
||||||
|
var audiobuffer = getSpecificFile({rate: samplerate, channels:1});
|
||||||
|
var source0 = oac.createBufferSource();
|
||||||
|
source0.buffer = audiobuffer;
|
||||||
|
source0.loop = true;
|
||||||
|
source0.connect(convolver);
|
||||||
|
source0.start(0);
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Convolution reverb"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function() {
|
||||||
|
var oac = new OfflineAudioContext(1, 30 * samplerate, samplerate);
|
||||||
|
var duration = 30 * samplerate;
|
||||||
|
var audiobuffer = getSpecificFile({rate: samplerate, channels:1});
|
||||||
|
var offset = 0;
|
||||||
|
while (offset < duration / samplerate) {
|
||||||
|
var grain = oac.createBufferSource();
|
||||||
|
var gain = oac.createGain();
|
||||||
|
grain.connect(gain);
|
||||||
|
gain.connect(oac.destination);
|
||||||
|
grain.buffer = audiobuffer;
|
||||||
|
// get a random 100-ish ms with enveloppes
|
||||||
|
var start = offset * Math.random() * 0.5;
|
||||||
|
var end = start + 0.005 * (0.999 * Math.random());
|
||||||
|
grain.start(offset, start, end);
|
||||||
|
gain.gain.setValueAtTime(offset, 0);
|
||||||
|
gain.gain.linearRampToValueAtTime(.5, offset + 0.005);
|
||||||
|
var startRelease = Math.max(offset + (end - start), 0);
|
||||||
|
gain.gain.setValueAtTime(0.5, startRelease);
|
||||||
|
gain.gain.linearRampToValueAtTime(0.0, startRelease + 0.05);
|
||||||
|
|
||||||
|
// some overlap
|
||||||
|
offset += 0.005;
|
||||||
|
}
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Granular synthesis"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function() {
|
||||||
|
var samplerate = 44100;
|
||||||
|
var duration = 30;
|
||||||
|
var oac = new OfflineAudioContext(1, duration * samplerate, 44100);
|
||||||
|
var offset = 0;
|
||||||
|
while (offset < duration) {
|
||||||
|
var note = oac.createOscillator();
|
||||||
|
var env = oac.createGain();
|
||||||
|
note.type = "sawtooth";
|
||||||
|
note.frequency.value = 110;
|
||||||
|
note.connect(env);
|
||||||
|
env.gain.setValueAtTime(0, 0);
|
||||||
|
env.gain.setValueAtTime(0.5, offset);
|
||||||
|
env.gain.setTargetAtTime(0, offset+0.01, 0.1);
|
||||||
|
env.connect(oac.destination);
|
||||||
|
note.start(offset);
|
||||||
|
note.stop(offset + 1.0);
|
||||||
|
offset += 140 / 60 / 4; // 140 bpm
|
||||||
|
}
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Synth"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function() {
|
||||||
|
var samplerate = 44100;
|
||||||
|
var duration = 30;
|
||||||
|
var oac = new OfflineAudioContext(1, duration * samplerate, samplerate);
|
||||||
|
var offset = 0;
|
||||||
|
var osc = oac.createOscillator();
|
||||||
|
osc.type = "sawtooth";
|
||||||
|
var enveloppe = oac.createGain();
|
||||||
|
enveloppe.gain.setValueAtTime(0, 0);
|
||||||
|
var filter = oac.createBiquadFilter();
|
||||||
|
osc.connect(enveloppe);
|
||||||
|
enveloppe.connect(filter);
|
||||||
|
filter.connect(oac.destination);
|
||||||
|
filter.frequency.setValueAtTime(0.0, 0.0);
|
||||||
|
filter.Q.setValueAtTime(20, 0.0);
|
||||||
|
osc.start(0);
|
||||||
|
osc.frequency.setValueAtTime(110, 0);
|
||||||
|
|
||||||
|
while (offset < duration) {
|
||||||
|
enveloppe.gain.setValueAtTime(1.0, offset);
|
||||||
|
enveloppe.gain.setTargetAtTime(0.0, offset, 0.1);
|
||||||
|
filter.frequency.setValueAtTime(0, offset);
|
||||||
|
filter.frequency.setTargetAtTime(3500, offset, 0.03);
|
||||||
|
offset += 140 / 60 / 16;
|
||||||
|
}
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Substractive synth"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function () {
|
||||||
|
var oac = new OfflineAudioContext(2, 120 * samplerate, samplerate);
|
||||||
|
var source0 = oac.createBufferSource();
|
||||||
|
var panner = oac.createStereoPanner();
|
||||||
|
source0.buffer = getSpecificFile({rate: oac.samplerate, channels:2});
|
||||||
|
source0.loop = true;
|
||||||
|
panner.pan = 0.1;
|
||||||
|
source0.connect(panner);
|
||||||
|
panner.connect(oac.destination);
|
||||||
|
source0.start(0);
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Stereo Panning"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function () {
|
||||||
|
var oac = new OfflineAudioContext(2, 120 * samplerate, samplerate);
|
||||||
|
var source0 = oac.createBufferSource();
|
||||||
|
var panner = oac.createStereoPanner();
|
||||||
|
source0.buffer = getSpecificFile({rate: oac.samplerate, channels:2});
|
||||||
|
source0.loop = true;
|
||||||
|
panner.pan.setValueAtTime(-0.1, 0.0);
|
||||||
|
panner.pan.setValueAtTime(0.2, 0.5);
|
||||||
|
source0.connect(panner);
|
||||||
|
panner.connect(oac.destination);
|
||||||
|
source0.start(0);
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Stereo Panning with Automation"
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTestCase({
|
||||||
|
func: function () {
|
||||||
|
var oac = new OfflineAudioContext(2, 120 * samplerate, samplerate);
|
||||||
|
var osc = oac.createOscillator();
|
||||||
|
osc.type = 'sawtooth';
|
||||||
|
var freq = 2000;
|
||||||
|
osc.frequency.value = freq;
|
||||||
|
osc.frequency.linearRampToValueAtTime(20, 10.0);
|
||||||
|
osc.connect(oac.destination);
|
||||||
|
osc.start(0);
|
||||||
|
return oac;
|
||||||
|
},
|
||||||
|
name: "Periodic Wave with Automation"
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (typeof(window) == "undefined") {
|
||||||
|
exports.benchmarks = benchmarks;
|
||||||
|
}
|
||||||
|
|
25
third_party/webkit/PerformanceTests/webaudio/generate-grafana-dashboard.js
поставляемый
Normal file
25
third_party/webkit/PerformanceTests/webaudio/generate-grafana-dashboard.js
поставляемый
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
var OUTPUT_PATH="webaudio.json";
|
||||||
|
|
||||||
|
var benchmarks = require("./benchmarks.js");
|
||||||
|
var template = require("./template-row.json");
|
||||||
|
var dashboard = require("./webaudio-dashboard.json");
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
var str = JSON.stringify(template);
|
||||||
|
|
||||||
|
var names = benchmarks.benchmarks;
|
||||||
|
|
||||||
|
for (var i in benchmarks.benchmarks) {
|
||||||
|
["win", "linux", "mac", "android"].forEach(function(platform) {
|
||||||
|
var out = str.replace(/{{benchmark}}/g, names[i]).replace(/{{platform}}/g, platform);
|
||||||
|
dashboard.rows.push(JSON.parse(out));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFile(OUTPUT_PATH, JSON.stringify(dashboard, " ", 2), function(err) {
|
||||||
|
if(err) {
|
||||||
|
return console.log(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("grafana dashboard saved as " + OUTPUT_PATH);
|
||||||
|
});
|
|
@ -0,0 +1,44 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src=webaudio-bench.js></script>
|
||||||
|
<script src=benchmarks.js></script>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
html {
|
||||||
|
font-family: helvetica, arial;
|
||||||
|
}
|
||||||
|
#in-progress {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
margin: 1em;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
thead {
|
||||||
|
background-color: #aaaaaa;
|
||||||
|
}
|
||||||
|
tr:nth-child(even) {
|
||||||
|
background-color: #eeeeee;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
border: 1px solid black;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#run-all {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<progress id=loading></progress>
|
||||||
|
<div class=controls>
|
||||||
|
<button id=run-all>Run all</button>
|
||||||
|
<div id=in-progress>
|
||||||
|
<progress> </progress>
|
||||||
|
Benchmark in progress...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id=results>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,79 @@
|
||||||
|
{
|
||||||
|
"title": "{{benchmark}} -- {{platform}}",
|
||||||
|
"height": "250px",
|
||||||
|
"editable": true,
|
||||||
|
"collapse": true,
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"title": "{{benchmark}} -- {{platform}}",
|
||||||
|
"error": false,
|
||||||
|
"span": 12,
|
||||||
|
"editable": true,
|
||||||
|
"type": "graph",
|
||||||
|
"id": 1,
|
||||||
|
"datasource": null,
|
||||||
|
"renderer": "flot",
|
||||||
|
"x-axis": true,
|
||||||
|
"y-axis": true,
|
||||||
|
"y_formats": [
|
||||||
|
"short",
|
||||||
|
"short"
|
||||||
|
],
|
||||||
|
"grid": {
|
||||||
|
"leftMax": null,
|
||||||
|
"rightMax": null,
|
||||||
|
"leftMin": null,
|
||||||
|
"rightMin": null,
|
||||||
|
"threshold1": null,
|
||||||
|
"threshold2": null,
|
||||||
|
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||||
|
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"fill": 0,
|
||||||
|
"linewidth": 1,
|
||||||
|
"points": true,
|
||||||
|
"pointradius": 5,
|
||||||
|
"bars": false,
|
||||||
|
"stack": false,
|
||||||
|
"percentage": false,
|
||||||
|
"legend": {
|
||||||
|
"show": true,
|
||||||
|
"values": false,
|
||||||
|
"min": false,
|
||||||
|
"max": false,
|
||||||
|
"current": false,
|
||||||
|
"total": false,
|
||||||
|
"avg": false,
|
||||||
|
"alignAsTable": false
|
||||||
|
},
|
||||||
|
"nullPointMode": "connected",
|
||||||
|
"steppedLine": false,
|
||||||
|
"tooltip": {
|
||||||
|
"value_type": "cumulative",
|
||||||
|
"shared": false
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"function": "mean",
|
||||||
|
"column": "value",
|
||||||
|
"series": "benchmarks.webaudio-padenot.{{benchmark}}.{{platform}}.firefox.nightly",
|
||||||
|
"query": "select mean(value) from \"benchmarks.webaudio-padenot.{{benchmark}}.{{platform}}.firefox.nightly\" where $timeFilter group by time($interval) order asc",
|
||||||
|
"hide": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"function": "mean",
|
||||||
|
"column": "value",
|
||||||
|
"series": "benchmarks.webaudio-padenot.{{benchmark}}.{{platform}}.chrome.canary",
|
||||||
|
"query": "select mean(value) from \"benchmarks.webaudio-padenot.{{benchmark}}.{{platform}}.chrome.canary\" where $timeFilter group by time($interval) order asc",
|
||||||
|
"hide": false,
|
||||||
|
"groupby_field": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"aliasColors": {},
|
||||||
|
"seriesOverrides": [],
|
||||||
|
"links": [],
|
||||||
|
"leftYAxisLabel": "Time in milliseconds, lower is better"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage:"
|
||||||
|
echo "\t$0" /path/to/webaudio-benchmarks
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# != "1" ]
|
||||||
|
then
|
||||||
|
usage $0
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp $1/* .
|
|
@ -0,0 +1,209 @@
|
||||||
|
if (window.AudioContext == undefined) {
|
||||||
|
window.AudioContext = window.webkitAudioContext;
|
||||||
|
window.OfflineAudioContext = window.webkitOfflineAudioContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global samplerate at which we run the context.
|
||||||
|
var samplerate = 48000;
|
||||||
|
// Array containing at first the url of the audio resources to fetch, and the
|
||||||
|
// the actual buffers audio buffer we have at our disposal to for tests.
|
||||||
|
var sources = [];
|
||||||
|
// Array containing the results, for each benchmark.
|
||||||
|
var results = [];
|
||||||
|
// Array containing the offline contexts used to run the testcases.
|
||||||
|
var testcases = [];
|
||||||
|
// Array containing the functions that can return a runnable testcase.
|
||||||
|
var testcases_registered = [];
|
||||||
|
// Array containing the audio buffers for each benchmark
|
||||||
|
var buffers = [];
|
||||||
|
var playingSource = null;
|
||||||
|
// audiocontext used to play back the result of the benchmarks
|
||||||
|
var ac = new AudioContext();
|
||||||
|
|
||||||
|
function getFile(url, callback) {
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.open("GET", url, true);
|
||||||
|
request.responseType = "arraybuffer";
|
||||||
|
|
||||||
|
request.onload = function() {
|
||||||
|
var ctx = new AudioContext();
|
||||||
|
ctx.decodeAudioData(request.response, function(data) {
|
||||||
|
callback(data, undefined);
|
||||||
|
}, function() {
|
||||||
|
callback(undefined, "Error decoding the file " + url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
request.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function recordResult(result) {
|
||||||
|
results.push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function benchmark(testcase, ended) {
|
||||||
|
var context = testcase.ctx;
|
||||||
|
var start;
|
||||||
|
|
||||||
|
context.oncomplete = function(e) {
|
||||||
|
var end = Date.now();
|
||||||
|
recordResult({
|
||||||
|
name: testcase.name,
|
||||||
|
duration: end - start,
|
||||||
|
buffer: e.renderedBuffer
|
||||||
|
});
|
||||||
|
ended();
|
||||||
|
};
|
||||||
|
|
||||||
|
start = Date.now();
|
||||||
|
context.startRendering();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMonoFile() {
|
||||||
|
return getSpecificFile({numberOfChannels: 1});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStereoFile() {
|
||||||
|
return getSpecificFile({numberOfChannels: 2});
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchIfSpecified(a, b) {
|
||||||
|
if (b) {
|
||||||
|
return a == b;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSpecificFile(spec) {
|
||||||
|
for (var i = 0 ; i < sources.length; i++) {
|
||||||
|
if (matchIfSpecified(sources[i].numberOfChannels, spec.numberOfChannels) &&
|
||||||
|
matchIfSpecified(sources[i].samplerate, spec.samplerate)) {
|
||||||
|
return sources[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error("Could not find a file that matches the specs.");
|
||||||
|
}
|
||||||
|
|
||||||
|
function allDone() {
|
||||||
|
document.getElementById("in-progress").style.display = "none";
|
||||||
|
var result = document.getElementById("results");
|
||||||
|
var str = "<table><thead><tr><td>Test name</td><td>Time in ms</td><td>Speedup vs. realtime</td><td>Sound</td></tr></thead>";
|
||||||
|
var buffers_base = buffers.length;
|
||||||
|
var product_of_durations = 1.0;
|
||||||
|
|
||||||
|
for (var i = 0 ; i < results.length; i++) {
|
||||||
|
var r = results[i];
|
||||||
|
product_of_durations *= r.duration;
|
||||||
|
str += "<tr><td>" + r.name + "</td>" +
|
||||||
|
"<td>" + r.duration + "</td>"+
|
||||||
|
"<td>" + Math.round((r.buffer.duration * 1000) / r.duration) + "x</td>"+
|
||||||
|
"<td><button data-soundindex="+(buffers_base + i)+">Play</button> ("+r.buffer.duration+"s)</td>"
|
||||||
|
+"</tr>";
|
||||||
|
buffers[buffers_base + i] = r.buffer;
|
||||||
|
}
|
||||||
|
recordResult({
|
||||||
|
name: "Geometric Mean",
|
||||||
|
duration: Math.round(Math.pow(product_of_durations, 1.0/results.length)),
|
||||||
|
buffer: {}
|
||||||
|
});
|
||||||
|
str += "</table>";
|
||||||
|
result.innerHTML += str;
|
||||||
|
result.addEventListener("click", function(e) {
|
||||||
|
var t = e.target;
|
||||||
|
if (t.dataset.soundindex != undefined) {
|
||||||
|
if (playingSource != null) {
|
||||||
|
playingSource.button.innerHTML = "Play";
|
||||||
|
playingSource.onended = undefined;
|
||||||
|
playingSource.stop(0);
|
||||||
|
if (playingSource.button == t) {
|
||||||
|
playingSource = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
playingSource = ac.createBufferSource();
|
||||||
|
playingSource.connect(ac.destination);
|
||||||
|
playingSource.buffer = buffers[t.dataset.soundindex];
|
||||||
|
playingSource.start(0);
|
||||||
|
playingSource.button = t;
|
||||||
|
t.innerHTML = "Pause";
|
||||||
|
playingSource.onended = function () {
|
||||||
|
playingSource = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("run-all").disabled = false;
|
||||||
|
|
||||||
|
if (location.search == '?raptor') {
|
||||||
|
var _data = ['raptor-benchmark', 'webaudio', JSON.stringify(results)];
|
||||||
|
window.postMessage(_data, '*');
|
||||||
|
} else {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("POST", "/results", true);
|
||||||
|
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||||
|
xhr.send("results=" + JSON.stringify(results));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function runOne(i) {
|
||||||
|
benchmark(testcases[i], function() {
|
||||||
|
i++;
|
||||||
|
if (i < testcases.length) {
|
||||||
|
runOne(i);
|
||||||
|
} else {
|
||||||
|
allDone();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function runAll() {
|
||||||
|
initAll();
|
||||||
|
results = [];
|
||||||
|
runOne(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initAll() {
|
||||||
|
for (var i = 0; i < testcases_registered.length; i++) {
|
||||||
|
testcases[i] = {};
|
||||||
|
testcases[i].ctx = testcases_registered[i].func();
|
||||||
|
testcases[i].name = testcases_registered[i].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadOne(i, endCallback) {
|
||||||
|
getFile(sources[i], function(b) {
|
||||||
|
sources[i] = b;
|
||||||
|
i++;
|
||||||
|
if (i == sources.length) {
|
||||||
|
loadOne(i);
|
||||||
|
} else {
|
||||||
|
endCallback();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadAllSources(endCallback) {
|
||||||
|
loadOne(0, endCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
document.getElementById("run-all").addEventListener("click", function() {
|
||||||
|
document.getElementById("in-progress").style.display = "inline";
|
||||||
|
document.getElementById("run-all").disabled = true;
|
||||||
|
runAll();
|
||||||
|
});
|
||||||
|
loadAllSources(function() {
|
||||||
|
document.getElementById("loading").style.display = "none";
|
||||||
|
document.getElementById("run-all").style.display = "inline";
|
||||||
|
document.getElementById("in-progress").style.display = "inline";
|
||||||
|
setTimeout(runAll, 100);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Public API */
|
||||||
|
function registerTestCase(testCase) {
|
||||||
|
testcases_registered.push(testCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerTestFile(url) {
|
||||||
|
sources.push(url);
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
{
|
||||||
|
"id": null,
|
||||||
|
"title": "Web Audio API benchmark",
|
||||||
|
"originalTitle": "Web Audio API benchmark",
|
||||||
|
"tags": [],
|
||||||
|
"style": "dark",
|
||||||
|
"timezone": "browser",
|
||||||
|
"editable": true,
|
||||||
|
"hideControls": false,
|
||||||
|
"sharedCrosshair": false,
|
||||||
|
"rows": [ ],
|
||||||
|
"nav": [
|
||||||
|
{
|
||||||
|
"type": "timepicker",
|
||||||
|
"collapse": false,
|
||||||
|
"enable": true,
|
||||||
|
"status": "Stable",
|
||||||
|
"time_options": [
|
||||||
|
"5m",
|
||||||
|
"15m",
|
||||||
|
"1h",
|
||||||
|
"6h",
|
||||||
|
"12h",
|
||||||
|
"24h",
|
||||||
|
"2d",
|
||||||
|
"7d",
|
||||||
|
"30d"
|
||||||
|
],
|
||||||
|
"refresh_intervals": [
|
||||||
|
"5s",
|
||||||
|
"10s",
|
||||||
|
"30s",
|
||||||
|
"1m",
|
||||||
|
"5m",
|
||||||
|
"15m",
|
||||||
|
"30m",
|
||||||
|
"1h",
|
||||||
|
"2h",
|
||||||
|
"1d"
|
||||||
|
],
|
||||||
|
"now": true,
|
||||||
|
"notice": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": {
|
||||||
|
"from": "now-7d",
|
||||||
|
"to": "now"
|
||||||
|
},
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"annotations": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"version": 6,
|
||||||
|
"hideAllLegends": false
|
||||||
|
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче