| # |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| # |
| # A collection of useful Python GDB modules and commands for |
| # debugging Impala core dumps. |
| # |
| import gdb |
| from collections import defaultdict |
| |
| |
| def get_fragment_instances(): |
| # Walk the threadlist to find fragment instance ids. Assumes IMPALA-6416, so |
| # this will not work with releases older than Impala 2.12. It may be possible |
| # to search for FragmentInstanceState::Exec() in the older releases to get |
| # to the FInstIDs. Returns a dictionary of FInstID->[gdb thread ID]. |
| # Note that multiple threads might be doing tasks for the same FInstID. |
| |
| fragment_instances = defaultdict(list) |
| for thread in gdb.selected_inferior().threads(): |
| thread.switch() |
| |
| f = gdb.newest_frame() |
| while f: |
| # Skip unresolved frame |
| if gdb.Frame.name(f) is None: |
| f = gdb.Frame.older(f) |
| continue |
| if 'impala::Thread::SuperviseThread' in gdb.Frame.name(f): |
| gdb.Frame.select(f) |
| block = gdb.Frame.block(f) |
| gdb.lookup_symbol('thread_debug_info', block) |
| tdi = f.read_var('thread_debug_info') |
| # No valid thread_debug_info |
| if not tdi: |
| break |
| hi = long(tdi['instance_id_']['hi']) |
| lo = long(tdi['instance_id_']['lo']) |
| fi = "%lx:%lx" % (hi, lo) |
| if fi != "0:0": |
| fragment_instances[fi.strip('"')].append(thread.num) |
| break |
| f = gdb.Frame.older(f) |
| return fragment_instances |
| |
| |
| class FindFragmentInstances(gdb.Command): |
| """Find all query fragment instance to thread Id mappings in this impalad.""" |
| |
| def __init__(self): |
| super(FindFragmentInstances, self).__init__( |
| "find-fragment-instances", |
| gdb.COMMAND_SUPPORT, |
| gdb.COMPLETE_NONE, |
| False) |
| |
| def invoke(self, arg, from_tty): |
| fragment_instances = get_fragment_instances() |
| print('Fragment Instance Id\tThread IDs\n') |
| for fid in sorted(fragment_instances): |
| print("{}\t{}".format(fid, fragment_instances[fid])) |
| |
| |
| class FindQueryIds(gdb.Command): |
| """Find IDs of all queries this impalad is currently executing.""" |
| |
| def __init__(self): |
| super(FindQueryIds, self).__init__( |
| "find-query-ids", |
| gdb.COMMAND_SUPPORT, |
| gdb.COMPLETE_NONE, |
| False) |
| |
| def invoke(self, arg, from_tty): |
| fragment_instances = get_fragment_instances() |
| query_ids = set() |
| for fi in fragment_instances: |
| qid_hi, qid_low = fi.split(':') |
| qid_low = format(int(qid_low, 16) & 0xFFFFFFFFFFFF0000, 'x') |
| query_ids.add("{}:{}".format(qid_hi, qid_low)) |
| print('\n'.join(query_ids)) |
| |
| |
| # Instantiate the command classes so they can be invoked from within GDB |
| FindFragmentInstances() |
| FindQueryIds() |