Performance-Aware Loops
Loop Order Shape
Match the Array Layout
Fortran arrays are column-major, so loop order is part of performance-aware design even when no elapsed-time measurement is run.
Program
Play the program to choose a traversal shape and see the same grid summarized with different visit patterns.
loop_order_shape.f90
Replay: real traced execution (multi-file project)
program loop_order_shape_demo
implicit none
integer :: grid(2, 3)
integer :: order_mode
integer :: row
integer :: col
integer :: visits
integer :: total
character(len=12) :: order_name
grid = reshape([1, 2, 3, 4, 5, 6], [2, 3])
order_mode = 1
visits = 0
total = 0
if (order_mode == 1) then
order_name = 'column'
do col = 1, 3
do row = 1, 2
visits = visits + 1
total = total + grid(row, col)
end do
end do
else if (order_mode == 2) then
order_name = 'row'
do row = 1, 2
do col = 1, 3
visits = visits + 1
total = total + grid(row, col)
end do
end do
else
order_name = 'sample'
do col = 1, 3
row = 1 + mod(col + 1, 2)
visits = visits + 1
total = total + grid(row, col)
end do
end if
print '(A, 1X, I0, 1X, I0)', trim(order_name), visits, total
end program loop_order_shape_demo
program loop_order_shape_demo
implicit none
integer :: grid(2, 3)
integer :: order_mode
integer :: row
integer :: col
integer :: visits
integer :: total
character(len=12) :: order_name
grid = reshape([1, 2, 3, 4, 5, 6], [2, 3])
order_mode = 2
visits = 0
total = 0
if (order_mode == 1) then
order_name = 'column'
do col = 1, 3
do row = 1, 2
visits = visits + 1
total = total + grid(row, col)
end do
end do
else if (order_mode == 2) then
order_name = 'row'
do row = 1, 2
do col = 1, 3
visits = visits + 1
total = total + grid(row, col)
end do
end do
else
order_name = 'sample'
do col = 1, 3
row = 1 + mod(col + 1, 2)
visits = visits + 1
total = total + grid(row, col)
end do
end if
print '(A, 1X, I0, 1X, I0)', trim(order_name), visits, total
end program loop_order_shape_demo
program loop_order_shape_demo
implicit none
integer :: grid(2, 3)
integer :: order_mode
integer :: row
integer :: col
integer :: visits
integer :: total
character(len=12) :: order_name
grid = reshape([1, 2, 3, 4, 5, 6], [2, 3])
order_mode = 3
visits = 0
total = 0
if (order_mode == 1) then
order_name = 'column'
do col = 1, 3
do row = 1, 2
visits = visits + 1
total = total + grid(row, col)
end do
end do
else if (order_mode == 2) then
order_name = 'row'
do row = 1, 2
do col = 1, 3
visits = visits + 1
total = total + grid(row, col)
end do
end do
else
order_name = 'sample'
do col = 1, 3
row = 1 + mod(col + 1, 2)
visits = visits + 1
total = total + grid(row, col)
end do
end if
print '(A, 1X, I0, 1X, I0)', trim(order_name), visits, total
end program loop_order_shape_demo
grid ← [[1, 3, 5], [2, 4, 6]]
11grid = reshape([1, 2, 3, 4, 5, 6], [2, 3])12order_mode = 1values this step[[1, 3, 5], [2, 4, 6]]gridorder_mode ← 1
11grid = reshape([1, 2, 3, 4, 5, 6], [2, 3])12order_mode = 113visits = 0values this step1order_modevisits ← 0
12order_mode = 113visits = 014total = 0values this step0visitstotal ← 0
13visits = 014total = 015if (order_mode == 1) thenvalues this step0totalorder_name ← column
15if (order_mode == 1) then16 order_name = 'column'17 do col = 1, 3values this stepcolumnorder_namevisits ← 1
18do row = 1, 219 visits = visits + 120 total = total + grid(row, col)values this step0 → 1visits1col1rowtotal ← 1
19 visits = visits + 120 total = total + grid(row, col)21end dovalues this step0 → 1total1grid(row,col)visits ← 2
18do row = 1, 219 visits = visits + 120 total = total + grid(row, col)values this step1 → 2visits1col2rowtotal ← 3
19 visits = visits + 120 total = total + grid(row, col)21end dovalues this step1 → 3total2grid(row,col)visits ← 6
18do row = 1, 219 visits = visits + 120 total = total + grid(row, col)values this step2 → 6visits2..3col1..2rowtotal ← 21
19 visits = visits + 120 total = total + grid(row, col)21end dovalues this step3 → 21total3,4,5,6remaining valuesprint '(A, 1X, I0, 1X, I0)', trim(order_name), visits, total
38 end if39 print '(A, 1X, I0, 1X, I0)', trim(order_name), visits, total40end program loop_order_shape_demooutputcolumn 6 21values this stepcolumnorder_name6visits21total
grid ← [[1, 3, 5], [2, 4, 6]]
11grid = reshape([1, 2, 3, 4, 5, 6], [2, 3])12order_mode = 2values this step[[1, 3, 5], [2, 4, 6]]gridorder_mode ← 2
11grid = reshape([1, 2, 3, 4, 5, 6], [2, 3])12order_mode = 213visits = 0values this step2order_modevisits ← 0
12order_mode = 213visits = 014total = 0values this step0visitstotal ← 0
13visits = 014total = 015if (order_mode == 1) thenvalues this step0totalorder_name ← row
23else if (order_mode == 2) then24 order_name = 'row'25 do row = 1, 2values this steproworder_namevisits ← 1
26do col = 1, 327 visits = visits + 128 total = total + grid(row, col)values this step0 → 1visits1row1coltotal ← 1
27 visits = visits + 128 total = total + grid(row, col)29end dovalues this step0 → 1total1grid(row,col)visits ← 2
26do col = 1, 327 visits = visits + 128 total = total + grid(row, col)values this step1 → 2visits1row2coltotal ← 4
27 visits = visits + 128 total = total + grid(row, col)29end dovalues this step1 → 4total3grid(row,col)visits ← 6
26do col = 1, 327 visits = visits + 128 total = total + grid(row, col)values this step2 → 6visitsremainingrow/coltotal ← 21
27 visits = visits + 128 total = total + grid(row, col)29end dovalues this step4 → 21total5,2,4,6remaining valuesprint '(A, 1X, I0, 1X, I0)', trim(order_name), visits, total
38 end if39 print '(A, 1X, I0, 1X, I0)', trim(order_name), visits, total40end program loop_order_shape_demooutputrow 6 21values this steproworder_name6visits21total
grid ← [[1, 3, 5], [2, 4, 6]]
11grid = reshape([1, 2, 3, 4, 5, 6], [2, 3])12order_mode = 3values this step[[1, 3, 5], [2, 4, 6]]gridorder_mode ← 3
11grid = reshape([1, 2, 3, 4, 5, 6], [2, 3])12order_mode = 313visits = 0values this step3order_modevisits ← 0
12order_mode = 313visits = 014total = 0values this step0visitstotal ← 0
13visits = 014total = 015if (order_mode == 1) thenvalues this step0totalorder_name ← sample
31else32 order_name = 'sample'33 do col = 1, 3values this stepsampleorder_namerow ← 1
33do col = 1, 334 row = 1 + mod(col + 1, 2)35 visits = visits + 1values this step1row1colvisits ← 1
34row = 1 + mod(col + 1, 2)35visits = visits + 136total = total + grid(row, col)values this step0 → 1visitstotal ← 1
35 visits = visits + 136 total = total + grid(row, col)37end dovalues this step0 → 1total1grid(row,col)row ← 2
33do col = 1, 334 row = 1 + mod(col + 1, 2)35 visits = visits + 1values this step2row2colvisits ← 2
34row = 1 + mod(col + 1, 2)35visits = visits + 136total = total + grid(row, col)values this step1 → 2visitstotal ← 5
35 visits = visits + 136 total = total + grid(row, col)37end dovalues this step1 → 5total4grid(row,col)row ← 1
33do col = 1, 334 row = 1 + mod(col + 1, 2)35 visits = visits + 1values this step1row3colvisits ← 3
34row = 1 + mod(col + 1, 2)35visits = visits + 136total = total + grid(row, col)values this step2 → 3visitstotal ← 10
35 visits = visits + 136 total = total + grid(row, col)37end dovalues this step5 → 10total5grid(row,col)print '(A, 1X, I0, 1X, I0)', trim(order_name), visits, total
38 end if39 print '(A, 1X, I0, 1X, I0)', trim(order_name), visits, total40end program loop_order_shape_demooutputsample 3 10values this stepsampleorder_name3visits10total
column-major
Fortran stores the leftmost subscript contiguously.
loop order
Changing traversal order changes the access pattern, not the mathematical total.
shape summary
A small visit count and total can explain the loop shape without timing.