Skip to content

Commit c9c0c8b

Browse files
committed
ci(test): build and run external example
1 parent 6868547 commit c9c0c8b

9 files changed

Lines changed: 149 additions & 6 deletions

File tree

.github/workflows/build-pull-request.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,22 @@ jobs:
183183
run: |
184184
docker pull ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
185185
186+
- name: Build and run external example
187+
run: |
188+
docker run --rm --gpus 'device=1' ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} bash -lc '
189+
set -euo pipefail
190+
build=/tmp/simphony-examples-build
191+
prefix=/tmp/simphony-examples-install
192+
cmake -S "$SIMPHONY_HOME/examples" -B "$build" -DCMAKE_PREFIX_PATH="$SIMPHONY_PREFIX" -DCMAKE_INSTALL_PREFIX="$prefix"
193+
cmake --build "$build" --target install
194+
cd /tmp
195+
"$prefix/bin/simphox" --cpu
196+
test -f /tmp/out/photons.npy
197+
rm -f /tmp/out/photons.npy
198+
"$prefix/bin/simphox" --gpu
199+
test -f /tmp/out/photons.npy
200+
'
201+
186202
- name: Run tests
187203
run: |
188204
docker run --rm --gpus 'device=1' ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} bash -lc 'ctest --test-dir "$SIMPHONY_BUILD" --output-on-failure'

cmake/Config.cmake.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ find_dependency(nlohmann_json REQUIRED)
99
find_dependency(plog REQUIRED)
1010
find_dependency(GLEW REQUIRED)
1111
find_dependency(glfw3 REQUIRED)
12+
find_dependency(glm REQUIRED)
1213
find_dependency(CUDAToolkit REQUIRED)
1314
find_dependency(OptiX 7 REQUIRED)
1415
find_dependency(Geant4 REQUIRED)

examples/CMakeLists.txt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
cmake_minimum_required(VERSION 3.22)
22

3-
project(simphox LANGUAGES CXX)
3+
project(simphox LANGUAGES CXX CUDA)
44

5-
set(CMAKE_CXX_STANDARD 17)
5+
set(CMAKE_CXX_STANDARD 20)
66
set(CMAKE_CXX_STANDARD_REQUIRED ON)
77
set(CMAKE_CXX_EXTENSIONS OFF)
8+
set(CMAKE_CUDA_STANDARD 17)
9+
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
10+
set(CMAKE_CUDA_EXTENSIONS OFF)
811

912
find_package(simphony REQUIRED)
1013

11-
add_executable(simphox simphox.cpp)
14+
add_executable(simphox simphox.cpp simphox_gpu.cu)
1215
target_link_libraries(simphox simphony::G4CX simphony::SysRap)
1316

1417
install(TARGETS simphox)

examples/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ example by simply doing from this directory:
55
cmake -S . -B build
66
cmake --build build
77
./simphox
8+
./simphox --gpu
89
```
910

1011
It generates a configurable set of optical photons using the built-in torch
1112
configuration, converts them into an NP array, prints the data, and saves it as
12-
`out/photons.npy`.
13+
`out/photons.npy`. The default `cpu` backend generates photons on the host. The
14+
`gpu` backend generates the same kind of torch photons in a CUDA kernel and
15+
copies them back before writing the same output file.
1316

1417

1518
## Examples

examples/simphox.cpp

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,74 @@
11
#include <iostream>
2+
#include <stdexcept>
23
#include <string>
34
#include <vector>
45

5-
#include "simphony/g4cx/G4CXOpticks.hh"
66
#include "simphony/sysrap/NP.hh"
77
#include "simphony/sysrap/sphoton.h"
88

99
#include "simphony/sysrap/config.h"
1010
#include "simphony/sysrap/torch.h"
1111

12+
#include "simphox_gpu.h"
13+
1214
using namespace std;
1315

1416
int main(int argc, char **argv)
1517
{
18+
bool use_gpu = false;
19+
constexpr unsigned int seed = 42;
20+
unsigned int num_photons = 0;
21+
22+
for (int i = 1; i < argc; i++)
23+
{
24+
string arg = argv[i];
25+
if (arg == "--cpu")
26+
{
27+
use_gpu = false;
28+
}
29+
else if (arg == "--gpu")
30+
{
31+
use_gpu = true;
32+
}
33+
else if (arg == "--num-photons" && i + 1 < argc)
34+
{
35+
num_photons = static_cast<unsigned int>(stoul(argv[++i]));
36+
}
37+
else if (arg == "-h" || arg == "--help")
38+
{
39+
cout << "Usage: simphox [--cpu] [--gpu] [--num-photons N]" << endl;
40+
return EXIT_SUCCESS;
41+
}
42+
else
43+
{
44+
cerr << "Unknown argument: " << arg << endl;
45+
return EXIT_FAILURE;
46+
}
47+
}
48+
1649
gphox::Config config("dev");
1750

1851
cout << config.torch.desc() << endl;
52+
cout << "backend " << (use_gpu ? "gpu" : "cpu") << endl;
53+
cout << "seed " << seed << endl;
1954

20-
vector<sphoton> phs = generate_photons(config.torch);
55+
vector<sphoton> phs;
56+
if (!use_gpu)
57+
{
58+
phs = generate_photons(config.torch, num_photons, seed);
59+
}
60+
else
61+
{
62+
try
63+
{
64+
phs = generate_photons_gpu(config.torch, num_photons, seed);
65+
}
66+
catch (const exception& err)
67+
{
68+
cerr << "GPU photon generation failed: " << err.what() << endl;
69+
return EXIT_FAILURE;
70+
}
71+
}
2172

2273
size_t num_floats = phs.size() * 4 * 4;
2374
float *data = reinterpret_cast<float *>(phs.data());

examples/simphox_gpu.cu

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#include "simphox_gpu.h"
2+
3+
#include <cuda_runtime.h>
4+
#include <curand_kernel.h>
5+
6+
#include "simphony/sysrap/CUDA_CHECK.h"
7+
#include "simphony/sysrap/srng.h"
8+
9+
namespace
10+
{
11+
12+
__global__ void generate_photons_kernel(storch torch, sphoton* photons, unsigned int num_photons, unsigned int seed)
13+
{
14+
unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x;
15+
if (idx >= num_photons)
16+
{
17+
return;
18+
}
19+
20+
curandStatePhilox4_32_10 rng;
21+
curand_init(seed, idx, 0, &rng);
22+
23+
qtorch qt;
24+
qt.t = torch;
25+
26+
sphoton photon;
27+
storch::generate(photon, rng, qt.q, idx, 0);
28+
photons[idx] = photon;
29+
}
30+
31+
} // namespace
32+
33+
std::vector<sphoton> generate_photons_gpu(const storch& torch, unsigned int num_photons, unsigned int seed)
34+
{
35+
if (num_photons == 0)
36+
{
37+
num_photons = torch.numphoton;
38+
}
39+
40+
std::vector<sphoton> photons(num_photons);
41+
if (num_photons == 0)
42+
{
43+
return photons;
44+
}
45+
46+
sphoton* d_photons = nullptr;
47+
CUDA_CHECK(cudaMalloc(reinterpret_cast<void**>(&d_photons), photons.size() * sizeof(sphoton)));
48+
49+
constexpr unsigned int threads_per_block = 256;
50+
unsigned int blocks = (num_photons + threads_per_block - 1) / threads_per_block;
51+
52+
generate_photons_kernel<<<blocks, threads_per_block>>>(torch, d_photons, num_photons, seed);
53+
CUDA_SYNC_CHECK();
54+
55+
CUDA_CHECK(cudaMemcpy(photons.data(), d_photons, photons.size() * sizeof(sphoton), cudaMemcpyDeviceToHost));
56+
CUDA_CHECK(cudaFree(d_photons));
57+
58+
return photons;
59+
}

examples/simphox_gpu.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#pragma once
2+
3+
#include <vector>
4+
5+
#include "simphony/sysrap/sphoton.h"
6+
#include "simphony/sysrap/storch.h"
7+
8+
std::vector<sphoton> generate_photons_gpu(const storch& torch, unsigned int num_photons = 0, unsigned int seed = 0);

sysrap/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ set(HEADERS
271271
tcomplex.h
272272

273273
srng.h
274+
srng_traits.h
274275
srngcpu.h
275276
scurand.h
276277

sysrap/storch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Techniques to implement the spirit of the old torch gensteps in much less code
3535
//#include "scurand.h"
3636
#include "smath.h"
3737
#include "sphoton.h"
38+
#include "squad.h"
3839
#include "srng_traits.h"
3940
#include "storchtype.h"
4041

0 commit comments

Comments
 (0)