<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/112924>112924</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[OpenMP][OMPT] Controlling a tool via `omp_control_tool` might incorrectly return that there is no tool
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
Thyre
</td>
</tr>
</table>
<pre>
The OpenMP interface offers a simple function to communicate with an attached tool, which can be just information dumping, sanitizer like Archer or performance tools like Score-P and TAU. While playing around with `omp_control_tool` and its counterpart `ompt_control_look` I noticed that the runtime might return `omp_control_tool_notool`, even though a tool was just initialized. This mainly affects offloading constructs and calling `omp_control_tool` as its first action.
My testing was unfortunately only done with LLVM 18.1.8. With LLVM trunk and an AMD GPU, trying to run any OpenMP example with offload fails with an error message. I'm building LLVM 19.1.2 right now to test against.
Here's a simple reproducer:
```c
#include <omp.h>
#include <omp-tools.h>
#include <stdio.h>
/* TOOL CODE */
int
callback_control_tool( uint64_t command,
uint64_t modifier,
void* arg,
const void* codeptr_ra )
{
const char* command_name;
switch ( command )
{
case omp_control_tool_start:
{
command_name = "omp_control_tool_start";
break;
}
case omp_control_tool_flush:
{
command_name = "omp_control_tool_flush";
break;
}
case omp_control_tool_pause:
{
command_name = "omp_control_tool_pause";
break;
}
case omp_control_tool_end:
{
command_name = "omp_control_tool_end";
break;
}
default:
command_name = NULL;
break;
}
printf( "[%s] command = %lu | modifier = %lu | arg = %p | codeptr_ra = %p\n",
__FUNCTION__,
command,
modifier,
arg,
codeptr_ra );
if( command_name )
{
return omp_control_tool_success;
}
return omp_control_tool_ignored;
}
int
tool_initialize( ompt_function_lookup_t lookup,
int initial_device_num,
ompt_data_t* tool_data )
{
ompt_set_callback_t set_callback = ( ompt_set_callback_t )lookup( "ompt_set_callback" );
if( !set_callback )
{
return 0;
}
ompt_set_result_t result = set_callback( ompt_callback_control_tool, (ompt_callback_t)&callback_control_tool );
if( result != ompt_set_always )
{
return 0;
}
printf( "[%s] Successfully initialized tool.\n", __FUNCTION__ );
return 1; /* non-zero indicates success */
}
void
tool_finalize( ompt_data_t* tool_data )
{
printf( "[%s] Finalized tool.\n", __FUNCTION__ );
}
ompt_start_tool_result_t *
ompt_start_tool( unsigned int omp_version,
const char* runtime_version )
{
static ompt_start_tool_result_t result = { &tool_initialize, &tool_finalize, {} };
return &result;
}
/* USER CODE */
/* If the OMPT interface state is inactive, the OpenMP implementation returns
* omp_control_tool_notool. If the OMPT interface state is active, but no callback is
* registered for the tool-control event, the OpenMP implementation returns
* omp_control_tool_nocallback. An OpenMP implementation may return other
* implementation-defined negative values strictly smaller than -64; an application may assume that
* any negative return value indicates that a tool has not received the command. A return value of
* omp_control_tool_success indicates that the tool has performed the specified command. A
* return value of omp_control_tool_ignored indicates that the tool has ignored the specified
* command. A tool may return other positive values strictly greater than 64 that are tool-defined.*/
void
print_tool_status( int controlToolReturnVal )
{
switch( controlToolReturnVal )
{
case omp_control_tool_notool:
printf("Tried to control tool. Result = no tool\n");
break;
case omp_control_tool_nocallback:
printf("Tried to control tool. Result = no callback\n");
break;
case omp_control_tool_success:
printf("Tried to control tool. Result = success\n");
break;
case omp_control_tool_ignored:
printf("Tried to control tool. Result = ignored\n");
break;
}
}
int
main( void )
{
#ifdef TARGET_REGION
#pragma omp target teams num_teams( 2 )
{
printf( "Hello World from accelerator team %d\n", omp_get_team_num() );
}
#endif
#ifdef PARALLEL_REGION
#pragma omp parallel num_threads( 2 )
{
#pragma omp critical
printf( "Hello World from thread %d\n", omp_get_thread_num() );
}
#endif
print_tool_status( omp_control_tool( omp_control_tool_start, 1, NULL ) );
print_tool_status( omp_control_tool( omp_control_tool_flush, 2, NULL ) );
print_tool_status( omp_control_tool( omp_control_tool_pause, 3, NULL ) );
print_tool_status( omp_control_tool( omp_control_tool_end, 4, NULL ) );
return 0;
}
```
The program tries to call `omp_control_tool` with the four specified options. Additional ones can be defined by a tool. The user code prints the result of `omp_control_tool`, the tool prints which command was used. Via defines, one can enable a target region and a parallel region.
**Without any OpenMP directives**
With LLVM 18.1.8, I get these results:
```console
$ clang -fopenmp reproducer.c && ./a.out
[tool_initialize] Successfully initialized tool.
Tried to control tool. Result = no tool
Tried to control tool. Result = no tool
Tried to control tool. Result = no tool
Tried to control tool. Result = no tool
[tool_finalize] Finalized tool.
```
This is broken. Even though a tool was initialized, the user code never gets that information. Once the first parallel region was created we finally get the information that a tool is attached and working.
```c
int
main( void )
{
#ifdef TARGET_REGION
#pragma omp target teams num_teams( 2 )
{
printf( "Hello World from accelerator team %d\n", omp_get_team_num() );
}
#endif
#ifdef PARALLEL_REGION
#pragma omp parallel num_threads( 2 )
{
#pragma omp critical
printf( "Hello World from thread %d\n", omp_get_thread_num() );
}
#endif
print_tool_status( omp_control_tool( omp_control_tool_start, 1, NULL ) );
print_tool_status( omp_control_tool( omp_control_tool_flush, 2, NULL ) );
print_tool_status( omp_control_tool( omp_control_tool_pause, 3, NULL ) );
print_tool_status( omp_control_tool( omp_control_tool_end, 4, NULL ) );
#pragma omp parallel
{}
print_tool_status( omp_control_tool( omp_control_tool_end, 4, NULL ) );
return 0;
}
```
```console
[tool_initialize] Successfully initialized tool.
Tried to control tool. Result = no tool
Tried to control tool. Result = no tool
Tried to control tool. Result = no tool
Tried to control tool. Result = no tool
[callback_control_tool] command = 4 | modifier = 4 | arg = (nil) | codeptr_ra = 0x590ddad43468
Tried to control tool. Result = success
[tool_finalize] Finalized tool.
```
**With a parallel region before `omp_control_tool`**
```console
$ clang -fopenmp reproducer.c -DPARALLEL_REGION && ./a.out
[tool_initialize] Successfully initialized tool.
Hello World from thread 0
Hello World from thread 1
[callback_control_tool] command = 1 | modifier = 1 | arg = (nil) | codeptr_ra = 0x562a65200475
Tried to control tool. Result = success
[callback_control_tool] command = 3 | modifier = 2 | arg = (nil) | codeptr_ra = 0x562a6520048f
Tried to control tool. Result = success
[callback_control_tool] command = 2 | modifier = 3 | arg = (nil) | codeptr_ra = 0x562a652004a9
Tried to control tool. Result = success
[callback_control_tool] command = 4 | modifier = 4 | arg = (nil) | codeptr_ra = 0x562a652004c0
Tried to control tool. Result = success
[tool_finalize] Finalized tool.
```
A parallel region gives the results one would expect.
**With a target region before `omp_control_tool`**
```console
$ clang -fopenmp --offload-arch=sm_80 omp_control_tool_incorrect_value.c -DTARGET_REGION && ./a.out
[tool_initialize] Successfully initialized tool.
Hello World from accelerator team 1
Hello World from accelerator team 0
Tried to control tool. Result = no tool
Tried to control tool. Result = no tool
Tried to control tool. Result = no tool
Tried to control tool. Result = no tool
[tool_finalize] Finalized tool.
```
A target region is not sufficient for `omp_control_tool` to succeed. Similar to the first case, the first parallel region will cause the call to work correctly.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzkWltv27jy_zTKy8CCTd8f8uA6yW6BtClad_to0NLI4oYiBZJK1vvp_yBF3WwrTdLkf3pwjKJ1peHMbzh30lRrtheIl8H0QzC9uqCFSaW63KQHhRc7GR8uNynCXY7i0xdgwqBKaIQgkwSVBgqaZTlHSAoRGSYFGAmRzLJCsIgahEdmUqACqDE0SjEGIyUPyBoeUxalEFEBO4S_C22AiUSqjDoucZHlTOwtoaaCGfYvKuDsHmGlohQVSAU5KrdAROi46pLgWyQVDr4AFTFsVt9D-JEyjpBzemBiD1TJQsQlrmA2lFm-jaQwSvKtgzYbupXMaIhkYfXNqTKe1NS0XMp7S_sRhDQssoql1IBJEVQhDMsQMrZPDSg0hRLnRG2F9BKtmviAAkwqi30K1OkDj1RXO8MMo5z9i3EIm5RpyCgT_AA0STAy2lqDSxpb_SIptFGFfWr1iCjn9nGfqtppmjClDVBnwTAYXgXDVfn3pwMY1MZysGgKayJTCGqQH0BaCLEU3sq3t399gtEiHIWLEH7UT4wqxL3DQgWsPl3BH1--W4WNcvYw0m4YUHGonAz_oc6lHFOvGSSUcV17EyolFWSoNd1jCB8DMs9gVzDutqAEsgxHIQHljCDkoxVkVQG6p0xo01HzT1QYkHnLnxXmSsZFhCoYr9qk1lzuT-T_T8ZMRLyIEYLxWmZ5mAbj6553A-envRTaxEy233qam4CsYHN3dwvru6trCIh71iJhwpRfrLl3NLrvGposoGDCzCZbAwAuPqmIA7IuF3VeZjJmCUPVvD3_eZAstrDKD1X7ZoFzwZogkjHmRm0VhYAsPer5h4Z5SR6lVJXkDtxW0AyDcYus-aYfmYlSsGp56oazo2xzdxKoRjgJP22oMrV1K9qTxa0dc6AgGF9BQEgPP0I6qKvPTiG9P3kTzK-qPTsLMeGFTt8QYsnvTSHmtND4hhBLfm8KEUX8hgAtt1fCizGhBT_1ubOyP3-_vX2OlJp9Q5krJkxi48MinX4IyFQH06smWpxqU15AMF_XEX_0mKp99SR3D9qB7J8H07WwIs7liu325vvn9ebj3efttp0bjnJP6_Nk6jnKMJ2cUu1Fs4olrezg9_TJFOHL9GlQF1GEWnczUW3QJxayvZAK4wZb10x1xi6J6wJvYbtGo2qoXKdR5FsD5Zf-vMxE3SlsY3xgEW5FkfXTOzExNXRrmkRuPw6SfdGTsN1CjWZbVxsD7f9691icJQzIslJk4eOrSxMQ4o3azvnMu_OoK-i8Tb1Nhv1Wq6Uq1AU3W9un2S8OeheNV6Onsq6tol0CY1GR2dkFHXf1SlWSycgKr5FR_kgP-nluO3xVOvhW-nZScH5o95jOAcImtjuh3NWggTCyBvOtipBi8C8qCUzEbgzQ4OOo27t0obqGoYmJhIluRDSu-qSD9ml74_m9QL0jgKVpbJUvQ7z2HavUOQrXeAk3X8UuPG2WeEClmRT9cdnth6pxolp3TmVtqGER9OJr-XYwt1aanWSddf202fe187f5lfOpMyYPyKzk3Ldh3h2-f7v-2te5epKPiRud7j592bSGTKsXAtPAhJ1NHhwm0xpHbaueoTDl0FjC0lUgkNVpVi5HrvBn8hppu8JOD1BnHNZmr3DPtEGFMSRSOY6W_cCLdDOdeQPMlfQQVqKHT0YPdSkyKaoWwy7lIMaEWX8UuKdWS3igvLARahSLDD-AzijnaNWhAgaziQ1sO8HnObfBXEmjWhcZurG3JczOcTVnD8gJaOUCNyn7GTel2k7QoDBC9uDGaKzqdgirLguZPLVPVYo5ElRZxYnyZwZejs4xsh1H3JLYMW9Hdm-Nf1JiRdOR1xLS0tWtOTYk5FKzs3baK6SmstNs4rdVeR_0Zg7bIddkWJck67HFFNqmKpuhvH4bKflXh-IvynvagHIMK_uspxadLVznO3V_InKuP67TekDIRjGXxivBZUaHr02aE7I8aKqS_PIF_XoftLoleBN4Nbe3g1j3qr-Mr-L0dtjqdviXsVWcXoStKUw9bXhGmbCubEOkx98DMmZJjAlsVl__uN5sv17_8fHucx3K41zRfUat6mCo2qMBgzTTIIps675Z_uQncdHpXv5EziX8kIrHkCiZAY0i5KiosdUGaWaHsLjVydht36Nx4srmfxGQ5UnL1rTCARmjiFnSKcmnGn9ZfV3d3l7fdnUuKVpq51TZ0sFLlVOFNH6W0l0ukWKGRZS_ZGNKYb3b4d6-ekNq8ccJ8-RE9cyz6lhoDSP7l53q4RyE1wvwhzprIP0CXs_dn8esYfwe3N1hyhomT27NSeM5PNNwVseybcNtUoRcyb2iGRjFbH0uE2_fcbg7X7aVOpGFarUHMrdtjw5hFcfMfqUcpEBd3V9UPdXu4PuaEKzsQqNyZxXlDunyeqBMZTLpAVH1i64b8Ov8ZYk_vnEn8RrjEP5i1MvWzt8FOkQo6I6jhVLmIdunSlGewTdBWj4Nu924_fODmVQWpn0mHzOFrifWJUl70Y-jw3-L5CO4_JeirhTWvefoUmjJsQIwgYhTsYdBInMUWd46iQ8jO3IEZAZhQG5oKAufvIPph-OB5ufjbekhz-4kfj_ySut6YDsz5D4VG3au0rBT8h5FCNfn759a-1Y5ZuPVAh9QWUv7xrd1gxfCnbuXs7HkLpeO3M4xj1wHG8OjJRLU2sm7TecysD0v2OGsukp0sSDVPRP78LxrvXGRPylV_zV1vkTeV-rfo87_zkW-Zzfeuci_b4X_pRbiOUX-lwT8vM7_zNe6sdQy5f9DD_LCtqOntP2vFqnzJ-dH11GT06uoydE11EIw7kxzehc1_Ge6HMYxjSfjyWzxXKDVlPsG1bRpnE47LNhhIhX2tnvH_dTrOqPB1VHyfvNeqS8fD59-PXqZI4xOHWH0IkeYETqbkuFwMp--1hGeBXR8CpS8DugieVeg5BTo-HVA6fJdgf5yDqiBRsP_QA5YnQT-3g5MraFPuwntURY8Bvwnx8j0TF8no9t7pZDBwP_AakBVlAbjK51tF8Mzx3ciksqOgFt3Cu3yTadDfv9sc9ITj55L-Gxn-K3L6C95ZtebWHnnooskYRFDYdz1Vc-ZiJFlkGAcwjeWMU6V-y1dPdlFVNcXcz2zHuMcIttjltc7lFt93ewG3q_4wStwEV-O4-V4SS_wcjQnSzKbzhfkIr3EZZzE82hECJ2PdqMhTqe75W5G5rsZWSYLcsEuyZBMRsPRYjQdz8gwHM6HdDKP6YKMKV1MR8FkiBllPOT8IQul2l8wrQu8HI3IkkwuON0h1-53sIQIfAT31l0iX12oS7tosCv2OpgMOdNGN2wMM9z9gLY8LQmmV_b7py8ba6Z1uZ_uV5h-iH1gtG-3yx-N1uHG68ug6mZJYWk-x-miUPwyNSZ3pyvkJiA3e2bSYhdGMgvIjUXo_xnkSv6NkQnIjdNLB-TGK_5wSf4vAAD__8Ido6c">