Barrier Synchronization
A barrier blocks every process until all processes in the communicator have reached it, giving a common synchronization point.
The operation
MPI_Barrier returns on a given rank only after every rank in the communicator has called it. No data moves; the sole effect is timing. Internally it is usually a dissemination or tree algorithm that completes in about log2(P) steps, so the barrier's own cost grows slowly with process count but is not free.
When it is needed and when it is not
Barriers are less often required than beginners assume. MPI point-to-point and collective calls already impose the ordering most programs need. Legitimate uses include: cleanly separating timing phases for benchmarking, ensuring all ranks have finished writing before a shared file is closed, and coordinating access to an external resource. Sprinkling barriers to be safe usually just adds synchronization delay and can mask, rather than fix, real ordering bugs.
- No data is exchanged; the effect is purely temporal.
- Cost is roughly logarithmic in the number of processes.
- Overuse serializes phases and amplifies load imbalance.
- Useful for clean benchmark timing and coordinating external side effects.
Barriers and load imbalance
A barrier exposes the slowest rank: everyone waits for the last arrival. Time spent in a barrier is therefore a direct measurement of load imbalance. Profilers report barrier wait time as an imbalance signal. Removing the barrier does not remove the imbalance; it only hides where the cost is charged, often pushing the wait into the next collective.
from mpi4py import MPI
comm = MPI.COMM_WORLD
comm.Barrier()
t0 = MPI.Wtime()
# ... timed region runs on all ranks ...
comm.Barrier()
elapsed = MPI.Wtime() - t0 # consistent phase timing across ranks
In practice
When timing a Hyperion transport kernel across nodes, a barrier before and after the region gives every rank the same start and stop reference, so reported phase times are comparable rather than skewed by staggered entry.