Skip to content

Commit 8f115c2

Browse files
authored
Merge pull request #10 from stevenewald/bench
Added benchmarks and ARM NEON support
2 parents 7cf35e8 + b0e8ecc commit 8f115c2

35 files changed

+733
-345
lines changed

CMakeLists.txt

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ include(cmake/project-is-top-level.cmake)
1414
include(cmake/variables.cmake)
1515

1616
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
17-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -mavx512f -mavx512dq -mavx512vl -mavx512bf16")
18-
add_compile_options(-fno-inline -fno-omit-frame-pointer)
17+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
18+
# add_compile_options(-fno-inline -fno-omit-frame-pointer)
1919

2020

2121
# ---- Declare library ----
@@ -27,17 +27,37 @@ add_library(
2727
source/mandelbrot/mandelbrot_window.cpp
2828
source/graphics/color_conversions/color_conversions.cpp
2929
source/graphics/aspect_ratio/aspect_ratio.cpp
30-
source/mandelbrot/equations_simd.cpp
31-
source/mandelbrot/equations.cpp
30+
source/units/coordinates.cpp
3231
)
3332

33+
include(CheckCXXCompilerFlag)
34+
check_cxx_compiler_flag("-mavx512f -mavx512dq -mavx512vl -mavx512bf16" HAS_AVX512)
35+
check_cxx_source_compiles("
36+
#include <arm_neon.h>
37+
int main() {
38+
float32x4_t vec = vdupq_n_f32(0.0f);
39+
return 0;
40+
}" HAS_NEON)
41+
42+
if (HAS_ALL_AVX512)
43+
message(STATUS "AVX-512 is supported by the compiler.")
44+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx512f -mavx512dq -mavx512vl -mavx512bf16")
45+
target_sources(fractal-generator_lib PRIVATE source/mandelbrot/equations_simd.cpp)
46+
elseif(HAS_NEON)
47+
message(STATUS "ARM NEON is supported by the compiler.")
48+
target_sources(fractal-generator_lib PRIVATE source/mandelbrot/equations_neon.cpp)
49+
else()
50+
message(STATUS "SIMD is not fully supported by the compiler. SIMD will not be enabled.")
51+
target_sources(fractal-generator_lib PRIVATE source/mandelbrot/equations_compat.cpp)
52+
endif()
53+
3454
target_include_directories(
3555
fractal-generator_lib ${warning_guard}
3656
PUBLIC
3757
"\$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/source>"
3858
)
3959

40-
target_compile_features(fractal-generator_lib PUBLIC cxx_std_20)
60+
target_compile_features(fractal-generator_lib PUBLIC cxx_std_23)
4161

4262
find_package(fmt REQUIRED)
4363
find_package(argparse REQUIRED)
@@ -55,8 +75,9 @@ add_executable(fractal-generator::exe ALIAS fractal-generator_exe)
5575

5676
set_property(TARGET fractal-generator_exe PROPERTY OUTPUT_NAME fractal-generator)
5777

58-
target_compile_features(fractal-generator_exe PRIVATE cxx_std_20)
78+
target_compile_features(fractal-generator_exe PRIVATE cxx_std_23)
5979

80+
target_link_libraries(fractal-generator_exe PRIVATE fmt::fmt)
6081
target_link_libraries(fractal-generator_exe PRIVATE fractal-generator_lib)
6182
target_link_libraries(fractal-generator_exe PRIVATE argparse::argparse)
6283
target_link_libraries(fractal-generator_exe PRIVATE sfml-graphics)

CMakePresets.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"hidden": true,
5151
"cacheVariables": {
5252
"CMAKE_CXX_EXTENSIONS": "OFF",
53-
"CMAKE_CXX_STANDARD": "20",
53+
"CMAKE_CXX_STANDARD": "23",
5454
"CMAKE_CXX_STANDARD_REQUIRED": "ON"
5555
}
5656
},
@@ -59,7 +59,7 @@
5959
"description": "These flags are supported by both GCC and Clang",
6060
"hidden": true,
6161
"cacheVariables": {
62-
"CMAKE_CXX_FLAGS": "-D_GLIBCXX_ASSERTIONS=1 -fstack-protector-strong -fcf-protection=full -fstack-clash-protection -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast",
62+
"CMAKE_CXX_FLAGS": "-D_GLIBCXX_ASSERTIONS=1 -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast",
6363
"CMAKE_EXE_LINKER_FLAGS": "-Wl,--allow-shlib-undefined,--as-needed,-z,noexecstack,-z,relro,-z,now,-z,nodlopen",
6464
"CMAKE_SHARED_LINKER_FLAGS": "-Wl,--allow-shlib-undefined,--as-needed,-z,noexecstack,-z,relro,-z,now,-z,nodlopen"
6565
}
@@ -68,7 +68,7 @@
6868
"name": "flags-appleclang",
6969
"hidden": true,
7070
"cacheVariables": {
71-
"CMAKE_CXX_FLAGS": "-fstack-protector-strong -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast"
71+
"CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast"
7272
}
7373
},
7474
{

Taskfile.yml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ version: '3'
22

33
vars:
44
NAME: fractal-generator
5-
RELEASE_BUILD: "false"
6-
RELEASE_PRESET: "ci-ubuntu"
5+
RELEASE_BUILD: "true"
6+
RELEASE_PRESET: "ci-macos"
77

88
tasks:
99
deps:
@@ -14,12 +14,11 @@ tasks:
1414

1515
init:
1616
dir: .
17-
vars:
18-
PRESET: '{{if eq .RELEASE_BUILD "true"}}{{.RELEASE_PRESET}}{{else}}dev{{end}}'
1917
preconditions:
2018
- test -f CMakeUserPresets.json
2119
cmds:
22-
- cmake --preset={{.PRESET}}
20+
- cmake --preset=dev
21+
- cmake --preset={{.RELEASE_PRESET}} -DCMAKE_BUILD_TYPE=Release
2322

2423

2524
build:
@@ -57,6 +56,12 @@ tasks:
5756
- task: build
5857
- ctest {{.TEST_FLAGS}}
5958

59+
bench:
60+
dir: .
61+
cmds:
62+
- task: build
63+
- ./build/benchmark/fractal_benchmarks --benchmark_repetitions=5 --benchmark_min_warmup_time=0.5 --benchmark_report_aggregates_only=true
64+
6065
fmt:
6166
dir: .
6267
cmds:

benchmark/CMakeLists.txt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
project(FractalBenchmarks LANGUAGES CXX)
2+
if(NOT CMAKE_BUILD_TYPE)
3+
set(CMAKE_BUILD_TYPE Debug)
4+
endif()
5+
# ---- Dependencies ----
6+
7+
find_package(benchmark REQUIRED)
8+
9+
# ---- Benchmarks ----
10+
add_executable(fractal_benchmarks
11+
source/bench.cpp
12+
source/main.cpp
13+
)
14+
15+
target_include_directories(
16+
fractal_benchmarks ${warning_guard}
17+
PUBLIC
18+
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/source>"
19+
)
20+
21+
target_link_libraries(
22+
fractal_benchmarks PRIVATE
23+
fractal-generator_lib
24+
sfml-graphics
25+
benchmark::benchmark
26+
)
27+
28+
# Enable lto for release builds
29+
include(CheckIPOSupported)
30+
check_ipo_supported(RESULT lto_supported OUTPUT error)
31+
if(lto_supported)
32+
set_target_properties(fractal_benchmarks PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
33+
else()
34+
message(WARNING "LTO is not supported: ${error}")
35+
endif()
36+
37+
target_compile_features(fractal_benchmarks PRIVATE cxx_std_23)

benchmark/source/bench.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include "config.hpp"
2+
#include "units/coordinates.hpp"
3+
#include "graphics/display_to_complex.hpp"
4+
#include "mandelbrot/equations.hpp"
5+
#include "mandelbrot/equations.hpp"
6+
#include "units/units.hpp"
7+
8+
#include <benchmark/benchmark.h>
9+
10+
using namespace fractal;
11+
12+
static void BM_GenerateMandelbrotSimd(benchmark::State& state)
13+
{
14+
DisplayDomain display = {
15+
{0, 0 },
16+
{800, 800}
17+
};
18+
complex_domain complex = START_COMPLEX_DOMAIN;
19+
avx512_complex start{};
20+
DisplayToComplexCoordinates t{display, complex};
21+
22+
std::int64_t prox = 0;
23+
for (auto _ : state) {
24+
for (auto it = display.begin(); it != display.end(); it += 8) {
25+
benchmark::DoNotOptimize(
26+
compute_iterations(start, t.to_complex_projections(*it), 100)
27+
);
28+
}
29+
prox += display.size();
30+
}
31+
state.SetItemsProcessed(prox);
32+
}
33+
34+
BENCHMARK(BM_GenerateMandelbrotSimd)->Arg(0);
35+
// BENCHMARK(BM_GenerateMandelbrotSimd)->Arg(100000);

benchmark/source/main.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include <benchmark/benchmark.h>
2+
BENCHMARK_MAIN();

cmake/dev-mode.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ include(cmake/folders.cmake)
22

33
include(CTest)
44
add_subdirectory(test)
5+
add_subdirectory(benchmark)
56

67
add_custom_target(
78
run-exe

conanfile.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ def configure(self):
1919

2020
def build_requirements(self):
2121
self.test_requires("catch2/3.7.0")
22+
self.test_requires("benchmark/1.9.0");

source/config.hpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
#pragma once
22

3-
#include "coordinates.hpp"
4-
#include "units.hpp"
3+
#include "units/coordinates.hpp"
4+
#include "units/units.hpp"
55

66
#include <cstddef>
77

88
namespace fractal {
99

10-
constexpr std::size_t WINDOW_WIDTH = 5120;
11-
constexpr std::size_t WINDOW_HEIGHT = 1440;
10+
constexpr std::size_t WINDOW_WIDTH = 800UZ;
11+
constexpr std::size_t WINDOW_HEIGHT = 600UZ;
1212
constexpr std::size_t FRAME_RATE = 60UZ;
1313

14-
constexpr display_domain DISPLAY_DOMAIN{
15-
{0, 0 },
16-
{WINDOW_WIDTH - 1, WINDOW_HEIGHT - 1}
17-
};
18-
1914
constexpr complex_domain START_COMPLEX_DOMAIN{
2015
{complex_underlying{-1.402}, complex_underlying{-.001}},
2116
{complex_underlying{-1.400}, complex_underlying{.001} }
Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
#include "aspect_ratio.hpp"
22

3+
#include "units/display_domain.hpp"
4+
35
namespace fractal {
46

5-
display_coordinate calculate_rectangle_end_point(
7+
DisplayDomain calculate_rectangle_end_points(
68
display_coordinate start, display_coordinate current, float target_aspect_ratio
79
)
810
{
9-
auto width = static_cast<float>(std::abs(current.first - start.first));
10-
auto height = static_cast<float>(std::abs(current.second - start.second));
11+
auto width = static_cast<float>(std::abs(current.x - start.x));
12+
auto height = static_cast<float>(std::abs(current.y - start.y));
1113

1214
// Adjust the dimensions to maintain the target aspect ratio
1315
if (width / height > target_aspect_ratio) {
@@ -19,18 +21,30 @@ display_coordinate calculate_rectangle_end_point(
1921
height = width / target_aspect_ratio;
2022
}
2123

22-
auto x = static_cast<float>(std::min(current.first, start.first));
23-
auto y = static_cast<float>(std::min(current.second, start.second));
24+
auto x_pos1 = static_cast<float>(start.x);
25+
auto y_pos1 = static_cast<float>(start.y);
26+
auto x_pos2 = x_pos1 + width;
27+
auto y_pos2 = y_pos1 + height;
28+
29+
bool flipped_horizontal = start.x > current.x;
30+
bool flipped_vertical = start.y > current.y;
2431

25-
// Adjust the top-left corner based on new dimensions
26-
if (current.first < start.first) {
27-
x = static_cast<float>(start.first) - width;
32+
if (flipped_vertical) {
33+
y_pos1 -= height;
34+
y_pos2 -= height;
2835
}
29-
if (current.second < start.second) {
30-
y = static_cast<float>(start.second) - height;
36+
if (flipped_horizontal) {
37+
x_pos1 -= width;
38+
x_pos2 -= width;
3139
}
3240

33-
// Return the top-left and bottom-right corners as a pair of sf::Vector2f
34-
return {x + width, y + height};
41+
display_coordinate top_left{
42+
static_cast<uint16_t>(x_pos1), static_cast<uint16_t>(y_pos1)
43+
};
44+
display_coordinate bottom_right{
45+
static_cast<uint16_t>(x_pos2), static_cast<uint16_t>(y_pos2)
46+
};
47+
48+
return {top_left, bottom_right};
3549
}
3650
} // namespace fractal

0 commit comments

Comments
 (0)