1from __future__ import print_function 2import ompdModule 3from ompd_handles import ompd_thread, ompd_task, ompd_parallel 4import gdb 5import sys 6import traceback 7from enum import Enum 8 9class ompd_scope(Enum): 10 ompd_scope_global = 1 11 ompd_scope_address_space = 2 12 ompd_scope_thread = 3 13 ompd_scope_parallel = 4 14 ompd_scope_implicit_task = 5 15 ompd_scope_task = 6 16 17class ompd_address_space(object): 18 19 def __init__(self): 20 """Initializes an ompd_address_space object by calling ompd_initialize 21 in ompdModule.c 22 """ 23 self.addr_space = ompdModule.call_ompd_initialize() 24 # maps thread_num (thread id given by gdb) to ompd_thread object with thread handle 25 self.threads = {} 26 self.states = None 27 self.icv_map = None 28 self.ompd_tool_test_bp = None 29 self.scope_map = {1:'global', 2:'address_space', 3:'thread', 4:'parallel', 5:'implicit_task', 6:'task'} 30 self.sched_map = {1:'static', 2:'dynamic', 3:'guided', 4:'auto'} 31 gdb.events.stop.connect(self.handle_stop_event) 32 self.new_thread_breakpoint = gdb.Breakpoint("ompd_bp_thread_begin", internal=True) 33 tool_break_symbol = gdb.lookup_global_symbol("ompd_tool_break") 34 if (tool_break_symbol is not None): 35 self.ompd_tool_test_bp = gdb.Breakpoint("ompd_tool_break", internal=True) 36 37 def handle_stop_event(self, event): 38 """Sets a breakpoint at different events, e.g. when a new OpenMP 39 thread is created. 40 """ 41 if (isinstance(event, gdb.BreakpointEvent)): 42 # check if breakpoint has already been hit 43 if (self.new_thread_breakpoint in event.breakpoints): 44 self.add_thread() 45 gdb.execute('continue') 46 return 47 elif (self.ompd_tool_test_bp is not None and self.ompd_tool_test_bp in event.breakpoints): 48 try: 49 self.compare_ompt_data() 50 gdb.execute('continue') 51 except(): 52 traceback.print_exc() 53 elif (isinstance(event, gdb.SignalEvent)): 54 # TODO: what do we need to do on SIGNALS? 55 pass 56 else: 57 # TODO: probably not possible? 58 pass 59 60 def get_icv_map(self): 61 """Fills ICV map. 62 """ 63 self.icv_map = {} 64 current = 0 65 more = 1 66 while more > 0: 67 tup = ompdModule.call_ompd_enumerate_icvs(self.addr_space, current) 68 (current, next_icv, next_scope, more) = tup 69 self.icv_map[next_icv] = (current, next_scope, self.scope_map[next_scope]) 70 print('Initialized ICV map successfully for checking OMP API values.') 71 72 def compare_ompt_data(self): 73 """Compares OMPT tool data about parallel region to data returned by OMPD functions. 74 """ 75 # make sure all threads and states are set 76 self.list_threads(False) 77 78 thread_id = gdb.selected_thread().ptid[1] 79 curr_thread = self.get_curr_thread() 80 81 # check if current thread is LWP thread; return if "ompd_rc_unavailable" 82 thread_handle = ompdModule.get_thread_handle(thread_id, self.addr_space) 83 if thread_handle == -1: 84 print("Skipping OMPT-OMPD checks for non-LWP thread.") 85 return 86 87 print('Comparing OMPT data to OMPD data...') 88 field_names = [i.name for i in gdb.parse_and_eval('thread_data').type.fields()] 89 thread_data = gdb.parse_and_eval('thread_data') 90 91 if self.icv_map is None: 92 self.get_icv_map() 93 94 # compare state values 95 if 'ompt_state' in field_names: 96 if self.states is None: 97 self.enumerate_states() 98 ompt_state = str(thread_data['ompt_state']) 99 ompd_state = str(self.states[curr_thread.get_state()[0]]) 100 if ompt_state != ompd_state: 101 print('OMPT-OMPD mismatch: ompt_state (%s) does not match OMPD state (%s)!' % (ompt_state, ompd_state)) 102 103 # compare wait_id values 104 if 'ompt_wait_id' in field_names: 105 ompt_wait_id = thread_data['ompt_wait_id'] 106 ompd_wait_id = curr_thread.get_state()[1] 107 if ompt_wait_id != ompd_wait_id: 108 print('OMPT-OMPD mismatch: ompt_wait_id (%d) does not match OMPD wait id (%d)!' % (ompt_wait_id, ompd_wait_id)) 109 110 # compare thread id 111 if 'omp_thread_num' in field_names and 'thread-num-var' in self.icv_map: 112 ompt_thread_num = thread_data['omp_thread_num'] 113 icv_value = ompdModule.call_ompd_get_icv_from_scope(curr_thread.thread_handle, self.icv_map['thread-num-var'][1], self.icv_map['thread-num-var'][0]) 114 if ompt_thread_num != icv_value: 115 print('OMPT-OMPD mismatch: omp_thread_num (%d) does not match OMPD thread num according to ICVs (%d)!' % (ompt_thread_num, icv_value)) 116 117 # compare thread data 118 if 'ompt_thread_data' in field_names: 119 ompt_thread_data = thread_data['ompt_thread_data'].dereference()['value'] 120 ompd_value = ompdModule.call_ompd_get_tool_data(3, curr_thread.thread_handle)[0] 121 if ompt_thread_data != ompd_value: 122 print('OMPT-OMPD mismatch: value of ompt_thread_data (%d) does not match that of OMPD data union (%d)!' % (ompt_thread_data, ompd_value)) 123 124 # compare number of threads 125 if 'omp_num_threads' in field_names and 'team-size-var' in self.icv_map: 126 ompt_num_threads = thread_data['omp_num_threads'] 127 icv_value = ompdModule.call_ompd_get_icv_from_scope(curr_thread.get_current_parallel_handle(), self.icv_map['team-size-var'][1], self.icv_map['team-size-var'][0]) 128 if ompt_num_threads != icv_value: 129 print('OMPT-OMPD mismatch: omp_num_threads (%d) does not match OMPD num threads according to ICVs (%d)!' % (ompt_num_threads, icv_value)) 130 131 # compare omp level 132 if 'omp_level' in field_names and 'levels-var' in self.icv_map: 133 ompt_levels = thread_data['omp_level'] 134 icv_value = ompdModule.call_ompd_get_icv_from_scope(curr_thread.get_current_parallel_handle(), self.icv_map['levels-var'][1], self.icv_map['levels-var'][0]) 135 if ompt_levels != icv_value: 136 print('OMPT-OMPD mismatch: omp_level (%d) does not match OMPD levels according to ICVs (%d)!' % (ompt_levels, icv_value)) 137 138 # compare active level 139 if 'omp_active_level' in field_names and 'active-levels-var' in self.icv_map: 140 ompt_active_levels = thread_data['omp_active_level'] 141 icv_value = ompdModule.call_ompd_get_icv_from_scope(curr_thread.get_current_parallel_handle(), self.icv_map['active-levels-var'][1], self.icv_map['active-levels-var'][0]) 142 if ompt_active_levels != icv_value: 143 print('OMPT-OMPD mismatch: active levels (%d) do not match active levels according to ICVs (%d)!' % (ompt_active_levels, icv_value)) 144 145 # compare parallel data 146 if 'ompt_parallel_data' in field_names: 147 ompt_parallel_data = thread_data['ompt_parallel_data'].dereference()['value'] 148 current_parallel_handle = curr_thread.get_current_parallel_handle() 149 ompd_value = ompdModule.call_ompd_get_tool_data(4, current_parallel_handle)[0] 150 if ompt_parallel_data != ompd_value: 151 print('OMPT-OMPD mismatch: value of ompt_parallel_data (%d) does not match that of OMPD data union (%d)!' % (ompt_parallel_data, ompd_value)) 152 153 # compare max threads 154 if 'omp_max_threads' in field_names and 'nthreads-var' in self.icv_map: 155 ompt_max_threads = thread_data['omp_max_threads'] 156 icv_value = ompdModule.call_ompd_get_icv_from_scope(curr_thread.thread_handle, self.icv_map['nthreads-var'][1], self.icv_map['nthreads-var'][0]) 157 if icv_value is None: 158 icv_string = ompdModule.call_ompd_get_icv_string_from_scope(curr_thread.thread_handle, self.icv_map['nthreads-var'][1], self.icv_map['nthreads-var'][0]) 159 if icv_string is None: 160 print('OMPT-OMPD mismatch: omp_max_threads (%d) does not match OMPD thread limit according to ICVs (None Object)' % (ompt_max_threads)) 161 else: 162 if ompt_max_threads != int(icv_string.split(',')[0]): 163 print('OMPT-OMPD mismatch: omp_max_threads (%d) does not match OMPD thread limit according to ICVs (%d)!' % (ompt_max_threads, int(icv_string.split(',')[0]))) 164 else: 165 if ompt_max_threads != icv_value: 166 print('OMPT-OMPD mismatch: omp_max_threads (%d) does not match OMPD thread limit according to ICVs (%d)!' % (ompt_max_threads, icv_value)) 167 168 # compare omp_parallel 169 # NOTE: omp_parallel = true if active-levels-var > 0 170 if 'omp_parallel' in field_names: 171 ompt_parallel = thread_data['omp_parallel'] 172 icv_value = ompdModule.call_ompd_get_icv_from_scope(curr_thread.get_current_parallel_handle(), self.icv_map['active-levels-var'][1], self.icv_map['active-levels-var'][0]) 173 if ompt_parallel == 1 and icv_value <= 0 or ompt_parallel == 0 and icv_value > 0: 174 print('OMPT-OMPD mismatch: ompt_parallel (%d) does not match OMPD parallel according to ICVs (%d)!' % (ompt_parallel, icv_value)) 175 176 # compare omp_final 177 if 'omp_final' in field_names and 'final-task-var' in self.icv_map: 178 ompt_final = thread_data['omp_final'] 179 current_task_handle = curr_thread.get_current_task_handle() 180 icv_value = ompdModule.call_ompd_get_icv_from_scope(current_task_handle, self.icv_map['final-task-var'][1], self.icv_map['final-task-var'][0]) 181 if icv_value != ompt_final: 182 print('OMPT-OMPD mismatch: omp_final (%d) does not match OMPD final according to ICVs (%d)!' % (ompt_final, icv_value)) 183 184 # compare omp_dynamic 185 if 'omp_dynamic' in field_names and 'dyn-var' in self.icv_map: 186 ompt_dynamic = thread_data['omp_dynamic'] 187 icv_value = ompdModule.call_ompd_get_icv_from_scope(curr_thread.thread_handle, self.icv_map['dyn-var'][1], self.icv_map['dyn-var'][0]) 188 if icv_value != ompt_dynamic: 189 print('OMPT-OMPD mismatch: omp_dynamic (%d) does not match OMPD dynamic according to ICVs (%d)!' % (ompt_dynamic, icv_value)) 190 191 # compare omp_max_active_levels 192 if 'omp_max_active_levels' in field_names and 'max-active-levels-var' in self.icv_map: 193 ompt_max_active_levels = thread_data['omp_max_active_levels'] 194 icv_value = ompdModule.call_ompd_get_icv_from_scope(curr_thread.get_current_task_handle(), self.icv_map['max-active-levels-var'][1], self.icv_map['max-active-levels-var'][0]) 195 if ompt_max_active_levels != icv_value: 196 print('OMPT-OMPD mismatch: omp_max_active_levels (%d) does not match OMPD max active levels (%d)!' % (ompt_max_active_levels, icv_value)) 197 198 # compare omp_kind: TODO: Add the test for monotonic/nonmonotonic modifier 199 if 'omp_kind' in field_names and 'run-sched-var' in self.icv_map: 200 ompt_sched_kind = thread_data['omp_kind'] 201 icv_value = ompdModule.call_ompd_get_icv_string_from_scope(curr_thread.get_current_task_handle(), self.icv_map['run-sched-var'][1], self.icv_map['run-sched-var'][0]) 202 ompd_sched_kind = icv_value.split(',')[0] 203 if self.sched_map.get(int(ompt_sched_kind)) != ompd_sched_kind: 204 print('OMPT-OMPD mismatch: omp_kind kind (%s) does not match OMPD schedule kind according to ICVs (%s)!' % (self.sched_map.get(int(ompt_sched_kind)), ompd_sched_kind)) 205 206 # compare omp_modifier 207 if 'omp_modifier' in field_names and 'run-sched-var' in self.icv_map: 208 ompt_sched_mod = thread_data['omp_modifier'] 209 icv_value = ompdModule.call_ompd_get_icv_string_from_scope(curr_thread.get_current_task_handle(), self.icv_map['run-sched-var'][1], self.icv_map['run-sched-var'][0]) 210 token = icv_value.split(',')[1] 211 if token is not None: 212 ompd_sched_mod = int(token) 213 else: 214 ompd_sched_mod = 0 215 if ompt_sched_mod != ompd_sched_mod: 216 print('OMPT-OMPD mismatch: omp_kind modifier does not match OMPD schedule modifier according to ICVs!') 217 218 # compare omp_proc_bind 219 if 'omp_proc_bind' in field_names and 'bind-var' in self.icv_map: 220 ompt_proc_bind = thread_data['omp_proc_bind'] 221 icv_value = ompdModule.call_ompd_get_icv_from_scope(curr_thread.get_current_task_handle(), self.icv_map['bind-var'][1], self.icv_map['bind-var'][0]) 222 if icv_value is None: 223 icv_string = ompdModule.call_ompd_get_icv_string_from_scope(curr_thread.get_current_task_handle(), self.icv_map['bind-var'][1], self.icv_map['bind-var'][0]) 224 if icv_string is None: 225 print('OMPT-OMPD mismatch: omp_proc_bind (%d) does not match OMPD proc bind according to ICVs (None Object)' % (ompt_proc_bind)) 226 else: 227 if ompt_proc_bind != int(icv_string.split(',')[0]): 228 print('OMPT-OMPD mismatch: omp_proc_bind (%d) does not match OMPD proc bind according to ICVs (%d)!' % (ompt_proc_bind, int(icv_string.split(',')[0]))) 229 else: 230 if ompt_proc_bind != icv_value: 231 print('OMPT-OMPD mismatch: omp_proc_bind (%d) does not match OMPD proc bind according to ICVs (%d)!' % (ompt_proc_bind, icv_value)) 232 233 # compare enter and exit frames 234 if 'ompt_frame_list' in field_names: 235 ompt_task_frame_dict = thread_data['ompt_frame_list'].dereference() 236 ompt_task_frames = (int(ompt_task_frame_dict['enter_frame'].cast(gdb.lookup_type('long'))), int(ompt_task_frame_dict['exit_frame'].cast(gdb.lookup_type('long')))) 237 current_task = curr_thread.get_current_task() 238 ompd_task_frames = current_task.get_task_frame() 239 if ompt_task_frames != ompd_task_frames: 240 print('OMPT-OMPD mismatch: ompt_task_frames (%s) do not match OMPD task frames (%s)!' % (ompt_task_frames, ompd_task_frames)) 241 242 # compare task data 243 if 'ompt_task_data' in field_names: 244 ompt_task_data = thread_data['ompt_task_data'].dereference()['value'] 245 current_task_handle = curr_thread.get_current_task_handle() 246 ompd_value = ompdModule.call_ompd_get_tool_data(6, current_task_handle)[0] 247 if ompt_task_data != ompd_value: 248 print('OMPT-OMPD mismatch: value of ompt_task_data (%d) does not match that of OMPD data union (%d)!' % (ompt_task_data, ompd_value)) 249 250 def save_thread_object(self, thread_num, thread_id, addr_space): 251 """Saves thread object for thread_num inside threads dictionary. 252 """ 253 thread_handle = ompdModule.get_thread_handle(thread_id, addr_space) 254 self.threads[int(thread_num)] = ompd_thread(thread_handle) 255 256 def get_thread(self, thread_num): 257 """ Get thread object from map. 258 """ 259 return self.threads[int(thread_num)] 260 261 def get_curr_thread(self): 262 """ Get current thread object from map or add new one to map, if missing. 263 """ 264 thread_num = int(gdb.selected_thread().num) 265 if thread_num not in self.threads: 266 self.add_thread() 267 return self.threads[thread_num] 268 269 def add_thread(self): 270 """Add currently selected (*) thread to dictionary threads. 271 """ 272 inf_thread = gdb.selected_thread() 273 try: 274 self.save_thread_object(inf_thread.num, inf_thread.ptid[1], self.addr_space) 275 except: 276 traceback.print_exc() 277 278 def list_threads(self, verbose): 279 """Prints OpenMP threads only that are being tracking inside the "threads" dictionary. 280 See handle_stop_event and add_thread. 281 """ 282 list_tids = [] 283 curr_inferior = gdb.selected_inferior() 284 285 for inf_thread in curr_inferior.threads(): 286 list_tids.append((inf_thread.num, inf_thread.ptid)) 287 if verbose: 288 if self.states is None: 289 self.enumerate_states() 290 for (thread_num, thread_ptid) in sorted(list_tids): 291 if thread_num in self.threads: 292 try: 293 print('Thread %i (%i) is an OpenMP thread; state: %s' % (thread_num, thread_ptid[1], self.states[self.threads[thread_num].get_state()[0]])) 294 except: 295 traceback.print_exc() 296 else: 297 print('Thread %i (%i) is no OpenMP thread' % (thread_num, thread_ptid[1])) 298 299 def enumerate_states(self): 300 """Helper function for list_threads: initializes map of OMPD states for output of 301 'ompd threads'. 302 """ 303 if self.states is None: 304 self.states = {} 305 current = int("0x102", 0) 306 count = 0 307 more = 1 308 309 while more > 0: 310 tup = ompdModule.call_ompd_enumerate_states(self.addr_space, current) 311 (next_state, next_state_name, more) = tup 312 313 self.states[next_state] = next_state_name 314 current = next_state 315