Commit 318d65a3 authored by Raymond Toy's avatar Raymond Toy Committed by Commit Bot

Reland: SIMD the main loop for k-rate Oscillator

The main processing loop for the k-rate Oscillator is updated to use
SSE2 instructions to speed up processing.

Four tests fail because we have slightly reduced accuracy.  Testing
shows that the loss of accuracy is due to using a float for
virtual_read_index in the loop instead of a double as previously.  A
implementation using a double passes all the original tests but does
show that it does lose performance.  I think the change in accuracy is
acceptable.

WebAudio Bench results from a linux machine.  In summary, the SIMD
version is about 60% as much time (about 1.75 times faster).

Without CL:
TEST	μs	MIN	Q1	MEDIAN	Q3	MAX	MEAN	STDDEV
Baseline	713	713	748	757	766	877	760.25	18.35
Oscillator	949	949	972	990	1005	1132	990.78	24.35

With CL:
TEST	μs	MIN	Q1	MEDIAN	Q3	MAX	MEAN	STDDEV
Baseline	728	728	747	756	763	908	757.46	16.81
Oscillator	521	521	549	564	581	874	566.87	27.77

Bug: 1013118
Change-Id: Ic5445cc152e960b41817f245ac306691f7c57f90
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2246831Reviewed-by: default avatarHongchan Choi <hongchan@chromium.org>
Commit-Queue: Raymond Toy <rtoy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#778579}
parent e4d6ced5
...@@ -89,6 +89,24 @@ class OscillatorHandler final : public AudioScheduledSourceHandler { ...@@ -89,6 +89,24 @@ class OscillatorHandler final : public AudioScheduledSourceHandler {
// Compute the output for k-rate AudioParams // Compute the output for k-rate AudioParams
double ProcessKRate(int n, float* dest_p, double virtual_read_index) const; double ProcessKRate(int n, float* dest_p, double virtual_read_index) const;
// Scalar version for the main loop in ProcessKRate(). Returns the updated
// virtual_read_index.
double ProcessKRateScalar(int start_index,
int n,
float* dest_p,
double virtual_read_index,
float frequency,
float rate_scale) const;
// Vectorized version (if available) for the main loop in ProcessKRate().
// Returns the number of elements processed and the updated
// virtual_read_index.
std::tuple<int, double> ProcessKRateVector(int n,
float* dest_p,
double virtual_read_index,
float frequency,
float rate_scale) const;
// Compute the output for a-rate AudioParams // Compute the output for a-rate AudioParams
double ProcessARate(int n, double ProcessARate(int n,
float* dest_p, float* dest_p,
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
testFFTSize(should, { testFFTSize(should, {
initialFFTSize: 128, initialFFTSize: 128,
finalFFTSize: 1024, finalFFTSize: 1024,
errorThreshold: {relativeThreshold: 1.9238e-6} errorThreshold: {relativeThreshold: 1.9455e-6}
}).then(() => task.done()); }).then(() => task.done());
}); });
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
testFFTSize(should, { testFFTSize(should, {
initialFFTSize: 512, initialFFTSize: 512,
finalFFTSize: 256, finalFFTSize: 256,
errorThreshold: {relativeThreshold: 1.8166e-6} errorThreshold: {relativeThreshold: 1.8592e-6}
}).then(() => task.done()); }).then(() => task.done());
}); });
......
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
frequency1: frequency1, frequency1: frequency1,
paramName: 'detune', paramName: 'detune',
newValue: detune, newValue: detune,
thresholds: [1.1921e-7, 1.3114e-6], thresholds: [1.1921e-7, 3.6657e-6],
}).then(() => task.done()); }).then(() => task.done());
}); });
......
...@@ -14,10 +14,10 @@ ...@@ -14,10 +14,10 @@
// Minimum allowed SNR between the actual oscillator and the expected // Minimum allowed SNR between the actual oscillator and the expected
// result. Experimentally determined. // result. Experimentally determined.
let snrThreshold = 59.287; let snrThreshold = 59.280;
// Max absolute difference between actual and expected oscillator // Max absolute difference between actual and expected oscillator
// outputs. Experimentally determined. // outputs. Experimentally determined.
let maxDiffThreshold = 1.5632e-3; let maxDiffThreshold = 1.5640e-3;
let audit = Audit.createTaskRunner(); let audit = Audit.createTaskRunner();
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
runTest(should, { runTest(should, {
message: 'Sum of positive and negative frequency sine oscillators', message: 'Sum of positive and negative frequency sine oscillators',
type: 'sine', type: 'sine',
threshold: 4.1724e-7 threshold: 1.5349e-6
}).then(() => task.done()); }).then(() => task.done());
}); });
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
runTest(should, { runTest(should, {
message: 'Sum of positive and negative frequency square oscillators', message: 'Sum of positive and negative frequency square oscillators',
type: 'square', type: 'square',
threshold: 1.4753e-6 threshold: 1.1496e-5
}).then(() => task.done()); }).then(() => task.done());
}); });
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
message: message:
'Sum of positive and negative frequency sawtooth oscillators', 'Sum of positive and negative frequency sawtooth oscillators',
type: 'sawtooth', type: 'sawtooth',
threshold: 1.4753e-6 threshold: 1.1506e-5
}).then(() => task.done()); }).then(() => task.done());
}); });
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
message: message:
'Sum of positive and negative frequency triangle oscillators', 'Sum of positive and negative frequency triangle oscillators',
type: 'triangle', type: 'triangle',
threshold: 2.9803e-7 threshold: 1.0133e-5
}).then(() => task.done()); }).then(() => task.done());
}); });
...@@ -145,7 +145,7 @@ ...@@ -145,7 +145,7 @@
should( should(
actual, actual,
'Sum of positive and negative frequency custom oscillators') 'Sum of positive and negative frequency custom oscillators')
.beCloseToArray(expected, {absoluteThreshold: 4.1724e-7}); .beCloseToArray(expected, {absoluteThreshold: 2.2352e-6});
}) })
.then(() => task.done()); .then(() => task.done());
}); });
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
}, },
function(task, should) { function(task, should) {
testStartSampling(should, 1.25, { testStartSampling(should, 1.25, {
error: 1.0843e-4, error: 1.0880e-4,
snrThreshold: 84.054 snrThreshold: 84.054
}).then(task.done.bind(task)); }).then(task.done.bind(task));
}); });
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
}, },
function(task, should) { function(task, should) {
testStartSampling(should, 1.75, { testStartSampling(should, 1.75, {
error: 1.0839e-4, error: 1.0844e-4,
snrThreshold: 84.056 snrThreshold: 84.056
}).then(task.done.bind(task)); }).then(task.done.bind(task));
}); });
...@@ -57,8 +57,8 @@ ...@@ -57,8 +57,8 @@
// 1/2 frame from the preceding sampling frame. This tests one path // 1/2 frame from the preceding sampling frame. This tests one path
// of the internal implementation. // of the internal implementation.
testStartWithGain(should, defaultSampleRate, { testStartWithGain(should, defaultSampleRate, {
error: 4.1724e-7, error: 1.9521e-6,
snrThreshold: 137.536 snrThreshold: 128.12
}).then(task.done.bind(task)); }).then(task.done.bind(task));
}); });
...@@ -75,8 +75,8 @@ ...@@ -75,8 +75,8 @@
// frame from the preceding sampling frame. This tests one path of // frame from the preceding sampling frame. This tests one path of
// the internal implementation. // the internal implementation.
testStartWithGain(should, 48000, { testStartWithGain(should, 48000, {
error: 4.1724e-7, error: 1.9521e-6,
snrThreshold: 137.536 snrThreshold: 122.92
}).then(task.done.bind(task)); }).then(task.done.bind(task));
}); });
......
...@@ -134,14 +134,14 @@ ...@@ -134,14 +134,14 @@
verifyPeriodicWaveOutput( verifyPeriodicWaveOutput(
should, {real: [0, 1], imag: [0, 1], disableNormalization: false}, should, {real: [0, 1], imag: [0, 1], disableNormalization: false},
generateReference(x => Math.SQRT1_2 * (Math.sin(x) + Math.cos(x))), generateReference(x => Math.SQRT1_2 * (Math.sin(x) + Math.cos(x))),
2.7165e-5) 2.7225e-5)
.then(() => task.done()); .then(() => task.done());
}); });
audit.define('3: real/imag periodicwave test', (task, should) => { audit.define('3: real/imag periodicwave test', (task, should) => {
verifyPeriodicWaveOutput( verifyPeriodicWaveOutput(
should, {real: [0, 1], imag: [0, 1], disableNormalization: true}, should, {real: [0, 1], imag: [0, 1], disableNormalization: true},
generateReference(x => Math.sin(x) + Math.cos(x)), 3.8416e-5) generateReference(x => Math.sin(x) + Math.cos(x)), 3.8501e-5)
.then(() => task.done()); .then(() => task.done());
}); });
......
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