aboutsummaryrefslogtreecommitdiff
path: root/openmp/libompd/gdb-plugin/ompd/frame_filter.py
blob: 0b049bdabd13fa1ded81da0e561d0c156fb210c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
import gdb
import ompdModule
import itertools
from gdb.FrameDecorator import FrameDecorator
import ompd
from ompd_handles import ompd_task, ompd_parallel, ompd_thread
import traceback
from tempfile import NamedTemporaryFile


class OmpdFrameDecorator(FrameDecorator):
    def __init__(self, fobj, curr_task_handle):
        """Initializes a FrameDecorator with the given GDB Frame object. The global OMPD address space defined in
        ompd.py is set as well.
        """
        super(OmpdFrameDecorator, self).__init__(fobj)
        self.addr_space = ompd.addr_space
        self.fobj = None
        if isinstance(fobj, gdb.Frame):
            self.fobj = fobj
        elif isinstance(fobj, FrameDecorator):
            self.fobj = fobj.inferior_frame()
        self.curr_task_handle = curr_task_handle

    def function(self):
        """This appends the name of a frame that is printed with the information whether the task started in the frame
        is implicit or explicit. The ICVs are evaluated to determine that.
        """
        name = str(self.fobj.name())

        if self.curr_task_handle is None:
            return name

        icv_value = ompdModule.call_ompd_get_icv_from_scope(
            self.curr_task_handle,
            ompd.icv_map["implicit-task-var"][1],
            ompd.icv_map["implicit-task-var"][0],
        )
        if icv_value == 0:
            name = '@thread %i: %s "#pragma omp task"' % (
                gdb.selected_thread().num,
                name,
            )
        elif icv_value == 1:
            name = '@thread %i: %s "#pragma omp parallel"' % (
                gdb.selected_thread().num,
                name,
            )
        else:
            name = "@thread %i: %s" % (gdb.selected_thread().num, name)
        return name


class OmpdFrameDecoratorThread(FrameDecorator):
    def __init__(self, fobj):
        """Initializes a FrameDecorator with the given GDB Frame object."""
        super(OmpdFrameDecoratorThread, self).__init__(fobj)
        if isinstance(fobj, gdb.Frame):
            self.fobj = fobj
        elif isinstance(fobj, FrameDecorator):
            self.fobj = fobj.inferior_frame()

    def function(self):
        name = str(self.fobj.name())
        return "@thread %i: %s" % (gdb.selected_thread().num, name)


class FrameFilter:
    def __init__(self, addr_space):
        """Initializes the FrameFilter, registers is in the GDB runtime and saves the given OMPD address space capsule."""
        self.addr_space = addr_space
        self.name = "Filter"
        self.priority = 100
        self.enabled = True
        gdb.frame_filters[self.name] = self
        self.switched_on = False
        self.continue_to_master = False

    def set_switch(self, on_off):
        """Prints output when executing 'ompd bt on' or 'ompd bt off'."""
        self.switched_on = on_off
        if self.switched_on:
            print('Enabled filter for "bt" output successfully.')
        else:
            print('Disabled filter for "bt" output successfully.')

    def set_switch_continue(self, on_off):
        """Prints output when executing 'ompd bt on continued'." """
        self.continue_to_master = on_off
        if self.continue_to_master:
            print(
                'Enabled "bt" mode that continues backtrace on to master thread for worker threads.'
            )
        else:
            print('Disabled "bt" mode that continues onto master thread.')

    def get_master_frames_for_worker(self, past_thread_num, latest_sp):
        """Prints master frames for worker thread with id past_thread_num."""
        gdb.execute("t 1")
        gdb.execute("ompd bt on")
        gdb.execute("bt")

        frame = gdb.newest_frame()

        while frame.older() is not None:
            print("master frame sp:", str(frame.read_register("sp")))
            yield OmpdFrameDecorator(frame)
            frame = frame.older()
        print("latest sp:", str(latest_sp))

        gdb.execute("ompd bt on continued")
        gdb.execute("t %d" % int(past_thread_num))

    def filter_frames(self, frame_iter):
        """Iterates through frames and only returns those that are relevant to the application
        being debugged. The OmpdFrameDecorator is applied automatically.
        """
        curr_thread_num = gdb.selected_thread().num
        is_no_omp_thread = False
        if curr_thread_num in self.addr_space.threads:
            curr_thread_obj = self.addr_space.threads[curr_thread_num]
            self.curr_task = curr_thread_obj.get_current_task()
            self.frames = self.curr_task.get_task_frame()
        else:
            is_no_omp_thread = True
            print(
                "Thread %d is no OpenMP thread, printing all frames:" % curr_thread_num
            )

        stop_iter = False
        for x in frame_iter:
            if is_no_omp_thread:
                yield OmpdFrameDecoratorThread(x)
                continue

            if x.inferior_frame().older() is None:
                continue
            if self.curr_task.task_handle is None:
                continue

            gdb_sp = int(str(x.inferior_frame().read_register("sp")), 16)
            gdb_sp_next_new = int(
                str(x.inferior_frame()).split(",")[0].split("=")[1], 16
            )
            if x.inferior_frame().older():
                gdb_sp_next = int(
                    str(x.inferior_frame().older().read_register("sp")), 16
                )
            else:
                gdb_sp_next = int(str(x.inferior_frame().read_register("sp")), 16)
            while 1:
                (ompd_enter_frame, ompd_exit_frame) = self.frames

                if ompd_enter_frame != 0 and gdb_sp_next_new < ompd_enter_frame:
                    break
                if ompd_exit_frame != 0 and gdb_sp_next_new < ompd_exit_frame:
                    if (
                        x.inferior_frame().older().older()
                        and int(
                            str(x.inferior_frame().older().older().read_register("sp")),
                            16,
                        )
                        < ompd_exit_frame
                    ):
                        if self.continue_to_master:
                            yield OmpdFrameDecoratorThread(x)
                        else:
                            yield OmpdFrameDecorator(x, self.curr_task.task_handle)
                    else:
                        yield OmpdFrameDecorator(x, self.curr_task.task_handle)
                    break
                sched_task_handle = self.curr_task.get_scheduling_task_handle()

                if sched_task_handle is None:
                    stop_iter = True
                    break

                self.curr_task = self.curr_task.get_scheduling_task()
                self.frames = self.curr_task.get_task_frame()
            if stop_iter:
                break

        # implementation of "ompd bt continued"
        if self.continue_to_master:

            orig_thread = gdb.selected_thread().num
            gdb_threads = dict([(t.num, t) for t in gdb.selected_inferior().threads()])

            # iterate through generating tasks until outermost task is reached
            while 1:
                # get OMPD thread id for master thread (systag in GDB output)
                try:
                    master_num = (
                        self.curr_task.get_task_parallel()
                        .get_thread_in_parallel(0)
                        .get_thread_id()
                    )
                except:
                    break
                # search for thread id without the "l" for long via "thread find" and get GDB thread num from output
                hex_str = str(hex(master_num))
                thread_output = gdb.execute(
                    "thread find %s" % hex_str[0 : len(hex_str) - 1], to_string=True
                ).split(" ")
                if thread_output[0] == "No":
                    raise ValueError("Master thread num could not be found!")
                gdb_master_num = int(thread_output[1])
                # get task that generated last task of worker thread
                try:
                    self.curr_task = (
                        self.curr_task.get_task_parallel()
                        .get_task_in_parallel(0)
                        .get_generating_task()
                    )
                except:
                    break
                self.frames = self.curr_task.get_task_frame()
                (enter_frame, exit_frame) = self.frames
                if exit_frame == 0:
                    print("outermost generating task was reached")
                    break

                # save GDB num for worker thread to change back to it later
                worker_thread = gdb.selected_thread().num

                # use InferiorThread.switch()
                gdb_threads = dict(
                    [(t.num, t) for t in gdb.selected_inferior().threads()]
                )
                gdb_threads[gdb_master_num].switch()
                print("#### switching to thread %i ####" % gdb_master_num)

                frame = gdb.newest_frame()
                stop_iter = False

                while not stop_iter:
                    if self.curr_task.task_handle is None:
                        break
                    self.frames = self.curr_task.get_task_frame()

                    while frame:
                        if self.curr_task.task_handle is None:
                            break

                        gdb_sp_next_new = int(
                            str(frame).split(",")[0].split("=")[1], 16
                        )

                        if frame.older():
                            gdb_sp_next = int(
                                str(frame.older().read_register("sp")), 16
                            )
                        else:
                            gdb_sp_next = int(str(frame.read_register("sp")), 16)

                        while 1:
                            (ompd_enter_frame, ompd_exit_frame) = self.frames

                            if (
                                ompd_enter_frame != 0
                                and gdb_sp_next_new < ompd_enter_frame
                            ):
                                break
                            if (
                                ompd_exit_frame == 0
                                or gdb_sp_next_new < ompd_exit_frame
                            ):
                                if (
                                    ompd_exit_frame == 0
                                    or frame.older()
                                    and frame.older().older()
                                    and int(
                                        str(frame.older().older().read_register("sp")),
                                        16,
                                    )
                                    < ompd_exit_frame
                                ):
                                    yield OmpdFrameDecoratorThread(frame)
                                else:
                                    yield OmpdFrameDecorator(
                                        frame, self.curr_task.task_handle
                                    )
                                break
                            sched_task_handle = (
                                ompdModule.call_ompd_get_scheduling_task_handle(
                                    self.curr_task.task_handle
                                )
                            )

                            if sched_task_handle is None:
                                stop_iter = True
                                break
                            self.curr_task = self.curr_task.get_generating_task()
                            self.frames = self.curr_task.get_task_frame()

                        frame = frame.older()
                    break

                gdb_threads[worker_thread].switch()

            gdb_threads[orig_thread].switch()

    def filter(self, frame_iter):
        """Function is called automatically with every 'bt' executed. If switched on, this will only let revelant frames be printed
        or all frames otherwise. If switched on, a FrameDecorator will be applied to state whether '.ompd_task_entry.' refers to an
        explicit or implicit task.
        """
        if self.switched_on:
            return self.filter_frames(frame_iter)
        else:
            return frame_iter