[flang-rt][cuda] Skip scope-exit cleanup when the context has a sticky error (#213184)
A sticky CUDA error (e.g. an illegal memory access in a kernel) leaves the primary context active but unusable, so CUFDeviceIsActive() reports it as fine and the compiler-generated scope-exit frees abort a program that ran to completion: 'cudaFree(p)' failed with 'cudaErrorIllegalAddress'. Detect this by freeing a null pointer, a no-op that still reports the sticky error. It runs only once the primary context is known active, so it cannot lazily create one.
This commit is contained in:
parent
36187ce08a
commit
5ca2b9313c
2 changed files with 13 additions and 0 deletions
|
|
@ -59,6 +59,13 @@ static bool deviceContextTornDown() {
|
||||||
int active{0};
|
int active{0};
|
||||||
if (getState(device, &flags, &active) == CUDA_SUCCESS) {
|
if (getState(device, &flags, &active) == CUDA_SUCCESS) {
|
||||||
tornDown = active == 0;
|
tornDown = active == 0;
|
||||||
|
// A sticky error (e.g. an illegal kernel memory access) leaves the
|
||||||
|
// primary context active but unusable: later calls all fail, so
|
||||||
|
// scope-exit frees would abort an otherwise successful program. A
|
||||||
|
// null free is a no-op that surfaces this without creating a context.
|
||||||
|
if (!tornDown && cudaFree(nullptr) != cudaSuccess) {
|
||||||
|
tornDown = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -31,13 +31,19 @@ end
|
||||||
|
|
||||||
program main
|
program main
|
||||||
integer, allocatable, device :: a(:)
|
integer, allocatable, device :: a(:)
|
||||||
|
integer, device, pointer :: p(:)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
! The descriptor of a device pointer lives in managed memory and is freed at
|
||||||
|
! scope exit, under the same device-active guard as the other cleanup.
|
||||||
|
|
||||||
! CHECK-LABEL: func.func @_QQmain() attributes {fir.bindc_name = "MAIN"}
|
! CHECK-LABEL: func.func @_QQmain() attributes {fir.bindc_name = "MAIN"}
|
||||||
! CHECK: cuf.alloc !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "a", data_attr = #cuf.cuda<device>, uniq_name = "_QFEa"} -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
|
! CHECK: cuf.alloc !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "a", data_attr = #cuf.cuda<device>, uniq_name = "_QFEa"} -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
|
||||||
|
! CHECK: %[[PTR:.*]]:2 = hlfir.declare %{{.*}} {data_attr = #cuf.cuda<device>, fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFEp"}
|
||||||
! CHECK: %[[ACTIVE:.*]] = fir.call @_FortranACUFDeviceIsActive() {{.*}} : () -> i1
|
! CHECK: %[[ACTIVE:.*]] = fir.call @_FortranACUFDeviceIsActive() {{.*}} : () -> i1
|
||||||
! CHECK-NEXT: fir.if %[[ACTIVE]] {
|
! CHECK-NEXT: fir.if %[[ACTIVE]] {
|
||||||
|
! CHECK-NEXT: cuf.free %[[PTR]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>{{.*}}
|
||||||
! CHECK: cuf.deallocate
|
! CHECK: cuf.deallocate
|
||||||
! CHECK: cuf.free{{.*}}
|
! CHECK: cuf.free{{.*}}
|
||||||
! CHECK-NEXT: }
|
! CHECK-NEXT: }
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue