Skip to content

Commit f25ea8b

Browse files
nhz2Copilot
andauthored
Add ZoneProfilers support (#40)
* Add ZoneProfilers support * Apply suggestions from code review Co-authored-by: Copilot <[email protected]> * fix copilot typofix * Improve zone text * Add zone for io --------- Co-authored-by: Copilot <[email protected]>
1 parent 6c108f5 commit f25ea8b

File tree

8 files changed

+214
-188
lines changed

8 files changed

+214
-188
lines changed

.github/workflows/CI.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
fail-fast: false
2222
matrix:
2323
version:
24-
- '1.11'
24+
- '1.12'
2525
- 'pre'
2626
- 'nightly'
2727
os:

Project.toml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
name = "MEDYANSimRunner"
22
uuid = "b58a3b99-22e3-44d1-b5ea-258f082a6fe8"
3+
version = "0.6.2-dev"
34
authors = ["nhz2 <[email protected]>"]
4-
version = "0.6.1"
5+
6+
[workspace]
7+
projects = ["test"]
58

69
[deps]
710
ArgCheck = "dce04be8-c92d-5529-be00-80e4d2c0e197"
@@ -16,6 +19,7 @@ OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
1619
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1720
SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce"
1821
SmallZarrGroups = "d423b6e5-1c84-4ae2-8d2d-b903aee15ac7"
22+
ZoneProfilers = "402d8ed9-92af-47cb-aae4-ae215e44b74b"
1923

2024
[compat]
2125
ArgCheck = "2"
@@ -30,7 +34,5 @@ OrderedCollections = "1"
3034
Random = "1"
3135
SHA = "0.7, 1"
3236
SmallZarrGroups = "0.8.3"
33-
julia = "1.11"
34-
35-
[workspace]
36-
projects = ["test"]
37+
ZoneProfilers = "0.1"
38+
julia = "1.12"

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,40 @@ end
5151

5252
To run the simulation if `main.jl` is called as a julia script.
5353

54+
## Performance Profiling with ZoneProfilers
55+
56+
MEDYANSimRunner integrates with [ZoneProfilers.jl](https://github.com/nhz2/ZoneProfilers.jl) to provide detailed performance instrumentation of your simulations. This allows you to visualize where time is spent in your `setup`, `loop`, `save`, `load`, and `done` functions, as well as in file I/O operations.
57+
58+
### Using the Profiler
59+
60+
To enable profiling, pass a profiler instance to the `run` function:
61+
62+
```julia
63+
if abspath(PROGRAM_FILE) == @__FILE__
64+
# Open and connect to the tracy GUI
65+
using ZoneProfilerTracy: TracyProfiler
66+
import TracyProfiler_jll
67+
profiler = TracyProfiler(TracyProfiler_jll)
68+
MEDYANSimRunner.run(ARGS; jobs, setup, loop, load, save, done, profiler)
69+
end
70+
```
71+
72+
### Adding Custom Profiling
73+
74+
You can add additional profiling zones within your user functions by using the `profiler` keyword argument:
75+
76+
```julia
77+
function loop(step::Int, state; output, profiler=NullProfiler())
78+
state = @zone profiler compute_physics(state)
79+
@zone profiler collect_data!(output, state)
80+
return state
81+
end
82+
```
83+
84+
For production runs without profiling overhead, simply omit the `profiler` parameter (defaults to `NullProfiler()` which has zero runtime cost).
85+
86+
See the [ZoneProfilers.jl documentation](https://github.com/nhz2/ZoneProfilers.jl) for more advanced profiling features.
87+
5488
#### Standard input parameters.
5589
- `step::Int`: starts out at 0 after setup and is incremented right before every call to `loop`.
5690

src/MEDYANSimRunner.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
module MEDYANSimRunner
22

3+
using ZoneProfilers: NullProfiler, @zone, frame_mark!, zone_text!, zone_color!, zone_active, message!, app_info!
4+
using ArgCheck: ArgCheck, @argcheck
5+
using Logging: Logging, current_logger, with_logger
6+
using SmallZarrGroups: SmallZarrGroups, ZGroup, attrs
7+
import InteractiveUtils
8+
import LoggingExtras
9+
import JSON3
10+
import Dates
11+
using SHA: sha256
12+
import FileWatching
13+
import OrderedCollections
14+
using Random: Random, RandomDevice
15+
import DeepDiffs
16+
317
include("constants.jl")
418
include("rng-load-save.jl")
519
include("file-saving.jl")

src/file-saving.jl

Lines changed: 29 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,6 @@ Helper functions to try to reliably save trajectories on distributed file system
44
None of these functions try to be thread safe, or prevent file system attacks.
55
=#
66

7-
8-
using SHA: sha256
9-
using Random: RandomDevice
10-
import Dates
11-
import LoggingExtras
12-
using Logging
13-
using ArgCheck
14-
157
const DATE_FORMAT = Dates.dateformat"yyyy-mm-ddTHH:MM:SS"
168

179
function timestamp_logger(file, level)
@@ -44,6 +36,7 @@ end
4436

4537

4638
"""
39+
Return the sha256 hash of the data.
4740
Ensure a file with the contents `data` exists at the path `joinpath(dir_name, file_name)`
4841
4942
This function can fail or be interrupted, in that case, an existing file
@@ -58,63 +51,52 @@ If interrupted, there may be a temporary file left behind in `dir_name`.
5851
function write_traj_file(
5952
dir_name::String,
6053
file_name::String,
61-
data::AbstractVector{UInt8},
62-
)::Nothing
63-
new_hash = sha256(data)
64-
file_path = joinpath(dir_name, file_name)
65-
if isfile(file_path)
66-
if filesize(file_path) == length(data)
67-
existing_hash = open(sha256, file_path)
68-
if new_hash == existing_hash
69-
# file exists and is correct, return
70-
return
54+
data::AbstractVector{UInt8};
55+
profiler= NullProfiler(),
56+
)::String
57+
@zone profiler name="write_traj_file" begin
58+
new_hash = sha256(data)
59+
file_path = joinpath(dir_name, file_name)
60+
zone_active(profiler) && zone_text!(profiler, repr(file_path))
61+
zone_active(profiler) && zone_text!(profiler, "$(round(length(data)*1E-3; sigdigits=4)) kB")
62+
if isfile(file_path)
63+
if filesize(file_path) == length(data)
64+
existing_hash = open(sha256, file_path)
65+
if new_hash == existing_hash
66+
zone_text!(profiler, "file exists and is correct")
67+
return bytes2hex(new_hash)
68+
end
7169
end
70+
zone_text!(profiler, "file exists but does not match")
7271
end
73-
end
74-
# safely create the new file.
75-
mktemp(dir_name) do temp_path, temp_out
76-
nb = write(temp_out, data)
77-
if nb != length(data)
78-
error("short write of $(repr(file_name)) data")
79-
end
80-
close(temp_out)
81-
# TODO Drop support for 1.11
82-
@static if VERSION > v"1.12.0-rc"
72+
# safely create the new file.
73+
mktemp(dir_name) do temp_path, temp_out
74+
nb = write(temp_out, data)
75+
if nb != length(data)
76+
error("short write of $(repr(file_name)) data")
77+
end
78+
close(temp_out)
8379
try
8480
Base.rename(temp_path, file_path)
8581
catch err
82+
zone_text!(profiler, "rename error")
83+
zone_color!(profiler, :red)
8684
err isa Base.IOError || rethrow()
8785
# on error, check if file was made by another process, and is still valid.
8886
if isfile(file_path)
8987
if filesize(file_path) == length(data)
9088
existing_hash = open(sha256, file_path)
9189
if new_hash == existing_hash
92-
# file exists and is correct, return
93-
return
94-
end
95-
end
96-
end
97-
# otherwise error
98-
error("$(repr(file_path)) is corrupted")
99-
end
100-
else
101-
err = ccall(:jl_fs_rename, Int32, (Cstring, Cstring), temp_path, file_path)
102-
# on error, check if file was made by another process, and is still valid.
103-
if err < 0
104-
if isfile(file_path)
105-
if filesize(file_path) == length(data)
106-
existing_hash = open(sha256, file_path)
107-
if new_hash == existing_hash
108-
# file exists and is correct, return
109-
return
90+
zone_text!(profiler, "file exists and is correct")
91+
return bytes2hex(new_hash)
11092
end
11193
end
11294
end
11395
# otherwise error
11496
error("$(repr(file_path)) is corrupted")
11597
end
98+
return bytes2hex(new_hash)
11699
end
117-
nothing
118100
end
119101
end
120102

src/outputdiff.jl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
# functions to show the difference between two job outputs
22

3-
import DeepDiffs
4-
using SmallZarrGroups
5-
import JSON3
6-
73

84
"""
95
print_json_diff(io::IO, json1::AbstractString, json2::AbstractString)

0 commit comments

Comments
 (0)