blob: a46b1ccc767f80e373b6b538163a73aec3737b87 [file] [log] [blame] [edit]
#!/usr/bin/env python3
# Copyright 2020 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#### CATEGORY=Run, inspect and debug
### Extract pprof data from inspect.json
##
## inspect.json holds Inspect data generated as part of a snapshot (see fx snapshot).
## pprof is a tool used to analyze profiling data (for more details, see
## https://github.com/google/pprof). Some components are configured to provide
## the Inspect tool with pprof data that can later be used to analyze the running
## program's state (memory, threads, etc.). This is especially useful after a
## crash where developers can observe the last known state before the crash.
##
## This tool extracts the pprof data for some component from inspect.json and
## decodes it from its stored format (base64 encoded) into the format the pprof
## tool will understand (raw binary). The pprof files will be extracted to a
## temporary directory.
##
## usage: fx extract_pprof --inspect FILE --component CMX
##
## --inspect Path to the inspect.json file
## --component Component to extract pprof data for (i.e. netstack.cmx)
import argparse
import base64
import json
import os
import sys
import tempfile
def main():
parser = argparse.ArgumentParser(
description="Extract pprof data from inspect.json")
parser.add_argument(
"--inspect", required=True, help="Path to inspect.json file")
parser.add_argument(
"--component",
required=True,
help="Component to extract pprof data for (i.e. netstack.cmx)")
args = parser.parse_args()
tempdir = tempfile.mkdtemp()
print("inspect.json @ %s" % (args.inspect))
print("component = %s" % (args.component))
print("output @ %s" % (tempdir))
with open(args.inspect, "r") as f:
inspect = json.loads(f.read())
for entry in inspect:
if entry["data_source"] != "Inspect" or entry["moniker"] != args.component:
continue
filepath = entry["metadata"]["filename"]
# We only care about pprof data.
if not filepath.startswith("pprof"):
continue
filepath = os.path.join(tempdir, filepath)
os.makedirs(filepath, exist_ok=True)
data = entry["payload"]["root"]["pprof"]
for k, v in data.items():
# The first 4 characters are used to indicate that the file is a
# base64 encoded file.
prefix, v = v[:4], v[4:]
if prefix != "b64:":
print("%s at %s is not base64 encoded" % (k, filepath))
with open(os.path.join(filepath, k), "wb") as f:
f.write(base64.b64decode(v))
if __name__ == "__main__":
main()