浏览代码

Implement --debug-profile

Marian Beermann 8 年之前
父节点
当前提交
4c441c75b1
共有 2 个文件被更改,包括 28 次插入1 次删除
  1. 18 1
      src/borg/archiver.py
  2. 10 0
      src/borg/testsuite/archiver.py

+ 18 - 1
src/borg/archiver.py

@@ -2049,6 +2049,8 @@ class Archiver:
             add_common_option('--consider-part-files', dest='consider_part_files',
                               action='store_true', default=False,
                               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',
+                              help='Store a Python profile at FILE')
 
         parser = argparse.ArgumentParser(prog=self.prog, description='Borg - Deduplicated Backups',
                                          add_help=False)
@@ -3542,7 +3544,22 @@ class Archiver:
         self.prerun_checks(logger)
         if is_slow_msgpack():
             logger.warning("Using a pure-python msgpack! This will result in lower performance.")
-        return set_ec(func(args))
+        if args.debug_profile:
+            # Import these only when needed - avoids a further increase in startup time
+            import cProfile
+            import marshal
+            logger.debug('Writing execution profile to %s', args.debug_profile)
+            # Open the file early, before running the main program, to avoid
+            # a very late crash in case the specified path is invalid
+            with open(args.debug_profile, 'wb') as fd:
+                profiler = cProfile.Profile()
+                variables = dict(locals())
+                profiler.runctx('rc = set_ec(func(args))', globals(), variables)
+                profiler.snapshot_stats()
+                marshal.dump(profiler.stats, fd)
+            return variables['rc']
+        else:
+            return set_ec(func(args))
 
 
 def sig_info_handler(sig_no, stack):  # pragma: no cover

+ 10 - 0
src/borg/testsuite/archiver.py

@@ -3,6 +3,7 @@ import errno
 import json
 import logging
 import os
+import pstats
 import random
 import shutil
 import socket
@@ -1681,6 +1682,15 @@ class ArchiverTestCase(ArchiverTestCaseBase):
         assert log_message['name'].startswith('borg.')
         assert isinstance(log_message['message'], str)
 
+    def test_debug_profile(self):
+        self.create_test_files()
+        self.cmd('init', '--encryption=repokey', self.repository_location)
+        self.cmd('create', self.repository_location + '::test', 'input', '--debug-profile=create.prof')
+        stats = pstats.Stats('create.prof')
+        stats.strip_dirs()
+        stats.sort_stats('cumtime')
+        # Ok, stats can be loaded, good enough.
+
     def test_common_options(self):
         self.create_test_files()
         self.cmd('init', '--encryption=repokey', self.repository_location)