Line data Source code
1 : /*----------------------------------------------------------------------------*/
2 : /* CP2K: A general program to perform molecular dynamics simulations */
3 : /* Copyright 2000-2024 CP2K developers group <https://cp2k.org> */
4 : /* */
5 : /* SPDX-License-Identifier: GPL-2.0-or-later */
6 : /*----------------------------------------------------------------------------*/
7 : #define OPENMP_TRACE_DISABLED ((unsigned int)-1)
8 :
9 : /* routine is exposed in Fortran, hence must be present */
10 : int openmp_trace_issues(void);
11 :
12 : /**
13 : * Simple compile-time check if OMPT is available (omp/iomp, not gomp).
14 : * __clang__: omp and iomp/icx, __INTEL_COMPILER: iomp/icc
15 : * __INTEL_LLVM_COMPILER: already covered by __clang__
16 : */
17 : #if defined(_OPENMP) && (defined(__clang__) || defined(__INTEL_COMPILER))
18 :
19 : #include <assert.h>
20 : #include <omp-tools.h>
21 : #include <stdio.h>
22 : #include <stdlib.h>
23 : #include <string.h>
24 :
25 : #if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(OPENMP_TRACE_SYMBOL)
26 : #define OPENMP_TRACE_SYMBOL
27 : #include <execinfo.h>
28 : #include <unistd.h>
29 : #endif
30 :
31 : #define OPENMP_TRACE_UNUSED(VAR) (void)VAR
32 :
33 : #define OPENMP_TRACE_SET_CALLBACK(PREFIX, NAME) \
34 : if (ompt_set_never == \
35 : set_callback(ompt_callback_##NAME, (ompt_callback_t)PREFIX##_##NAME)) { \
36 : ++openmp_trace_issues_count; \
37 : }
38 :
39 : static unsigned int openmp_trace_level;
40 : static unsigned int openmp_trace_issues_count;
41 : static unsigned int openmp_trace_parallel_count;
42 : static unsigned int openmp_trace_parallel_count_max;
43 :
44 : static const void *openmp_trace_parallel_nested_codeptr;
45 : static const void *openmp_trace_master_codeptr;
46 :
47 : int openmp_trace_issues(void) { return (int)openmp_trace_issues_count; }
48 :
49 : /* attempt to translate symbol/address to character string */
50 : static void openmp_trace_symbol(const void *symbol, char *buffer, size_t size,
51 : int cleanup) {
52 : #if !defined(OPENMP_TRACE_SYMBOL)
53 : OPENMP_TRACE_UNUSED(symbol);
54 : if (0 < size) {
55 : buffer[0] = '\0';
56 : }
57 : #else
58 : int pipefd[2];
59 : if (NULL != symbol && NULL != buffer && 0 < size && 0 == pipe(pipefd)) {
60 : void *const backtrace[] = {(void *)symbol};
61 : backtrace_symbols_fd(backtrace, 1, pipefd[1]);
62 : close(pipefd[1]);
63 : if (0 < read(pipefd[0], buffer, size)) {
64 : if (0 != cleanup) {
65 : char *const str = (char *)memchr(buffer, '(', size);
66 : if (NULL != str) {
67 : char *const end = (char *)memchr(str + 1, '+', size - (str - buffer));
68 : if (NULL != end) {
69 : *end = '\0';
70 : memmove(buffer, str + 1, end - str);
71 : }
72 : }
73 : } else {
74 : char *const str = (char *)memchr(buffer, '\n', size);
75 : if (NULL != str) {
76 : *str = '\0';
77 : }
78 : }
79 : } else {
80 : buffer[0] = '\0';
81 : }
82 : close(pipefd[0]);
83 : }
84 : #endif
85 : }
86 :
87 : /* https://www.openmp.org/spec-html/5.0/openmpsu187.html */
88 : static void openmp_trace_parallel_begin(
89 : ompt_data_t *encountering_task_data,
90 : const ompt_frame_t *encountering_task_frame, ompt_data_t *parallel_data,
91 : unsigned int requested_parallelism, int flags, const void *codeptr_ra) {
92 : OPENMP_TRACE_UNUSED(encountering_task_data);
93 : OPENMP_TRACE_UNUSED(encountering_task_frame);
94 : OPENMP_TRACE_UNUSED(parallel_data);
95 : OPENMP_TRACE_UNUSED(requested_parallelism);
96 : OPENMP_TRACE_UNUSED(flags);
97 : ++openmp_trace_parallel_count;
98 : if (openmp_trace_parallel_count_max < openmp_trace_parallel_count) {
99 : openmp_trace_parallel_count_max = openmp_trace_parallel_count;
100 : openmp_trace_parallel_nested_codeptr = codeptr_ra;
101 : }
102 : if (NULL != openmp_trace_master_codeptr) {
103 : ++openmp_trace_issues_count;
104 : if (2 <= openmp_trace_level || 0 > openmp_trace_level) {
105 : char sym_master[1024], sym_parallel[1024];
106 : openmp_trace_symbol(openmp_trace_master_codeptr, sym_master,
107 : sizeof(sym_master), 1 /*cleanup*/);
108 : openmp_trace_symbol(codeptr_ra, sym_parallel, sizeof(sym_parallel),
109 : 1 /*cleanup*/);
110 : if ('\0' != *sym_master && '\0' != *sym_parallel) {
111 : fprintf(stderr,
112 : "OMP TRACE ERROR: parallel region \"%s\""
113 : " opened in master section \"%s\"\n",
114 : sym_parallel, sym_master);
115 : } else {
116 : fprintf(stderr,
117 : "OMP TRACE ERROR: parallel region opened in master section\n");
118 : }
119 : } else {
120 : assert(0);
121 : }
122 : }
123 : }
124 :
125 : /* https://www.openmp.org/spec-html/5.0/openmpsu187.html */
126 : static void openmp_trace_parallel_end(ompt_data_t *parallel_data,
127 : ompt_data_t *encountering_task_data,
128 : int flags, const void *codeptr_ra) {
129 : OPENMP_TRACE_UNUSED(parallel_data);
130 : OPENMP_TRACE_UNUSED(encountering_task_data);
131 : OPENMP_TRACE_UNUSED(flags);
132 : OPENMP_TRACE_UNUSED(codeptr_ra);
133 : if (0 < openmp_trace_parallel_count) {
134 : --openmp_trace_parallel_count;
135 : }
136 : }
137 :
138 : /* https://www.openmp.org/spec-html/5.0/openmpsu187.html */
139 : static void openmp_trace_master(ompt_scope_endpoint_t endpoint,
140 : ompt_data_t *parallel_data,
141 : ompt_data_t *task_data,
142 : const void *codeptr_ra) {
143 : OPENMP_TRACE_UNUSED(parallel_data);
144 : OPENMP_TRACE_UNUSED(task_data);
145 : switch (endpoint) {
146 : case ompt_scope_begin: {
147 : openmp_trace_master_codeptr = codeptr_ra;
148 : } break;
149 : case ompt_scope_end: {
150 : openmp_trace_master_codeptr = NULL;
151 : } break;
152 : default:; /* ompt_scope_beginend */
153 : }
154 : }
155 :
156 : /* initially, events of interest are registered */
157 : static int openmp_trace_initialize(ompt_function_lookup_t lookup,
158 : int initial_device_num,
159 : ompt_data_t *tool_data) {
160 : const ompt_set_callback_t set_callback =
161 : (ompt_set_callback_t)lookup("ompt_set_callback");
162 : OPENMP_TRACE_UNUSED(initial_device_num);
163 : OPENMP_TRACE_UNUSED(tool_data);
164 : OPENMP_TRACE_SET_CALLBACK(openmp_trace, parallel_begin);
165 : OPENMP_TRACE_SET_CALLBACK(openmp_trace, parallel_end);
166 : OPENMP_TRACE_SET_CALLBACK(openmp_trace, master);
167 : return 0 == openmp_trace_issues();
168 : }
169 :
170 : /* here tool_data might be freed and analysis concludes */
171 : static void openmp_trace_finalize(ompt_data_t *tool_data) {
172 : OPENMP_TRACE_UNUSED(tool_data);
173 : if (3 <= openmp_trace_level || 0 > openmp_trace_level) {
174 : if (1 < openmp_trace_parallel_count_max) { /* nested */
175 : char sym_parallel[1024];
176 : openmp_trace_symbol(openmp_trace_parallel_nested_codeptr, sym_parallel,
177 : sizeof(sym_parallel), 1 /*cleanup*/);
178 : if ('\0' != *sym_parallel) {
179 : fprintf(stderr,
180 : "OMP TRACE INFO: maximal nested parallelism "
181 : "in \"%s\" has depth %u\n",
182 : sym_parallel, openmp_trace_parallel_count_max);
183 : } else {
184 : fprintf(stderr,
185 : "OMP TRACE INFO: maximal nested parallelism has depth %u\n",
186 : openmp_trace_parallel_count_max);
187 : }
188 : }
189 : }
190 : }
191 :
192 : /* entry point which is automatically called by the OpenMP runtime */
193 : ompt_start_tool_result_t *ompt_start_tool(unsigned int omp_version,
194 : const char *runtime_version) {
195 : static ompt_start_tool_result_t openmp_start_tool = {
196 : openmp_trace_initialize, openmp_trace_finalize, {0}};
197 : const char *const enabled_env = getenv("CP2K_OMP_TRACE");
198 : ompt_start_tool_result_t *result = NULL;
199 : openmp_trace_level = (NULL == enabled_env ? 0 : atoi(enabled_env));
200 : OPENMP_TRACE_UNUSED(omp_version);
201 : OPENMP_TRACE_UNUSED(runtime_version);
202 : if (0 == openmp_trace_level) { /* not enabled */
203 : openmp_trace_issues_count = OPENMP_TRACE_DISABLED;
204 : assert(NULL == result);
205 : } else { /* trace OpenMP constructs */
206 : assert(0 == openmp_trace_issues_count);
207 : result = &openmp_start_tool;
208 : }
209 : return result;
210 : }
211 :
212 : #else
213 :
214 9334 : int openmp_trace_issues(void) { return OPENMP_TRACE_DISABLED; }
215 :
216 : #endif
|