Last active
May 26, 2017 19:26
-
-
Save ddurst/fd9ecb8a51372264f9aef7238d2f18d4 to your computer and use it in GitHub Desktop.
pingsig
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "raw", | |
"metadata": {}, | |
"source": [ | |
"---\n", | |
"title: Top Crashers list from client-side stacks\n", | |
"authors:\n", | |
"- Adam Gashlin \n", | |
"- David Durst\n", | |
"tags:\n", | |
"- crash\n", | |
"- client-side\n", | |
"- signature\n", | |
"created_at: 2017-05-10\n", | |
"updated_at: 2017-05-25\n", | |
"tldr: This queries crash pings from a specified day, symbolicates then to assign signatures, and then makes a top crasher list for that day.\n", | |
"---" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# Top crash ping signatures, by day" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 11, | |
"metadata": { | |
"collapsed": false, | |
"scrolled": true | |
}, | |
"outputs": [], | |
"source": [ | |
"# This Source Code Form is subject to the terms of the Mozilla Public\n", | |
"# License, v. 2.0. If a copy of the MPL was not distributed with this\n", | |
"# file, You can obtain one at http://mozilla.org/MPL/2.0/.\n", | |
"\n", | |
"from moztelemetry import get_pings_properties\n", | |
"from moztelemetry import Dataset\n", | |
"\n", | |
"import json\n", | |
"import requests\n", | |
"import re\n", | |
"from itertools import islice" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Ping processing" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 12, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"SYMBOLICATION_API_URL = 'http://symbolapi.mozilla.org/'\n", | |
"\n", | |
"COLLAPSE_ARGUMENTS = True\n", | |
"ESCAPE_SINGLE_QUOTE = True\n", | |
"MAXIMUM_FRAMES_TO_CONSIDER = 40\n", | |
"SIGNATURE_MAX_LEN = 255\n", | |
"\n", | |
"TWO_WEEKS = 14\n", | |
"SIX_WEEKS = 42" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Symbolication" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 13, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"# extract function name from \"fn (in module)\"\n", | |
"EXTRACT_FUNCTION_NAME = re.compile(r'\\A(.+) (\\(in .+\\))\\Z')\n", | |
"\n", | |
"HEX_ADDR = re.compile(r'\\A0x[0-9a-fA-F]+\\Z')\n", | |
"\n", | |
"def symbolicate_ping(ping):\n", | |
" \"\"\"Take a crash ping and return symbolicated stack traces.\n", | |
" Uses the symbolication API to look up function names.\n", | |
" \"\"\"\n", | |
" \n", | |
" # if there is no payload or stackTraces, return nothing\n", | |
" stack_traces = None\n", | |
" if not ping.get('payload', None):\n", | |
" # return None\n", | |
" raise ValueError('No payload')\n", | |
" else:\n", | |
" payload = ping['payload']\n", | |
" \n", | |
" if not payload.get('stackTraces', None):\n", | |
" # return None\n", | |
" raise ValueError('No stackTraces')\n", | |
" else:\n", | |
" stack_traces = payload['stackTraces']\n", | |
" \n", | |
" # make sure we have threads, modules, and crashing_thread\n", | |
" missing = ''\n", | |
" if 'threads' not in stack_traces:\n", | |
" missing = 'threads'\n", | |
" elif 'modules' not in stack_traces:\n", | |
" missing = 'modules'\n", | |
" elif not stack_traces.get('crash_info', None):\n", | |
" missing = 'crash_info'\n", | |
" else:\n", | |
" threads = stack_traces['threads']\n", | |
" modules = stack_traces['modules']\n", | |
" if 'crashing_thread' not in stack_traces['crash_info']:\n", | |
" missing = 'crashing_thread'\n", | |
" else:\n", | |
" crashing_thread = stack_traces['crash_info']['crashing_thread']\n", | |
" \n", | |
" if missing:\n", | |
" msg = \"missing \" + missing\n", | |
" if stack_traces:\n", | |
" msg += \"; \" + stack_traces.get('status', 'STATUS MISSING')\n", | |
" raise ValueError(msg)\n", | |
" \n", | |
" if not (crashing_thread >= 0 and crashing_thread < len(threads)):\n", | |
" msg = \"crashing_thread \" + crashing_thread\n", | |
" msg += \" out of range\"\n", | |
" raise ValueError(msg)\n", | |
" \n", | |
" symbolicated_threads = []\n", | |
" \n", | |
" modules_to_symbolicate = []\n", | |
" threads_to_symbolicate = []\n", | |
"\n", | |
" for thread_idx, src_thread in enumerate(threads):\n", | |
" out_thread_frames = []\n", | |
" symbolicated_threads.append(out_thread_frames)\n", | |
"\n", | |
" frames_to_symbolicate = []\n", | |
"\n", | |
" # only the crashing thread and thread 0 are used for the\n", | |
" # signature, skip symbol lookup for others\n", | |
" if thread_idx != 0 and thread_idx != crashing_thread:\n", | |
" continue\n", | |
" \n", | |
" if 'frames' not in src_thread:\n", | |
" continue\n", | |
"\n", | |
" for frame_idx, src_frame in enumerate(islice(\n", | |
" src_thread['frames'], MAXIMUM_FRAMES_TO_CONSIDER)):\n", | |
" out_frame = {}\n", | |
" out_thread_frames.append(out_frame)\n", | |
"\n", | |
" if 'ip' not in src_frame:\n", | |
" msg = \"missing ip for thread \" + thread_idx + \" frame \"\n", | |
" msg += frame_idx\n", | |
" raise ValueError(msg)\n", | |
"\n", | |
" ip_int = int(src_frame['ip'], 16)\n", | |
" out_frame['offset'] = src_frame['ip']\n", | |
"\n", | |
" if 'module_index' not in src_frame:\n", | |
" continue\n", | |
"\n", | |
" module_index = src_frame['module_index']\n", | |
" if not (module_index >= 0 and module_index < len(modules)):\n", | |
" msg = \"module_index \" + module_index + \" out of range for \"\n", | |
" msg += \"thread \" + thread_idx + \" frame \" + frame_idx\n", | |
" raise ValueError(msg)\n", | |
" \n", | |
" module = modules[module_index]\n", | |
" \n", | |
" if 'base_addr' not in module:\n", | |
" msg = \"missing base_addr for module \" + module_index\n", | |
" raise ValueError(msg)\n", | |
" \n", | |
" try:\n", | |
" module_offset_int = ip_int - int(module['base_addr'], 16)\n", | |
" except ValueError:\n", | |
" msg = \"bad base_addr \" + module['base_addr']\n", | |
" msg += \" for module \" + module_index\n", | |
" raise ValueError(msg)\n", | |
"\n", | |
" if 'filename' in module:\n", | |
" out_frame['module'] = module['filename']\n", | |
" out_frame['module_offset'] = '0x%x' % module_offset_int\n", | |
"\n", | |
" # prepare this frame for symbol lookup\n", | |
"\n", | |
" if 'debug_file' in module and 'debug_id' in module:\n", | |
" mp = (module['debug_file'], module['debug_id'])\n", | |
" if mp not in modules_to_symbolicate:\n", | |
" modules_to_symbolicate.append(mp)\n", | |
"\n", | |
" frames_to_symbolicate.append(\n", | |
" {'lookup': [modules_to_symbolicate.index(mp),\n", | |
" module_offset_int],\n", | |
" 'output': out_frame})\n", | |
"\n", | |
" if len(frames_to_symbolicate) > 0:\n", | |
" threads_to_symbolicate.append(frames_to_symbolicate)\n", | |
"\n", | |
" if len(threads_to_symbolicate) == 0:\n", | |
" return symbolicated_threads\n", | |
"\n", | |
" sym_request = {\n", | |
" 'stacks': [[f['lookup'] for f in t] for t in threads_to_symbolicate],\n", | |
" 'memoryMap':\n", | |
" [[debug_file, debug_id] for\n", | |
" (debug_file, debug_id) in modules_to_symbolicate],\n", | |
" 'version': 4}\n", | |
"\n", | |
" response = requests.post(SYMBOLICATION_API_URL,\n", | |
" json=sym_request)\n", | |
" response.raise_for_status()\n", | |
" sym_result = response.json()\n", | |
" \n", | |
" stacks = sym_result['symbolicatedStacks']\n", | |
" for thread, thread_result in zip(threads_to_symbolicate, stacks):\n", | |
" for f, symbol in zip(thread, thread_result):\n", | |
" module_idx = f['lookup'][0]\n", | |
" if sym_result['knownModules'][module_idx]:\n", | |
" function_name = EXTRACT_FUNCTION_NAME.match(symbol).group(1)\n", | |
" if function_name and not HEX_ADDR.match(function_name):\n", | |
" f['output']['function'] = function_name\n", | |
"\n", | |
" return symbolicated_threads" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Signature generation\n", | |
"from https://github.com/mozilla/socorro/blob/master/socorro/processor/signature_utilities.py" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 14, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"def generate_signature(ping, symbolicated_threads):\n", | |
" \"\"\"Using a crash ping and associated symbolicated stacks from each thread,\n", | |
" generate a signature identifying the crash. This is intended to behave\n", | |
" similarly to Socorro, given the data available in the pings.\n", | |
" \"\"\"\n", | |
" \n", | |
" # SignatureGenerationRule\n", | |
" try:\n", | |
" lowercase = 'Windows_NT' in ping['environment']['system']['os']['name']\n", | |
" except KeyError:\n", | |
" lowercase = False\n", | |
"\n", | |
" stack_traces = ping['payload']['stackTraces']\n", | |
" crashing_thread_idx = stack_traces['crash_info']['crashing_thread']\n", | |
" crashing_thread = symbolicated_threads[crashing_thread_idx]\n", | |
" \n", | |
" signature_list = create_frame_list(crashing_thread, lowercase)\n", | |
" signature = signature_from_list(signature_list)\n", | |
" \n", | |
" # StackwalkerErrorSignatureRule\n", | |
" if signature.startswith('EMPTY'):\n", | |
" try:\n", | |
" signature = \"%s; %s\" % (signature, stack_traces['status'])\n", | |
" except KeyError:\n", | |
" pass\n", | |
"\n", | |
" # OOMSignature\n", | |
" signature = oom_signature(ping, signature)\n", | |
" \n", | |
" # AbortSignature\n", | |
" signature = abort_signature(ping, signature)\n", | |
"\n", | |
" # TODO: something about MozCrashReason?\n", | |
" \n", | |
" # TODO: something more useful for BaseThreadInitThunk\n", | |
"\n", | |
" # SignatureShutdownTimeout\n", | |
" signature = shutdown_timeout_signature(ping, signature)\n", | |
"\n", | |
" # SignatureRunWatchDog\n", | |
" # TODO: detect more types of hang watchdog timeout\n", | |
" if 'RunWatchdog' in signature:\n", | |
" # Always use thread 0 in this case, because that's the thread that\n", | |
" # was hanging when the software was artificially crashed.\n", | |
" crashing_thread = symbolicated_threads[0]\n", | |
" signature_list = create_frame_list(crashing_thread, lowercase)\n", | |
"\n", | |
" signature = \"shutdownhang | %s\" % signature_from_list(signature_list)\n", | |
" \n", | |
" # SigTrim\n", | |
" signature = signature.strip()\n", | |
" \n", | |
" # SigTrunc\n", | |
" if len(signature) > SIGNATURE_MAX_LEN:\n", | |
" signature = \"%s...\" % signature[:SIGNATURE_MAX_LEN - 3]\n", | |
"\n", | |
" return signature\n", | |
"\n", | |
"\n", | |
"# from SignatureGenerationRule._create_frame_list\n", | |
"def create_frame_list(thread, make_modules_lower_case):\n", | |
" frame_signatures_list = []\n", | |
"\n", | |
" for a_frame in thread:\n", | |
" if make_modules_lower_case and 'module' in a_frame:\n", | |
" a_frame['module'] = a_frame['module'].lower()\n", | |
"\n", | |
" normalized_signature = normalize_signature(**a_frame)\n", | |
" if 'normalized' not in a_frame:\n", | |
" a_frame['normalized'] = normalized_signature\n", | |
" frame_signatures_list.append(normalized_signature)\n", | |
"\n", | |
" return frame_signatures_list\n", | |
"\n", | |
"\n", | |
"# from CSignatureToolBase._do_generate\n", | |
"def signature_from_list(source_list):\n", | |
" \"\"\"\n", | |
" each element of signatureList names a frame in the crash stack; and is:\n", | |
" - a prefix of a relevant frame: Append this element to the signature\n", | |
" - a relevant frame: Append this element and stop looking\n", | |
" - irrelevant: Append this element only after seeing a prefix frame\n", | |
" The signature is a ' | ' separated string of frame names.\n", | |
" \"\"\"\n", | |
"\n", | |
" # shorten source_list to the first signatureSentinel\n", | |
" sentinel_locations = []\n", | |
" for a_sentinel in signature_sentinels:\n", | |
" if type(a_sentinel) == tuple:\n", | |
" a_sentinel, condition_fn = a_sentinel\n", | |
" if not condition_fn(source_list):\n", | |
" continue\n", | |
" try:\n", | |
" sentinel_locations.append(source_list.index(a_sentinel))\n", | |
" except ValueError:\n", | |
" pass\n", | |
" if sentinel_locations:\n", | |
" source_list = source_list[min(sentinel_locations):]\n", | |
"\n", | |
" # Get all the relevant frame signatures.\n", | |
" new_signature_list = []\n", | |
" for a_signature in source_list:\n", | |
" # If the signature matches the irrelevant signatures regex,\n", | |
" # skip to the next frame.\n", | |
" if irrelevant_signature_re.match(a_signature):\n", | |
" continue\n", | |
"\n", | |
" # If the signature matches the trim dll signatures regex,\n", | |
" # rewrite it to remove all but the module name.\n", | |
" if trim_dll_signature_re.match(a_signature):\n", | |
" a_signature = a_signature.split('@')[0]\n", | |
"\n", | |
" # If this trimmed DLL signature is the same as the previous\n", | |
" # frame's, we do not want to add it.\n", | |
" if (\n", | |
" new_signature_list and\n", | |
" a_signature == new_signature_list[-1]\n", | |
" ):\n", | |
" continue\n", | |
"\n", | |
" new_signature_list.append(a_signature)\n", | |
"\n", | |
" # If the signature does not match the prefix signatures regex,\n", | |
" # then it is the last one we add to the list.\n", | |
" if not prefix_signature_re.match(a_signature):\n", | |
" break\n", | |
"\n", | |
" # Add a special marker for hang crash reports.\n", | |
" #if hang_type:\n", | |
" # new_signature_list.insert(0, self.hang_prefixes[hang_type])\n", | |
"\n", | |
" signature = ' | '.join(new_signature_list)\n", | |
"\n", | |
" # Handle empty signatures to explain why we failed generating them.\n", | |
" if signature == '' or signature is None:\n", | |
" try:\n", | |
" signature = source_list[0]\n", | |
" except IndexError:\n", | |
" signature = \"EMPTY: no frame data available\"\n", | |
"\n", | |
" if ESCAPE_SINGLE_QUOTE:\n", | |
" signature = signature.replace(\"'\", \"''\")\n", | |
" if len(signature) > SIGNATURE_MAX_LEN:\n", | |
" signature = \"%s...\" % signature[:SIGNATURE_MAX_LEN - 3]\n", | |
"\n", | |
" return signature\n", | |
"\n", | |
"FIXUP_SPACE = re.compile(r' (?=[\\*&,])')\n", | |
"FIXUP_COMMA = re.compile(r',(?! )')\n", | |
" \n", | |
"# from CSignatureToolBase.normalize_signature and friends\n", | |
"def normalize_signature(\n", | |
" module=None,\n", | |
" function=None,\n", | |
" file=None,\n", | |
" line=None,\n", | |
" module_offset=None,\n", | |
" offset=None,\n", | |
" function_offset=None,\n", | |
" normalized=None,\n", | |
" **kwargs # eat any extra kwargs passed in\n", | |
"):\n", | |
" \"\"\" returns a structured conglomeration of the input parameters to\n", | |
" serve as a signature. the parameter names of this function reflect the\n", | |
" exact names of the fields from the jsonmdsw frame output. this allows\n", | |
" this function to be invoked by passing a frame as **a_frame. sometimes,\n", | |
" a frame may already have a normalized version cached. if that exists,\n", | |
" return it instead.\n", | |
" \"\"\"\n", | |
" if normalized is not None:\n", | |
" return normalized\n", | |
"\n", | |
" def collapse(\n", | |
" function_signature_str,\n", | |
" open_string,\n", | |
" replacement_open_string,\n", | |
" close_string,\n", | |
" replacement_close_string,\n", | |
" exception_substring_list=(), # list of exceptions that shouldn't collapse\n", | |
" ):\n", | |
" \"\"\"takes a string representing a C/C++ function signature\n", | |
" and replaces anything between to possibly nested delimiters\"\"\"\n", | |
" target_counter = 0\n", | |
" collapsed_list = []\n", | |
" exception_mode = False\n", | |
"\n", | |
" def append_if_not_in_collapse_mode(a_character):\n", | |
" if not target_counter:\n", | |
" collapsed_list.append(a_character)\n", | |
"\n", | |
" def is_exception(\n", | |
" exception_list,\n", | |
" remaining_original_line,\n", | |
" line_up_to_current_position\n", | |
" ):\n", | |
" for an_exception in exception_list:\n", | |
" if remaining_original_line.startswith(an_exception):\n", | |
" return True\n", | |
" if line_up_to_current_position.endswith(an_exception):\n", | |
" return True\n", | |
" return False\n", | |
"\n", | |
" for index, a_character in enumerate(function_signature_str):\n", | |
" if a_character == open_string:\n", | |
" if is_exception(\n", | |
" exception_substring_list,\n", | |
" function_signature_str[index + 1:],\n", | |
" function_signature_str[:index]\n", | |
" ):\n", | |
" exception_mode = True\n", | |
" append_if_not_in_collapse_mode(a_character)\n", | |
" continue\n", | |
" append_if_not_in_collapse_mode(replacement_open_string)\n", | |
" target_counter += 1\n", | |
" elif a_character == close_string:\n", | |
" if exception_mode:\n", | |
" append_if_not_in_collapse_mode(a_character)\n", | |
" exception_mode = False\n", | |
" else:\n", | |
" target_counter -= 1\n", | |
" append_if_not_in_collapse_mode(replacement_close_string)\n", | |
" else:\n", | |
" append_if_not_in_collapse_mode(a_character)\n", | |
"\n", | |
" edited_function = ''.join(collapsed_list)\n", | |
" return edited_function\n", | |
"\n", | |
"\n", | |
" if function:\n", | |
" function = collapse(\n", | |
" function,\n", | |
" '<',\n", | |
" '<',\n", | |
" '>',\n", | |
" 'T>',\n", | |
" ('name omitted', 'IPC::ParamTraits')\n", | |
" )\n", | |
" if COLLAPSE_ARGUMENTS:\n", | |
" function = collapse(\n", | |
" function,\n", | |
" '(',\n", | |
" '',\n", | |
" ')',\n", | |
" '',\n", | |
" ('anonymous namespace', 'operator')\n", | |
" )\n", | |
"\n", | |
" # Remove spaces before all stars, ampersands, and commas\n", | |
" function = FIXUP_SPACE.sub('', function)\n", | |
" # Ensure a space after commas\n", | |
" function = FIXUP_COMMA.sub(', ', function)\n", | |
" return function\n", | |
"\n", | |
" if not module and not module_offset and offset:\n", | |
" return \"@%s\" % offset\n", | |
" if not module:\n", | |
" module = '' # might have been None\n", | |
" return '%s@%s' % (module, module_offset)\n", | |
"\n", | |
"\n", | |
"def oom_signature(ping, signature):\n", | |
" match = False\n", | |
" if 'metadata' in ping['payload']:\n", | |
" if 'OOMAllocationSize' in ping['payload']['metadata']:\n", | |
" match = True\n", | |
" for a_signature_fragment in ( 'NS_ABORT_OOM',\n", | |
" 'mozalloc_handle_oom',\n", | |
" 'CrashAtUnhandlableOOM',\n", | |
" 'AutoEnterOOMUnsafeRegion'):\n", | |
" if a_signature_fragment in signature:\n", | |
" match = True\n", | |
"\n", | |
" if not match:\n", | |
" return signature\n", | |
"\n", | |
" try:\n", | |
" oom_size = int(ping['payload']['metadata']['OOMAllocationSize'])\n", | |
" if oom_size <= 262144: # 256K\n", | |
" signature = \"OOM | small\"\n", | |
" else:\n", | |
" signature = (\n", | |
" \"OOM | large | \" + signature\n", | |
" )\n", | |
" except (TypeError, AttributeError, KeyError):\n", | |
" signature = (\n", | |
" \"OOM | unknown | \" + signature\n", | |
" )\n", | |
"\n", | |
" return signature\n", | |
"\n", | |
"\n", | |
"def abort_signature(ping, signature):\n", | |
" if 'metadata' not in ping['payload']:\n", | |
" return signature\n", | |
" if 'AbortMessage' not in ping['payload']['metadata']:\n", | |
" return signature\n", | |
" if not ping['payload']['metadata']['AbortMessage']:\n", | |
" return signature\n", | |
"\n", | |
" abort_message = ping['payload']['metadata']['AbortMessage']\n", | |
"\n", | |
" if '###!!! ABORT: file ' in abort_message:\n", | |
" # This is an abort message that contains no interesting\n", | |
" # information. We just want to put the \"Abort\" marker in the\n", | |
" # signature.\n", | |
" return 'Abort | {}'.format(signature)\n", | |
" \n", | |
" if '###!!! ABORT:' in abort_message:\n", | |
" # Recent crash reports added some irrelevant information at the\n", | |
" # beginning of the abort message. We want to remove that and keep\n", | |
" # just the actual abort message.\n", | |
" abort_message = abort_message.split('###!!! ABORT:', 1)[1].strip()\n", | |
"\n", | |
" if ': file ' in abort_message:\n", | |
" # Abort messages contain a file name and a line number. Since\n", | |
" # those are very likely to change between builds, we want to\n", | |
" # remove those parts from the signature.\n", | |
" abort_message = abort_message.split(': file ', 1)[0].strip()\n", | |
"\n", | |
" if len(abort_message) > 80:\n", | |
" abort_message = abort_message[:77] + '...'\n", | |
"\n", | |
" return 'Abort | {} | {}'.format(abort_message, signature)\n", | |
"\n", | |
"\n", | |
"def shutdown_timeout_signature(ping, signature):\n", | |
" if 'metadata' not in ping['payload']:\n", | |
" return signature\n", | |
" timeout_json = ping['payload']['metadata'].get('AsyncShutdownTimeout','')\n", | |
"\n", | |
" if not timeout_json:\n", | |
" return signature\n", | |
"\n", | |
" parts = ['AsyncShutdownTimeout']\n", | |
" try:\n", | |
" shutdown_data = json.loads(timeout_json)\n", | |
" parts.append(shutdown_data['phase'])\n", | |
" conditions = [c['name'] for c in shutdown_data['conditions']]\n", | |
" if conditions:\n", | |
" conditions.sort()\n", | |
" parts.append(','.join(conditions))\n", | |
" else:\n", | |
" parts.append(\"(none)\")\n", | |
" except (ValueError, KeyError), e:\n", | |
" parts.append(\"UNKNOWN\")\n", | |
"\n", | |
" new_sig = ' | '.join(parts)\n", | |
"\n", | |
" return new_sig" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Lists of function signatures used in signature generation\n", | |
"from https://github.com/mozilla/socorro/tree/master/socorro/siglists" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 15, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"irrelevant_signature_re = re.compile(\n", | |
"'|'.join(\"\"\"@0x[0-9a-fA-F]{2,}\n", | |
"@0x[1-9a-fA-F]\n", | |
"__aeabi_fcmpgt.*\n", | |
"ashmem\n", | |
"app_process@0x.*\n", | |
"core\\.odex@0x.*\n", | |
"core::panicking::.*\n", | |
"CrashStatsLogForwarder::CrashAction\n", | |
"_CxxThrowException\n", | |
"dalvik-heap\n", | |
"dalvik-jit-code-cache\n", | |
"dalvik-LinearAlloc\n", | |
"dalvik-mark-stack\n", | |
"data@app@org\\.mozilla\\.f.*-\\d\\.apk@classes\\.dex@0x.*\n", | |
"framework\\.odex@0x.*\n", | |
"google_breakpad::ExceptionHandler::HandleInvalidParameter.*\n", | |
"KiFastSystemCallRet\n", | |
"libandroid_runtime\\.so@0x.*\n", | |
"libbinder\\.so@0x.*\n", | |
"libc\\.so@.*\n", | |
"libc-2\\.5\\.so@.*\n", | |
"libEGL\\.so@.*\n", | |
"libdvm\\.so\\s*@\\s*0x.*\n", | |
"libgui\\.so@0x.*\n", | |
"libicudata.so@.*\n", | |
"libMali\\.so@0x.*\n", | |
"libutils\\.so@0x.*\n", | |
"libz\\.so@0x.*\n", | |
"linux-gate\\.so@0x.*\n", | |
"mnt@asec@org\\.mozilla\\.f.*-\\d@pkg\\.apk@classes\\.dex@0x.*\n", | |
"MOZ_Assert\n", | |
"MOZ_Crash\n", | |
"mozcrt19.dll@0x.*\n", | |
"mozilla::gfx::Log<.*\n", | |
"mozilla::ipc::RPCChannel::Call\n", | |
"_NSRaiseError\n", | |
"(Nt|Zw)?WaitForSingleObject(Ex)?\n", | |
"(Nt|Zw)?WaitForMultipleObjects(Ex)?\n", | |
"nvmap@0x.*\n", | |
"org\\.mozilla\\.f.*-\\d\\.apk@0x.*\n", | |
"PR_WaitCondVar\n", | |
"RaiseException\n", | |
"RtlpAdjustHeapLookasideDepth\n", | |
"std::_Atomic_fetch_add_4\n", | |
"std::panicking::.*\n", | |
"system@framework@.*\\.jar@classes\\.dex@0x.*\n", | |
"___TERMINATING_DUE_TO_UNCAUGHT_EXCEPTION___\n", | |
"WaitForSingleObjectExImplementation\n", | |
"WaitForMultipleObjectsExImplementation\n", | |
"RealMsgWaitFor.*\n", | |
"_ZdlPv\n", | |
"zero\"\"\".split('\\n')))\n", | |
"\n", | |
"prefix_signature_re = re.compile(\n", | |
"'|'.join(\"\"\"@0x0\n", | |
".*CrashAtUnhandlableOOM\n", | |
"Abort\n", | |
".*abort\n", | |
".*alloc_impl\n", | |
"_alloca_probe.*\n", | |
"__android_log_assert\n", | |
"arena_.*\n", | |
"BaseGetNamedObjectDirectory\n", | |
".*calloc\n", | |
"cert_.*\n", | |
"CERT_.*\n", | |
"CFRelease\n", | |
"_chkstk\n", | |
"CleanupPerAppKey\n", | |
"CrashInJS\n", | |
"__delayLoadHelper2\n", | |
"dlmalloc\n", | |
"dlmalloc_trim\n", | |
"dvm.*\n", | |
"EtwEventEnabled\n", | |
"extent_.*\n", | |
"fastcopy_I\n", | |
"fastzero_I\n", | |
"_files_getaddrinfo\n", | |
".*free\n", | |
"free_impl\n", | |
"GCGraphBuilder::NoteXPCOMChild\n", | |
"getanswer\n", | |
"HandleInvalidParameter\n", | |
"HeapFree\n", | |
"huge_dalloc\n", | |
"huge_palloc\n", | |
"ialloc\n", | |
"imalloc\n", | |
"init_library\n", | |
"InvalidArrayIndex_CRASH\n", | |
"invalid_parameter_noinfo\n", | |
"_invalid_parameter_noinfo\n", | |
"isalloc\n", | |
"jemalloc_crash\n", | |
"je_.*\n", | |
"JNI_CreateJavaVM\n", | |
"_JNIEnv.*\n", | |
"JNI_GetCreatedJavaVM.*\n", | |
"js::AutoCompartment::AutoCompartment.*\n", | |
"js::AutoEnterOOMUnsafeRegion::crash\n", | |
"js::detail::HashTable<.*>::.*\n", | |
"js::HashSet<.*>::.*\n", | |
"js::HashMap<.*>::.*\n", | |
"js::LifoAlloc::getOrCreateChunk\n", | |
"JSAutoCompartment::JSAutoCompartment.*\n", | |
"JS_DHashTableEnumerate\n", | |
"JS_DHashTableOperate\n", | |
"JS_NewStringCopyZ.*\n", | |
"kill\n", | |
"__libc_android_abort\n", | |
"libobjc.A.dylib@0x1568.\n", | |
"(libxul\\.so|xul\\.dll|XUL)@0x.*\n", | |
"LL_.*\n", | |
"malloc\n", | |
"_MD_.*\n", | |
"memcmp\n", | |
"__memcmp16\n", | |
"memcpy\n", | |
"memmove\n", | |
"memset\n", | |
"mozalloc_abort.*\n", | |
"mozalloc_handle_oom\n", | |
"moz_free\n", | |
"mozilla::AndroidBridge::AutoLocalJNIFrame::~AutoLocalJNIFrame\n", | |
"mozilla::CondVar::.*\n", | |
"mozilla::ipc::LogicError\n", | |
"mozilla::ipc::MessageChannel::AssertWorkerThread\n", | |
"mozilla::ipc::MessageChannel::Call\n", | |
"mozilla::ipc::MessageChannel::CxxStackFrame::CxxStackFrame\n", | |
"mozilla::ipc::MessageChannel::Send\n", | |
"mozilla::ipc::RPCChannel::Call\n", | |
"mozilla::ipc::RPCChannel::CxxStackFrame::CxxStackFrame\n", | |
"mozilla::ipc::RPCChannel::EnteredCxxStack\n", | |
"mozilla::ipc::RPCChannel::Send\n", | |
"mozilla::layers::CompositorD3D11::Failed\n", | |
"mozilla::layers::CompositorD3D11::HandleError\n", | |
"mozilla.*FatalError\n", | |
"moz_xmalloc\n", | |
"moz_xrealloc\n", | |
"MOZ_CrashOOL\n", | |
"MOZ_CrashPrintf\n", | |
"msvcr120\\.dll@0x.*\n", | |
"\\<name omitted\\>\n", | |
"NP_Shutdown\n", | |
"(NS_)?(Lossy)?(Copy|Append|Convert).*UTF.*\n", | |
"nsACString_internal::Assign.*\n", | |
"nsAString_internal::Assign.*\n", | |
"nsACString_internal::BeginWriting\n", | |
"nsAString_internal::BeginWriting\n", | |
"nsACString_internal::SetCapacity\n", | |
"NS_strcmp\n", | |
"nsBaseHashtable<.*>::.*\n", | |
"nsClassHashtable<.*>::.*\n", | |
"nsCOMPtr.*\n", | |
"NS_ABORT_OOM.*\n", | |
"nsDataHashtable<.*>::.*\n", | |
"NS_DebugBreak.*\n", | |
"nsDebugImpl::Abort\n", | |
"nsDependentString::nsDependentString\n", | |
"nsEventQueue::GetEvent\n", | |
"nsThread::GetEvent\n", | |
"nsThread::nsChainedEventQueue::GetEvent\n", | |
"[-+]\\[NSException raise(:format:(arguments:)?)?\\]\n", | |
"nsInterfaceHashtable<.*>::.*\n", | |
"nsJSThingHashtable<.*>::.*\n", | |
"nsObjCExceptionLogAbort\n", | |
"nsRefPtr.*\n", | |
"NSS.*\n", | |
"nss.*\n", | |
"nsTArray<.*\n", | |
"nsTArray_base<.*\n", | |
"nsTArray_Impl<.*\n", | |
"nsTHashtable<.*>::.*\n", | |
"nsThread::Shutdown\n", | |
"NtUser.*\n", | |
"objc_exception_throw\n", | |
"objc_msgSend\n", | |
"operator new\n", | |
"<.*>::operator()\n", | |
"PLDHashTable::.*\n", | |
"PL_.*\n", | |
"port_.*\n", | |
"PORT_.*\n", | |
"_PR_.*\n", | |
"PR_.*\n", | |
".*ProcessNextEvent.*\n", | |
"__psynch_cvwait\n", | |
"_pthread_cond_wait\n", | |
"pthread_mutex_lock\n", | |
"_purecall\n", | |
"raise\n", | |
"realloc\n", | |
"recv\n", | |
".*ReentrantMonitor::Wait.*\n", | |
"RefPtr.*\n", | |
"_RTC_Terminate\n", | |
"Rtl.*\n", | |
"_Rtl.*\n", | |
"__Rtl.*\n", | |
"__rust_start_panic\n", | |
"SEC_.*Item\n", | |
"seckey_.*\n", | |
"SECKEY_.*\n", | |
"__security_check_cookie\n", | |
"send\n", | |
"setjmp\n", | |
"sigblock\n", | |
"sigprocmask\n", | |
"SocketAccept\n", | |
"SocketAcceptRead\n", | |
"SocketAvailable\n", | |
"SocketAvailable64\n", | |
"SocketBind\n", | |
"SocketClose\n", | |
"SocketConnect\n", | |
"SocketGetName\n", | |
"SocketGetPeerName\n", | |
"SocketListen\n", | |
"SocketPoll\n", | |
"SocketRead\n", | |
"SocketRecv\n", | |
"SocketSend\n", | |
"SocketShutdown\n", | |
"SocketSync\n", | |
"SocketTransmitFile\n", | |
"SocketWrite\n", | |
"SocketWritev\n", | |
"ssl_.*\n", | |
"SSL_.*\n", | |
"std::_Allocate.*\n", | |
"std::list<.*>::.*\n", | |
"strcat\n", | |
"strncmp\n", | |
"ssl3_.*\n", | |
"strchr\n", | |
"strcmp\n", | |
"strcpy\n", | |
".*strdup\n", | |
"strlen\n", | |
"strncpy\n", | |
"strzcmp16\n", | |
"strstr\n", | |
"__swrite\n", | |
"TlsGetValue\n", | |
"TouchBadMemory\n", | |
"vcruntime140\\.dll@0x.*\n", | |
"_VEC_memcpy\n", | |
"_VEC_memzero\n", | |
".*WaitFor.*\n", | |
"wcslen\n", | |
"__wrap_realloc\n", | |
"WSARecv.*\n", | |
"WSASend.*\n", | |
"_ZdaPvRKSt9nothrow_t\"\n", | |
"zzz_AsmCodeRange_.*\n", | |
".*DebugAbort.*\n", | |
"mozilla::ipc::MessageChannel::~MessageChannel.*\n", | |
"mozilla::MakeUnique<.*>\n", | |
"aticfx32\\.dll\n", | |
"aticfx64\\.dll\n", | |
"atidxx32\\.dll\n", | |
"atidxx64\\.dll\n", | |
"atiu9pag\\.dll\n", | |
"atiu9p64\\.dll\n", | |
"atiumd6a\\.dll\n", | |
"atiumdag\\.dll\n", | |
"atiumdva\\.dll\n", | |
"atiuxpag\\.dll\n", | |
"igd10iumd32\\.dll\n", | |
"igd10iumd64\\.dll\n", | |
"igd10umd32\\.dll\n", | |
"igd10umd64\\.dll\n", | |
"igdumd32\\.dll\n", | |
"igdumd64\\.dll\n", | |
"igdumdim32\\.dll\n", | |
"igdumdim64\\.dll\n", | |
"igd11dxva32\\.dll\n", | |
"igd11dxva64\\.dll\n", | |
"igdusc32\\.dll\n", | |
"igdusc64\\.dll\n", | |
"nvd3dum\\.dll\n", | |
"nvd3dumx\\.dll\n", | |
"nvoglnt\\.dll\n", | |
"nvumdshim\\.dll\n", | |
"nvumdshimx\\.dll\n", | |
"nvwgf2um\\.dll\n", | |
"nvwgf2umx\\.dll\n", | |
"nvapi\\.dll\n", | |
"nvapi64\\.dll\n", | |
"nvscpapi\\.dll\n", | |
"nvoglv32\\.dll\n", | |
"nvoglv64\\.dll\"\"\".split('\\n')))\n", | |
"\n", | |
"trim_dll_signature_re = re.compile(\n", | |
"'|'.join(\"\"\"aticfx32\\.dll.*\n", | |
"aticfx64\\.dll.*\n", | |
"atidxx32\\.dll.*\n", | |
"atidxx64\\.dll.*\n", | |
"atiu9pag\\.dll.*\n", | |
"atiu9p64\\.dll.*\n", | |
"atiumd6a\\.dll.*\n", | |
"atiumdag\\.dll.*\n", | |
"atiumdva\\.dll.*\n", | |
"atiuxpag\\.dll.*\n", | |
"igd10iumd32\\.dll.*\n", | |
"igd10iumd64\\.dll.*\n", | |
"igd10umd32\\.dll.*\n", | |
"igd10umd64\\.dll.*\n", | |
"igdumd32\\.dll.*\n", | |
"igdumd64\\.dll.*\n", | |
"igdumdim32\\.dll.*\n", | |
"igdumdim64\\.dll.*\n", | |
"igd11dxva32\\.dll.*\n", | |
"igd11dxva64\\.dll.*\n", | |
"igdusc32\\.dll.*\n", | |
"igdusc64\\.dll.*\n", | |
"nvd3dum\\.dll.*\n", | |
"nvd3dumx\\.dll.*\n", | |
"nvoglnt\\.dll.*\n", | |
"nvumdshim\\.dll.*\n", | |
"nvumdshimx\\.dll.*\n", | |
"nvwgf2um\\.dll.*\n", | |
"nvwgf2umx\\.dll.*\n", | |
"nvapi\\.dll.*\n", | |
"nvapi64\\.dll.*\n", | |
"nvscpapi\\.dll.*\n", | |
"nvoglv32\\.dll.*\n", | |
"nvoglv64\\.dll.*\"\"\".split('\\n')))\n", | |
"\n", | |
"signature_sentinels = \"\"\"_purecall\n", | |
"Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash\n", | |
"google_breakpad::ExceptionHandler::HandleInvalidParameter\"\"\".split('\\n')\n", | |
"signature_sentinels.append(\n", | |
" (\n", | |
" 'mozilla::ipc::RPCChannel::Call(IPC::Message*, IPC::Message*)',\n", | |
" lambda x: (\n", | |
" 'CrashReporter::CreatePairedMinidumps(void*, '\n", | |
" 'unsigned long, nsAString_internal*, nsILocalFile**, '\n", | |
" 'nsILocalFile**)'\n", | |
" ) in x\n", | |
" )\n", | |
")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# Query\n", | |
"Gather one day of crashes with stackTraces" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 16, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"import datetime\n", | |
"import traceback\n", | |
"# ignoring \"main\" and null since null should imply \"main\" (also, I think the RTD are wrong on this point) \n", | |
"PROCESS_TYPES = ['content', 'gpu']\n", | |
"\n", | |
"def top_crashers(qd, qw, ssc, ptype):\n", | |
" if qw:\n", | |
" print \"Top 50 {} process crashers on {}/{}/{}\\nwithin the first {} weeks since profile creation\\n---\".format(ptype, qd[:4], qd[4:6], qd[6:], int(qw/7))\n", | |
" else:\n", | |
" print \"Top 50 {} process crashers on {}/{}/{}\\nwith no consideration of profile creation date\\n---\".format(ptype, qd[:4], qd[4:6], qd[6:])\n", | |
" for list in ssc[:50]:\n", | |
" print \"{}\\t{}\\t{}\".format(list[0], list[1], ptype)\n", | |
" \n", | |
"\n", | |
"def stats(errs, res):\n", | |
" rate = 0\n", | |
" if res > 0:\n", | |
" rate = float(len(errs))/res\n", | |
" print \"Error rate: {:.4%} ({} total, {} errors)\".format(rate, res, len(errs))\n", | |
" # If it's not a long list of errors, show them\n", | |
" if len(errs) > 0:\n", | |
" if len(errs) > 50:\n", | |
" print \"Errors (more than 50, only 50 shown):\"\n", | |
" print '\\n'.join(errs[:50])\n", | |
" else:\n", | |
" print \"Errors:\"\n", | |
" print '\\n'.join(errs)\n", | |
"\n", | |
"\n", | |
"def get_dataset(submission_date, channel):\n", | |
" \"\"\"Return crash pings for that channel on that date.\"\"\"\n", | |
" pings = Dataset.from_source(\"telemetry\") \\\n", | |
" .where(docType='crash', \\\n", | |
" appUpdateChannel=channel, \\\n", | |
" submissionDate=submission_date) \\\n", | |
" .records(sc, sample=1.0)\n", | |
" return pings\n", | |
"\n", | |
"\n", | |
"def pingsig(ping):\n", | |
" try:\n", | |
" symbolicated_threads = symbolicate_ping(ping)\n", | |
" if symbolicated_threads:\n", | |
" signature = generate_signature(ping, symbolicated_threads)\n", | |
" else:\n", | |
" signature = ''\n", | |
"\n", | |
" return (ping['id'], signature, None)\n", | |
" \n", | |
" except ValueError as e:\n", | |
" return (ping['id'], None, e[0])\n", | |
" except Exception as e:\n", | |
" return (ping['id'], None, traceback.format_exc())\n", | |
"\n", | |
"\n", | |
"def qualify_ping(ping, time_delta, submission_date, process_type):\n", | |
" \"\"\"Return True for pings that meet the specified criteria.\"\"\"\n", | |
" retval = False\n", | |
" step1, step2, step3 = False, False, False\n", | |
" \n", | |
" # hasCrashEnvironment is boolean, but not significant for these purposes.\n", | |
" # It should not be a criteria for crash ping consideration.\n", | |
"# try:\n", | |
"# step1 = ping['payload'].get('hasCrashEnvironment')\n", | |
"# except:\n", | |
"# print \"hasCrashEnvironment error\"\n", | |
"# else:\n", | |
"# if step1:\n", | |
" process_filter = 'main' # or blank, which is also main\n", | |
" if process_type in PROCESS_TYPES:\n", | |
" process_filter = process_type\n", | |
"\n", | |
" try:\n", | |
" step1 = ping['payload'].get('processType', None)\n", | |
" except:\n", | |
" print \"processType error\"\n", | |
" else:\n", | |
" if (step1 is None) or (step1 == ''):\n", | |
" step1 = 'main'\n", | |
" if step1 == process_filter:\n", | |
" if time_delta:\n", | |
" try:\n", | |
" step2 = int(ping['environment']['profile'].get('creationDate', 0)) + time_delta >= submission_date \\\n", | |
" and submission_date >= int(ping['environment']['profile'].get('creationDate', 0))\n", | |
" except:\n", | |
" print \"date check error\"\n", | |
" else:\n", | |
" if step2:\n", | |
" try:\n", | |
" step3 = ping['payload'].get('stackTraces', None) != None\n", | |
" except:\n", | |
" print \"stackTraces error\"\n", | |
" else:\n", | |
" if step3:\n", | |
" retval = True\n", | |
" else: # no time_delta\n", | |
" try:\n", | |
" step2 = ping['payload'].get('stackTraces', None) != None\n", | |
" except:\n", | |
" print \"stackTraces error (no date)\"\n", | |
" else:\n", | |
" if step2:\n", | |
" retval = True\n", | |
" return retval\n", | |
"\n", | |
"\n", | |
"def query_pings(query_date, pings, process_type):\n", | |
" \"\"\"Given pings and process type, map signatures and output top crashers.\"\"\"\n", | |
" total_errors = 0\n", | |
" total_results = pings.count()\n", | |
" print \"\\nTotal {} process results: {}\".format(process_type, total_results)\n", | |
" \n", | |
" if total_results > 0:\n", | |
" results = pings.map(pingsig)\n", | |
" results.cache()\n", | |
" signatures = results.flatMap(lambda r: [r[1]] if r[1] != None else [])\n", | |
" errors = results.flatMap(lambda r: [r[0] + \" \" + r[2]] if r[2] != None else [])\n", | |
" total_errors = errors.collect()\n", | |
"\n", | |
" stack_counts = signatures.map(lambda sig: (sig, 1)).countByKey()\n", | |
" print \"Stack counts: {}\".format(len(stack_counts))\n", | |
"\n", | |
" sorted_stack_counts = sorted(stack_counts.items(), key=lambda x: x[1], reverse=True)\n", | |
" top_crashers(query_date, query_window, sorted_stack_counts, process_type)\n", | |
" results.unpersist()\n", | |
" return total_errors, total_results\n", | |
"\n", | |
" \n", | |
"def query(profile_window, submission_date, channel, process_type=None):\n", | |
" \"\"\"Given a submission date, channel, possibly-null consideration \n", | |
" window, and optional process type, get and query all matching pings. \n", | |
" If no process type is specified, all process types will be output; if \n", | |
" consideration window is None, all pings with a matching submission date \n", | |
" (regardless of profile creation date) will be output.\"\"\"\n", | |
" epoch = datetime.datetime.utcfromtimestamp(0).date()\n", | |
" time_delta = profile_window\n", | |
" querydate = datetime.datetime.strptime(submission_date, \"%Y%m%d\").date()\n", | |
" querydate_days = (querydate - epoch).days\n", | |
"\n", | |
" pings = get_dataset(submission_date, channel)\n", | |
" pings.cache()\n", | |
" \n", | |
" def query_stats(time_delta, process_type, errors_count, results_count):\n", | |
" \"\"\"Output somewhat meaningul statistics for that query.\"\"\"\n", | |
" if time_delta:\n", | |
" print \"\\nStats and errors for {} days ({} process)\".format(time_delta, process_type)\n", | |
" else:\n", | |
" print \"\\nStats and errors ({} process)\".format(process_type)\n", | |
" stats(errors_count, results_count)\n", | |
" \n", | |
" if process_type:\n", | |
" subset = pings.filter(lambda p: qualify_ping(p, time_delta, querydate_days, process_type))\n", | |
" errors_count, results_count = query_pings(submission_date, subset, process_type)\n", | |
" if results_count > 0:\n", | |
" query_stats(time_delta, process_type, errors_count, results_count)\n", | |
" else:\n", | |
" all_processes = ['main', 'content', 'gpu']\n", | |
" for each_process in all_processes:\n", | |
" subset = pings.filter(lambda p: qualify_ping(p, time_delta, querydate_days, each_process))\n", | |
" errors_count, results_count = query_pings(submission_date, subset, each_process)\n", | |
" if results_count > 0:\n", | |
" query_stats(time_delta, each_process, errors_count, results_count)\n", | |
" pings.unpersist()\n", | |
"\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 17, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"query_date = '20170524'\n", | |
"query_channel = 'nightly'" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Top 50 crashers (by signature) within the first two weeks of use" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 18, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"fetching 79.69703MB in 1852 files...\n", | |
"\n", | |
"Total main process results: 26\n", | |
"Stack counts: 20\n", | |
"Top 50 main process crashers on 2017/05/24\n", | |
"within the first 2 weeks since profile creation\n", | |
"---\n", | |
"mozilla::ipc::MessageChannel::Clear\t3\tmain\n", | |
"@0\t3\tmain\n", | |
"igd10umd32.dll | atiuxpag.dll | CContext::TID3D11DeviceContext_UpdateSubresource_<T>\t2\tmain\n", | |
"`Microsoft::WRL::Module<T>::Create''::`2''::`dynamic atexit destructor for ''moduleSingleton''''\t2\tmain\n", | |
"js::jit::DoIteratorMoreFallback\t1\tmain\n", | |
"js::TraceLoggerEvent::TraceLoggerEvent\t1\tmain\n", | |
"libxul.so.moz-backup (deleted)@0xc4a71d\t1\tmain\n", | |
"mozalloc_abort | NS_DebugBreak | nsDebugImpl::Abort | NS_InvokeByIndex\t1\tmain\n", | |
"mozilla::dom::TimeoutManager::MaybeStartThrottleTrackingTimout\t1\tmain\n", | |
"js::jit::DoGetPropFallback\t1\tmain\n", | |
"shutdownhang | NtWaitForKeyedEvent | RtlSleepConditionVariableSRW | mozilla::BaseTimeDuration<T>::FromMilliseconds\t1\tmain\n", | |
"shutdownhang | FreeArenaList\t1\tmain\n", | |
"shutdownhang | libpthread-2.25.so@0xd756\t1\tmain\n", | |
"js::ReportMagicWordFailure\t1\tmain\n", | |
"OOM | small\t1\tmain\n", | |
"mozilla::ipc::PBackgroundParent::OnMessageReceived\t1\tmain\n", | |
"mozilla::layers::LockD3DTexture<T>\t1\tmain\n", | |
"libxul.so (deleted)@0xc4e13b\t1\tmain\n", | |
"InvalidArrayIndex_CRASH | mozilla::a11y::AccessibleWrap::GetRemoteIAccessibleFor\t1\tmain\n", | |
"js::TenuringTracer::traverse<T>\t1\tmain\n", | |
"\n", | |
"Stats and errors for 14 days (main process)\n", | |
"Error rate: 0.0000% (26 total, 0 errors)\n", | |
"\n", | |
"Total content process results: 467\n", | |
"Stack counts: 262\n", | |
"Top 50 content process crashers on 2017/05/24\n", | |
"within the first 2 weeks since profile creation\n", | |
"---\n", | |
"mozilla::dom::TimeoutManager::MaybeStartThrottleTrackingTimout\t50\tcontent\n", | |
"RtlAnsiStringToUnicodeString | mozilla::layout::VsyncChild::RecvNotify\t30\tcontent\n", | |
"ntdll.dll@0x46c74\t18\tcontent\n", | |
"RtlDoesFileExists_UstrEx | RtlDosSearchPath_Ustr | BasepLoadLibraryAsDataFileInternal\t11\tcontent\n", | |
"mozilla::widget::WinUtils::WaitForMessage | nsAppShell::ProcessNextNativeEvent\t10\tcontent\n", | |
"IGeckoCustom_IID_Lookup\t10\tcontent\n", | |
"MsgWaitForMultipleObjectsEx | mozilla::widget::WinUtils::WaitForMessage | nsAppShell::ProcessNextNativeEvent\t9\tcontent\n", | |
"mozalloc_abort | NS_DebugBreak | mozilla::ipc::LogicError | mozilla::gfx::VRDisplayPresentation::DestroyLayers\t6\tcontent\n", | |
"MsgWaitForMultipleObjects | mozilla::ipc::MessageChannel::WaitForInterruptNotify | mozilla::ipc::MessageChannel::Call | mozilla::plugins::PPluginInstanceParent::CallNPP_Destroy\t6\tcontent\n", | |
"RtlDoesFileExists_UstrEx | TppGlobalpGetKeyedEvent\t5\tcontent\n", | |
"LdrpNtCreateFileUnredirected\t4\tcontent\n", | |
"js::jit::CreateMIRRootList\t4\tcontent\n", | |
"nsACString::Assign\t4\tcontent\n", | |
"js::DecompressStringChunk\t4\tcontent\n", | |
"RtlImageNtHeaderEx | RtlImageNtHeader | LdrpMapResourceFile\t4\tcontent\n", | |
"RtlAnsiStringToUnicodeString | NlsGetCacheUpdateCount\t4\tcontent\n", | |
"CCliModalLoop::BlockFn\t4\tcontent\n", | |
"EnterBaseline\t4\tcontent\n", | |
"DispatchToTracer<T>\t4\tcontent\n", | |
"nsZipArchive::GetDataOffset\t4\tcontent\n", | |
"RtlAnsiStringToUnicodeString | _fnHkINLPMSG\t3\tcontent\n", | |
"mozalloc_abort | mozilla::layout::FrameChildListIterator::~FrameChildListIterator\t3\tcontent\n", | |
"mozalloc_abort | nsACString::Assign\t3\tcontent\n", | |
"TargetNtOpenFile\t2\tcontent\n", | |
"mozalloc_abort | double_conversion::TrimAndCut\t2\tcontent\n", | |
"js::SharedScriptData::traceChildren\t2\tcontent\n", | |
"mozalloc_abort | js::Debugger::dispatchHook<T>\t2\tcontent\n", | |
"CDeviceEnumerator::DestroyHWndNotificationThread\t2\tcontent\n", | |
"win32u.dll@0x8ea4\t2\tcontent\n", | |
"LongestPhaseSelfTime\t2\tcontent\n", | |
"arena_run_split | PostQueuedCompletionStatus\t2\tcontent\n", | |
"GetPdbInfo\t2\tcontent\n", | |
"RtlAnsiStringToUnicodeString | mozilla::TimeStamp::operator+=\t2\tcontent\n", | |
"nsINode::QuerySelectorAll\t2\tcontent\n", | |
"js::gc::ArenaLists::allocateFromArena\t2\tcontent\n", | |
"RtlDoesFileExists_UstrEx | RtlDoesFileExists_UstrEx | SwitchToThread\t2\tcontent\n", | |
"PR_MD_WAIT_CV | InitializeCriticalSectionEx\t2\tcontent\n", | |
"PLDHashTable::~PLDHashTable | RuleCascadeData::`scalar deleting destructor''\t2\tcontent\n", | |
"mozilla::dom::XMLHttpRequestMainThread::CloseRequest\t2\tcontent\n", | |
"js::WrappedPtrOperations<T>::lookupForAdd\t2\tcontent\n", | |
"nsRuleNode::~nsRuleNode\t2\tcontent\n", | |
"NtWaitForAlertByThreadId | IGeckoCustom_IID_Lookup\t2\tcontent\n", | |
"SetWindowsHookExAW\t2\tcontent\n", | |
"ReleaseData\t2\tcontent\n", | |
"js::GCMarker::processMarkStackTop\t2\tcontent\n", | |
"nsStyleSet::GCRuleTrees\t2\tcontent\n", | |
"FindModule\t2\tcontent\n", | |
"nsFtpChannel::Release\t1\tcontent\n", | |
"mozalloc_abort | nsCOMPtr_base::~nsCOMPtr_base | nsPropertyTable::GetPropertyListFor\t1\tcontent\n", | |
"js::gc::ArenaLists::unmarkAll\t1\tcontent\n", | |
"\n", | |
"Stats and errors for 14 days (content process)\n", | |
"Error rate: 0.0000% (467 total, 0 errors)\n", | |
"\n", | |
"Total gpu process results: 19\n", | |
"Stack counts: 6\n", | |
"Top 50 gpu process crashers on 2017/05/24\n", | |
"within the first 2 weeks since profile creation\n", | |
"---\n", | |
"mozilla::layers::LockD3DTexture<T>\t10\tgpu\n", | |
"libovrrt32_1.dll@0x2eba9\t5\tgpu\n", | |
"libovrrt32_1.dll@0x2f359\t1\tgpu\n", | |
"moz_abort | double_conversion::TrimAndCut\t1\tgpu\n", | |
"IGeckoCustom_IID_Lookup\t1\tgpu\n", | |
"nvd3dumx.dll\t1\tgpu\n", | |
"\n", | |
"Stats and errors for 14 days (gpu process)\n", | |
"Error rate: 0.0000% (19 total, 0 errors)\n" | |
] | |
} | |
], | |
"source": [ | |
"query_window = TWO_WEEKS\n", | |
"# process_type = None\n", | |
"# pings = query(query_window, query_date, query_channel, process_type)\n", | |
"# NOTE: if process_type is not used, all process types will be output\n", | |
"pings = query(query_window, query_date, query_channel)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Top 50 crashers (by signature) within the first six weeks of use" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 19, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"fetching 79.69703MB in 1852 files...\n", | |
"\n", | |
"Total main process results: 72\n", | |
"Stack counts: 48\n", | |
"Top 50 main process crashers on 2017/05/24\n", | |
"within the first 6 weeks since profile creation\n", | |
"---\n", | |
"mozilla::ipc::MessageChannel::Clear\t8\tmain\n", | |
"mozalloc_abort | NS_DebugBreak | nsDebugImpl::Abort | NS_InvokeByIndex\t5\tmain\n", | |
"@0\t4\tmain\n", | |
"`Microsoft::WRL::Module<T>::Create''::`2''::`dynamic atexit destructor for ''moduleSingleton''''\t3\tmain\n", | |
"JSAutoCompartment::JSAutoCompartment | mozilla::ScriptPreloader::PrepareCacheWrite\t3\tmain\n", | |
"OOM | small\t2\tmain\n", | |
"CDragDropHelper::MakeRectOpaqueOnBitmap\t2\tmain\n", | |
"shutdownhang | NtWaitForAlertByThreadId | SleepConditionVariableCS\t2\tmain\n", | |
"shutdownhang | SleepConditionVariableSRW\t2\tmain\n", | |
"js::TraceLoggerEvent::TraceLoggerEvent\t2\tmain\n", | |
"igd10umd32.dll | atiuxpag.dll | CContext::TID3D11DeviceContext_UpdateSubresource_<T>\t2\tmain\n", | |
"js::TenuringTracer::traverse<T>\t1\tmain\n", | |
"js::jit::DoGetPropFallback\t1\tmain\n", | |
"mozalloc_abort | js::NativeObject::addProperty\t1\tmain\n", | |
"@0xe7e2209\t1\tmain\n", | |
"shutdownhang | NtWaitForAlertByThreadId | RtlAcquireSRWLockExclusive | nsLocalFile::Release\t1\tmain\n", | |
"mozilla::ipc::FatalError | IGeckoCustom_IID_Lookup\t1\tmain\n", | |
"mozilla::CycleCollectedJSContext::ProcessMetastableStateQueue\t1\tmain\n", | |
"mozilla::PeerConnectionImpl::Initialize\t1\tmain\n", | |
"InvalidArrayIndex_CRASH | mozilla::a11y::AccessibleWrap::GetRemoteIAccessibleFor\t1\tmain\n", | |
"AsyncShutdownTimeout | profile-before-change-telemetry | TelemetryController: shutting down\t1\tmain\n", | |
"shutdownhang | NtWaitForKeyedEvent | RtlSleepConditionVariableSRW | mozilla::BaseTimeDuration<T>::FromMilliseconds\t1\tmain\n", | |
"shutdownhang | atidxx64.dll | HeapFree | atidxx64.dll | RtlpAllocateHeap | atidxx64.dll | RtlpAllocateHeap | atidxx64.dll | HeapFree | atidxx64.dll | RtlpAllocateHeap | atidxx64.dll | CCLSAllocator::Free\t1\tmain\n", | |
"XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs\t1\tmain\n", | |
"shutdownhang | nsTArray_base<T>::SwapArrayElements<T> | mozilla::dom::CustomEvent::WrapObjectInternal\t1\tmain\n", | |
"mozilla::dom::TimeoutManager::MaybeStartThrottleTrackingTimout\t1\tmain\n", | |
"js::jit::DoIteratorMoreFallback\t1\tmain\n", | |
"moz_abort | arena_run_split | arena_run_split | IGeckoCustom_IID_Lookup\t1\tmain\n", | |
"`anonymous namespace''::MessageEventRunnable::DispatchDOMEvent\t1\tmain\n", | |
"shutdownhang | RtlpWaitOnCriticalSection | free_impl | CloseHandle\t1\tmain\n", | |
"mactype64.dll@0x4147\t1\tmain\n", | |
"EnterBaseline\t1\tmain\n", | |
"js::ReportMagicWordFailure\t1\tmain\n", | |
"JSAutoCompartment::JSAutoCompartment | mozilla::loader::HashElemIter<T>::begin\t1\tmain\n", | |
"libc-2.25.so@0x132430\t1\tmain\n", | |
"libxul.so.moz-backup (deleted)@0xc4a71d\t1\tmain\n", | |
"libxul.so (deleted)@0xc4e13b\t1\tmain\n", | |
"shutdownhang | NtWaitForAlertByThreadId | IGeckoCustom_IID_Lookup\t1\tmain\n", | |
"nsContentSink::~nsContentSink\t1\tmain\n", | |
"shutdownhang | FreeArenaList\t1\tmain\n", | |
"shutdownhang | libpthread-2.25.so@0xd756\t1\tmain\n", | |
"libc-2.19.so@0x35067\t1\tmain\n", | |
"shutdownhang | NtWaitForAlertByThreadId | RtlSleepConditionVariableSRW | SleepConditionVariableSRW\t1\tmain\n", | |
"OOM | large | mozalloc_abort | mozalloc_handle_oom | moz_xmalloc | CheckTargetAndPopulate\t1\tmain\n", | |
"mozilla::ipc::PBackgroundParent::OnMessageReceived\t1\tmain\n", | |
"moz_abort | arena_run_split | arena_malloc_large | arena_ralloc_large | nsTextNode::Release\t1\tmain\n", | |
"shutdownhang | free_impl | IGeckoCustom_IID_Lookup\t1\tmain\n", | |
"mozilla::layers::LockD3DTexture<T>\t1\tmain\n", | |
"\n", | |
"Stats and errors for 42 days (main process)\n", | |
"Error rate: 0.0000% (72 total, 0 errors)\n", | |
"\n", | |
"Total content process results: 966\n", | |
"Stack counts: 488\n", | |
"Top 50 content process crashers on 2017/05/24\n", | |
"within the first 6 weeks since profile creation\n", | |
"---\n", | |
"mozilla::dom::TimeoutManager::MaybeStartThrottleTrackingTimout\t69\tcontent\n", | |
"RtlDoesFileExists_UstrEx | RtlDosSearchPath_Ustr | BasepLoadLibraryAsDataFileInternal\t44\tcontent\n", | |
"ntdll.dll@0x46c74\t35\tcontent\n", | |
"RtlAnsiStringToUnicodeString | mozilla::layout::VsyncChild::RecvNotify\t30\tcontent\n", | |
"MsgWaitForMultipleObjectsEx | mozilla::widget::WinUtils::WaitForMessage | nsAppShell::ProcessNextNativeEvent\t29\tcontent\n", | |
"mozilla::widget::WinUtils::WaitForMessage | nsAppShell::ProcessNextNativeEvent\t19\tcontent\n", | |
"IGeckoCustom_IID_Lookup\t14\tcontent\n", | |
"nsACString::Assign\t12\tcontent\n", | |
"RtlDoesFileExists_UstrEx | TppGlobalpGetKeyedEvent\t12\tcontent\n", | |
"js::GCMarker::processMarkStackTop\t9\tcontent\n", | |
"RtlAnsiStringToUnicodeString | NlsGetCacheUpdateCount\t8\tcontent\n", | |
"LdrpNtCreateFileUnredirected\t7\tcontent\n", | |
"RtlDosSearchPath_Ustr | BasepLoadLibraryAsDataFileInternal\t7\tcontent\n", | |
"mozalloc_abort | NS_DebugBreak | mozilla::ipc::LogicError | mozilla::gfx::VRDisplayPresentation::DestroyLayers\t7\tcontent\n", | |
"EnterBaseline\t7\tcontent\n", | |
"MsgWaitForMultipleObjects | mozilla::ipc::MessageChannel::WaitForInterruptNotify | mozilla::ipc::MessageChannel::Call | mozilla::plugins::PPluginInstanceParent::CallNPP_Destroy\t7\tcontent\n", | |
"CCliModalLoop::BlockFn\t7\tcontent\n", | |
"nsZipArchive::GetDataOffset\t6\tcontent\n", | |
"nsStyleSet::GCRuleTrees\t6\tcontent\n", | |
"mozilla::DefaultDelete<T>::operator() const [clone .isra.229]\t5\tcontent\n", | |
"mozilla::a11y::Accessible::HasGenericType\t5\tcontent\n", | |
"CascadeRuleEnumFunc\t5\tcontent\n", | |
"js::DecompressStringChunk\t5\tcontent\n", | |
"MsgWaitForMultipleObjectsEx | CCliModalLoop::BlockFn\t5\tcontent\n", | |
"FindModule\t5\tcontent\n", | |
"GetPdbInfo\t4\tcontent\n", | |
"js::NukeCrossCompartmentWrappers\t4\tcontent\n", | |
"RtlImageNtHeaderEx | RtlImageNtHeader | LdrpMapResourceFile\t4\tcontent\n", | |
"PR_MD_WAIT_CV | InitializeCriticalSectionEx\t4\tcontent\n", | |
"mozilla::dom::XMLHttpRequestMainThread::CloseRequest\t4\tcontent\n", | |
"mozalloc_abort | nsACString::Assign\t4\tcontent\n", | |
"MsgWaitForMultipleObjects | mozilla::ipc::MessageChannel::WaitForInterruptNotify | mozilla::ipc::MessageChannel::Call | mozilla::plugins::PPluginModuleParent::CallOptionalFunctionsSupported\t4\tcontent\n", | |
"arena_run_split | PostQueuedCompletionStatus\t4\tcontent\n", | |
"gfxPlatform::InitAcceleration\t4\tcontent\n", | |
"nsHtml5StreamParser::DispatchToMain\t4\tcontent\n", | |
"DispatchToTracer<T>\t4\tcontent\n", | |
"nsCSSRuleProcessor::RefreshRuleCascade\t4\tcontent\n", | |
"js::jit::CreateMIRRootList\t4\tcontent\n", | |
"ReleaseData\t4\tcontent\n", | |
"RtlAnsiStringToUnicodeString | _fnHkINLPMSG\t3\tcontent\n", | |
"CDeviceEnumerator::DestroyHWndNotificationThread\t3\tcontent\n", | |
"js::gc::ArenaLists::allocateFromArena\t3\tcontent\n", | |
"js::WrappedPtrOperations<T>::lookupForAdd\t3\tcontent\n", | |
"nsHtml5StreamParserPtr::release\t3\tcontent\n", | |
"mozilla::dom::FragmentOrElement::SaveSubtreeState\t3\tcontent\n", | |
"win32u.dll@0x8ea4\t3\tcontent\n", | |
"RtlAnsiStringToUnicodeString | mozilla::TimeStamp::operator+=\t3\tcontent\n", | |
"ThreadInvoke\t3\tcontent\n", | |
"TargetNtQueryAttributesFile\t3\tcontent\n", | |
"FlsSetValue\t3\tcontent\n", | |
"\n", | |
"Stats and errors for 42 days (content process)\n", | |
"Error rate: 0.1035% (966 total, 1 errors)\n", | |
"Errors:\n", | |
"6d1faf26-1e7d-4b6e-a2c1-525c8c7c3e33 missing crashing_thread; ERROR_NO_THREAD_LIST\n", | |
"\n", | |
"Total gpu process results: 28\n", | |
"Stack counts: 8\n", | |
"Top 50 gpu process crashers on 2017/05/24\n", | |
"within the first 6 weeks since profile creation\n", | |
"---\n", | |
"mozilla::layers::LockD3DTexture<T>\t16\tgpu\n", | |
"libovrrt32_1.dll@0x2eba9\t5\tgpu\n", | |
"mozalloc_abort | abort | webrender::texture_cache::TextureCache::insert::h347a9026e1a9160a\t2\tgpu\n", | |
"libovrrt32_1.dll@0x2f359\t1\tgpu\n", | |
"std::operator<\t1\tgpu\n", | |
"moz_abort | double_conversion::TrimAndCut\t1\tgpu\n", | |
"IGeckoCustom_IID_Lookup\t1\tgpu\n", | |
"nvd3dumx.dll\t1\tgpu\n", | |
"\n", | |
"Stats and errors for 42 days (gpu process)\n", | |
"Error rate: 0.0000% (28 total, 0 errors)\n" | |
] | |
} | |
], | |
"source": [ | |
"query_window = SIX_WEEKS\n", | |
"# process_type = None\n", | |
"# pings = query(query_window, query_date, query_channel, process_type)\n", | |
"# NOTE: if process_type is not used, all process types will be output\n", | |
"pings = query(query_window, query_date, query_channel)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Top 50 crashers (by signature), no profile creation date consideration" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 20, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"fetching 79.69703MB in 1852 files...\n", | |
"\n", | |
"Total main process results: 596\n", | |
"Stack counts: 312\n", | |
"Top 50 main process crashers on 2017/05/24\n", | |
"with no consideration of profile creation date\n", | |
"---\n", | |
"mozilla::dom::TimeoutManager::MaybeStartThrottleTrackingTimout\t32\tmain\n", | |
"mozilla::ipc::MessageChannel::Clear\t30\tmain\n", | |
"mozalloc_abort | NS_DebugBreak | nsDebugImpl::Abort | NS_InvokeByIndex\t28\tmain\n", | |
"JSAutoCompartment::JSAutoCompartment | mozilla::loader::HashElemIter<T>::begin\t19\tmain\n", | |
"mozilla::layers::LockD3DTexture<T>\t15\tmain\n", | |
"OOM | small\t12\tmain\n", | |
"nsDependentAtomString::nsDependentAtomString\t10\tmain\n", | |
"`Microsoft::WRL::Module<T>::Create''::`2''::`dynamic atexit destructor for ''moduleSingleton''''\t8\tmain\n", | |
"OOM | large | NS_ABORT_OOM | nsACString::Replace\t7\tmain\n", | |
"@0\t7\tmain\n", | |
"nsHtml5StreamParser::DispatchToMain\t7\tmain\n", | |
"JSAutoCompartment::JSAutoCompartment | mozilla::ScriptPreloader::PrepareCacheWrite\t7\tmain\n", | |
"moz_abort | arena_run_split | IGeckoCustom_IID_Lookup\t6\tmain\n", | |
"EnterBaseline\t6\tmain\n", | |
"js::TraceLoggerEvent::TraceLoggerEvent\t5\tmain\n", | |
"shutdownhang | NtUserPeekMessage | PeekMessageW\t5\tmain\n", | |
"shutdownhang | SleepConditionVariableSRW\t5\tmain\n", | |
"shutdownhang | NtWaitForAlertByThreadId | RtlSleepConditionVariableSRW | SleepConditionVariableSRW\t5\tmain\n", | |
"libxul.so (deleted)@0xc4d2bb\t5\tmain\n", | |
"mozilla::DefaultDelete<T>::operator() const [clone .isra.229]\t4\tmain\n", | |
"moz_abort | arena_run_split | arena_malloc_large | choose_arena\t4\tmain\n", | |
"shutdownhang | NtWaitForAlertByThreadId | IGeckoCustom_IID_Lookup\t4\tmain\n", | |
"mozilla::net::nsHttpConnection::CloseConnectionFastOpenTakesTooLongOrError\t4\tmain\n", | |
"mozalloc_abort | Abort | NS_DebugBreak | ErrorLoadingSheet\t4\tmain\n", | |
"MOZ_XMLIsNCNameChar\t4\tmain\n", | |
"DWriteFontTypeface::onFilterRec\t4\tmain\n", | |
"PLDHashTable::Search | mozilla::dom::ContentParent::TransmitPermissionsFor\t4\tmain\n", | |
"shutdownhang | `anonymous namespace''::InterposedNtWriteFile\t3\tmain\n", | |
"shutdownhang | NtWaitForKeyedEvent | RtlSleepConditionVariableSRW | mozilla::BaseTimeDuration<T>::FromMilliseconds\t3\tmain\n", | |
"shutdownhang | GenGetDebugRecord\t3\tmain\n", | |
"shutdownhang | NtReadVirtualMemory\t3\tmain\n", | |
"shutdownhang | ntdll.dll@0x46c74\t3\tmain\n", | |
"_have_cleartype_quality\t3\tmain\n", | |
"CDragDropHelper::MakeRectOpaqueOnBitmap\t3\tmain\n", | |
"PLDHashTable::Search | mozilla::dom::ContentParent::EnsurePermissionsByKey\t3\tmain\n", | |
"shutdownhang | NtSetInformationFile\t3\tmain\n", | |
"mozalloc_abort | mozJSComponentLoader::IsModuleLoaded\t3\tmain\n", | |
"shutdownhang | GenImageNtHeader\t3\tmain\n", | |
"libxul.so (deleted)@0xc4a71d\t3\tmain\n", | |
"shutdownhang | js::jit::IonCannon\t3\tmain\n", | |
"mozalloc_abort | JS::Zone::getUniqueIdInfallible\t3\tmain\n", | |
"js::TenuringTracer::traverse<T>\t2\tmain\n", | |
"fnHkINLPCWPRETSTRUCTW\t2\tmain\n", | |
"avmsnd.dll@0x3918\t2\tmain\n", | |
"js::DispatchTyped<T>\t2\tmain\n", | |
"shutdownhang | NtAlertThreadByThreadId\t2\tmain\n", | |
"mozilla::net::HttpChannelParent::NotifyDiversionFailed\t2\tmain\n", | |
"GetProxiedAccessibleInSubtree\t2\tmain\n", | |
"libxul.so (deleted)@0xc4e13b\t2\tmain\n", | |
"JSAutoCompartment::JSAutoCompartment | mozilla::ScriptPreloader::CachedScript::XDREncode\t2\tmain\n", | |
"\n", | |
"Stats and errors (main process)\n", | |
"Error rate: 0.0000% (596 total, 0 errors)\n", | |
"\n", | |
"Total content process results: 6489\n", | |
"Stack counts: 2048\n", | |
"Top 50 content process crashers on 2017/05/24\n", | |
"with no consideration of profile creation date\n", | |
"---\n", | |
"mozilla::dom::TimeoutManager::MaybeStartThrottleTrackingTimout\t359\tcontent\n", | |
"ntdll.dll@0x46c74\t207\tcontent\n", | |
"RtlDoesFileExists_UstrEx | RtlDosSearchPath_Ustr | BasepLoadLibraryAsDataFileInternal\t203\tcontent\n", | |
"MsgWaitForMultipleObjectsEx | mozilla::widget::WinUtils::WaitForMessage | nsAppShell::ProcessNextNativeEvent\t190\tcontent\n", | |
"mozilla::widget::WinUtils::WaitForMessage | nsAppShell::ProcessNextNativeEvent\t178\tcontent\n", | |
"RtlDosSearchPath_Ustr | BasepLoadLibraryAsDataFileInternal\t132\tcontent\n", | |
"IGeckoCustom_IID_Lookup\t129\tcontent\n", | |
"RtlDoesFileExists_UstrEx | TppGlobalpGetKeyedEvent\t86\tcontent\n", | |
"nsACString::Assign\t83\tcontent\n", | |
"LdrpNtCreateFileUnredirected\t72\tcontent\n", | |
"RtlAnsiStringToUnicodeString | mozilla::TimeStamp::operator+=\t57\tcontent\n", | |
"RtlAnsiStringToUnicodeString | NlsGetCacheUpdateCount\t54\tcontent\n", | |
"GetCurrentThread\t53\tcontent\n", | |
"js::GCMarker::processMarkStackTop\t49\tcontent\n", | |
"RtlDoesFileExists_UstrEx | RtlDoesFileExists_UstrEx | SwitchToThread\t46\tcontent\n", | |
"EnterBaseline\t40\tcontent\n", | |
"RtlImageNtHeaderEx | RtlImageNtHeader | LdrpMapResourceFile\t40\tcontent\n", | |
"CCliModalLoop::BlockFn\t38\tcontent\n", | |
"arena_run_split | PostQueuedCompletionStatus\t38\tcontent\n", | |
"nsZipArchive::GetDataOffset\t37\tcontent\n", | |
"nsHtml5StreamParser::DispatchToMain\t35\tcontent\n", | |
"CascadeRuleEnumFunc\t34\tcontent\n", | |
"nsContainerFrame::GetChildLists\t34\tcontent\n", | |
"MsgWaitForMultipleObjectsEx | CCliModalLoop::BlockFn\t34\tcontent\n", | |
"libc-2.25.so@0xe267d\t31\tcontent\n", | |
"GetTickCount\t31\tcontent\n", | |
"js::NukeCrossCompartmentWrappers\t30\tcontent\n", | |
"RtlAnsiStringToUnicodeString | mozilla::layout::VsyncChild::RecvNotify\t30\tcontent\n", | |
"ReleaseData\t29\tcontent\n", | |
"NtReadVirtualMemory\t29\tcontent\n", | |
"libc-2.23.so@0xfab5d\t28\tcontent\n", | |
"TargetNtOpenFile\t27\tcontent\n", | |
"mach_msg_trap\t25\tcontent\n", | |
"mozilla::DefaultDelete<T>::operator() const [clone .isra.229]\t24\tcontent\n", | |
"mozalloc_abort | double_conversion::TrimAndCut\t23\tcontent\n", | |
"RtlAnsiStringToUnicodeString | IGeckoCustom_IID_Lookup\t23\tcontent\n", | |
"js::gc::GCRuntime::beginMarkPhase\t23\tcontent\n", | |
"TargetNtQueryAttributesFile\t23\tcontent\n", | |
"base::MessagePumpForIO::ScheduleWork\t23\tcontent\n", | |
"nsFrameManager::CaptureFrameState\t22\tcontent\n", | |
"FindModule\t22\tcontent\n", | |
"win32u.dll@0x8ea4\t21\tcontent\n", | |
"PostQueuedCompletionStatus\t21\tcontent\n", | |
"nsRuleNode::~nsRuleNode\t20\tcontent\n", | |
"libsystem_kernel.dylib@0x10f72\t20\tcontent\n", | |
"nsStyleSet::GCRuleTrees\t20\tcontent\n", | |
"GetPdbInfo\t19\tcontent\n", | |
"MsgWaitForMultipleObjects | mozilla::ipc::MessageChannel::WaitForInterruptNotify | mozilla::ipc::MessageChannel::Call | mozilla::plugins::PPluginInstanceParent::CallNPP_Destroy\t18\tcontent\n", | |
"nsAString::Assign\t18\tcontent\n", | |
"GetFileVersionInfoSizeExW\t18\tcontent\n", | |
"\n", | |
"Stats and errors (content process)\n", | |
"Error rate: 0.4161% (6489 total, 27 errors)\n", | |
"Errors:\n", | |
"ab7d6fe6-f24d-fd42-8d77-5318f56bafb3 missing crashing_thread; OK\n", | |
"5bf91b34-1e9f-4260-a0e0-c91bfd854544 missing crashing_thread; ERROR_NO_THREAD_LIST\n", | |
"458213e3-d55d-f543-aaca-a81ba1b9b1ed missing crashing_thread; ERROR_NO_THREAD_LIST\n", | |
"cd6dcaeb-32a7-49ca-b56b-77d9bcd74f35 missing crashing_thread; OK\n", | |
"0f03f0aa-c73a-fe4c-84cf-0c88a2177e13 missing crashing_thread; OK\n", | |
"42837aa7-3147-4f31-b6d7-2e42b9c45b90 missing crashing_thread; ERROR_NO_THREAD_LIST\n", | |
"c41ab712-7940-0541-96ce-f4d367ef8b75 missing crashing_thread; OK\n", | |
"d59b2280-5f8e-4791-a7e6-a5d1f3e14c70 missing crashing_thread; OK\n", | |
"80f943ba-06b2-483a-9a42-0939dc4ba24c missing crashing_thread; ERROR_NO_THREAD_LIST\n", | |
"589f630e-182d-6949-836c-f15a940cf835 missing crashing_thread; OK\n", | |
"6d1faf26-1e7d-4b6e-a2c1-525c8c7c3e33 missing crashing_thread; ERROR_NO_THREAD_LIST\n", | |
"bff3673b-ef34-4029-b1d9-6111b8b79a82 missing crashing_thread; OK\n", | |
"8ad30265-25af-4fb2-8806-c12840220dd0 missing crashing_thread; ERROR_NO_THREAD_LIST\n", | |
"a2b31620-9d04-46f2-8b6c-256a90c071d7 missing crashing_thread; OK\n", | |
"9b6a66fb-f75c-d240-bf23-ed5aa7356d3e missing crashing_thread; OK\n", | |
"b331abfc-79e7-4c3d-8660-bf27a417448c missing crashing_thread; ERROR_NO_THREAD_LIST\n", | |
"1cc0462c-b547-4b42-9d36-76828dcd4ca7 missing crashing_thread; OK\n", | |
"6bb228bd-cfb1-4492-b8ba-815ba05f383d missing crashing_thread; OK\n", | |
"817bc032-8f17-4124-95a5-ce99b6a55128 missing crashing_thread; ERROR_NO_THREAD_LIST\n", | |
"9284db71-a6e3-1141-ae70-39f550ea1c40 missing crashing_thread; OK\n", | |
"71a70ece-dab0-5f4b-97b8-a18cecb113ec missing crashing_thread; OK\n", | |
"00557aca-3987-1548-b3f6-bbef7d9cd0f2 missing crashing_thread; OK\n", | |
"6acf7098-0df4-984a-8f0d-35e7091bff61 missing crashing_thread; ERROR_NO_THREAD_LIST\n", | |
"849e2919-8a61-5a46-8404-f68b83ffc5a5 missing crashing_thread; OK\n", | |
"bc2673ff-8264-4207-b919-2405bd04c535 missing crashing_thread; ERROR_NO_THREAD_LIST\n", | |
"ae8f840b-253e-0248-be9c-c706be3828eb missing crashing_thread; OK\n", | |
"132338e0-dfa6-4b83-a875-f9514db0fdaa Traceback (most recent call last):\n", | |
" File \"<ipython-input-16-71c20440b0fe>\", line 38, in pingsig\n", | |
" File \"<ipython-input-13-886c2c418318>\", line 137, in symbolicate_ping\n", | |
" File \"/mnt/anaconda2/lib/python2.7/site-packages/requests/models.py\", line 862, in raise_for_status\n", | |
" raise HTTPError(http_error_msg, response=self)\n", | |
"HTTPError: 400 Client Error: Bad Request for url: http://symbolapi.mozilla.org/\n", | |
"\n", | |
"\n", | |
"Total gpu process results: 83\n", | |
"Stack counts: 30\n", | |
"Top 50 gpu process crashers on 2017/05/24\n", | |
"with no consideration of profile creation date\n", | |
"---\n", | |
"mozilla::layers::LockD3DTexture<T>\t31\tgpu\n", | |
"libovrrt32_1.dll@0x2eba9\t10\tgpu\n", | |
"nvwgf2um.dll | CContext::RelocateVideoFuncs\t5\tgpu\n", | |
"libovrrt32_1.dll@0x2f359\t4\tgpu\n", | |
"igd10iumd64.dll | TppCallbackEpilog\t4\tgpu\n", | |
"nvwgf2umx.dll | RtlFreeHeap | RtlFreeHeap | nvwgf2umx.dll | NDXGI::CDevice::DestroySynchronizationObjectCB\t2\tgpu\n", | |
"mozalloc_abort | abort | webrender::texture_cache::TextureCache::insert::h347a9026e1a9160a\t2\tgpu\n", | |
"libX11.so.6.3.0@0x38559\t2\tgpu\n", | |
"mozilla::layers::CompositorD3D11::BeginFrame\t2\tgpu\n", | |
"mozilla::ipc::FatalError | IGeckoCustom_IID_Lookup\t1\tgpu\n", | |
"OOM | unknown | mozalloc_abort | mozalloc_handle_oom | moz_xmalloc | mozilla::BufferList<T>::AllocateSegment\t1\tgpu\n", | |
"moz_abort | double_conversion::TrimAndCut\t1\tgpu\n", | |
"nvwgf2umx.dll\t1\tgpu\n", | |
"memcpy | mozilla::layers::MappedYCbCrTextureData::CopyInto\t1\tgpu\n", | |
"RtlSizeHeap | RtlAllocateHeap | MemAlloc\t1\tgpu\n", | |
"mozalloc_abort | double_conversion::TrimAndCut\t1\tgpu\n", | |
"libX11.so.6.3.0@0x38779\t1\tgpu\n", | |
"nvwgf2umx.dll | stdext::_Hash<T>::insert\t1\tgpu\n", | |
"`anonymous namespace''::internal_RemoteAccumulate\t1\tgpu\n", | |
"atidxx64.dll | atiumd6a.dll | atidxx64.dll | atiumd6a.dll | atidxx64.dll | atiumd6a.dll | ReleaseMutex\t1\tgpu\n", | |
"libX11.so.6.3.0@0x41d5b\t1\tgpu\n", | |
"std::operator<\t1\tgpu\n", | |
"nvd3dumx.dll\t1\tgpu\n", | |
"IGeckoCustom_IID_Lookup\t1\tgpu\n", | |
"igd10iumd64.dll | arena_dalloc_small | free_impl | igd10iumd64.dll | free_impl | igd10iumd64.dll | mozilla::layers::LayerTransactionParent::`scalar deleting destructor''\t1\tgpu\n", | |
"nvwgf2umx.dll | TCLSWrappers<T>::CLSDestroy\t1\tgpu\n", | |
"igd10iumd64.dll | RtlAllocateHeap | RtlpTpWaitCallback | igd10iumd64.dll | TppCritSetThread\t1\tgpu\n", | |
"OOM | unknown | NS_ABORT_OOM | nsBaseHashtable<T>::Put | mozilla::layers::CompositorAnimationStorage::SetAnimatedValue\t1\tgpu\n", | |
"igd10iumd64.dll | CContext::ResolveOMUnacquiredHazards\t1\tgpu\n", | |
"nvwgf2um.dll | CContext::ID3D11DeviceContext1_UpdateSubresource_<T>\t1\tgpu\n", | |
"\n", | |
"Stats and errors (gpu process)\n", | |
"Error rate: 0.0000% (83 total, 0 errors)\n" | |
] | |
} | |
], | |
"source": [ | |
"query_window = None\n", | |
"# process_type = None\n", | |
"# pings = query(query_window, query_date, query_channel, process_type)\n", | |
"# NOTE: if process_type is not used, all process types will be output\n", | |
"pings = query(query_window, query_date, query_channel)" | |
] | |
} | |
], | |
"metadata": { | |
"anaconda-cloud": {}, | |
"kernelspec": { | |
"display_name": "Python [default]", | |
"language": "python", | |
"name": "python2" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 2 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython2", | |
"version": "2.7.12" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 0 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding: utf-8 | |
--- | |
title: Top Crashers list from client-side stacks | |
authors: | |
- Adam Gashlin | |
- David Durst | |
tags: | |
- crash | |
- client-side | |
- signature | |
created_at: 2017-05-10 | |
updated_at: 2017-05-25 | |
tldr: This queries crash pings from a specified day, symbolicates then to assign signatures, and then makes a top crasher list for that day. | |
--- | |
# # Top crash ping signatures, by day | |
# In[11]: | |
# This Source Code Form is subject to the terms of the Mozilla Public | |
# License, v. 2.0. If a copy of the MPL was not distributed with this | |
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
from moztelemetry import get_pings_properties | |
from moztelemetry import Dataset | |
import json | |
import requests | |
import re | |
from itertools import islice | |
# ## Ping processing | |
# In[12]: | |
SYMBOLICATION_API_URL = 'http://symbolapi.mozilla.org/' | |
COLLAPSE_ARGUMENTS = True | |
ESCAPE_SINGLE_QUOTE = True | |
MAXIMUM_FRAMES_TO_CONSIDER = 40 | |
SIGNATURE_MAX_LEN = 255 | |
TWO_WEEKS = 14 | |
SIX_WEEKS = 42 | |
# ## Symbolication | |
# In[13]: | |
# extract function name from "fn (in module)" | |
EXTRACT_FUNCTION_NAME = re.compile(r'\A(.+) (\(in .+\))\Z') | |
HEX_ADDR = re.compile(r'\A0x[0-9a-fA-F]+\Z') | |
def symbolicate_ping(ping): | |
"""Take a crash ping and return symbolicated stack traces. | |
Uses the symbolication API to look up function names. | |
""" | |
# if there is no payload or stackTraces, return nothing | |
stack_traces = None | |
if not ping.get('payload', None): | |
# return None | |
raise ValueError('No payload') | |
else: | |
payload = ping['payload'] | |
if not payload.get('stackTraces', None): | |
# return None | |
raise ValueError('No stackTraces') | |
else: | |
stack_traces = payload['stackTraces'] | |
# make sure we have threads, modules, and crashing_thread | |
missing = '' | |
if 'threads' not in stack_traces: | |
missing = 'threads' | |
elif 'modules' not in stack_traces: | |
missing = 'modules' | |
elif not stack_traces.get('crash_info', None): | |
missing = 'crash_info' | |
else: | |
threads = stack_traces['threads'] | |
modules = stack_traces['modules'] | |
if 'crashing_thread' not in stack_traces['crash_info']: | |
missing = 'crashing_thread' | |
else: | |
crashing_thread = stack_traces['crash_info']['crashing_thread'] | |
if missing: | |
msg = "missing " + missing | |
if stack_traces: | |
msg += "; " + stack_traces.get('status', 'STATUS MISSING') | |
raise ValueError(msg) | |
if not (crashing_thread >= 0 and crashing_thread < len(threads)): | |
msg = "crashing_thread " + crashing_thread | |
msg += " out of range" | |
raise ValueError(msg) | |
symbolicated_threads = [] | |
modules_to_symbolicate = [] | |
threads_to_symbolicate = [] | |
for thread_idx, src_thread in enumerate(threads): | |
out_thread_frames = [] | |
symbolicated_threads.append(out_thread_frames) | |
frames_to_symbolicate = [] | |
# only the crashing thread and thread 0 are used for the | |
# signature, skip symbol lookup for others | |
if thread_idx != 0 and thread_idx != crashing_thread: | |
continue | |
if 'frames' not in src_thread: | |
continue | |
for frame_idx, src_frame in enumerate(islice( | |
src_thread['frames'], MAXIMUM_FRAMES_TO_CONSIDER)): | |
out_frame = {} | |
out_thread_frames.append(out_frame) | |
if 'ip' not in src_frame: | |
msg = "missing ip for thread " + thread_idx + " frame " | |
msg += frame_idx | |
raise ValueError(msg) | |
ip_int = int(src_frame['ip'], 16) | |
out_frame['offset'] = src_frame['ip'] | |
if 'module_index' not in src_frame: | |
continue | |
module_index = src_frame['module_index'] | |
if not (module_index >= 0 and module_index < len(modules)): | |
msg = "module_index " + module_index + " out of range for " | |
msg += "thread " + thread_idx + " frame " + frame_idx | |
raise ValueError(msg) | |
module = modules[module_index] | |
if 'base_addr' not in module: | |
msg = "missing base_addr for module " + module_index | |
raise ValueError(msg) | |
try: | |
module_offset_int = ip_int - int(module['base_addr'], 16) | |
except ValueError: | |
msg = "bad base_addr " + module['base_addr'] | |
msg += " for module " + module_index | |
raise ValueError(msg) | |
if 'filename' in module: | |
out_frame['module'] = module['filename'] | |
out_frame['module_offset'] = '0x%x' % module_offset_int | |
# prepare this frame for symbol lookup | |
if 'debug_file' in module and 'debug_id' in module: | |
mp = (module['debug_file'], module['debug_id']) | |
if mp not in modules_to_symbolicate: | |
modules_to_symbolicate.append(mp) | |
frames_to_symbolicate.append( | |
{'lookup': [modules_to_symbolicate.index(mp), | |
module_offset_int], | |
'output': out_frame}) | |
if len(frames_to_symbolicate) > 0: | |
threads_to_symbolicate.append(frames_to_symbolicate) | |
if len(threads_to_symbolicate) == 0: | |
return symbolicated_threads | |
sym_request = { | |
'stacks': [[f['lookup'] for f in t] for t in threads_to_symbolicate], | |
'memoryMap': | |
[[debug_file, debug_id] for | |
(debug_file, debug_id) in modules_to_symbolicate], | |
'version': 4} | |
response = requests.post(SYMBOLICATION_API_URL, | |
json=sym_request) | |
response.raise_for_status() | |
sym_result = response.json() | |
stacks = sym_result['symbolicatedStacks'] | |
for thread, thread_result in zip(threads_to_symbolicate, stacks): | |
for f, symbol in zip(thread, thread_result): | |
module_idx = f['lookup'][0] | |
if sym_result['knownModules'][module_idx]: | |
function_name = EXTRACT_FUNCTION_NAME.match(symbol).group(1) | |
if function_name and not HEX_ADDR.match(function_name): | |
f['output']['function'] = function_name | |
return symbolicated_threads | |
# ## Signature generation | |
# from https://github.com/mozilla/socorro/blob/master/socorro/processor/signature_utilities.py | |
# In[14]: | |
def generate_signature(ping, symbolicated_threads): | |
"""Using a crash ping and associated symbolicated stacks from each thread, | |
generate a signature identifying the crash. This is intended to behave | |
similarly to Socorro, given the data available in the pings. | |
""" | |
# SignatureGenerationRule | |
try: | |
lowercase = 'Windows_NT' in ping['environment']['system']['os']['name'] | |
except KeyError: | |
lowercase = False | |
stack_traces = ping['payload']['stackTraces'] | |
crashing_thread_idx = stack_traces['crash_info']['crashing_thread'] | |
crashing_thread = symbolicated_threads[crashing_thread_idx] | |
signature_list = create_frame_list(crashing_thread, lowercase) | |
signature = signature_from_list(signature_list) | |
# StackwalkerErrorSignatureRule | |
if signature.startswith('EMPTY'): | |
try: | |
signature = "%s; %s" % (signature, stack_traces['status']) | |
except KeyError: | |
pass | |
# OOMSignature | |
signature = oom_signature(ping, signature) | |
# AbortSignature | |
signature = abort_signature(ping, signature) | |
# TODO: something about MozCrashReason? | |
# TODO: something more useful for BaseThreadInitThunk | |
# SignatureShutdownTimeout | |
signature = shutdown_timeout_signature(ping, signature) | |
# SignatureRunWatchDog | |
# TODO: detect more types of hang watchdog timeout | |
if 'RunWatchdog' in signature: | |
# Always use thread 0 in this case, because that's the thread that | |
# was hanging when the software was artificially crashed. | |
crashing_thread = symbolicated_threads[0] | |
signature_list = create_frame_list(crashing_thread, lowercase) | |
signature = "shutdownhang | %s" % signature_from_list(signature_list) | |
# SigTrim | |
signature = signature.strip() | |
# SigTrunc | |
if len(signature) > SIGNATURE_MAX_LEN: | |
signature = "%s..." % signature[:SIGNATURE_MAX_LEN - 3] | |
return signature | |
# from SignatureGenerationRule._create_frame_list | |
def create_frame_list(thread, make_modules_lower_case): | |
frame_signatures_list = [] | |
for a_frame in thread: | |
if make_modules_lower_case and 'module' in a_frame: | |
a_frame['module'] = a_frame['module'].lower() | |
normalized_signature = normalize_signature(**a_frame) | |
if 'normalized' not in a_frame: | |
a_frame['normalized'] = normalized_signature | |
frame_signatures_list.append(normalized_signature) | |
return frame_signatures_list | |
# from CSignatureToolBase._do_generate | |
def signature_from_list(source_list): | |
""" | |
each element of signatureList names a frame in the crash stack; and is: | |
- a prefix of a relevant frame: Append this element to the signature | |
- a relevant frame: Append this element and stop looking | |
- irrelevant: Append this element only after seeing a prefix frame | |
The signature is a ' | ' separated string of frame names. | |
""" | |
# shorten source_list to the first signatureSentinel | |
sentinel_locations = [] | |
for a_sentinel in signature_sentinels: | |
if type(a_sentinel) == tuple: | |
a_sentinel, condition_fn = a_sentinel | |
if not condition_fn(source_list): | |
continue | |
try: | |
sentinel_locations.append(source_list.index(a_sentinel)) | |
except ValueError: | |
pass | |
if sentinel_locations: | |
source_list = source_list[min(sentinel_locations):] | |
# Get all the relevant frame signatures. | |
new_signature_list = [] | |
for a_signature in source_list: | |
# If the signature matches the irrelevant signatures regex, | |
# skip to the next frame. | |
if irrelevant_signature_re.match(a_signature): | |
continue | |
# If the signature matches the trim dll signatures regex, | |
# rewrite it to remove all but the module name. | |
if trim_dll_signature_re.match(a_signature): | |
a_signature = a_signature.split('@')[0] | |
# If this trimmed DLL signature is the same as the previous | |
# frame's, we do not want to add it. | |
if ( | |
new_signature_list and | |
a_signature == new_signature_list[-1] | |
): | |
continue | |
new_signature_list.append(a_signature) | |
# If the signature does not match the prefix signatures regex, | |
# then it is the last one we add to the list. | |
if not prefix_signature_re.match(a_signature): | |
break | |
# Add a special marker for hang crash reports. | |
#if hang_type: | |
# new_signature_list.insert(0, self.hang_prefixes[hang_type]) | |
signature = ' | '.join(new_signature_list) | |
# Handle empty signatures to explain why we failed generating them. | |
if signature == '' or signature is None: | |
try: | |
signature = source_list[0] | |
except IndexError: | |
signature = "EMPTY: no frame data available" | |
if ESCAPE_SINGLE_QUOTE: | |
signature = signature.replace("'", "''") | |
if len(signature) > SIGNATURE_MAX_LEN: | |
signature = "%s..." % signature[:SIGNATURE_MAX_LEN - 3] | |
return signature | |
FIXUP_SPACE = re.compile(r' (?=[\*&,])') | |
FIXUP_COMMA = re.compile(r',(?! )') | |
# from CSignatureToolBase.normalize_signature and friends | |
def normalize_signature( | |
module=None, | |
function=None, | |
file=None, | |
line=None, | |
module_offset=None, | |
offset=None, | |
function_offset=None, | |
normalized=None, | |
**kwargs # eat any extra kwargs passed in | |
): | |
""" returns a structured conglomeration of the input parameters to | |
serve as a signature. the parameter names of this function reflect the | |
exact names of the fields from the jsonmdsw frame output. this allows | |
this function to be invoked by passing a frame as **a_frame. sometimes, | |
a frame may already have a normalized version cached. if that exists, | |
return it instead. | |
""" | |
if normalized is not None: | |
return normalized | |
def collapse( | |
function_signature_str, | |
open_string, | |
replacement_open_string, | |
close_string, | |
replacement_close_string, | |
exception_substring_list=(), # list of exceptions that shouldn't collapse | |
): | |
"""takes a string representing a C/C++ function signature | |
and replaces anything between to possibly nested delimiters""" | |
target_counter = 0 | |
collapsed_list = [] | |
exception_mode = False | |
def append_if_not_in_collapse_mode(a_character): | |
if not target_counter: | |
collapsed_list.append(a_character) | |
def is_exception( | |
exception_list, | |
remaining_original_line, | |
line_up_to_current_position | |
): | |
for an_exception in exception_list: | |
if remaining_original_line.startswith(an_exception): | |
return True | |
if line_up_to_current_position.endswith(an_exception): | |
return True | |
return False | |
for index, a_character in enumerate(function_signature_str): | |
if a_character == open_string: | |
if is_exception( | |
exception_substring_list, | |
function_signature_str[index + 1:], | |
function_signature_str[:index] | |
): | |
exception_mode = True | |
append_if_not_in_collapse_mode(a_character) | |
continue | |
append_if_not_in_collapse_mode(replacement_open_string) | |
target_counter += 1 | |
elif a_character == close_string: | |
if exception_mode: | |
append_if_not_in_collapse_mode(a_character) | |
exception_mode = False | |
else: | |
target_counter -= 1 | |
append_if_not_in_collapse_mode(replacement_close_string) | |
else: | |
append_if_not_in_collapse_mode(a_character) | |
edited_function = ''.join(collapsed_list) | |
return edited_function | |
if function: | |
function = collapse( | |
function, | |
'<', | |
'<', | |
'>', | |
'T>', | |
('name omitted', 'IPC::ParamTraits') | |
) | |
if COLLAPSE_ARGUMENTS: | |
function = collapse( | |
function, | |
'(', | |
'', | |
')', | |
'', | |
('anonymous namespace', 'operator') | |
) | |
# Remove spaces before all stars, ampersands, and commas | |
function = FIXUP_SPACE.sub('', function) | |
# Ensure a space after commas | |
function = FIXUP_COMMA.sub(', ', function) | |
return function | |
if not module and not module_offset and offset: | |
return "@%s" % offset | |
if not module: | |
module = '' # might have been None | |
return '%s@%s' % (module, module_offset) | |
def oom_signature(ping, signature): | |
match = False | |
if 'metadata' in ping['payload']: | |
if 'OOMAllocationSize' in ping['payload']['metadata']: | |
match = True | |
for a_signature_fragment in ( 'NS_ABORT_OOM', | |
'mozalloc_handle_oom', | |
'CrashAtUnhandlableOOM', | |
'AutoEnterOOMUnsafeRegion'): | |
if a_signature_fragment in signature: | |
match = True | |
if not match: | |
return signature | |
try: | |
oom_size = int(ping['payload']['metadata']['OOMAllocationSize']) | |
if oom_size <= 262144: # 256K | |
signature = "OOM | small" | |
else: | |
signature = ( | |
"OOM | large | " + signature | |
) | |
except (TypeError, AttributeError, KeyError): | |
signature = ( | |
"OOM | unknown | " + signature | |
) | |
return signature | |
def abort_signature(ping, signature): | |
if 'metadata' not in ping['payload']: | |
return signature | |
if 'AbortMessage' not in ping['payload']['metadata']: | |
return signature | |
if not ping['payload']['metadata']['AbortMessage']: | |
return signature | |
abort_message = ping['payload']['metadata']['AbortMessage'] | |
if '###!!! ABORT: file ' in abort_message: | |
# This is an abort message that contains no interesting | |
# information. We just want to put the "Abort" marker in the | |
# signature. | |
return 'Abort | {}'.format(signature) | |
if '###!!! ABORT:' in abort_message: | |
# Recent crash reports added some irrelevant information at the | |
# beginning of the abort message. We want to remove that and keep | |
# just the actual abort message. | |
abort_message = abort_message.split('###!!! ABORT:', 1)[1].strip() | |
if ': file ' in abort_message: | |
# Abort messages contain a file name and a line number. Since | |
# those are very likely to change between builds, we want to | |
# remove those parts from the signature. | |
abort_message = abort_message.split(': file ', 1)[0].strip() | |
if len(abort_message) > 80: | |
abort_message = abort_message[:77] + '...' | |
return 'Abort | {} | {}'.format(abort_message, signature) | |
def shutdown_timeout_signature(ping, signature): | |
if 'metadata' not in ping['payload']: | |
return signature | |
timeout_json = ping['payload']['metadata'].get('AsyncShutdownTimeout','') | |
if not timeout_json: | |
return signature | |
parts = ['AsyncShutdownTimeout'] | |
try: | |
shutdown_data = json.loads(timeout_json) | |
parts.append(shutdown_data['phase']) | |
conditions = [c['name'] for c in shutdown_data['conditions']] | |
if conditions: | |
conditions.sort() | |
parts.append(','.join(conditions)) | |
else: | |
parts.append("(none)") | |
except (ValueError, KeyError), e: | |
parts.append("UNKNOWN") | |
new_sig = ' | '.join(parts) | |
return new_sig | |
# ## Lists of function signatures used in signature generation | |
# from https://github.com/mozilla/socorro/tree/master/socorro/siglists | |
# In[15]: | |
irrelevant_signature_re = re.compile( | |
'|'.join("""@0x[0-9a-fA-F]{2,} | |
@0x[1-9a-fA-F] | |
__aeabi_fcmpgt.* | |
ashmem | |
app_process@0x.* | |
core\.odex@0x.* | |
core::panicking::.* | |
CrashStatsLogForwarder::CrashAction | |
_CxxThrowException | |
dalvik-heap | |
dalvik-jit-code-cache | |
dalvik-LinearAlloc | |
dalvik-mark-stack | |
data@app@org\.mozilla\.f.*-\d\.apk@classes\.dex@0x.* | |
framework\.odex@0x.* | |
google_breakpad::ExceptionHandler::HandleInvalidParameter.* | |
KiFastSystemCallRet | |
libandroid_runtime\.so@0x.* | |
libbinder\.so@0x.* | |
libc\.so@.* | |
libc-2\.5\.so@.* | |
libEGL\.so@.* | |
libdvm\.so\s*@\s*0x.* | |
libgui\.so@0x.* | |
libicudata.so@.* | |
libMali\.so@0x.* | |
libutils\.so@0x.* | |
libz\.so@0x.* | |
linux-gate\.so@0x.* | |
mnt@asec@org\.mozilla\.f.*-\d@pkg\.apk@classes\.dex@0x.* | |
MOZ_Assert | |
MOZ_Crash | |
mozcrt19.dll@0x.* | |
mozilla::gfx::Log<.* | |
mozilla::ipc::RPCChannel::Call | |
_NSRaiseError | |
(Nt|Zw)?WaitForSingleObject(Ex)? | |
(Nt|Zw)?WaitForMultipleObjects(Ex)? | |
nvmap@0x.* | |
org\.mozilla\.f.*-\d\.apk@0x.* | |
PR_WaitCondVar | |
RaiseException | |
RtlpAdjustHeapLookasideDepth | |
std::_Atomic_fetch_add_4 | |
std::panicking::.* | |
system@framework@.*\.jar@classes\.dex@0x.* | |
___TERMINATING_DUE_TO_UNCAUGHT_EXCEPTION___ | |
WaitForSingleObjectExImplementation | |
WaitForMultipleObjectsExImplementation | |
RealMsgWaitFor.* | |
_ZdlPv | |
zero""".split('\n'))) | |
prefix_signature_re = re.compile( | |
'|'.join("""@0x0 | |
.*CrashAtUnhandlableOOM | |
Abort | |
.*abort | |
.*alloc_impl | |
_alloca_probe.* | |
__android_log_assert | |
arena_.* | |
BaseGetNamedObjectDirectory | |
.*calloc | |
cert_.* | |
CERT_.* | |
CFRelease | |
_chkstk | |
CleanupPerAppKey | |
CrashInJS | |
__delayLoadHelper2 | |
dlmalloc | |
dlmalloc_trim | |
dvm.* | |
EtwEventEnabled | |
extent_.* | |
fastcopy_I | |
fastzero_I | |
_files_getaddrinfo | |
.*free | |
free_impl | |
GCGraphBuilder::NoteXPCOMChild | |
getanswer | |
HandleInvalidParameter | |
HeapFree | |
huge_dalloc | |
huge_palloc | |
ialloc | |
imalloc | |
init_library | |
InvalidArrayIndex_CRASH | |
invalid_parameter_noinfo | |
_invalid_parameter_noinfo | |
isalloc | |
jemalloc_crash | |
je_.* | |
JNI_CreateJavaVM | |
_JNIEnv.* | |
JNI_GetCreatedJavaVM.* | |
js::AutoCompartment::AutoCompartment.* | |
js::AutoEnterOOMUnsafeRegion::crash | |
js::detail::HashTable<.*>::.* | |
js::HashSet<.*>::.* | |
js::HashMap<.*>::.* | |
js::LifoAlloc::getOrCreateChunk | |
JSAutoCompartment::JSAutoCompartment.* | |
JS_DHashTableEnumerate | |
JS_DHashTableOperate | |
JS_NewStringCopyZ.* | |
kill | |
__libc_android_abort | |
libobjc.A.dylib@0x1568. | |
(libxul\.so|xul\.dll|XUL)@0x.* | |
LL_.* | |
malloc | |
_MD_.* | |
memcmp | |
__memcmp16 | |
memcpy | |
memmove | |
memset | |
mozalloc_abort.* | |
mozalloc_handle_oom | |
moz_free | |
mozilla::AndroidBridge::AutoLocalJNIFrame::~AutoLocalJNIFrame | |
mozilla::CondVar::.* | |
mozilla::ipc::LogicError | |
mozilla::ipc::MessageChannel::AssertWorkerThread | |
mozilla::ipc::MessageChannel::Call | |
mozilla::ipc::MessageChannel::CxxStackFrame::CxxStackFrame | |
mozilla::ipc::MessageChannel::Send | |
mozilla::ipc::RPCChannel::Call | |
mozilla::ipc::RPCChannel::CxxStackFrame::CxxStackFrame | |
mozilla::ipc::RPCChannel::EnteredCxxStack | |
mozilla::ipc::RPCChannel::Send | |
mozilla::layers::CompositorD3D11::Failed | |
mozilla::layers::CompositorD3D11::HandleError | |
mozilla.*FatalError | |
moz_xmalloc | |
moz_xrealloc | |
MOZ_CrashOOL | |
MOZ_CrashPrintf | |
msvcr120\.dll@0x.* | |
\<name omitted\> | |
NP_Shutdown | |
(NS_)?(Lossy)?(Copy|Append|Convert).*UTF.* | |
nsACString_internal::Assign.* | |
nsAString_internal::Assign.* | |
nsACString_internal::BeginWriting | |
nsAString_internal::BeginWriting | |
nsACString_internal::SetCapacity | |
NS_strcmp | |
nsBaseHashtable<.*>::.* | |
nsClassHashtable<.*>::.* | |
nsCOMPtr.* | |
NS_ABORT_OOM.* | |
nsDataHashtable<.*>::.* | |
NS_DebugBreak.* | |
nsDebugImpl::Abort | |
nsDependentString::nsDependentString | |
nsEventQueue::GetEvent | |
nsThread::GetEvent | |
nsThread::nsChainedEventQueue::GetEvent | |
[-+]\[NSException raise(:format:(arguments:)?)?\] | |
nsInterfaceHashtable<.*>::.* | |
nsJSThingHashtable<.*>::.* | |
nsObjCExceptionLogAbort | |
nsRefPtr.* | |
NSS.* | |
nss.* | |
nsTArray<.* | |
nsTArray_base<.* | |
nsTArray_Impl<.* | |
nsTHashtable<.*>::.* | |
nsThread::Shutdown | |
NtUser.* | |
objc_exception_throw | |
objc_msgSend | |
operator new | |
<.*>::operator() | |
PLDHashTable::.* | |
PL_.* | |
port_.* | |
PORT_.* | |
_PR_.* | |
PR_.* | |
.*ProcessNextEvent.* | |
__psynch_cvwait | |
_pthread_cond_wait | |
pthread_mutex_lock | |
_purecall | |
raise | |
realloc | |
recv | |
.*ReentrantMonitor::Wait.* | |
RefPtr.* | |
_RTC_Terminate | |
Rtl.* | |
_Rtl.* | |
__Rtl.* | |
__rust_start_panic | |
SEC_.*Item | |
seckey_.* | |
SECKEY_.* | |
__security_check_cookie | |
send | |
setjmp | |
sigblock | |
sigprocmask | |
SocketAccept | |
SocketAcceptRead | |
SocketAvailable | |
SocketAvailable64 | |
SocketBind | |
SocketClose | |
SocketConnect | |
SocketGetName | |
SocketGetPeerName | |
SocketListen | |
SocketPoll | |
SocketRead | |
SocketRecv | |
SocketSend | |
SocketShutdown | |
SocketSync | |
SocketTransmitFile | |
SocketWrite | |
SocketWritev | |
ssl_.* | |
SSL_.* | |
std::_Allocate.* | |
std::list<.*>::.* | |
strcat | |
strncmp | |
ssl3_.* | |
strchr | |
strcmp | |
strcpy | |
.*strdup | |
strlen | |
strncpy | |
strzcmp16 | |
strstr | |
__swrite | |
TlsGetValue | |
TouchBadMemory | |
vcruntime140\.dll@0x.* | |
_VEC_memcpy | |
_VEC_memzero | |
.*WaitFor.* | |
wcslen | |
__wrap_realloc | |
WSARecv.* | |
WSASend.* | |
_ZdaPvRKSt9nothrow_t" | |
zzz_AsmCodeRange_.* | |
.*DebugAbort.* | |
mozilla::ipc::MessageChannel::~MessageChannel.* | |
mozilla::MakeUnique<.*> | |
aticfx32\.dll | |
aticfx64\.dll | |
atidxx32\.dll | |
atidxx64\.dll | |
atiu9pag\.dll | |
atiu9p64\.dll | |
atiumd6a\.dll | |
atiumdag\.dll | |
atiumdva\.dll | |
atiuxpag\.dll | |
igd10iumd32\.dll | |
igd10iumd64\.dll | |
igd10umd32\.dll | |
igd10umd64\.dll | |
igdumd32\.dll | |
igdumd64\.dll | |
igdumdim32\.dll | |
igdumdim64\.dll | |
igd11dxva32\.dll | |
igd11dxva64\.dll | |
igdusc32\.dll | |
igdusc64\.dll | |
nvd3dum\.dll | |
nvd3dumx\.dll | |
nvoglnt\.dll | |
nvumdshim\.dll | |
nvumdshimx\.dll | |
nvwgf2um\.dll | |
nvwgf2umx\.dll | |
nvapi\.dll | |
nvapi64\.dll | |
nvscpapi\.dll | |
nvoglv32\.dll | |
nvoglv64\.dll""".split('\n'))) | |
trim_dll_signature_re = re.compile( | |
'|'.join("""aticfx32\.dll.* | |
aticfx64\.dll.* | |
atidxx32\.dll.* | |
atidxx64\.dll.* | |
atiu9pag\.dll.* | |
atiu9p64\.dll.* | |
atiumd6a\.dll.* | |
atiumdag\.dll.* | |
atiumdva\.dll.* | |
atiuxpag\.dll.* | |
igd10iumd32\.dll.* | |
igd10iumd64\.dll.* | |
igd10umd32\.dll.* | |
igd10umd64\.dll.* | |
igdumd32\.dll.* | |
igdumd64\.dll.* | |
igdumdim32\.dll.* | |
igdumdim64\.dll.* | |
igd11dxva32\.dll.* | |
igd11dxva64\.dll.* | |
igdusc32\.dll.* | |
igdusc64\.dll.* | |
nvd3dum\.dll.* | |
nvd3dumx\.dll.* | |
nvoglnt\.dll.* | |
nvumdshim\.dll.* | |
nvumdshimx\.dll.* | |
nvwgf2um\.dll.* | |
nvwgf2umx\.dll.* | |
nvapi\.dll.* | |
nvapi64\.dll.* | |
nvscpapi\.dll.* | |
nvoglv32\.dll.* | |
nvoglv64\.dll.*""".split('\n'))) | |
signature_sentinels = """_purecall | |
Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash | |
google_breakpad::ExceptionHandler::HandleInvalidParameter""".split('\n') | |
signature_sentinels.append( | |
( | |
'mozilla::ipc::RPCChannel::Call(IPC::Message*, IPC::Message*)', | |
lambda x: ( | |
'CrashReporter::CreatePairedMinidumps(void*, ' | |
'unsigned long, nsAString_internal*, nsILocalFile**, ' | |
'nsILocalFile**)' | |
) in x | |
) | |
) | |
# # Query | |
# Gather one day of crashes with stackTraces | |
# In[16]: | |
import datetime | |
import traceback | |
# ignoring "main" and null since null should imply "main" (also, I think the RTD are wrong on this point) | |
PROCESS_TYPES = ['content', 'gpu'] | |
def top_crashers(qd, qw, ssc, ptype): | |
if qw: | |
print "Top 50 {} process crashers on {}/{}/{}\nwithin the first {} weeks since profile creation\n---".format(ptype, qd[:4], qd[4:6], qd[6:], int(qw/7)) | |
else: | |
print "Top 50 {} process crashers on {}/{}/{}\nwith no consideration of profile creation date\n---".format(ptype, qd[:4], qd[4:6], qd[6:]) | |
for list in ssc[:50]: | |
print "{}\t{}\t{}".format(list[0], list[1], ptype) | |
def stats(errs, res): | |
rate = 0 | |
if res > 0: | |
rate = float(len(errs))/res | |
print "Error rate: {:.4%} ({} total, {} errors)".format(rate, res, len(errs)) | |
# If it's not a long list of errors, show them | |
if len(errs) > 0: | |
if len(errs) > 50: | |
print "Errors (more than 50, only 50 shown):" | |
print '\n'.join(errs[:50]) | |
else: | |
print "Errors:" | |
print '\n'.join(errs) | |
def get_dataset(submission_date, channel): | |
"""Return crash pings for that channel on that date.""" | |
pings = Dataset.from_source("telemetry") .where(docType='crash', appUpdateChannel=channel, submissionDate=submission_date) .records(sc, sample=1.0) | |
return pings | |
def pingsig(ping): | |
try: | |
symbolicated_threads = symbolicate_ping(ping) | |
if symbolicated_threads: | |
signature = generate_signature(ping, symbolicated_threads) | |
else: | |
signature = '' | |
return (ping['id'], signature, None) | |
except ValueError as e: | |
return (ping['id'], None, e[0]) | |
except Exception as e: | |
return (ping['id'], None, traceback.format_exc()) | |
def qualify_ping(ping, time_delta, submission_date, process_type): | |
"""Return True for pings that meet the specified criteria.""" | |
retval = False | |
step1, step2, step3 = False, False, False | |
# hasCrashEnvironment is boolean, but not significant for these purposes. | |
# It should not be a criteria for crash ping consideration. | |
# try: | |
# step1 = ping['payload'].get('hasCrashEnvironment') | |
# except: | |
# print "hasCrashEnvironment error" | |
# else: | |
# if step1: | |
process_filter = 'main' # or blank, which is also main | |
if process_type in PROCESS_TYPES: | |
process_filter = process_type | |
try: | |
step1 = ping['payload'].get('processType', None) | |
except: | |
print "processType error" | |
else: | |
if (step1 is None) or (step1 == ''): | |
step1 = 'main' | |
if step1 == process_filter: | |
if time_delta: | |
try: | |
step2 = int(ping['environment']['profile'].get('creationDate', 0)) + time_delta >= submission_date and submission_date >= int(ping['environment']['profile'].get('creationDate', 0)) | |
except: | |
print "date check error" | |
else: | |
if step2: | |
try: | |
step3 = ping['payload'].get('stackTraces', None) != None | |
except: | |
print "stackTraces error" | |
else: | |
if step3: | |
retval = True | |
else: # no time_delta | |
try: | |
step2 = ping['payload'].get('stackTraces', None) != None | |
except: | |
print "stackTraces error (no date)" | |
else: | |
if step2: | |
retval = True | |
return retval | |
def query_pings(query_date, pings, process_type): | |
"""Given pings and process type, map signatures and output top crashers.""" | |
total_errors = 0 | |
total_results = pings.count() | |
print "\nTotal {} process results: {}".format(process_type, total_results) | |
if total_results > 0: | |
results = pings.map(pingsig) | |
results.cache() | |
signatures = results.flatMap(lambda r: [r[1]] if r[1] != None else []) | |
errors = results.flatMap(lambda r: [r[0] + " " + r[2]] if r[2] != None else []) | |
total_errors = errors.collect() | |
stack_counts = signatures.map(lambda sig: (sig, 1)).countByKey() | |
print "Stack counts: {}".format(len(stack_counts)) | |
sorted_stack_counts = sorted(stack_counts.items(), key=lambda x: x[1], reverse=True) | |
top_crashers(query_date, query_window, sorted_stack_counts, process_type) | |
results.unpersist() | |
return total_errors, total_results | |
def query(profile_window, submission_date, channel, process_type=None): | |
"""Given a submission date, channel, possibly-null consideration | |
window, and optional process type, get and query all matching pings. | |
If no process type is specified, all process types will be output; if | |
consideration window is None, all pings with a matching submission date | |
(regardless of profile creation date) will be output.""" | |
epoch = datetime.datetime.utcfromtimestamp(0).date() | |
time_delta = profile_window | |
querydate = datetime.datetime.strptime(submission_date, "%Y%m%d").date() | |
querydate_days = (querydate - epoch).days | |
pings = get_dataset(submission_date, channel) | |
pings.cache() | |
def query_stats(time_delta, process_type, errors_count, results_count): | |
"""Output somewhat meaningul statistics for that query.""" | |
if time_delta: | |
print "\nStats and errors for {} days ({} process)".format(time_delta, process_type) | |
else: | |
print "\nStats and errors ({} process)".format(process_type) | |
stats(errors_count, results_count) | |
if process_type: | |
subset = pings.filter(lambda p: qualify_ping(p, time_delta, querydate_days, process_type)) | |
errors_count, results_count = query_pings(submission_date, subset, process_type) | |
if results_count > 0: | |
query_stats(time_delta, process_type, errors_count, results_count) | |
else: | |
all_processes = ['main', 'content', 'gpu'] | |
for each_process in all_processes: | |
subset = pings.filter(lambda p: qualify_ping(p, time_delta, querydate_days, each_process)) | |
errors_count, results_count = query_pings(submission_date, subset, each_process) | |
if results_count > 0: | |
query_stats(time_delta, each_process, errors_count, results_count) | |
pings.unpersist() | |
# In[17]: | |
query_date = '20170524' | |
query_channel = 'nightly' | |
# ### Top 50 crashers (by signature) within the first two weeks of use | |
# In[18]: | |
query_window = TWO_WEEKS | |
# process_type = None | |
# pings = query(query_window, query_date, query_channel, process_type) | |
# NOTE: if process_type is not used, all process types will be output | |
pings = query(query_window, query_date, query_channel) | |
# ### Top 50 crashers (by signature) within the first six weeks of use | |
# In[19]: | |
query_window = SIX_WEEKS | |
# process_type = None | |
# pings = query(query_window, query_date, query_channel, process_type) | |
# NOTE: if process_type is not used, all process types will be output | |
pings = query(query_window, query_date, query_channel) | |
# ### Top 50 crashers (by signature), no profile creation date consideration | |
# In[20]: | |
query_window = None | |
# process_type = None | |
# pings = query(query_window, query_date, query_channel, process_type) | |
# NOTE: if process_type is not used, all process types will be output | |
pings = query(query_window, query_date, query_channel) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment