|
@@ -2050,7 +2050,8 @@ class Archiver:
|
|
action='store_true', default=False,
|
|
action='store_true', default=False,
|
|
help='treat part files like normal files (e.g. to list/extract them)')
|
|
help='treat part files like normal files (e.g. to list/extract them)')
|
|
add_common_option('--debug-profile', dest='debug_profile', default=None, metavar='FILE',
|
|
add_common_option('--debug-profile', dest='debug_profile', default=None, metavar='FILE',
|
|
- help='Store a Python profile at FILE')
|
|
|
|
|
|
+ help='Write Python profile in msgpack format into FILE. For local use a cProfile-'
|
|
|
|
+ 'compatible file can be generated by suffixing FILE with ".pyprof".')
|
|
|
|
|
|
parser = argparse.ArgumentParser(prog=self.prog, description='Borg - Deduplicated Backups',
|
|
parser = argparse.ArgumentParser(prog=self.prog, description='Borg - Deduplicated Backups',
|
|
add_help=False)
|
|
add_help=False)
|
|
@@ -3545,7 +3546,7 @@ class Archiver:
|
|
if is_slow_msgpack():
|
|
if is_slow_msgpack():
|
|
logger.warning("Using a pure-python msgpack! This will result in lower performance.")
|
|
logger.warning("Using a pure-python msgpack! This will result in lower performance.")
|
|
if args.debug_profile:
|
|
if args.debug_profile:
|
|
- # Import these only when needed - avoids a further increase in startup time
|
|
|
|
|
|
+ # Import only when needed - avoids a further increase in startup time
|
|
import cProfile
|
|
import cProfile
|
|
import marshal
|
|
import marshal
|
|
logger.debug('Writing execution profile to %s', args.debug_profile)
|
|
logger.debug('Writing execution profile to %s', args.debug_profile)
|
|
@@ -3554,10 +3555,24 @@ class Archiver:
|
|
with open(args.debug_profile, 'wb') as fd:
|
|
with open(args.debug_profile, 'wb') as fd:
|
|
profiler = cProfile.Profile()
|
|
profiler = cProfile.Profile()
|
|
variables = dict(locals())
|
|
variables = dict(locals())
|
|
- profiler.runctx('rc = set_ec(func(args))', globals(), variables)
|
|
|
|
- profiler.snapshot_stats()
|
|
|
|
- marshal.dump(profiler.stats, fd)
|
|
|
|
- return variables['rc']
|
|
|
|
|
|
+ profiler.enable()
|
|
|
|
+ try:
|
|
|
|
+ return set_ec(func(args))
|
|
|
|
+ finally:
|
|
|
|
+ profiler.disable()
|
|
|
|
+ profiler.snapshot_stats()
|
|
|
|
+ if args.debug_profile.endswith('.pyprof'):
|
|
|
|
+ marshal.dump(profiler.stats, fd)
|
|
|
|
+ else:
|
|
|
|
+ # We use msgpack here instead of the marshal module used by cProfile itself,
|
|
|
|
+ # because the latter is insecure. Since these files may be shared over the
|
|
|
|
+ # internet we don't want a format that is impossible to interpret outside
|
|
|
|
+ # an insecure implementation.
|
|
|
|
+ # See scripts/msgpack2marshal.py for a small script that turns a msgpack file
|
|
|
|
+ # into a marshal file that can be read by e.g. pyprof2calltree.
|
|
|
|
+ # For local use it's unnecessary hassle, though, that's why .pyprof makes
|
|
|
|
+ # it compatible (see above).
|
|
|
|
+ msgpack.pack(profiler.stats, fd, use_bin_type=True)
|
|
else:
|
|
else:
|
|
return set_ec(func(args))
|
|
return set_ec(func(args))
|
|
|
|
|