Skip to content

Commit

Permalink
Parallel (#44)
Browse files Browse the repository at this point in the history
* Remove approximation when circles overlapping*

When a particle's circle is overlapping with a group's circle.

Term:
- Group: A bunch of particles can be summarized as a "group" of particles which is a giant circle that contains the smaller particles. Control of level of detail for long-distance force computations.

Context:
- The net force onto a particle due to a group (of particles) is being computed.
- The particle's circle is both large and close enough to the group's circle: Overlapping.
- Retract the approximation and resolve more detail.

* (Fix up distance comparison)

* Attempt adding pragma omp

* Fix MSVC Warnings

* Make basic parallelism work

The problem is that it's burning all my CPU (probably starting a team of threads every frame).

* MSVC: Use performant llvm OpenMP

* Document how to build and run on MSVC with OpenMP

* Enable OpenMP for macOS

* Attempt to enable OpenMP for all platforms and compilers

* Try to put OpenMP in the CI file

* (fix CI)

* (Fix CI 2)

* (Fix CI 3)

* Fix compilation issue on certain platforms and compilers

* (Fix CI 5)

* (CI Fix 6)

* (CI Fix 7)
  • Loading branch information
axionbuster authored Mar 10, 2024
1 parent 24dee58 commit 812eb67
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 48 deletions.
33 changes: 5 additions & 28 deletions .github/workflows/cmake-multi-platform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ jobs:
matrix:
os: [ ubuntu-latest, windows-latest, macos-latest ]
c_compiler: [ gcc, clang-17, cl, icx ]
build_type: [ RelWithDebInfo ]
build_type: [ Debug ]
other_options: [ "", "-DOPENMP=1" ]
exclude:
- os: ubuntu-latest
c_compiler: cl
Expand Down Expand Up @@ -82,12 +83,12 @@ jobs:
sudo apt-get install -y intel-oneapi-dpcpp-cpp-compiler
echo "/opt/intel/oneapi/compiler/latest/bin" >> $GITHUB_PATH
- name: Install Raylib dependencies (Ubuntu)
- name: Install APT dependencies (Ubuntu)
id: install-deps-u
if: matrix.os == 'ubuntu-latest'
run: >
sudo apt install libasound2-dev libx11-dev libxrandr-dev libxi-dev libgl1-mesa-dev libglu1-mesa-dev
libxcursor-dev libxinerama-dev
libxcursor-dev libxinerama-dev libomp-15-dev
- name: Install Clang 17 (macOS)
if: matrix.os == 'macos-latest'
Expand All @@ -96,40 +97,16 @@ jobs:
echo "/usr/local/opt/llvm/bin" >> $GITHUB_PATH
ls /usr/local/opt/llvm/bin
- name: Print PATH (macOS)
if: matrix.os == 'macos-latest'
run: |
echo "PATH = $PATH"
- name: Configure CMake
if: matrix.cxx_flags == ''
run: >
cmake -B ${{ steps.strings.outputs.build-output-dir }}
-DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
-S ${{ github.workspace }}
- name: Configure CMake (Coverage)
if: matrix.cxx_flags != ''
run: >
cmake -B ${{ steps.strings.outputs.build-output-dir }}
-DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
-DCMAKE_CXX_FLAGS="${{ matrix.cxx_flags }}"
-DCMAKE_C_FLAGS="${{ matrix.c_flags }}"
${{ matrix.other_options }}
-S ${{ github.workspace }}
- name: Build
# Build your program with the given configuration. Note that --config is needed because the default Windows
# generator is a multi-config generator (Visual Studio generator).
run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }}

- name: Test
if: matrix.cxx_flags == ''
working-directory: ${{ steps.strings.outputs.build-output-dir }}
# Execute tests defined by the CMake configuration. Note that --build-config is needed because the default
# Windows generator is a multi-config generator (Visual Studio generator).
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest --build-config ${{ matrix.build_type }}
2 changes: 1 addition & 1 deletion .github/workflows/cover.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
shell: bash
run: |
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
- name: Instal build dependencies
- name: Install build dependencies
run: |
# LLVM 17
wget https://apt.llvm.org/llvm.sh
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
shell: bash
run: |
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
- name: Instal build dependencies
- name: Install build dependencies
run: |
# LLVM 17
wget https://apt.llvm.org/llvm.sh
Expand Down
14 changes: 14 additions & 0 deletions demo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,22 @@ add_executable(grass main.cpp

if (MSVC)
target_compile_options(grass PRIVATE /W4)
if (OPENMP)
target_compile_options(grass PRIVATE /openmp:llvm)
endif ()
else ()
target_compile_options(grass PRIVATE -Wall -Wextra -Wpedantic)
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT APPLE)
if (OPENMP)
target_compile_options(grass PRIVATE -fopenmp=libiomp5)
target_link_options(grass PRIVATE -fopenmp=libiomp5)
endif ()
else ()
if (OPENMP)
target_compile_options(grass PRIVATE -fopenmp)
target_link_options(grass PRIVATE -fopenmp)
endif ()
endif ()
endif ()

target_link_libraries(grass raylib)
Expand Down
21 changes: 21 additions & 0 deletions demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,24 @@ When publishing the demo online, use a host that uses HTTPS connections.

(Screenshot: Add localhost:8080 as an exception)
![Step 2. Add localhost:8080 as an exception](disarm1.png)

## Building with OpenMP Parallelism

On Windows/MSVC, you can build the application with OpenMP-based parallelism applied.

When configuring the project, simply set the `OPENMP` flag:

```
cmake -B build <... stuff ...> -DOPENMP=1
```

Build normally.

When running the application, supply the `OMP_WAIT_POLICY` environment variable to `PASSIVE`
to avoid the spinlocks.

```powershell
$Env:OMP_WAIT_POLICY = "PASSIVE"
<run the application>
```
31 changes: 20 additions & 11 deletions demo/Table.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@

#include <algorithm>
#include <barnes_hut.h>
#include <cassert>
#include <circle.h>
#include <cmath>
#include <complex>
#include <cstdint>
#include <newton.h>
#include <optional>
#include <type_traits>
#include <utility>
#include <vector>
#include <verlet.h>

Expand Down Expand Up @@ -137,10 +140,11 @@ class Table : public std::vector<Particle> {
auto norm = std::norm(group.xy - circle), rsq = square(group.radius);
// If a non-singular group either:
// - contains the center of `circle` inside said group's circle, or
// - if circles are overlapping, resolve more detail, or
// - the (underapproximated) view angle is too wide, then
// resolve more detail.
if (group.many &&
(norm < rsq || square(tan_angle_threshold) < rsq / norm))
if (group.many && (norm < rsq || norm < square(circle.radius) ||
square(tan_angle_threshold) < rsq / norm))
return !TRUNCATE;
// Compute the acceleration due to the group.
// Also, insert the value of G, the universal gravitational constant, in a
Expand Down Expand Up @@ -176,19 +180,24 @@ class Table : public std::vector<Particle> {
else
return {};
};

// Compute the Barnes-Hut tree over the particles this has.
auto const tree =
bh::tree<Physicals<decltype(begin())>>(begin(), end(), morton_masked);
using E = Physicals<decltype(begin())>;
auto const tree = bh::tree<E>(begin(), end(), morton_masked);

// Iterate over the particles, summing up their forces.
for (auto i = begin(); i != end(); ++i) {
auto &&p = *i;
// Supposing that particle p is located instead at the position xy below,
// what is the acceleration experienced by p due to all the other
// particles or approximations (g)?
auto const b = begin();
auto const m = static_cast<int>(size());
auto n = 0;
#pragma omp parallel for
for (n = 0; n < m; ++n) {
auto &&p = (*this)[n];
// Supposing that particle p is located at the position xy below, instead
// of p's own xy, what is the acceleration experienced by p due to all the
// other particles or approximations (g)?
auto ig = Integrator{p.xy, p.v};
ig.step(dt, [this, &tree, &p, &i](auto xy) {
return this->accelerate(tree, {xy, p.radius}, i);
ig.step(dt, [this, &tree, &p, b, n](auto xy) {
return this->accelerate(tree, {xy, p.radius}, b + n);
});
p.xy = ig.y0, p.v = ig.y1;
}
Expand Down
6 changes: 3 additions & 3 deletions demo/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ namespace env {

std::optional<std::string> get(char const *sv) {
#ifdef _WIN32
char *s;
size_t n;
char *s{};
size_t n{};
// On Windows, _dupenv_s is the Microsoft-recommended way of reading an
// environment variable. When the variable isn't found, the error (e) is 0 and
// the count (n) is also 0 (also, the buffer [s] is set to NULL).
if (auto e = _dupenv_s(&s, &n, sv); e || !n)
if (auto e = _dupenv_s(&s, &n, sv); e || !s)
return {};
std::string t{s, n};
// According to Microsoft, the buffer s must be freed using a call to `free`.
Expand Down
14 changes: 10 additions & 4 deletions demo/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#include <cmath>
#include <complex>
#include <cstdlib>
#include <halton.h>
#include <random>
#include <raylib.h>
#include <stdexcept>
Expand All @@ -15,9 +14,13 @@
#include "Table.h"
#include "env.h"
#include "user.h"
#include <numbers>
#include <utility>

using namespace phy;

namespace main_program {

/// Constants controlling the program.
struct Constants {
/// Inclusive upper limit of the number of particles.
Expand Down Expand Up @@ -53,7 +56,7 @@ struct Constants {
};

template <typename... Args> static constexpr Table<Args...> figure8() {
Table table;
Table<Args...> table;

// Make the mystical figure-8 shape below work at first.
// (This G value is too large in most cases, so I will lower it once the
Expand Down Expand Up @@ -211,7 +214,7 @@ struct State {
EndDrawing();
}

User make_user() {
User make_user() const {
User u;
if (constants.flags.galaxies)
u.control.demo = false;
Expand All @@ -222,10 +225,13 @@ struct State {
return constants.flags.galaxies ? galaxies(constants) : figure8();
}
} state;
} // namespace main_program

void do_loop() { state.loop(); }
void do_loop() { main_program::state.loop(); }

static int do_main() {
using namespace main_program;

SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(600, 600, "Grass Gravity Simulation");

Expand Down

0 comments on commit 812eb67

Please sign in to comment.