Commit 7fb54b10 authored by phoglund's avatar phoglund Committed by Commit bot

Rewriting WebRTC output level tests to be more reliable under load.

This greatly reduces the variance in test execution time when running
in parallel on a heavily loaded bot, in which setTimeout becomes
increasingly unpredictable. These tests were quite sensitive to load -
they run 200 consecutive setTimeout calls with short timeouts, but if
the machine is under load it can take up to 1000 ms to call back to
a 50 ms setTimeout. This means the test would take 200 * 1000 =
200 seconds to run, but it obviously times out long before then.

Running with this patch, the tests reliably stay under 10 seconds of
execution time even under the most heavy load, which is a massive
improvement to reliability. The only risk I see with this patch is that
the tests will become more resource-hungry when there are resources
available, so maybe they will starve out other sensitive tests?

BUG=472087

Review URL: https://codereview.chromium.org/1132483003

Cr-Commit-Position: refs/heads/master@{#329400}
parent 5ea9ee00
...@@ -15,8 +15,7 @@ var MAX_AUDIO_OUTPUT_ENERGY = 32768; ...@@ -15,8 +15,7 @@ var MAX_AUDIO_OUTPUT_ENERGY = 32768;
function ensureAudioPlaying(peerConnection, beLenient) { function ensureAudioPlaying(peerConnection, beLenient) {
addExpectedEvent(); addExpectedEvent();
// Gather 50 samples per second for 2 seconds. gatherAudioLevelSamples(peerConnection, 3 * 1000, function(samples) {
gatherAudioLevelSamples(peerConnection, 100, 50, function(samples) {
identifyFakeDeviceSignal_(samples, beLenient); identifyFakeDeviceSignal_(samples, beLenient);
eventOccured(); eventOccured();
}); });
...@@ -27,7 +26,7 @@ function ensureAudioPlaying(peerConnection, beLenient) { ...@@ -27,7 +26,7 @@ function ensureAudioPlaying(peerConnection, beLenient) {
function ensureSilence(peerConnection) { function ensureSilence(peerConnection) {
addExpectedEvent(); addExpectedEvent();
setTimeout(function() { setTimeout(function() {
gatherAudioLevelSamples(peerConnection, 100, 50, function(samples) { gatherAudioLevelSamples(peerConnection, 1 * 1000, function(samples) {
identifySilence_(samples); identifySilence_(samples);
eventOccured(); eventOccured();
}); });
...@@ -48,32 +47,38 @@ function workAroundSeveralReportsIssue(audioOutputLevels) { ...@@ -48,32 +47,38 @@ function workAroundSeveralReportsIssue(audioOutputLevels) {
return Math.max(audioOutputLevels[0], audioOutputLevels[1]); return Math.max(audioOutputLevels[0], audioOutputLevels[1]);
} }
// Gathers |numSamples| samples at |frequency| number of times per second and // Gathers samples from WebRTC stats as fast as possible for |durationMs|
// calls back |callback| with an array with numbers in the [0, 32768] range. // milliseconds and calls back |callback| with an array with numbers in the
function gatherAudioLevelSamples(peerConnection, numSamples, frequency, // [0, 32768] range. There are no guarantees for how often we will be able to
callback) { // collect values, but this function deliberately avoids setTimeout calls in
console.log('Gathering ' + numSamples + ' audio samples...'); // order be as insensitive as possible to starvation (particularly when this
// code runs in parallel with other tests on a heavily loaded bot).
function gatherAudioLevelSamples(peerConnection, durationMs, callback) {
console.log('Gathering audio samples for ' + durationMs + ' milliseconds...');
var audioLevelSamples = [] var audioLevelSamples = []
// If this times out and never found any audio output levels, the call // If this times out and never found any audio output levels, the call
// probably doesn't have an audio stream. // probably doesn't have an audio stream.
var gatherSamples = setInterval(function() { var startTime = new Date();
peerConnection.getStats(function(response) { var gotStats = function(response) {
audioOutputLevels = getAudioLevelFromStats_(response); audioOutputLevels = getAudioLevelFromStats_(response);
if (audioOutputLevels.length == 0) { if (audioOutputLevels.length == 0) {
// The call probably isn't up yet. // The call probably isn't up yet.
return; peerConnection.getStats(gotStats);
} return;
var outputLevel = workAroundSeveralReportsIssue(audioOutputLevels); }
audioLevelSamples.push(outputLevel); var outputLevel = workAroundSeveralReportsIssue(audioOutputLevels);
audioLevelSamples.push(outputLevel);
if (audioLevelSamples.length == numSamples) {
console.log('Gathered all samples.'); var elapsed = new Date() - startTime;
clearInterval(gatherSamples); if (elapsed > durationMs) {
callback(audioLevelSamples); console.log('Gathered all samples.');
} callback(audioLevelSamples);
}); return;
}, 1000 / frequency); }
peerConnection.getStats(gotStats);
}
peerConnection.getStats(gotStats);
} }
/** /**
...@@ -96,7 +101,7 @@ function identifyFakeDeviceSignal_(samples, beLenient) { ...@@ -96,7 +101,7 @@ function identifyFakeDeviceSignal_(samples, beLenient) {
var currentlyOverThreshold = false; var currentlyOverThreshold = false;
// Detect when we have been been over the threshold and is going back again // Detect when we have been been over the threshold and is going back again
// (i.e. count peaks). We should see about one peak per second. // (i.e. count peaks). We should see about two peaks per second.
for (var i = 0; i < samples.length; ++i) { for (var i = 0; i < samples.length; ++i) {
if (currentlyOverThreshold && samples[i] < threshold) if (currentlyOverThreshold && samples[i] < threshold)
numPeaks++; numPeaks++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment