Skip to content

OpenMP element coloring + conditional velocity gather skip - #14

Open
mohitt31 wants to merge 4 commits into
jpampuero:masterfrom
mohitt31:feature/openmp-coloring
Open

OpenMP element coloring + conditional velocity gather skip#14
mohitt31 wants to merge 4 commits into
jpampuero:masterfrom
mohitt31:feature/openmp-coloring

Conversation

@mohitt31

Copy link
Copy Markdown
Collaborator

Two changes to compute_Fint, both on the 2.5D_inplane case (12800 elements, ngll 5):

1. OpenMP parallelism via element coloring

  • Graph-coloring of the element mesh so elements sharing nodes get different colors
  • Each color batch runs in parallel without race conditions on the scatter
  • Verified: round-off level agreement at 1, 2, 4, 8, 10 threads (max abs diff 1.14e-13 Ux, 1.39e-17 Uz)

2. Conditional velocity gather

  • compute_Fint gathered both displ and veloc every timestep, but MAT_Fint only reads veloc on the Kelvin-Voigt path
  • Added MAT_needs_veloc(matpro) query in mat_gen to gate the gather
  • compute_Fint wall: 18.81 s → 16.42 s (12.7% drop), ~9% end to end
  • Seismograms: bit-for-bit identical (0 of 1610 values differ)

Gather/scatter analysis

  • Microbenchmarked (npoin,ndof) vs (ndof,npoin) layout on the real ibool
  • RCM order: gather 1.00x, scatter 1.13x → ~1.5-2% end to end, not worth the invasive change
  • Full analysis in GATHER_SCATTER_ANALYSIS.md

Ports the element coloring from feature/batched-force-apply (trimmed,
drops the batch_const/VEC_W batching machinery that branch needed for
AVX2 but this doesn't) and adds an OPT_OMP build path that runs each
color's elements across threads with the original scalar MAT_Fint, no
new kernel. Correctness holds at every thread count tested, round off
level diffs against the unflagged baseline, identical regardless of
thread count since the reordering comes from the coloring, not from
thread scheduling. Speedup is real but caps around 1.67x at 4 threads
and doesn't improve past that on this machine's 10 cores, details and
the honest read on why in README_OPENMP_COLORING.md.
Second full pass reproduces the plateau (1.7x/1.66x/1.62x at 4/8/10
threads, within a couple percent of the first run, correctness diffs
bit for bit identical). Also built a diagnostic variant that skips the
parallel region for the two tiny colors (75 and 2 elements) to test
whether fork-join overhead on those was capping the scaling. It wasn't,
the threshold run landed inside the same noise band as the untouched
build at every thread count, so that hypothesis is out and the 4
performance core count looks like the real explanation. Didn't keep the
threshold change since it tested negative.
…filer

Adds DEFAULT(NONE) to the compute_Fint parallel region so every variable
has to be classified explicitly, which turns an accidental shared write
into a compile error instead of a race. Also adds an OPT_FINT_PROFILE
build flag that wraps compute_Fint and the time loop in wall-clock timers,
so the parallelizable fraction can be measured directly rather than
inferred. Measured it at 0.689 (compute_Fint is 68.9% of the loop),
matching the earlier profiling estimate, and with that fraction the
observed thread scaling tracks Amdahl's law: the plateau at 4 threads is
the serial-fraction ceiling plus the M4 only having 4 performance cores,
not a bug. README updated with the measurement and the Amdahl check.
Profiled the gather/scatter, which the earlier work flagged as the next
bottleneck. The data-layout transpose (npoin,ndof)->(ndof,npoin) that
looked promising turns out to be worth only about 1 to 2% when measured
with a microbenchmark on the real ibool, and it would touch field access
everywhere, so it is not worth the churn. The real waste is that
compute_Fint gathers both d and v every element every timestep, but
MAT_Fint only reads v on the Kelvin-Voigt path, so for elastic (and any
non Kelvin-Voigt material) the v gather is pure overhead.

Added MAT_needs_veloc in mat_gen next to MAT_Fint to answer whether a
material reads v, and compute_Fint now gathers v only when it does, in
both the serial and OpenMP paths. On 2.5D_inplane this drops compute_Fint
by 12.7% (about 9% end to end) with bit for bit identical seismograms,
since v was dead for that material. Full analysis and the microbenchmark
are in GATHER_SCATTER_ANALYSIS.md and gs_bench.f90.

@jpampuero jpampuero left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work. I have only minor suggestions.

Comment thread SRC/color_elem.f90
do j = 1, ngll
do i = 1, ngll
p = ibool(i, j, e)
if (p >= 1 .and. p <= npoin) then

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this check really necessary? (also below)

Comment thread SRC/color_elem.f90
enddo

! Clear node_owner for this color
do idx = 1, coloring%colors(icol)%nelem

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this loop be replaced by simply "node_owner = 0" ?

Comment thread SRC/color_elem.f90
do e = 1, nelem
do j = 1, ngll
do i = 1, ngll
p = ibool(i, j, e)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be more efficient to apply the greedy coloring algorithm to knods instead of ibool, because knods is much smaller: it's based on the element control nodes (4 to 9 per element) instead of the GLL nodes (ngll*ngll per element)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants