Commit 8e4cf155 authored by Alessio Bazzica's avatar Alessio Bazzica Committed by Commit Bot

Add build file for PFFFT

- fuzzer corpus generator and fuzzer targets
- fftpack isolated as private test only target (only needed for the benchmark)

Bug: webrtc:9577
Change-Id: Idc904bc4b05f945a7461a14893518551bbe34b84
Reviewed-on: https://chromium-review.googlesource.com/c/1452000
Commit-Queue: Ale Bzk <alessiob@chromium.org>
Reviewed-by: default avatarNico Weber <thakis@chromium.org>
Reviewed-by: default avatarOlga Sharonova <olka@chromium.org>
Reviewed-by: default avatarMax Moroz <mmoroz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#629627}
parent 68442b1e
...@@ -698,6 +698,7 @@ group("gn_all") { ...@@ -698,6 +698,7 @@ group("gn_all") {
"//third_party/opus:test_opus_decode", "//third_party/opus:test_opus_decode",
"//third_party/opus:test_opus_encode", "//third_party/opus:test_opus_encode",
"//third_party/opus:test_opus_padding", "//third_party/opus:test_opus_padding",
"//third_party/pffft:pffft_benchmark",
"//ui/display/types", "//ui/display/types",
"//ui/shell_dialogs:shell_dialogs_unittests", "//ui/shell_dialogs:shell_dialogs_unittests",
] ]
......
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//testing/libfuzzer/fuzzer_test.gni")
import("//testing/test.gni")
# TODO(https://crbug.com/webrtc/9577): Add architecture specific flags.
static_library("pffft") {
sources = [
"src/pffft.c",
"src/pffft.h",
]
}
# Fuzzing.
fuzzer_testdata_dir = "$target_gen_dir/testdata"
action("generate_pffft_fuzzer_corpus") {
script = "generate_seed_corpus.py"
sources = [
"generate_seed_corpus.py",
]
args = [ rebase_path(fuzzer_testdata_dir, root_build_dir) ]
outputs = [
fuzzer_testdata_dir,
]
}
fuzzer_test("pffft_real_fuzzer") {
sources = [
"pffft_fuzzer.cc",
]
cflags = [ "-DTRANSFORM_REAL" ]
deps = [
":pffft",
]
seed_corpus = fuzzer_testdata_dir
seed_corpus_deps = [ ":generate_pffft_fuzzer_corpus" ]
}
fuzzer_test("pffft_complex_fuzzer") {
sources = [
"pffft_fuzzer.cc",
]
cflags = [ "-DTRANSFORM_COMPLEX" ]
deps = [
":pffft",
]
seed_corpus = fuzzer_testdata_dir
seed_corpus_deps = [ ":generate_pffft_fuzzer_corpus" ]
}
# Unit tests and benchmark.
# TODO(https://crbug.com/webrtc/9577): Add unit test.
# This target must be used only for testing and benchmark purposes.
static_library("fftpack") {
testonly = true
sources = [
"src/fftpack.c",
"src/fftpack.h",
]
deps = []
visibility = [ ":*" ]
}
executable("pffft_benchmark") {
testonly = true
sources = [
"src/test_pffft.c",
]
deps = [
":fftpack",
":pffft",
]
}
#!/usr/bin/env python
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from __future__ import division
from __future__ import print_function
from array import array
import os
import random
import sys
MAX_INPUT_SIZE = int(1e6)
MAX_FLOAT32 = 3.4028235e+38
def IsValidSize(n):
if n == 0:
return False
# PFFFT only supports transforms for inputs of length N of the form
# N = (2^a)*(3^b)*(5^c) where a >= 5, b >=0, c >= 0.
FACTORS = [2, 3, 5]
factorization = [0, 0, 0]
for i, factor in enumerate(FACTORS):
while n % factor == 0:
n = n // factor
factorization[i] += 1
return factorization[0] >= 5 and n == 1
def WriteFloat32ArrayToFile(file_path, size, generator):
"""Generate an array of float32 values and writes to file."""
with open(file_path, 'wb') as f:
float_array = array('f', [generator() for _ in range(size)])
float_array.tofile(f)
def main():
if len(sys.argv) < 2:
print('Usage: %s <path to output directory>' % sys.argv[0])
sys.exit(1)
output_path = sys.argv[1]
# Create output directory if missing.
if not os.path.exists(output_path):
os.makedirs(output_path)
# List of valid input sizes.
N = [n for n in range(MAX_INPUT_SIZE) if IsValidSize(n)]
# Set the seed to always generate the same random data.
random.seed(0)
# Generate different types of input arrays for each target length.
for n in N:
# Zeros.
WriteFloat32ArrayToFile(
os.path.join(output_path, 'zeros_%d' % n), n, lambda: 0)
# Max float 32.
WriteFloat32ArrayToFile(
os.path.join(output_path, 'max_%d' % n), n, lambda: MAX_FLOAT32)
# Random values in the s16 range.
rnd_s16 = lambda: 32768.0 * 2.0 * (random.random() - 0.5)
WriteFloat32ArrayToFile(
os.path.join(output_path, 'rnd_s16_%d' % n), n, rnd_s16)
sys.exit(0)
if __name__ == '__main__':
main()
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <algorithm>
#include <array>
#include <cassert>
#include <cstring>
#include "third_party/pffft/src/pffft.h"
namespace {
#if defined(TRANSFORM_REAL)
// Real FFT.
constexpr pffft_transform_t kTransform = PFFFT_REAL;
constexpr size_t kSizeOfOneSample = sizeof(float);
#elif defined(TRANSFORM_COMPLEX)
// Complex FFT.
constexpr pffft_transform_t kTransform = PFFFT_COMPLEX;
constexpr size_t kSizeOfOneSample = 2 * sizeof(float); // Real plus imaginary.
#else
#error FFT transform type not defined.
#endif
bool IsValidSize(size_t n) {
if (n == 0) {
return false;
}
// PFFFT only supports transforms for inputs of length N of the form
// N = (2^a)*(3^b)*(5^c) where a >= 5, b >=0, c >= 0.
constexpr std::array<int, 3> kFactors = {2, 3, 5};
std::array<int, kFactors.size()> factorization{};
for (size_t i = 0; i < kFactors.size(); ++i) {
const int factor = kFactors[i];
while (n % factor == 0) {
n /= factor;
factorization[i]++;
}
}
return factorization[0] >= 5 && n == 1;
}
float* AllocatePffftBuffer(size_t number_of_bytes) {
return static_cast<float*>(pffft_aligned_malloc(number_of_bytes));
}
} // namespace
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Set the number of FFT points to use |data| as input vector.
// The latter is truncated if the number of bytes is not an integer
// multiple of the size of one sample (which is either a real or a complex
// floating point number).
const size_t fft_size = size / kSizeOfOneSample;
if (!IsValidSize(fft_size)) {
return 0;
}
const size_t number_of_bytes = fft_size * kSizeOfOneSample;
assert(number_of_bytes <= size);
// Allocate input and output buffers.
float* in = AllocatePffftBuffer(number_of_bytes);
float* out = AllocatePffftBuffer(number_of_bytes);
// Copy input data.
std::memcpy(in, reinterpret_cast<const float*>(data), number_of_bytes);
// Setup FFT.
PFFFT_Setup* pffft_setup = pffft_new_setup(fft_size, kTransform);
// Call different PFFFT functions to maximize the coverage.
pffft_transform(pffft_setup, in, out, nullptr, PFFFT_FORWARD);
pffft_zconvolve_accumulate(pffft_setup, out, out, out, 1.f);
pffft_transform_ordered(pffft_setup, in, out, nullptr, PFFFT_BACKWARD);
// Release memory.
pffft_aligned_free(in);
pffft_aligned_free(out);
pffft_destroy_setup(pffft_setup);
return 0;
}
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