Problem Description
When compiling a FORTRAN OpenMP program which includes a GPU kernel that is conditionally executed on the device, a missing optimisation makes the kernel's occupancy decrease unacceptably.
As per the spec, !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO IF ( using_openmp ) applies the IF clause to both TARGET and PARALLEL DO by default. However, the compiler doesn't infer that if running on the target, then the IF clause has to be true for PARALLEL DO as well, missing crucial optimisations.
For example, for the included MRE:
- When using the longer pragma, the kernel uses 16 SGPRs and 8 VGPRs, no AGPRs and no scratch, close to what I would expect. (Note that this technically specifies that in the fallback case (on the host), the loop should still run in parallel, so not semantically equivalent. The other pragma is just as "correct")
- When using the shorter pragma, the kernel instead uses 100 SGPRs, 115 VGPRs, 1 AGPRs and 24B of scratch per lane, reducing the maximum occupancy by half.
This seems to be because of generation of a fallback codebase including unrolling and copying the using_openmp value around.
While this is just a performance issue, I do believe that it's a very common occurence and a lot of users would benefit from a fix. In the LLVM IR, that would translate to figuring out that in this IR:
%34 = llvm.load %arg7 {tbaa = [#tbaa_tag1]} : !llvm.ptr -> i32
%35 = llvm.mlir.constant(0 : i64) : i32
%36 = llvm.icmp "ne" %34, %35 : i32
omp.teams if(%36) {
%37 = llvm.load %arg7 {tbaa = [#tbaa_tag1]} : !llvm.ptr -> i32
%38 = llvm.mlir.constant(0 : i64) : i32
%39 = llvm.icmp "ne" %37, %38 : i32
omp.parallel if(%39) private(@_QFmy_reproEn_private_i32 %arg6 -> %arg12 : !llvm.ptr) {
…
omp.parallel is enabled IFF omp.teams also is, thus forgoeing the unreacheable fallback path in the kernel generation.
Operating System
Red Hat Enterprise Linux 8.10 (Ootpa)
CPU
AMD EPYC 9124 16-Core Processor
GPU
AMD Instinct MI210
ROCm Version
ROCm 7.2.1
ROCm Component
flang
Steps to Reproduce
With the following fortran file,
SUBROUTINE my_repro ( using_openmp,nlen,z1,z2 )
IMPLICIT NONE
! IN/OUT
LOGICAL, INTENT(IN) :: using_openmp
INTEGER, INTENT(IN) :: nlen
REAL(8), INTENT(IN) :: z1(1:nlen)
REAL(8), INTENT(OUT) :: z2(1:nlen)
! LOCAL
INTEGER :: n
! As per the OpenMP spec, passing a variable to the IF clause also applies to the PARALLEL DO.
! As such `TARGET: ` needs to be applied.
!$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(n) MAP(present: z1, z2) IF ( using_openmp )
!!$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO PRIVATE(n) MAP(present: z1, z2) IF ( TARGET: using_openmp )
DO n=1,nlen
z2(n) = z1(n)
END DO
END SUBROUTINE my_repro
amdflang -Rpass-analysis=kernel-resource-usage -fopenmp --offload-arch=gfx90a -O3 -g -o repro test.f90 will output the number of registers required. It should be the same number when toggling between the first and second pragma lines.
(Optional for Linux users) Output of /opt/rocm/bin/rocminfo --support
rocminfo --support output
ROCk module version 6.12.12 is loaded
=====================
HSA System Attributes
=====================
Runtime Version: 1.15
Runtime Ext Version: 1.7
System Timestamp Freq.: 1000.000000MHz
Sig. Max Wait Duration: 18446744073709551615 (0xFFFFFFFFFFFFFFFF) (timestamp count)
Machine Model: LARGE
System Endianness: LITTLE
Mwaitx: DISABLED
XNACK enabled: NO
DMAbuf Support: YES
VMM Support: YES
==========
HSA Agents
==========
*******
Agent 1
*******
Name: AMD EPYC 9124 16-Core Processor
Uuid: CPU-XX
Marketing Name: AMD EPYC 9124 16-Core Processor
Vendor Name: CPU
Feature: None specified
Profile: FULL_PROFILE
Float Round Mode: NEAR
Max Queue Number: 0(0x0)
Queue Min Size: 0(0x0)
Queue Max Size: 0(0x0)
Queue Type: MULTI
Node: 0
Device Type: CPU
Cache Info:
L1: 32768(0x8000) KB
Chip ID: 0(0x0)
ASIC Revision: 0(0x0)
Cacheline Size: 64(0x40)
Max Clock Freq. (MHz): 3711
BDFID: 0
Internal Node ID: 0
Compute Unit: 16
SIMDs per CU: 0
Shader Engines: 0
Shader Arrs. per Eng.: 0
WatchPts on Addr. Ranges:1
Memory Properties:
Features: None
Pool Info:
Pool 1
Segment: GLOBAL; FLAGS: FINE GRAINED
Size: 197254728(0xbc1de48) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Recommended Granule:4KB
Alloc Alignment: 4KB
Accessible by all: TRUE
Pool 2
Segment: GLOBAL; FLAGS: EXTENDED FINE GRAINED
Size: 197254728(0xbc1de48) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Recommended Granule:4KB
Alloc Alignment: 4KB
Accessible by all: TRUE
Pool 3
Segment: GLOBAL; FLAGS: KERNARG, FINE GRAINED
Size: 197254728(0xbc1de48) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Recommended Granule:4KB
Alloc Alignment: 4KB
Accessible by all: TRUE
Pool 4
Segment: GLOBAL; FLAGS: COARSE GRAINED
Size: 197254728(0xbc1de48) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Recommended Granule:4KB
Alloc Alignment: 4KB
Accessible by all: TRUE
ISA Info:
*******
Agent 2
*******
Name: AMD EPYC 9124 16-Core Processor
Uuid: CPU-XX
Marketing Name: AMD EPYC 9124 16-Core Processor
Vendor Name: CPU
Feature: None specified
Profile: FULL_PROFILE
Float Round Mode: NEAR
Max Queue Number: 0(0x0)
Queue Min Size: 0(0x0)
Queue Max Size: 0(0x0)
Queue Type: MULTI
Node: 1
Device Type: CPU
Cache Info:
L1: 32768(0x8000) KB
Chip ID: 0(0x0)
ASIC Revision: 0(0x0)
Cacheline Size: 64(0x40)
Max Clock Freq. (MHz): 3711
BDFID: 0
Internal Node ID: 1
Compute Unit: 16
SIMDs per CU: 0
Shader Engines: 0
Shader Arrs. per Eng.: 0
WatchPts on Addr. Ranges:1
Memory Properties:
Features: None
Pool Info:
Pool 1
Segment: GLOBAL; FLAGS: FINE GRAINED
Size: 198133208(0xbcf45d8) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Recommended Granule:4KB
Alloc Alignment: 4KB
Accessible by all: TRUE
Pool 2
Segment: GLOBAL; FLAGS: EXTENDED FINE GRAINED
Size: 198133208(0xbcf45d8) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Recommended Granule:4KB
Alloc Alignment: 4KB
Accessible by all: TRUE
Pool 3
Segment: GLOBAL; FLAGS: KERNARG, FINE GRAINED
Size: 198133208(0xbcf45d8) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Recommended Granule:4KB
Alloc Alignment: 4KB
Accessible by all: TRUE
Pool 4
Segment: GLOBAL; FLAGS: COARSE GRAINED
Size: 198133208(0xbcf45d8) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Recommended Granule:4KB
Alloc Alignment: 4KB
Accessible by all: TRUE
ISA Info:
*******
Agent 3
*******
Name: gfx90a
Uuid: GPU-f945d33cda6dd19d
Marketing Name: AMD Instinct MI210
Vendor Name: AMD
Feature: KERNEL_DISPATCH
Profile: BASE_PROFILE
Float Round Mode: NEAR
Max Queue Number: 128(0x80)
Queue Min Size: 64(0x40)
Queue Max Size: 131072(0x20000)
Queue Type: MULTI
Node: 2
Device Type: GPU
Cache Info:
L1: 16(0x10) KB
L2: 8192(0x2000) KB
Chip ID: 29711(0x740f)
ASIC Revision: 1(0x1)
Cacheline Size: 128(0x80)
Max Clock Freq. (MHz): 1700
BDFID: 8960
Internal Node ID: 2
Compute Unit: 104
SIMDs per CU: 4
Shader Engines: 8
Shader Arrs. per Eng.: 1
WatchPts on Addr. Ranges:4
Coherent Host Access: FALSE
Memory Properties:
Features: KERNEL_DISPATCH
Fast F16 Operation: TRUE
Wavefront Size: 64(0x40)
Workgroup Max Size: 1024(0x400)
Workgroup Max Size per Dimension:
x 1024(0x400)
y 1024(0x400)
z 1024(0x400)
Max Waves Per CU: 32(0x20)
Max Work-item Per CU: 2048(0x800)
Grid Max Size: 4294967295(0xffffffff)
Grid Max Size per Dimension:
x 4294967295(0xffffffff)
y 4294967295(0xffffffff)
z 4294967295(0xffffffff)
Max fbarriers/Workgrp: 32
Packet Processor uCode:: 96
SDMA engine uCode:: 9
IOMMU Support:: None
Pool Info:
Pool 1
Segment: GLOBAL; FLAGS: COARSE GRAINED
Size: 67092480(0x3ffc000) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Recommended Granule:2048KB
Alloc Alignment: 4KB
Accessible by all: FALSE
Pool 2
Segment: GLOBAL; FLAGS: EXTENDED FINE GRAINED
Size: 67092480(0x3ffc000) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Recommended Granule:2048KB
Alloc Alignment: 4KB
Accessible by all: FALSE
Pool 3
Segment: GLOBAL; FLAGS: FINE GRAINED
Size: 67092480(0x3ffc000) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Recommended Granule:2048KB
Alloc Alignment: 4KB
Accessible by all: FALSE
Pool 4
Segment: GROUP
Size: 64(0x40) KB
Allocatable: FALSE
Alloc Granule: 0KB
Alloc Recommended Granule:0KB
Alloc Alignment: 0KB
Accessible by all: FALSE
ISA Info:
ISA 1
Name: amdgcn-amd-amdhsa--gfx90a:sramecc+:xnack-
Machine Models: HSA_MACHINE_MODEL_LARGE
Profiles: HSA_PROFILE_BASE
Default Rounding Mode: NEAR
Default Rounding Mode: NEAR
Fast f16: TRUE
Workgroup Max Size: 1024(0x400)
Workgroup Max Size per Dimension:
x 1024(0x400)
y 1024(0x400)
z 1024(0x400)
Grid Max Size: 4294967295(0xffffffff)
Grid Max Size per Dimension:
x 4294967295(0xffffffff)
y 4294967295(0xffffffff)
z 4294967295(0xffffffff)
FBarrier Max Size: 32
*** Done ***
Additional Information
$ amdflang --version
AMD AFAR drop #23.2.0 04/18/26 flang version 23.0.0git (https://github.com/ROCm/llvm-project.git 3584941+PATCHED:440716f8b87be9d8e20ed910e10e5b6d14d57cf6)
Problem Description
When compiling a FORTRAN OpenMP program which includes a GPU kernel that is conditionally executed on the device, a missing optimisation makes the kernel's occupancy decrease unacceptably.
As per the spec,
!$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO IF ( using_openmp )applies the IF clause to bothTARGETandPARALLEL DOby default. However, the compiler doesn't infer that if running on the target, then theIFclause has to be true forPARALLEL DOas well, missing crucial optimisations.For example, for the included MRE:
This seems to be because of generation of a fallback codebase including unrolling and copying the
using_openmpvalue around.While this is just a performance issue, I do believe that it's a very common occurence and a lot of users would benefit from a fix. In the LLVM IR, that would translate to figuring out that in this IR:
omp.parallelis enabled IFFomp.teamsalso is, thus forgoeing the unreacheable fallback path in the kernel generation.Operating System
Red Hat Enterprise Linux 8.10 (Ootpa)
CPU
AMD EPYC 9124 16-Core Processor
GPU
AMD Instinct MI210
ROCm Version
ROCm 7.2.1
ROCm Component
flang
Steps to Reproduce
With the following fortran file,
amdflang -Rpass-analysis=kernel-resource-usage -fopenmp --offload-arch=gfx90a -O3 -g -o repro test.f90will output the number of registers required. It should be the same number when toggling between the first and second pragma lines.(Optional for Linux users) Output of /opt/rocm/bin/rocminfo --support
rocminfo --support output
Additional Information