Skip to content

Commit f53a402

Browse files
author
Ryan Kim
authored
Merge pull request #339 from kroma-network/feat/add-fft-benchmark
feat: add fft benchmark
2 parents 04cf201 + 88e4660 commit f53a402

32 files changed

+1155
-648
lines changed

Cargo.Bazel.lock

Lines changed: 423 additions & 501 deletions
Large diffs are not rendered by default.

Cargo.lock

Lines changed: 108 additions & 113 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ members = [
33
"benchmark/msm/arkworks",
44
"benchmark/msm/bellman",
55
"benchmark/msm/halo2",
6+
"benchmark/fft/halo2",
67
"tachyon/rs",
78
"vendors/halo2",
89
]

WORKSPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ crates_repository(
5454
"//benchmark/msm/arkworks:Cargo.toml",
5555
"//benchmark/msm/bellman:Cargo.toml",
5656
"//benchmark/msm/halo2:Cargo.toml",
57+
"//benchmark/fft/halo2:Cargo.toml",
5758
"//tachyon/rs:Cargo.toml",
5859
"//vendors/halo2:Cargo.toml",
5960
],

benchmark/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,14 @@ build --build_tag_filters -rust //enables cuda targets
3737
build --build_tag_filters="" //enables all targets
3838
```
3939

40-
To harness the plot chart feature, first ensure that matplotlib is installed (refer to the [installation guide](https://github.com/kroma-network/tachyon#matplotlib)). Then, append the `--//:has_rtti` and `--//:has_matplotlib` flags to your command:
40+
To harness the plot chart feature, first ensure that matplotlib is installed (refer to the [installation guide](/docs/how_to_use/how_to_build.md#matplotliboptional)). Then, append the `--//:has_rtti` and `--//:has_matplotlib` flags to your command:
4141

4242
```shell
4343
bazel run -c opt --//:has_rtti --//:has_matplotlib //benchmark/path/to/target:target_name -- -n <test_set_size>
4444
```
4545

46+
A build error with error message like `terminate called after throwing an instance of 'pybind11::error_already_set' what(): ImportError: ... : undefined symbol: PyTuple_Type` may occur when building the benchmark. This is because bazel does not know about updates to the python environment. To fix this, set environment varible [`PYTHON_LIB_PATH`](/third_party/py/python_configure.bzl) and rebuild the benchmark.
47+
4648
For executing GPU benchmarks, make sure to configure [GPU config](https://github.com/kroma-network/tachyon#hardware-acceleration) for your environment. For instance, in CUDA:
4749

4850
```shell

benchmark/ec/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ tachyon_cc_library(
1717
visibility = ["//benchmark:__subpackages__"],
1818
deps = [
1919
"//benchmark:simple_benchmark_reporter",
20+
"//tachyon/base/containers:container_util",
2021
"//tachyon/base/strings:string_number_conversions",
2122
],
2223
)

benchmark/ec/simple_ec_benchmark_reporter.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@
55

66
#include "absl/strings/substitute.h"
77

8+
#include "tachyon/base/containers/container_util.h"
89
#include "tachyon/base/strings/string_number_conversions.h"
910

1011
namespace tachyon {
1112

1213
SimpleECBenchmarkReporter::SimpleECBenchmarkReporter(
13-
std::string_view title, const std::vector<uint64_t>& nums) {
14-
title_ = std::string(title);
14+
std::string_view title, const std::vector<uint64_t>& nums)
15+
: SimpleBenchmarkReporter(title) {
1516
column_headers_.push_back("CPU");
1617
column_headers_.push_back("GPU");
17-
for (uint64_t num : nums) {
18-
targets_.push_back(base::NumberToString(num));
19-
}
18+
targets_ =
19+
base::Map(nums, [](uint64_t num) { return base::NumberToString(num); });
2020
results_.resize(nums.size());
2121
}
2222

benchmark/fft/BUILD.bazel

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
load(
2+
"//bazel:tachyon_cc.bzl",
3+
"tachyon_cc_binary",
4+
"tachyon_cc_library",
5+
)
6+
7+
tachyon_cc_library(
8+
name = "fft_config",
9+
testonly = True,
10+
srcs = ["fft_config.cc"],
11+
hdrs = ["fft_config.h"],
12+
deps = [
13+
"//tachyon/base/console",
14+
"//tachyon/base/containers:container_util",
15+
"//tachyon/base/flag:flag_parser",
16+
"//tachyon/base/ranges:algorithm",
17+
],
18+
)
19+
20+
tachyon_cc_library(
21+
name = "fft_runner",
22+
testonly = True,
23+
hdrs = ["fft_runner.h"],
24+
deps = [
25+
":simple_fft_benchmark_reporter",
26+
"//tachyon/base/time",
27+
],
28+
)
29+
30+
tachyon_cc_library(
31+
name = "simple_fft_benchmark_reporter",
32+
testonly = True,
33+
srcs = ["simple_fft_benchmark_reporter.cc"],
34+
hdrs = ["simple_fft_benchmark_reporter.h"],
35+
deps = [
36+
"//benchmark:simple_benchmark_reporter",
37+
"//tachyon/base/containers:container_util",
38+
"//tachyon/base/strings:string_number_conversions",
39+
],
40+
)
41+
42+
tachyon_cc_binary(
43+
name = "fft_benchmark",
44+
testonly = True,
45+
srcs = ["fft_benchmark.cc"],
46+
deps = [
47+
":fft_config",
48+
":fft_runner",
49+
"//benchmark/fft/halo2",
50+
"//tachyon/c/math/polynomials/univariate:bn254_univariate_evaluation_domain",
51+
"//tachyon/math/elliptic_curves/bn/bn254:fr",
52+
"//tachyon/math/polynomials/univariate:univariate_evaluation_domain",
53+
"//tachyon/math/polynomials/univariate:univariate_evaluation_domain_factory",
54+
],
55+
)

benchmark/fft/FFT Benchmark.png

14.7 KB
Loading

benchmark/fft/IFFT Benchmark.png

14.9 KB
Loading

benchmark/fft/README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# (I)FFT Benchmark
2+
3+
```
4+
Run on 13th Gen Intel(R) Core(TM) i9-13900K (32 X 5500 MHz CPU s)
5+
CPU Caches:
6+
L1 Data 48 KiB (x16)
7+
L1 Instruction 32 KiB (x16)
8+
L2 Unified 2048 KiB (x16)
9+
L3 Unified 36864 KiB (x1)
10+
```
11+
12+
## FFT
13+
14+
```shell
15+
bazel run -c opt --config halo2 --//:has_openmp --//:polygon_zkevm_backend --//:has_rtti --//:has_matplotlib //benchmark/fft:fft_benchmark -- -k 16 -k 17 -k 18 -k 19 -k 20 -k 21 -k 22 -k 23
16+
```
17+
18+
| Exponent | Tachyon | Halo2 |
19+
| :------: | ------------ | ------------ |
20+
| 16 | **0.001964** | 0.005087 |
21+
| 17 | **0.006411** | 0.00705 |
22+
| 18 | **0.016552** | 0.023917 |
23+
| 19 | **0.027728** | 0.067646 |
24+
| 20 | 0.057617 | **0.056551** |
25+
| 21 | 0.123259 | **0.086488** |
26+
| 22 | 0.297385 | **0.18532** |
27+
| 23 | 0.619081 | **0.399886** |
28+
29+
![image](/benchmark/fft/FFT%20Benchmark.png)
30+
31+
## IFFT
32+
33+
```shell
34+
bazel run -c opt --config halo2 --//:has_openmp --//:polygon_zkevm_backend --//:has_rtti --//:has_matplotlib //benchmark/fft:fft_benchmark -- -k 16 -k 17 -k 18 -k 19 -k 20 -k 21 -k 22 -k 23 --run_ifft
35+
```
36+
37+
| Exponent | Tachyon | Halo2 |
38+
| :------: | ------------ | ------------ |
39+
| 16 | **0.002298** | 0.004557 |
40+
| 17 | **0.005008** | 0.005661 |
41+
| 18 | **0.009929** | 0.011304 |
42+
| 19 | **0.039518** | 0.044937 |
43+
| 20 | **0.045926** | 0.08374 |
44+
| 21 | 0.130692 | **0.108806** |
45+
| 22 | 0.316693 | **0.204709** |
46+
| 23 | 0.637058 | **0.451356** |
47+
48+
![image](/benchmark/fft/IFFT%20Benchmark.png)

benchmark/fft/fft_benchmark.cc

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#include <stddef.h>
2+
#include <stdint.h>
3+
4+
#include <iostream>
5+
6+
// clang-format off
7+
#include "benchmark/fft/fft_config.h"
8+
#include "benchmark/fft/fft_runner.h"
9+
#include "benchmark/fft/simple_fft_benchmark_reporter.h"
10+
// clang-format on
11+
#include "tachyon/c/math/polynomials/univariate/bn254_univariate_evaluation_domain.h"
12+
#include "tachyon/math/elliptic_curves/bn/bn254/fr.h"
13+
#include "tachyon/math/polynomials/univariate/univariate_evaluation_domain.h"
14+
#include "tachyon/math/polynomials/univariate/univariate_evaluation_domain_factory.h"
15+
16+
namespace tachyon {
17+
18+
using namespace math;
19+
20+
extern "C" tachyon_bn254_fr* run_fft_halo2(const tachyon_bn254_fr* coeffs,
21+
size_t n,
22+
const tachyon_bn254_fr* omega,
23+
uint32_t k,
24+
uint64_t* duration_in_us);
25+
26+
extern "C" tachyon_bn254_fr* run_ifft_halo2(const tachyon_bn254_fr* coeffs,
27+
size_t n,
28+
const tachyon_bn254_fr* omega_inv,
29+
uint32_t k,
30+
uint64_t* duration_in_us);
31+
32+
template <typename PolyOrEvals>
33+
void CheckResults(bool check_results, const std::vector<PolyOrEvals>& results,
34+
const std::vector<PolyOrEvals>& results_halo2) {
35+
if (check_results) {
36+
CHECK(results == results_halo2) << "Results not matched";
37+
}
38+
}
39+
40+
template <typename Domain, typename PolyOrEvals,
41+
typename RetPoly = std::conditional_t<
42+
std::is_same_v<PolyOrEvals, typename Domain::Evals>,
43+
typename Domain::DensePoly, typename Domain::Evals>>
44+
void Run(const FFTConfig& config) {
45+
// NOTE(TomTaehoonKim): To remove code duplication, we named it as "(I)FFT
46+
// Benchmark" in the code, but for the plots in benchmark.md, I used "FFT
47+
// Benchmark" and "IFFT Benchmark" for better readability.
48+
SimpleFFTBenchmarkReporter reporter("(I)FFT Benchmark", config.exponents());
49+
reporter.AddVendor("halo2");
50+
51+
std::vector<uint64_t> degrees = config.GetDegrees();
52+
53+
std::cout << "Generating evaluation domain and random polys..." << std::endl;
54+
std::vector<std::unique_ptr<Domain>> domains = base::Map(
55+
degrees, [](uint64_t degree) { return Domain::Create(degree); });
56+
std::vector<PolyOrEvals> polys = base::Map(
57+
degrees, [](uint64_t degree) { return PolyOrEvals::Random(degree); });
58+
std::cout << "Generation completed" << std::endl;
59+
60+
FFTRunner<Domain, PolyOrEvals> runner(&reporter);
61+
runner.SetInputs(&polys, std::move(domains));
62+
63+
std::vector<RetPoly> results;
64+
std::vector<RetPoly> results_halo2;
65+
if constexpr (std::is_same_v<PolyOrEvals, typename Domain::Evals>) {
66+
runner.Run(tachyon_bn254_univariate_evaluation_domain_ifft, degrees,
67+
&results);
68+
runner.RunExternal(run_ifft_halo2, config.exponents(), &results_halo2);
69+
// NOLINTNEXTLINE(readability/braces)
70+
} else if constexpr (std::is_same_v<PolyOrEvals,
71+
typename Domain::DensePoly>) {
72+
runner.Run(tachyon_bn254_univariate_evaluation_domain_fft, degrees,
73+
&results);
74+
runner.RunExternal(run_fft_halo2, config.exponents(), &results_halo2);
75+
}
76+
CheckResults(config.check_results(), results, results_halo2);
77+
78+
reporter.Show();
79+
}
80+
81+
int RealMain(int argc, char** argv) {
82+
using Field = bn254::Fr;
83+
constexpr size_t kMaxDegree = SIZE_MAX - 1;
84+
using Domain = UnivariateEvaluationDomain<Field, kMaxDegree>;
85+
using DensePoly = Domain::DensePoly;
86+
using Evals = Domain::Evals;
87+
88+
Field::Init();
89+
90+
FFTConfig config;
91+
if (!config.Parse(argc, argv)) {
92+
return 1;
93+
}
94+
95+
if (config.run_ifft()) {
96+
Run<Domain, Evals>(config);
97+
} else {
98+
Run<Domain, DensePoly>(config);
99+
}
100+
101+
return 0;
102+
}
103+
104+
} // namespace tachyon
105+
106+
int main(int argc, char** argv) { return tachyon::RealMain(argc, argv); }

benchmark/fft/fft_config.cc

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#include "benchmark/fft/fft_config.h"
2+
3+
#include <string>
4+
5+
#include "tachyon/base/console/iostream.h"
6+
#include "tachyon/base/containers/container_util.h"
7+
#include "tachyon/base/flag/flag_parser.h"
8+
#include "tachyon/base/ranges/algorithm.h"
9+
10+
namespace tachyon {
11+
12+
bool FFTConfig::Parse(int argc, char** argv) {
13+
base::FlagParser parser;
14+
// clang-format off
15+
parser.AddFlag<base::Flag<std::vector<uint64_t>>>(&exponents_)
16+
.set_short_name("-k")
17+
.set_required()
18+
.set_help("Specify the exponent 'k's where the degree of poly to test is 2ᵏ.");
19+
// clang-format on
20+
parser.AddFlag<base::BoolFlag>(&run_ifft_)
21+
.set_long_name("--run_ifft")
22+
.set_help("Run IFFT benchmark. Default is FFT benchmark.");
23+
parser.AddFlag<base::BoolFlag>(&check_results_)
24+
.set_long_name("--check_results")
25+
.set_help("Whether checks results generated by each fft runner.");
26+
{
27+
std::string error;
28+
if (!parser.Parse(argc, argv, &error)) {
29+
tachyon_cerr << error << std::endl;
30+
return false;
31+
}
32+
}
33+
34+
base::ranges::sort(exponents_); // NOLINT
35+
return true;
36+
}
37+
38+
std::vector<uint64_t> FFTConfig::GetDegrees() const {
39+
return base::Map(exponents_,
40+
[](uint64_t exponent) { return uint64_t{1} << exponent; });
41+
}
42+
43+
} // namespace tachyon

benchmark/fft/fft_config.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#ifndef BENCHMARK_FFT_FFT_CONFIG_H_
2+
#define BENCHMARK_FFT_FFT_CONFIG_H_
3+
4+
#include <stdint.h>
5+
6+
#include <vector>
7+
8+
namespace tachyon {
9+
10+
class FFTConfig {
11+
public:
12+
FFTConfig() = default;
13+
FFTConfig(const FFTConfig& other) = delete;
14+
FFTConfig& operator=(const FFTConfig& other) = delete;
15+
16+
const std::vector<uint64_t>& exponents() const { return exponents_; }
17+
bool run_ifft() const { return run_ifft_; }
18+
bool check_results() const { return check_results_; }
19+
20+
bool Parse(int argc, char** argv);
21+
22+
std::vector<uint64_t> GetDegrees() const;
23+
24+
private:
25+
std::vector<uint64_t> exponents_;
26+
bool run_ifft_ = false;
27+
bool check_results_ = false;
28+
};
29+
30+
} // namespace tachyon
31+
32+
#endif // BENCHMARK_FFT_FFT_CONFIG_H_

0 commit comments

Comments
 (0)