Skip to content

Commit 235b47f

Browse files
jmarkJohannes MarkertJoshuaLampert
authored
Addition: Cleanup logic. (#75)
* Adding cleanup logic. * Applying review comments and adding a test. * Applied review suggestions. * Adding format utility. * Renamed formatter. * Removed trixi formatter. * Limited folders to format. * Applie formatter. * Fixed error in code. * Updated formatter. * Formatted examples. * Revised package version. * Downgraded formatter. * Fixed version number of formatter. * Applied formater with version x.x.60. * Fixing compats. * Bumped MPIPreferences. * Update Project.toml Co-authored-by: Joshua Lampert <[email protected]> * Update test/Project.toml Co-authored-by: Joshua Lampert <[email protected]> * Refining test. * Added test evals. * Added further test eval. --------- Co-authored-by: Johannes Markert <[email protected]> Co-authored-by: Joshua Lampert <[email protected]>
1 parent 4739391 commit 235b47f

File tree

10 files changed

+165
-11
lines changed

10 files changed

+165
-11
lines changed

.github/workflows/FormatCheck.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- uses: julia-actions/cache@v2
2424
- name: Install JuliaFormatter and format
2525
run: |
26-
julia -e 'using Pkg; Pkg.add(PackageSpec(name = "JuliaFormatter", version="1.0.45"))'
26+
julia -e 'using Pkg; Pkg.add(PackageSpec(name = "JuliaFormatter", version="1.0.60"))'
2727
julia -e 'using JuliaFormatter; format(["examples", "src/T8code.jl", "test"])'
2828
- name: Format check
2929
run: |

Project.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "T8code"
22
uuid = "d0cc0030-9a40-4274-8435-baadcfd54fa1"
33
authors = ["Johannes Markert <[email protected]>"]
4-
version = "0.7.0"
4+
version = "0.7.1"
55

66
[deps]
77
CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82"
@@ -16,8 +16,8 @@ t8code_jll = "4ee9bed8-4011-53f7-90c2-22363c2f500d"
1616
[compat]
1717
CEnum = "0.4, 0.5"
1818
Libdl = "1"
19-
MPI = "0.20"
20-
MPIPreferences = "0.1.3"
19+
MPI = "0.20.6"
20+
MPIPreferences = "0.1.6"
2121
Preferences = "1.2"
2222
Reexport = "0.2, 1.0"
2323
UUIDs = "1"

examples/t8_step6_stencil.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ function t8_step6_output_data_to_vtu(forest, element_data, prefix)
348348
pointer(schlieren)),
349349
t8_vtk_data_field_t(T8_VTK_SCALAR,
350350
NTuple{8192, Cchar}(rpad("curvature\0", 8192, ' ')),
351-
pointer(curvature)),
351+
pointer(curvature))
352352
]
353353

354354
# The number of user defined data fields to write.

examples/t8_tutorial_build_cmesh.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ function t8_cmesh_new_periodic_hybrid_2d(comm)
154154
1, 1, 0,
155155
0.5, 0.5, 0, # tree 5, triangle
156156
1, 1, 0,
157-
0.5, 1, 0,
157+
0.5, 1, 0
158158
]
159159

160160
# 2. Initialization of the mesh.

src/T8code.jl

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module T8code
22

3+
using MPI
4+
35
using Reexport: @reexport
46
using Libdl: Libdl
57

@@ -157,6 +159,85 @@ not a system-provided `t8code` installation. In this case, T8code.jl is not usab
157159
preferences_set_correctly() = !(_PREFERENCE_LIBT8 == "t8code_jll" &&
158160
MPIPreferences.binary == "system")
159161

162+
"""
163+
ForestWrapper
164+
165+
Lightweight `t8_forest_t` pointer wrapper which helps to free
166+
resources allocated by t8code in an orderly fashion.
167+
168+
When initialized with a t8code forest pointer the wrapper
169+
registers itself with a t8code object tracker called `T8CODE_OBJECT_TRACKER`.
170+
171+
In serial mode the wrapper and in consequence the t8code forest
172+
can be finalized immediately whenever Julia's garbage collector sees fit.
173+
174+
In (MPI) parallel mode the wrapper (and the t8code forest) is kept till the end
175+
of the session or when finalized explicitly. At the end of the session (resp.
176+
when the program shuts down) the object tracker finalizes all registered t8code
177+
objects in sync with all MPI ranks. This is necessary since t8code internally
178+
allocates MPI shared arrays.
179+
"""
180+
mutable struct ForestWrapper
181+
pointer::Ptr{t8_forest} # cpointer to t8code forest
182+
183+
function ForestWrapper(pointer::Ptr{t8_forest})
184+
wrapper = new(pointer)
185+
186+
# Compute a unique id from the ForestWrapper object.
187+
unique_id = UInt64(pointer_from_objref(wrapper))
188+
189+
if MPI.Comm_size(MPI.Comm(t8_forest_get_mpicomm(pointer))) > 1
190+
# Make sure the unique id is identical for each MPI rank.
191+
unique_id = MPI.bcast(unique_id, MPI.Comm(t8_forest_get_mpicomm(pointer)))
192+
end
193+
194+
finalizer(wrapper) do wrapper
195+
# When finalizing, `forest`, `scheme`, `cmesh`, and `geometry` are
196+
# also cleaned up from within `t8code`. The cleanup code for
197+
# `cmesh` does some MPI calls for deallocating shared memory
198+
# arrays. Due to garbage collection in Julia the order of shutdown
199+
# is not deterministic. Hence, deterministic finalization is necessary in
200+
# order to avoid MPI-related error output when closing the Julia
201+
# program/session.
202+
t8_forest_unref(Ref(wrapper.pointer))
203+
204+
# Deregister from the object tracker.
205+
delete!(T8CODE_OBJECT_TRACKER, unique_id)
206+
end
207+
208+
# Register the T8codeForestWrapper with the object tracker.
209+
T8CODE_OBJECT_TRACKER[unique_id] = wrapper
210+
211+
return wrapper
212+
end
213+
end
214+
215+
function clean_up()
216+
# Finalize all registered t8code objects before MPI shuts down.
217+
while length(T8CODE_OBJECT_TRACKER) > 0
218+
unique_id = first(T8CODE_OBJECT_TRACKER).first
219+
220+
forest_wrapper = T8CODE_OBJECT_TRACKER[unique_id]
221+
222+
# Make sure all MPI ranks finalize the same object.
223+
if MPI.Comm_size(MPI.Comm(t8_forest_get_mpicomm(forest_wrapper.pointer))) > 1
224+
unique_id = MPI.bcast(unique_id,
225+
MPI.Comm(t8_forest_get_mpicomm(forest_wrapper.pointer)))
226+
end
227+
228+
# Finalize the object. The object deregisters itself from the
229+
# object tracker automatically.
230+
finalize(forest_wrapper)
231+
end
232+
end
233+
234+
# Minimal reference tracker holding active t8code related objects
235+
# created throughout the life time of a Julia session. t8code objects
236+
# should remove themselves from the tracker when they get finalized.
237+
if !@isdefined(T8CODE_OBJECT_TRACKER)
238+
T8CODE_OBJECT_TRACKER = Dict{UInt64, ForestWrapper}()
239+
end
240+
160241
const T8_QUAD_MAXLEVEL = 30
161242
const T8_HEX_MAXLEVEL = 19
162243

test/Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
66

77
[compat]
88
Aqua = "0.7, 0.8"
9-
MPI = "0.20"
10-
MPIPreferences = "0.1.3"
9+
MPI = "0.20.6"
10+
MPIPreferences = "0.1.6"
1111
Test = "1"

test/cmesh/test_readmshfile.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,22 @@ function t8_supported_msh_file(cmesh)
1010
[4, 0],
1111
[1, 2],
1212
[3, 2],
13-
[2, 4],
13+
[2, 4]
1414
]
1515

1616
# 0-based indexing
1717
elements = [
1818
[0, 1, 3],
1919
[1, 4, 3],
2020
[1, 2, 4],
21-
[3, 4, 5],
21+
[3, 4, 5]
2222
]
2323

2424
face_neigh_elem = [
2525
[1, -1, -1],
2626
[3, 0, 2],
2727
[-1, 1, -1],
28-
[-1, -1, 1],
28+
[-1, -1, 1]
2929
]
3030

3131
@assert cmesh != C_NULL

test/test_all.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ end
2323
end
2424
end
2525

26+
@testset "forestwrapper" begin
27+
include("test_forestwrapper.jl")
28+
end
29+
2630
@testset "cmesh" begin
2731
include("cmesh/test_readmshfile.jl")
2832
end

test/test_forestwrapper.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
@testset "test forestwrapper" begin
2+
3+
# Clean up t8code before MPI shuts down.
4+
MPI.add_finalize_hook!() do
5+
T8code.clean_up()
6+
@test length(T8code.T8CODE_OBJECT_TRACKER) == 0
7+
status = T8code.Libt8.sc_finalize_noabort()
8+
# If the following test fails the allocated objects were not cleaned up
9+
# properly before shutting down.
10+
@test status == 0
11+
end
12+
13+
@test length(T8code.T8CODE_OBJECT_TRACKER) == 0
14+
15+
# Create a forest and wrap by `ForestWrapper`
16+
scheme = t8_scheme_new_default_cxx()
17+
cmesh = t8_cmesh_new_hypercube(T8_ECLASS_QUAD, comm, 0, 0, 0)
18+
forest = t8_forest_new_uniform(cmesh, scheme, 0, 0, comm)
19+
wrapper_A = T8code.ForestWrapper(forest)
20+
21+
@test length(T8code.T8CODE_OBJECT_TRACKER) == 1
22+
23+
# Create another forest and wrap by `ForestWrapper`
24+
scheme = t8_scheme_new_default_cxx()
25+
cmesh = t8_cmesh_new_hypercube(T8_ECLASS_TRIANGLE, comm, 0, 0, 0)
26+
forest = t8_forest_new_uniform(cmesh, scheme, 0, 0, comm)
27+
wrapper_B = T8code.ForestWrapper(forest)
28+
29+
@test length(T8code.T8CODE_OBJECT_TRACKER) == 2
30+
31+
# Finalize the first wrapper.
32+
finalize(wrapper_A)
33+
34+
@test length(T8code.T8CODE_OBJECT_TRACKER) == 1
35+
36+
# The second wrapper should be finalized automatically when Julia shuts down.
37+
# ... finalize(wrapper_B) ...
38+
end

utils/format.jl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env julia
2+
3+
using Pkg
4+
Pkg.activate(; temp = true, io = devnull)
5+
Pkg.add(PackageSpec(name = "JuliaFormatter", version = "1.0.60"); preserve = PRESERVE_ALL,
6+
io = devnull)
7+
8+
using JuliaFormatter: format
9+
10+
function main()
11+
# Show help
12+
if "-h" in ARGS || "--help" in ARGS
13+
println("usage: trixi-format.jl PATH [PATH...]")
14+
println()
15+
println("positional arguments:")
16+
println()
17+
println(" PATH One or more paths (directories or files) to format. Default: '.'")
18+
return nothing
19+
end
20+
21+
# Set default path if none is given on command line
22+
if isempty(ARGS)
23+
paths = String["./src/T8code.jl", "./test", "./examples"]
24+
else
25+
paths = ARGS
26+
end
27+
28+
return format(paths)
29+
end
30+
31+
main()

0 commit comments

Comments
 (0)