blob: 788057a30dc913b3e81177bb588a0d6590b95e92 [file] [log] [blame]
# Profile helper for the SafeHardlinks FUSE filesystem
#
# Run this from a project directory and pass it the name of an element to
# stage.
#
# It will stage the artifact and then block the main process. At this point
# you can open a bwrap sandbox and run a command inside the FUSE mount
# manually. Once you are done, hit CTRL+C and a profile will be written to
# disk of what happened inside the FUSE mount.
import cProfile
import os
import signal
import subprocess
import sys
import tempfile
import buildstream
import buildstream._frontend
# This works by monkeypatching the .mount() method on the SafeHardlinks
# filesystem. The normal implementation in the _fuse.mount module spawns
# a multiprocessing.Process subprocess to actually run the filesystem
# and the main process carries on independently. We override that so that
# it blocks
def mount_in_process_and_block(self, mountpoint):
self._Mount__mountpoint = mountpoint
self._Mount__operations = self.create_operations()
profile = os.path.abspath('fuse.pstats')
print("Mounting a SafeHardlinks filesystem at {} then blocking".format(mountpoint))
print("Profile will be written to {}".format(profile))
print("Try: bwrap --bind {} / --dev /dev --proc /proc --tmpfs /tmp COMMAND".format(mountpoint))
profiler = cProfile.Profile()
profiler.runcall(
buildstream._fuse.fuse.FUSE,
self._Mount__operations, self._Mount__mountpoint,
nothreads=True, foreground=True, nonempty=True)
profiler.dump_stats(profile)
buildstream._fuse.hardlinks.SafeHardlinks.mount = mount_in_process_and_block
if len(sys.argv) != 2:
raise RuntimeError("Usage: {} ELEMENT".format(sys.argv[0]))
element = sys.argv[1]
cli = buildstream._frontend.main.cli
cli.main(args=('shell', element), prog_name=cli.name)