summaryrefslogtreecommitdiffstats
path: root/dom/quota/scripts/analyze_qm_failures.py
diff options
context:
space:
mode:
Diffstat (limited to 'dom/quota/scripts/analyze_qm_failures.py')
-rwxr-xr-xdom/quota/scripts/analyze_qm_failures.py137
1 files changed, 137 insertions, 0 deletions
diff --git a/dom/quota/scripts/analyze_qm_failures.py b/dom/quota/scripts/analyze_qm_failures.py
new file mode 100755
index 0000000000..f4afd64ab4
--- /dev/null
+++ b/dom/quota/scripts/analyze_qm_failures.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python3
+# 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/.
+
+import getopt
+import sys
+
+import fn_anchors
+import stackanalysis
+import utils
+
+"""
+The analysis is based on stack frames of the following form:
+
+[
+ {
+ "event_timeabs": 1617121013137,
+ "session_startabs": 1617120840000,
+ "build_id": "20210329095128",
+ "client_id": "0013a68f-9893-461a-93d4-2d7a2f85583f",
+ "session_id": "8cd37159-bd5c-481c-99ad-9eace9ea726a",
+ "seq": 1,
+ "context": "Initialization::TemporaryStorage",
+ "source_file": "dom/localstorage/ActorsParent.cpp",
+ "source_line": "1018",
+ "severity": "ERROR",
+ "result": "NS_ERROR_FILE_NOT_FOUND"
+ },
+...
+]
+
+The location of the input file is expected to be found in the
+last item of the list inside qmexecutions.json.
+"""
+
+
+def usage():
+ print("analyze_qm_faiures.py -w <workdir=.>")
+ print("")
+ print("Analyzes the results from fetch_qm_failures.py's JSON file.")
+ print(
+ "Writes out several JSON results as files and a bugzilla markup table on stdout."
+ )
+ print("-w <workdir>: Working directory, default is '.'")
+ sys.exit(2)
+
+
+days = 1
+workdir = "."
+
+try:
+ opts, args = getopt.getopt(sys.argv[1:], "w:", ["workdir="])
+ for opt, arg in opts:
+ if opt == "-w":
+ workdir = arg
+except getopt.GetoptError:
+ usage()
+
+run = utils.getLastRunFromExecutionFile(workdir)
+if "numrows" not in run:
+ print("No previous execution from fetch_qm_failures.py found.")
+ usage()
+if run["numrows"] == 0:
+ print("The last execution yielded no result.")
+
+infile = run["rawfile"]
+
+
+def getFname(prefix):
+ return "{}/{}_until_{}.json".format(workdir, prefix, run["lasteventtime"])
+
+
+# read rows from JSON
+rows = utils.readJSONFile(getFname("qmrows"))
+print("Found {} rows of data.".format(len(rows)))
+rows = stackanalysis.sanitize(rows)
+
+# enrich rows with hg locations
+buildids = stackanalysis.extractBuildIDs(rows)
+utils.fetchBuildRevisions(buildids)
+stackanalysis.constructHGLinks(buildids, rows)
+
+# transform rows to unique stacks
+raw_stacks = stackanalysis.collectRawStacks(rows)
+all_stacks = stackanalysis.mergeEqualStacks(raw_stacks)
+
+# enrich with function anchors
+for stack in all_stacks:
+ for frame in stack["frames"]:
+ frame["anchor"] = "{}:{}".format(
+ frame["source_file"], fn_anchors.getFunctionName(frame["location"])
+ )
+
+# separate stacks for relevance
+error_stacks = []
+warn_stacks = []
+info_stacks = []
+abort_stacks = []
+stackanalysis.filterStacksForPropagation(
+ all_stacks, error_stacks, warn_stacks, info_stacks, abort_stacks
+)
+run["errorfile"] = getFname("qmerrors")
+utils.writeJSONFile(run["errorfile"], error_stacks)
+run["warnfile"] = getFname("qmwarnings")
+utils.writeJSONFile(run["warnfile"], warn_stacks)
+run["infofile"] = getFname("qminfo")
+utils.writeJSONFile(run["infofile"], info_stacks)
+run["abortfile"] = getFname("qmabort")
+utils.writeJSONFile(run["abortfile"], abort_stacks)
+utils.updateLastRunToExecutionFile(workdir, run)
+
+
+# print results to stdout
+print("Found {} error stacks.".format(len(error_stacks)))
+print("Found {} warning stacks.".format(len(warn_stacks)))
+print("Found {} info stacks.".format(len(info_stacks)))
+print("Found {} aborted stacks.".format(len(abort_stacks)))
+print("")
+print("Error stacks:")
+print(stackanalysis.printStacks(error_stacks))
+print("")
+print("Error stacks grouped by anchors:")
+anchors = stackanalysis.groupStacksForAnchors(error_stacks)
+anchornames = list(anchors.keys())
+for a in anchornames:
+ print(stackanalysis.printStacks(anchors[a]["stacks"]))
+ print("")
+print("")
+print("Warning stacks:")
+print(stackanalysis.printStacks(warn_stacks))
+print("")
+print("Info stacks:")
+print(stackanalysis.printStacks(info_stacks))
+print("")
+print("Aborted stacks:")
+print(stackanalysis.printStacks(abort_stacks))