Merge pull request #51 from doinachiroiu:master

PiperOrigin-RevId: 331767052
Change-Id: I286e746fec6248c88df563be00da9451ddd63eb7
This commit is contained in:
Copybara-Service 2020-09-15 07:46:03 -07:00
commit da41899797
5 changed files with 404 additions and 0 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "oss-internship-2020/pffft/master"]
path = oss-internship-2020/pffft/master
url = https://bitbucket.org/jpommier/pffft/src/master/

3
oss-internship-2020/pffft/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.o
*.a
pffft_main

View File

@ -0,0 +1,104 @@
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
cmake_minimum_required(VERSION 3.10)
project(pffft CXX C)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_library(pffft STATIC
master/pffft.c
master/pffft.h
master/fftpack.c
master/fftpack.h
)
add_executable(pffft_main
master/test_pffft.c
)
target_link_libraries(pffft_main PRIVATE
pffft
)
set(MATH_LIBS "")
include(CheckLibraryExists)
check_library_exists(m sin "" LIBM)
if(LIBM)
list(APPEND MATH_LIBS "m")
endif()
target_link_libraries(pffft PUBLIC ${MATH_LIBS})
# Adding dependencies
set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree")
# Then configure:
# mkdir -p build && cd build
# cmake .. -G Ninja -DSAPI_ROOT=$HOME/sapi_root
set(SAPI_ENABLE_EXAMPLES OFF CACHE BOOL "")
set(SAPI_ENABLE_TESTS OFF CACHE BOOL "")
add_subdirectory("${SAPI_ROOT}"
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
# Omit this to have the full Sandboxed API in IDE
EXCLUDE_FROM_ALL)
add_sapi_library(pffft_sapi
FUNCTIONS pffft_new_setup
pffft_destroy_setup
pffft_transform
pffft_transform_ordered
pffft_zreorder
pffft_zconvolve_accumulate
pffft_aligned_malloc
pffft_aligned_free
pffft_simd_size
cffti
cfftf
cfftb
rffti
rfftf
rfftb
cosqi
cosqf
cosqb
costi
cost
sinqi
sinqb
sinqf
sinti
sint
INPUTS master/pffft.h master/fftpack.h
LIBRARY pffft
LIBRARY_NAME Pffft
NAMESPACE ""
)
target_include_directories(pffft_sapi INTERFACE
"${PROJECT_BINARY_DIR}"
)
add_executable(pffft_sandboxed
main_pffft_sandboxed.cc
)
target_link_libraries(pffft_sandboxed PRIVATE
pffft_sapi
sapi::sapi
)

View File

@ -0,0 +1,87 @@
# Sandboxing PFFFT library
Build System: CMake
OS: Linux
### Check out the PFFFT library & CMake set up
```
git submodule update --init --recursive
mkdir -p build && cd build
cmake .. -G Ninja -DPFFFT_ROOT_DIR=$PWD
ninjas
```
### For testing:
`cd build`, then `./pffft_sandboxed`
### For debug:
display custom info with
`./pffft_sandboxed --logtostderr`
## ***About the project***
*PFFFT library is concerned with 1D Fast-Fourier Transformations finding a
compromise between accuracy and speed. It deals with real and complex
vectors, both cases being illustrated in the testing part (`test_pffft.c`
for initially and original version, `main_pffft_sandboxed.cc` for our
currently implemented sandboxed version).
The original files can be found at: https://bitbucket.org/jpommier/pffft/src.*
*The purpose of sandboxing is to limit the permissions and capabilities of
librarys methods, in order to secure the usage of them.
After obtaining the sandbox, the functions will be called through an
Sandbox API (being called `api` in the current test) and so, the
operations, system calls or namspaces access may be controlled.
From both `pffft.h` and `fftpack.h` headers, useful methods are added to
sapi library builded with CMake. There is also a need to link math library
as the transformations made require mathematical operators.
Regarding the testing of the methods, one main is doing this job by
iterating through a set of values, that represents the accuracy of
transformations and print the speed for each value and type of
transformation. More specifically, the input length is the target for
accuracy (named as `n`) and it stands for the number of data points from
the series that calculate the result of transformation. It is also
important to mention that the `complex` variable stands for a boolean value
that tells the type of transformation (0 for REAL and 1 for COMPLEX) and
it is taken into account while testing.
In the end, the performance of PFFFT library it is outlined by the output.
There are two output formats available, from which you can choose through
`--output_format=` command-line flag.
Without using this type of argument when running, the output format is set
by default.*
#### CMake observations resume:
* linking pffft and fftpack (which contains necessary functions for pffft)
* set math library
#### Sandboxed main observations resume:
* containing two testing parts (fft / pffft benchmarks)
* showing the performance of the transformations implies
testing them through various FFT dimenstions.
Variable n, the input length, will take specific values
meaning the number of points to which it is set the calculus
(more details of mathematical purpose of n - https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm).
* output shows speed depending on the input length
* use `--output_format=0` or `--output_format=1` arguments to choose between output formats.
`0` is for a detailed output, while `1` is only displaying each transformation process speed.
### Bugs history
1. [Solved] pffft benchmark bug: "Sandbox not active"
n = 64, status OK, `pffft_transform` generates error
n > 64, status not OK
Problem on initialising `sapi::StatusOr<PFFFT_Setup *> s;` the memory that stays
for s is not the same with the address passed in `pffft_transform` function.
(`sapi::v::GenericPtr` - to be changed)
Temporary solution: change the generated files to accept
`uintptr_t` instead of `PFFFT_Setup`
Solution: using `sapi::v::RemotePtr` instead of `sapi::v::GenericPtr`
to access the memory of object `s`
2. [Unresolved] compiling bug: "No space left on device"
The building process creates some `embed` files that use lots of
memory, trying to write them on `/tmp`.
Temporary solution: clean /tmp directory by `sudo rm -rf /tmp/*`

View File

@ -0,0 +1,207 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gflags/gflags.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <glog/logging.h>
#include "pffft_sapi.sapi.h" // NOLINT(build/include)
#include "sandboxed_api/util/flag.h"
#include "sandboxed_api/vars.h"
ABSL_DECLARE_FLAG(string, sandbox2_danger_danger_permit_all);
ABSL_DECLARE_FLAG(string, sandbox2_danger_danger_permit_all_and_log);
class PffftSapiSandbox : public PffftSandbox {
public:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(sandbox2::PolicyBuilder*) {
return sandbox2::PolicyBuilder()
.AllowStaticStartup()
.AllowOpen()
.AllowRead()
.AllowWrite()
.AllowSystemMalloc()
.AllowExit()
.AllowSyscalls({
__NR_futex,
__NR_close,
__NR_getrusage,
})
.BuildOrDie();
}
};
// output_format flag determines whether the output shows information in detail
// or not. By default, the flag is set as 0, meaning an elaborate display
// (see ShowOutput method).
static bool ValidateFlag(const char* flagname, int32_t value) {
if (value >= 0 && value < 32768) {
return true;
}
LOG(ERROR) << "Invalid value for --" << flagname << ".";
return false;
}
DEFINE_int32(output_format, 0, "Value to specific the output format.");
DEFINE_validator(output_format, &ValidateFlag);
double UclockSec() { return static_cast<double>(clock()) / CLOCKS_PER_SEC; }
void ShowOutput(const char* name, int n, int complex, float flops, float t0,
float t1, int max_iter) {
float mflops = flops / 1e6 / (t1 - t0 + 1e-16);
if (FLAGS_output_format) {
if (flops != -1) {
printf("|%9.0f ", mflops);
} else {
printf("| n/a ");
}
} else if (flops != -1) {
printf("n=%5d, %s %16s : %6.0f MFlops [t=%6.0f ns, %d runs]\n", n,
(complex ? "CPLX" : "REAL"), name, mflops,
(t1 - t0) / 2 / max_iter * 1e9, max_iter);
}
fflush(stdout);
}
absl::Status PffftMain() {
LOG(INFO) << "Initializing sandbox...\n";
PffftSapiSandbox sandbox;
SAPI_RETURN_IF_ERROR(sandbox.Init());
PffftApi api(&sandbox);
// kTransformSizes is a vector keeping the values by which iterates n, its
// value representing the input length. More concrete, n is the number of data
// points the caclulus is up to (determinating its accuracy). To show the
// performance of Fast-Fourier Transformations the program is testing for
// various values of n.
constexpr int kTransformSizes[] = {
64, 96, 128, 160, 192, 256, 384, 5 * 96, 512, 5 * 128,
3 * 256, 800, 1024, 2048, 2400, 4096, 8192, 9 * 1024, 16384, 32768};
for (int complex : {0, 1}) {
for (int n : kTransformSizes) {
const int n_float = n * (complex ? 2 : 1);
int n_bytes = n_float * sizeof(float);
std::vector<float> work(2 * n_float + 15, 0.0);
sapi::v::Array<float> work_array(&work[0], work.size());
std::vector<float> x(n_bytes, 0.0);
sapi::v::Array<float> x_array(&x[0], x.size());
std::vector<float> y(n_bytes, 0.0);
sapi::v::Array<float> y_array(&y[0], y.size());
std::vector<float> z(n_bytes, 0.0);
sapi::v::Array<float> z_array(&z[0], z.size());
double t0;
double t1;
double flops;
int max_iter = 5120000 / n * 4;
for (int k = 0; k < n_float; ++k) {
x[k] = 0;
}
// FFTPack benchmark
{
// SIMD_SZ == 4 (returning value of pffft_simd_size())
int simd_size_iter = max_iter / 4;
if (simd_size_iter == 0) simd_size_iter = 1;
if (complex) {
SAPI_RETURN_IF_ERROR(api.cffti(n, work_array.PtrBoth()))
} else {
SAPI_RETURN_IF_ERROR(api.rffti(n, work_array.PtrBoth()));
}
t0 = UclockSec();
for (int iter = 0; iter < simd_size_iter; ++iter) {
if (complex) {
SAPI_RETURN_IF_ERROR(
api.cfftf(n, x_array.PtrBoth(), work_array.PtrBoth()));
SAPI_RETURN_IF_ERROR(
api.cfftb(n, x_array.PtrBoth(), work_array.PtrBoth()));
} else {
SAPI_RETURN_IF_ERROR(
api.rfftf(n, x_array.PtrBoth(), work_array.PtrBoth()));
SAPI_RETURN_IF_ERROR(
api.rfftb(n, x_array.PtrBoth(), work_array.PtrBoth()));
}
}
t1 = UclockSec();
flops = (simd_size_iter * 2) *
((complex ? 5 : 2.5) * static_cast<double>(n) *
log(static_cast<double>(n)) / M_LN2);
ShowOutput("FFTPack", n, complex, flops, t0, t1, simd_size_iter);
}
// PFFFT benchmark
{
SAPI_ASSIGN_OR_RETURN(
PFFFT_Setup * s,
api.pffft_new_setup(n, complex ? PFFFT_COMPLEX : PFFFT_REAL));
sapi::v::RemotePtr s_reg(s);
t0 = UclockSec();
for (int iter = 0; iter < max_iter; ++iter) {
SAPI_RETURN_IF_ERROR(
api.pffft_transform(&s_reg, x_array.PtrBoth(), z_array.PtrBoth(),
y_array.PtrBoth(), PFFFT_FORWARD));
SAPI_RETURN_IF_ERROR(
api.pffft_transform(&s_reg, x_array.PtrBoth(), z_array.PtrBoth(),
y_array.PtrBoth(), PFFFT_FORWARD));
}
t1 = UclockSec();
SAPI_RETURN_IF_ERROR(api.pffft_destroy_setup(&s_reg));
flops = (max_iter * 2) * ((complex ? 5 : 2.5) * static_cast<double>(n) *
log(static_cast<double>(n)) / M_LN2);
ShowOutput("PFFFT", n, complex, flops, t0, t1, max_iter);
LOG(INFO) << "n = " << n << " SUCCESSFULLY";
}
}
}
return absl::OkStatus();
}
int main(int argc, char* argv[]) {
// Initialize Google's logging library.
google::InitGoogleLogging(argv[0]);
gflags::ParseCommandLineFlags(&argc, &argv, true);
if (absl::Status status = PffftMain(); !status.ok()) {
LOG(ERROR) << "Initialization failed: " << status.ToString();
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}