xref: /aosp_15_r20/external/sandboxed-api/contrib/pffft/main_pffft_sandboxed.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <syscall.h>
16 
17 #include <cmath>
18 #include <cstdio>
19 #include <cstdlib>
20 #include <cstring>
21 #include <ctime>
22 
23 #include "pffft_sapi.sapi.h"  // NOLINT(build/include)
24 #include "absl/flags/flag.h"
25 #include "absl/flags/parse.h"
26 #include "absl/log/globals.h"
27 #include "absl/log/initialize.h"
28 #include "sandboxed_api/vars.h"
29 
30 class PffftSapiSandbox : public PffftSandbox {
31  public:
ModifyPolicy(sandbox2::PolicyBuilder *)32   std::unique_ptr<sandbox2::Policy> ModifyPolicy(sandbox2::PolicyBuilder*) {
33     return sandbox2::PolicyBuilder()
34         .AllowStaticStartup()
35         .AllowOpen()
36         .AllowRead()
37         .AllowWrite()
38         .AllowSystemMalloc()
39         .AllowExit()
40         .AllowSyscalls({
41             __NR_futex,
42             __NR_close,
43             __NR_getrusage,
44         })
45         .BuildOrDie();
46   }
47 };
48 
49 ABSL_FLAG(bool, verbose_output, true, "Whether to display verbose output");
50 
UclockSec()51 double UclockSec() { return static_cast<double>(clock()) / CLOCKS_PER_SEC; }
52 
ShowOutput(const char * name,int n,int complex,float flops,float t0,float t1,int max_iter)53 void ShowOutput(const char* name, int n, int complex, float flops, float t0,
54                 float t1, int max_iter) {
55   float mflops = flops / 1e6 / (t1 - t0 + 1e-16);
56   if (absl::GetFlag(FLAGS_verbose_output)) {
57     if (flops != -1) {
58       printf("|%9.0f   ", mflops);
59     } else {
60       printf("|      n/a   ");
61     }
62   } else if (flops != -1) {
63     printf("n=%5d, %s %16s : %6.0f MFlops [t=%6.0f ns, %d runs]\n", n,
64            (complex ? "CPLX" : "REAL"), name, mflops,
65            (t1 - t0) / 2 / max_iter * 1e9, max_iter);
66   }
67   fflush(stdout);
68 }
69 
PffftMain()70 absl::Status PffftMain() {
71   LOG(INFO) << "Initializing sandbox...\n";
72 
73   PffftSapiSandbox sandbox;
74   SAPI_RETURN_IF_ERROR(sandbox.Init());
75 
76   PffftApi api(&sandbox);
77 
78   // kTransformSizes is a vector keeping the values by which iterates n, its
79   // value representing the input length. More concrete, n is the number of data
80   // points the caclulus is up to (determinating its accuracy). To show the
81   // performance of Fast-Fourier Transformations the program is testing for
82   // various values of n.
83   constexpr int kTransformSizes[] = {
84       64,      96,  128,  160,  192,  256,  384,  5 * 96,   512,   5 * 128,
85       3 * 256, 800, 1024, 2048, 2400, 4096, 8192, 9 * 1024, 16384, 32768};
86 
87   for (int complex : {0, 1}) {
88     for (int n : kTransformSizes) {
89       const int n_float = n * (complex ? 2 : 1);
90       int n_bytes = n_float * sizeof(float);
91 
92       std::vector<float> work(2 * n_float + 15, 0.0);
93       sapi::v::Array<float> work_array(&work[0], work.size());
94 
95       std::vector<float> x(n_bytes, 0.0);
96       sapi::v::Array<float> x_array(&x[0], x.size());
97 
98       std::vector<float> y(n_bytes, 0.0);
99       sapi::v::Array<float> y_array(&y[0], y.size());
100 
101       std::vector<float> z(n_bytes, 0.0);
102       sapi::v::Array<float> z_array(&z[0], z.size());
103 
104       double t0;
105       double t1;
106       double flops;
107 
108       int max_iter = 5120000 / n * 4;
109 
110       for (int k = 0; k < n_float; ++k) {
111         x[k] = 0;
112       }
113 
114       // FFTPack benchmark
115       {
116         // SIMD_SZ == 4 (returning value of pffft_simd_size())
117         int simd_size_iter = max_iter / 4;
118 
119         if (simd_size_iter == 0) simd_size_iter = 1;
120         if (complex) {
121           SAPI_RETURN_IF_ERROR(api.cffti(n, work_array.PtrBoth()));
122         } else {
123           SAPI_RETURN_IF_ERROR(api.rffti(n, work_array.PtrBoth()));
124         }
125         t0 = UclockSec();
126 
127         for (int iter = 0; iter < simd_size_iter; ++iter) {
128           if (complex) {
129             SAPI_RETURN_IF_ERROR(
130                 api.cfftf(n, x_array.PtrBoth(), work_array.PtrBoth()));
131             SAPI_RETURN_IF_ERROR(
132                 api.cfftb(n, x_array.PtrBoth(), work_array.PtrBoth()));
133           } else {
134             SAPI_RETURN_IF_ERROR(
135                 api.rfftf(n, x_array.PtrBoth(), work_array.PtrBoth()));
136             SAPI_RETURN_IF_ERROR(
137                 api.rfftb(n, x_array.PtrBoth(), work_array.PtrBoth()));
138           }
139         }
140         t1 = UclockSec();
141 
142         flops = (simd_size_iter * 2) *
143                 ((complex ? 5 : 2.5) * static_cast<double>(n) *
144                  log(static_cast<double>(n)) / M_LN2);
145         ShowOutput("FFTPack", n, complex, flops, t0, t1, simd_size_iter);
146       }
147 
148       // PFFFT benchmark
149       {
150         SAPI_ASSIGN_OR_RETURN(
151             PFFFT_Setup * s,
152             api.pffft_new_setup(n, complex ? PFFFT_COMPLEX : PFFFT_REAL));
153 
154         sapi::v::RemotePtr s_reg(s);
155 
156         t0 = UclockSec();
157         for (int iter = 0; iter < max_iter; ++iter) {
158           SAPI_RETURN_IF_ERROR(
159               api.pffft_transform(&s_reg, x_array.PtrBoth(), z_array.PtrBoth(),
160                                   y_array.PtrBoth(), PFFFT_FORWARD));
161           SAPI_RETURN_IF_ERROR(
162               api.pffft_transform(&s_reg, x_array.PtrBoth(), z_array.PtrBoth(),
163                                   y_array.PtrBoth(), PFFFT_FORWARD));
164         }
165 
166         t1 = UclockSec();
167         SAPI_RETURN_IF_ERROR(api.pffft_destroy_setup(&s_reg));
168 
169         flops = (max_iter * 2) * ((complex ? 5 : 2.5) * static_cast<double>(n) *
170                                   log(static_cast<double>(n)) / M_LN2);
171         ShowOutput("PFFFT", n, complex, flops, t0, t1, max_iter);
172 
173         LOG(INFO) << "n = " << n << " SUCCESSFULLY";
174       }
175     }
176   }
177 
178   return absl::OkStatus();
179 }
180 
main(int argc,char * argv[])181 int main(int argc, char* argv[]) {
182   absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
183   absl::ParseCommandLine(argc, argv);
184   absl::InitializeLog();
185 
186   if (absl::Status status = PffftMain(); !status.ok()) {
187     LOG(ERROR) << "Initialization failed: " << status.ToString();
188     return EXIT_FAILURE;
189   }
190 
191   return EXIT_SUCCESS;
192 }
193