[Openmp-commits] [openmp] [OpenMP] Emit `dispatch` callback for serial and zero-trip loops (PR #207773)
Jan André Reuter via Openmp-commits
openmp-commits at lists.llvm.org
Mon Jul 6 09:46:46 PDT 2026
https://github.com/Thyre created https://github.com/llvm/llvm-project/pull/207773
While `__kmp_for_static_init` implemented handling for the dispatch callback, the callback was only emitted when a static loop was neither serialized, nor a zero-trip loop. In both cases, only a work callback was emitted, with the `dispatch` callback being ignored entirely.
To fix this, add the same handling done for generic static loops to both serialized and zero-trip loops as well.
Add two tests to ensure that the correct callbacks are dispatched in both cases.
Closes https://github.com/llvm/llvm-project/issues/96698
>From 3e9eb9ae903f9a4e0ace14a5e9d516bc5e9d0f5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Andr=C3=A9=20Reuter?= <jan at zyten.de>
Date: Mon, 6 Jul 2026 18:09:53 +0200
Subject: [PATCH] [OpenMP] Emit `dispatch` callback for serial and zero-trip
loops
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
While `__kmp_for_static_init` implemented handling for the dispatch callback,
the callback was only emitted when a static loop was neither serialized, nor
a zero-trip loop. In both cases, only a work callback was emitted, with the
`dispatch` callback being ignored entirely.
To fix this, add the same handling done for generic static loops to both
serialized and zero-trip loops as well.
Add two tests to ensure that the correct callbacks are dispatched in both
cases.
Closes https://github.com/llvm/llvm-project/issues/96698
Signed-off-by: Jan André Reuter <jan at zyten.de>
---
openmp/runtime/src/kmp_sched.cpp | 36 +++++
.../worksharing/for/zero_trip_loop_dispatch.c | 133 ++++++++++++++++++
.../test/ompt/worksharing/serial_sections.c | 37 +++++
3 files changed, 206 insertions(+)
create mode 100644 openmp/runtime/test/ompt/worksharing/for/zero_trip_loop_dispatch.c
create mode 100644 openmp/runtime/test/ompt/worksharing/serial_sections.c
diff --git a/openmp/runtime/src/kmp_sched.cpp b/openmp/runtime/src/kmp_sched.cpp
index 2b1bb6f595f9a..cbbcfca635046 100644
--- a/openmp/runtime/src/kmp_sched.cpp
+++ b/openmp/runtime/src/kmp_sched.cpp
@@ -187,6 +187,24 @@ static void __kmp_for_static_init(ident_t *loc, kmp_int32 global_tid,
ompt_work_type, ompt_scope_begin, &(team_info->parallel_data),
&(task_info->task_data), 0, codeptr);
}
+ if (ompt_enabled.ompt_callback_dispatch) {
+ ompt_dispatch_t dispatch_type;
+ ompt_data_t instance = ompt_data_none;
+ ompt_dispatch_chunk_t dispatch_chunk;
+ if (ompt_work_type == ompt_work_sections) {
+ dispatch_type = ompt_dispatch_section;
+ instance.ptr = codeptr;
+ } else {
+ OMPT_GET_DISPATCH_CHUNK(dispatch_chunk, *plower, *pupper, incr);
+ dispatch_type = (ompt_work_type == ompt_work_distribute)
+ ? ompt_dispatch_distribute_chunk
+ : ompt_dispatch_ws_loop_chunk;
+ instance.ptr = &dispatch_chunk;
+ }
+ ompt_callbacks.ompt_callback(ompt_callback_dispatch)(
+ &(team_info->parallel_data), &(task_info->task_data), dispatch_type,
+ instance);
+ }
#endif
KMP_STATS_LOOP_END(OMP_loop_static_iterations);
return;
@@ -241,6 +259,24 @@ static void __kmp_for_static_init(ident_t *loc, kmp_int32 global_tid,
ompt_work_type, ompt_scope_begin, &(team_info->parallel_data),
&(task_info->task_data), *pstride, codeptr);
}
+ if (ompt_enabled.ompt_callback_dispatch) {
+ ompt_dispatch_t dispatch_type;
+ ompt_data_t instance = ompt_data_none;
+ ompt_dispatch_chunk_t dispatch_chunk;
+ if (ompt_work_type == ompt_work_sections) {
+ dispatch_type = ompt_dispatch_section;
+ instance.ptr = codeptr;
+ } else {
+ OMPT_GET_DISPATCH_CHUNK(dispatch_chunk, *plower, *pupper, incr);
+ dispatch_type = (ompt_work_type == ompt_work_distribute)
+ ? ompt_dispatch_distribute_chunk
+ : ompt_dispatch_ws_loop_chunk;
+ instance.ptr = &dispatch_chunk;
+ }
+ ompt_callbacks.ompt_callback(ompt_callback_dispatch)(
+ &(team_info->parallel_data), &(task_info->task_data), dispatch_type,
+ instance);
+ }
#endif
KMP_STATS_LOOP_END(OMP_loop_static_iterations);
return;
diff --git a/openmp/runtime/test/ompt/worksharing/for/zero_trip_loop_dispatch.c b/openmp/runtime/test/ompt/worksharing/for/zero_trip_loop_dispatch.c
new file mode 100644
index 0000000000000..44e27c94299bf
--- /dev/null
+++ b/openmp/runtime/test/ompt/worksharing/for/zero_trip_loop_dispatch.c
@@ -0,0 +1,133 @@
+// clang-format off
+// RUN: %libomp-compile-and-run | %sort-threads | FileCheck %s
+// REQUIRES: ompt
+// XFAIL: gcc
+// GCC doesn't call runtime for static schedule
+// clang-format on
+
+#include "callback.h"
+
+#define WORK_SIZE 64
+#define WORK_BOUND 10
+
+int main() {
+ int i;
+ int wait_s = 0;
+
+#pragma omp parallel num_threads(4)
+ {
+ int wait_id = 0;
+ int team_size = omp_get_num_threads();
+#pragma omp for schedule(static, WORK_SIZE / 4)
+ for (i = WORK_SIZE; i > WORK_BOUND; i--) {
+ }
+
+#pragma omp for schedule(dynamic)
+ for (i = WORK_SIZE; i > WORK_BOUND; i--) {
+ if (wait_id == 0) {
+ // Wait until every thread has at least one iteration assigned
+ OMPT_SIGNAL(wait_s);
+ OMPT_WAIT(wait_s, team_size);
+ wait_id++;
+ }
+ }
+
+#pragma omp for schedule(guided)
+ for (i = WORK_SIZE; i > WORK_BOUND; i--) {
+ if (wait_id == 1) {
+ // Wait until every thread has at least one iteration assigned
+ OMPT_SIGNAL(wait_s);
+ OMPT_WAIT(wait_s, 2 * team_size);
+ wait_id++;
+ }
+ }
+ }
+
+ return 0;
+}
+
+// clang-format off
+// CHECK-NOT: {{^}}0: Could not register callback 'ompt_callback_parallel_begin'
+// CHECK-NOT: {{^}}0: Could not register callback 'ompt_callback_implicit_task'
+// CHECK-NOT: {{^}}0: Could not register callback 'ompt_callback_work'
+// CHECK-NOT: {{^}}0: Could not register callback 'ompt_callback_dispatch'
+
+// CHECK: 0: NULL_POINTER=[[NULL:.*$]]
+// CHECK: {{^}}[[THREAD_ID0:[0-9]+]]: ompt_event_parallel_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID:[0-f]+]]
+
+// Each thread should have at least one ws-loop-chunk-begin event for each
+// for loop.
+
+// CHECK: {{^}}[[THREAD_ID0]]: ompt_event_implicit_task_begin:
+// CHECK-SAME: task_id=[[TASK_ID0:[0-9]+]]
+// CHECK: {{^}}[[THREAD_ID0]]: ompt_event_loop_static_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID0]]
+// CHECK: {{^}}[[THREAD_ID0]]: ompt_event_ws_loop_chunk_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID0]]
+// CHECK-SAME: chunk_start={{[0-9]+}}, chunk_iterations=16
+// CHECK: {{^}}[[THREAD_ID0]]: ompt_event_loop_dynamic_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID0]]
+// CHECK: {{^}}[[THREAD_ID0]]: ompt_event_ws_loop_chunk_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID0]]
+// CHECK-SAME: chunk_start={{[0-9]+}}, chunk_iterations=1
+// CHECK: {{^}}[[THREAD_ID0]]: ompt_event_loop_guided_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID0]]
+// CHECK: {{^}}[[THREAD_ID0]]: ompt_event_ws_loop_chunk_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID0]]
+// CHECK-SAME: chunk_start={{[0-9]+}}, chunk_iterations={{[1-9][0-9]*}}
+
+// CHECK: {{^}}[[THREAD_ID1:[0-9]+]]: ompt_event_implicit_task_begin:
+// CHECK-SAME: task_id=[[TASK_ID1:[0-9]+]]
+// CHECK: {{^}}[[THREAD_ID1]]: ompt_event_loop_static_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID1]]
+// CHECK: {{^}}[[THREAD_ID1]]: ompt_event_ws_loop_chunk_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID1]]
+// CHECK-SAME: chunk_start={{[0-9]+}}, chunk_iterations=16
+// CHECK: {{^}}[[THREAD_ID1]]: ompt_event_loop_dynamic_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID1]]
+// CHECK: {{^}}[[THREAD_ID1]]: ompt_event_ws_loop_chunk_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID1]]
+// CHECK-SAME: chunk_start={{[0-9]+}}, chunk_iterations=1
+// CHECK: {{^}}[[THREAD_ID1]]: ompt_event_loop_guided_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID1]]
+// CHECK: {{^}}[[THREAD_ID1]]: ompt_event_ws_loop_chunk_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID1]]
+// CHECK-SAME: chunk_start={{[0-9]+}}, chunk_iterations={{[1-9][0-9]*}}
+
+// CHECK: {{^}}[[THREAD_ID2:[0-9]+]]: ompt_event_implicit_task_begin:
+// CHECK-SAME: task_id=[[TASK_ID2:[0-9]+]]
+// CHECK: {{^}}[[THREAD_ID2]]: ompt_event_loop_static_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID2]]
+// CHECK: {{^}}[[THREAD_ID2]]: ompt_event_ws_loop_chunk_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID2]]
+// CHECK-SAME: chunk_start={{[0-9]+}}, chunk_iterations=16
+// CHECK: {{^}}[[THREAD_ID2]]: ompt_event_loop_dynamic_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID2]]
+// CHECK: {{^}}[[THREAD_ID2]]: ompt_event_ws_loop_chunk_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID2]]
+// CHECK-SAME: chunk_start={{[0-9]+}}, chunk_iterations=1
+// CHECK: {{^}}[[THREAD_ID2]]: ompt_event_loop_guided_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID2]]
+// CHECK: {{^}}[[THREAD_ID2]]: ompt_event_ws_loop_chunk_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID2]]
+// CHECK-SAME: chunk_start={{[0-9]+}}, chunk_iterations={{[1-9][0-9]*}}
+
+// CHECK: {{^}}[[THREAD_ID3:[0-9]+]]: ompt_event_implicit_task_begin:
+// CHECK-SAME: task_id=[[TASK_ID3:[0-9]+]]
+// CHECK: {{^}}[[THREAD_ID3]]: ompt_event_loop_static_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID3]]
+// CHECK: {{^}}[[THREAD_ID3]]: ompt_event_ws_loop_chunk_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID3]]
+// CHECK-SAME: chunk_start={{[0-9]+}}, chunk_iterations=16
+// CHECK: {{^}}[[THREAD_ID3]]: ompt_event_loop_dynamic_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID3]]
+// CHECK: {{^}}[[THREAD_ID3]]: ompt_event_ws_loop_chunk_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID3]]
+// CHECK-SAME: chunk_start={{[0-9]+}}, chunk_iterations=1
+// CHECK: {{^}}[[THREAD_ID3]]: ompt_event_loop_guided_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID3]]
+// CHECK: {{^}}[[THREAD_ID3]]: ompt_event_ws_loop_chunk_begin:
+// CHECK-SAME: parallel_id=[[PARALLEL_ID]], task_id=[[TASK_ID3]]
+// CHECK-SAME: chunk_start={{[0-9]+}}, chunk_iterations={{[1-9][0-9]*}}
+// clang-format on
diff --git a/openmp/runtime/test/ompt/worksharing/serial_sections.c b/openmp/runtime/test/ompt/worksharing/serial_sections.c
new file mode 100644
index 0000000000000..e40efc10c37e6
--- /dev/null
+++ b/openmp/runtime/test/ompt/worksharing/serial_sections.c
@@ -0,0 +1,37 @@
+// clang-format off
+// RUN: %libomp-compile-and-run | FileCheck %s
+// REQUIRES: ompt
+// UNSUPPORTED: gcc-4, gcc-5, gcc-6, gcc-7
+// clang-format on
+#include "callback.h"
+
+int main(void) {
+#pragma omp parallel num_threads(1)
+#pragma omp sections
+ {
+#pragma omp section
+ {
+ }
+ }
+}
+
+// clang-format off
+// Check if libomp supports the callbacks for this test.
+// CHECK-NOT: {{^}}0: Could not register callback 'ompt_callback_parallel_begin'
+// CHECK-NOT: {{^}}0: Could not register callback 'ompt_callback_parallel_end'
+// CHECK-NOT: {{^}}0: Could not register callback 'ompt_event_implicit_task_begin'
+// CHECK-NOT: {{^}}0: Could not register callback 'ompt_event_implicit_task_end'
+// CHECK-NOT: {{^}}0: Could not register callback 'ompt_event_work'
+// CHECK-NOT: {{^}}0: Could not register callback 'ompt_event_dispatch'
+
+// CHECK: 0: NULL_POINTER=[[NULL:.*$]]
+
+// CHECK: {{^}}[[MASTER_ID:[0-9]+]]: ompt_event_parallel_begin: parent_task_id=[[PARENT_TASK_ID:[0-f]+]], parent_task_frame.exit=[[NULL]], parent_task_frame.reenter={{(0x)?[0-f]+}}, parallel_id=[[PARALLEL_ID:[0-f]+]], requested_team_size=1, codeptr_ra=[[RETURN_ADDRESS:(0x)?[0-f]+]]{{[0-f][0-f]}}, invoker=[[PARALLEL_INVOKER:[0-9]+]]
+// CHECK: {{^}}[[MASTER_ID]]: ompt_event_implicit_task_begin: parallel_id=[[PARALLEL_ID]], task_id=[[IMPLICIT_TASK_ID:[0-f]+]]
+// CHECK: {{^}}[[MASTER_ID]]: ompt_event_sections_begin: parallel_id=[[PARALLEL_ID]], task_id=[[IMPLICIT_TASK_ID]]
+// CHECK: {{^}}[[MASTER_ID]]: ompt_event_section_begin: parallel_id=[[PARALLEL_ID]], task_id=[[IMPLICIT_TASK_ID]]
+// CHECK: {{^}}[[MASTER_ID]]: ompt_event_sections_end: parallel_id=[[PARALLEL_ID]], task_id=[[IMPLICIT_TASK_ID]]
+// CHECK: {{^}}[[MASTER_ID]]: ompt_event_implicit_task_end: parallel_id=0, task_id=[[IMPLICIT_TASK_ID]]
+// CHECK: {{^}}[[MASTER_ID]]: ompt_event_parallel_end: parallel_id=[[PARALLEL_ID]], task_id=[[PARENT_TASK_ID]], invoker=[[PARALLEL_INVOKER]], codeptr_ra=[[RETURN_ADDRESS]]{{[0-f][0-f]}}
+
+// clang-format on
More information about the Openmp-commits
mailing list