pyperf 2.8.1__tar.gz → 2.9.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. {pyperf-2.8.1/pyperf.egg-info → pyperf-2.9.0}/PKG-INFO +2 -2
  2. {pyperf-2.8.1 → pyperf-2.9.0}/doc/api.rst +13 -0
  3. {pyperf-2.8.1 → pyperf-2.9.0}/doc/changelog.rst +9 -0
  4. {pyperf-2.8.1 → pyperf-2.9.0}/doc/conf.py +1 -1
  5. {pyperf-2.8.1 → pyperf-2.9.0}/doc/run_benchmark.rst +14 -0
  6. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/__init__.py +1 -1
  7. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/__main__.py +6 -2
  8. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_bench.py +41 -0
  9. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_cli.py +25 -3
  10. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_hooks.py +60 -0
  11. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_utils.py +4 -1
  12. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/test_perf_cli.py +13 -3
  13. {pyperf-2.8.1 → pyperf-2.9.0/pyperf.egg-info}/PKG-INFO +2 -2
  14. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf.egg-info/entry_points.txt +1 -0
  15. {pyperf-2.8.1 → pyperf-2.9.0}/pyproject.toml +1 -0
  16. {pyperf-2.8.1 → pyperf-2.9.0}/COPYING +0 -0
  17. {pyperf-2.8.1 → pyperf-2.9.0}/MANIFEST.in +0 -0
  18. {pyperf-2.8.1 → pyperf-2.9.0}/README.rst +0 -0
  19. {pyperf-2.8.1 → pyperf-2.9.0}/TODO.rst +0 -0
  20. {pyperf-2.8.1 → pyperf-2.9.0}/doc/Makefile +0 -0
  21. {pyperf-2.8.1 → pyperf-2.9.0}/doc/analyze.rst +0 -0
  22. {pyperf-2.8.1 → pyperf-2.9.0}/doc/cli.rst +0 -0
  23. {pyperf-2.8.1 → pyperf-2.9.0}/doc/developer_guide.rst +0 -0
  24. {pyperf-2.8.1 → pyperf-2.9.0}/doc/examples/bench_async_func.py +0 -0
  25. {pyperf-2.8.1 → pyperf-2.9.0}/doc/examples/bench_async_func_with_loop_factory.py +0 -0
  26. {pyperf-2.8.1 → pyperf-2.9.0}/doc/examples/bench_command.py +0 -0
  27. {pyperf-2.8.1 → pyperf-2.9.0}/doc/examples/bench_func.py +0 -0
  28. {pyperf-2.8.1 → pyperf-2.9.0}/doc/examples/bench_time_func.py +0 -0
  29. {pyperf-2.8.1 → pyperf-2.9.0}/doc/examples/bench_timeit.py +0 -0
  30. {pyperf-2.8.1 → pyperf-2.9.0}/doc/examples/export_csv.py +0 -0
  31. {pyperf-2.8.1 → pyperf-2.9.0}/doc/examples/hist_scipy.py +0 -0
  32. {pyperf-2.8.1 → pyperf-2.9.0}/doc/examples/plot.py +0 -0
  33. {pyperf-2.8.1 → pyperf-2.9.0}/doc/examples.rst +0 -0
  34. {pyperf-2.8.1 → pyperf-2.9.0}/doc/hist_scipy_telco.png +0 -0
  35. {pyperf-2.8.1 → pyperf-2.9.0}/doc/index.rst +0 -0
  36. {pyperf-2.8.1 → pyperf-2.9.0}/doc/make.bat +0 -0
  37. {pyperf-2.8.1 → pyperf-2.9.0}/doc/outliers.json.gz +0 -0
  38. {pyperf-2.8.1 → pyperf-2.9.0}/doc/py2.json.gz +0 -0
  39. {pyperf-2.8.1 → pyperf-2.9.0}/doc/py3.json.gz +0 -0
  40. {pyperf-2.8.1 → pyperf-2.9.0}/doc/runner.rst +0 -0
  41. {pyperf-2.8.1 → pyperf-2.9.0}/doc/system.rst +0 -0
  42. {pyperf-2.8.1 → pyperf-2.9.0}/doc/timeit_strip.json.gz +0 -0
  43. {pyperf-2.8.1 → pyperf-2.9.0}/doc/user_guide.rst +0 -0
  44. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_collect_metadata.py +0 -0
  45. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_command.py +0 -0
  46. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_compare.py +0 -0
  47. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_cpu_utils.py +0 -0
  48. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_formatter.py +0 -0
  49. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_linux_memory.py +0 -0
  50. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_manager.py +0 -0
  51. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_metadata.py +0 -0
  52. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_process_time.py +0 -0
  53. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_psutil_memory.py +0 -0
  54. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_runner.py +0 -0
  55. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_system.py +0 -0
  56. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_timeit.py +0 -0
  57. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_timeit_cli.py +0 -0
  58. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_win_memory.py +0 -0
  59. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/_worker.py +0 -0
  60. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/__init__.py +0 -0
  61. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/mult_list_bench.py +0 -0
  62. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/mult_list_py36.json +0 -0
  63. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/mult_list_py36_tags.json +0 -0
  64. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/mult_list_py37.json +0 -0
  65. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/mult_list_py37_tags.json +0 -0
  66. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/mult_list_py38.json +0 -0
  67. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/replay.py +0 -0
  68. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/telco.json +0 -0
  69. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/test_bench.py +0 -0
  70. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/test_cli.py +0 -0
  71. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/test_examples.py +0 -0
  72. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/test_metadata.py +0 -0
  73. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/test_misc.py +0 -0
  74. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/test_runner.py +0 -0
  75. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/test_system.py +0 -0
  76. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/test_timeit.py +0 -0
  77. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/test_utils.py +0 -0
  78. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf/tests/track_memory.json +0 -0
  79. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf.egg-info/SOURCES.txt +0 -0
  80. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf.egg-info/dependency_links.txt +0 -0
  81. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf.egg-info/requires.txt +0 -0
  82. {pyperf-2.8.1 → pyperf-2.9.0}/pyperf.egg-info/top_level.txt +0 -0
  83. {pyperf-2.8.1 → pyperf-2.9.0}/setup.cfg +0 -0
  84. {pyperf-2.8.1 → pyperf-2.9.0}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: pyperf
3
- Version: 2.8.1
3
+ Version: 2.9.0
4
4
  Summary: Python module to run and analyze benchmarks
5
5
  Author-email: Victor Stinner <vstinner@redhat.com>
6
6
  Maintainer-email: Dong-hee Na <donghee.na@python.org>
@@ -345,6 +345,19 @@ Benchmark class
345
345
 
346
346
  Raise an exception if the benchmark has no values.
347
347
 
348
+ .. method:: required_nprocesses()
349
+
350
+ Determines the number of separate process runs that would be required
351
+ achieve stable results. Specifically, the target is to have 95% certainty
352
+ that there is a variance of less than 1%. If the result is greater than
353
+ the number of processes recorded in the input data, the value is
354
+ meaningless and only means "more samples are required".
355
+
356
+ The method used is described in this Wikipedia article about estimating
357
+ the sampling of a mean:
358
+
359
+ https://en.wikipedia.org/wiki/Sample_size_determination#Estimation_of_a_mean
360
+
348
361
  .. method:: update_metadata(metadata: dict)
349
362
 
350
363
  Update metadata of all runs of the benchmark.
@@ -1,6 +1,15 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ Version 2.9.0 (2025-03-03)
5
+ --------------------------
6
+
7
+ * Feature: A new hook, ``perf_record``, is available to turn Linux perf profiling on and off around the benchmark code.
8
+ To use it, pass ``--hook perf_record``.
9
+ Patch by Matt Page.
10
+ * Feature: pyperf will now warn if you are collecting too few or too many samples for stable results.
11
+ Patch by Michael Droettboom
12
+
4
13
  Version 2.8.1 (2024-11-13)
5
14
  --------------------------
6
15
 
@@ -50,7 +50,7 @@ author = 'Victor Stinner'
50
50
  # built documents.
51
51
  #
52
52
  # The short X.Y version.
53
- version = release = '2.8.1'
53
+ version = release = '2.9.0'
54
54
 
55
55
  # The language for content autogenerated by Sphinx. Refer to documentation
56
56
  # for a list of supported languages.
@@ -206,3 +206,17 @@ The `Tools/scripts/summarize_stats.py <https://github.com/python/cpython/blob/ma
206
206
 
207
207
  Statistics are not cleared between runs.
208
208
  If you need to delete statistics from a previous run, remove the files in ``/tmp/py_stats`` (Unix) or ``C:\temp\py_stats`` (Windows).
209
+
210
+ Profiling benchmarks using ``perf record``
211
+ ==========================================
212
+ ``pyperf`` supports profiling benchmark execution using ``perf
213
+ record``. ``perf`` is only enabled while the benchmark is running to avoid
214
+ profiling unrelated parts of ``pyperf`` itself.
215
+
216
+ One profile data file is generated for each benchmark run. These files have
217
+ the basename of ``perf.data.<uuid>`` and are written to the current directory
218
+ by default. The directory can be overridden by setting the
219
+ ``PYPERF_PERF_RECORD_DATA_DIR`` environment variable.
220
+
221
+ The value of the ``PYPERF_PERF_RECORD_EXTRA_OPTS`` environment variable is
222
+ appended to the command line of ``perf record`` if it is provided.
@@ -1,6 +1,6 @@
1
1
  from time import perf_counter
2
2
 
3
- VERSION = (2, 8, 1)
3
+ VERSION = (2, 9, 0)
4
4
  __version__ = '.'.join(map(str, VERSION))
5
5
 
6
6
  # Export pyperf.perf_counter for backward compatibility with pyperf 1.7
@@ -455,7 +455,8 @@ def display_benchmarks(args, show_metadata=False, hist=False, stats=False,
455
455
  dump=dump,
456
456
  checks=checks,
457
457
  result=result,
458
- display_runs_args=display_runs_args)
458
+ display_runs_args=display_runs_args,
459
+ only_checks=only_checks)
459
460
 
460
461
  if bench_lines:
461
462
  empty_line(lines)
@@ -491,10 +492,13 @@ def display_benchmarks(args, show_metadata=False, hist=False, stats=False,
491
492
  empty_line(output)
492
493
  output.extend(lines)
493
494
 
495
+ contains_warning = False
494
496
  for line in output:
497
+ if line.startswith("WARNING:"):
498
+ contains_warning = True
495
499
  print(line)
496
500
 
497
- if not output and only_checks:
501
+ if not contains_warning and only_checks:
498
502
  if len(data) == 1:
499
503
  print("The benchmark seems to be stable")
500
504
  else:
@@ -424,6 +424,47 @@ class Benchmark:
424
424
  raise ValueError("MAD must be >= 0")
425
425
  return value
426
426
 
427
+ def required_nprocesses(self):
428
+ """
429
+ Determines the number of separate process runs that would be required
430
+ achieve stable results. Specifically, the target is to have 95%
431
+ certainty that there is a variance of less than 1%. If the result is
432
+ greater than the number of processes recorded in the input data, the
433
+ value is meaningless and only means "more samples are required".
434
+
435
+ The method used is described in this Wikipedia article about estimating
436
+ the sampling of a mean:
437
+
438
+ https://en.wikipedia.org/wiki/Sample_size_determination#Estimation_of_a_mean
439
+ """
440
+ # Get the means of the values per process. The values within the process
441
+ # often vary considerably (e.g. due to cache effects), but the variances
442
+ # between processes should be fairly consistent. Additionally, this
443
+ # value is intended to be advice for the number of processes to run.
444
+ values = []
445
+ for run in self._runs:
446
+ if len(run.values):
447
+ values.append(statistics.mean(run.values))
448
+
449
+ if len(values) < 2:
450
+ return None
451
+
452
+ total = math.fsum(values)
453
+ mean = total / len(values)
454
+ stddev = statistics.stdev(values)
455
+
456
+ # Normalize the stddev so we can target "percentage changed" rather than
457
+ # absolute time
458
+ sigma = stddev / mean
459
+
460
+ # 95% certainty
461
+ Z = 1.96
462
+ # 1% variation
463
+ W = 0.01
464
+
465
+ # (4Z²σ²)/(W²)
466
+ return math.ceil((4 * Z ** 2 * sigma ** 2) / (W ** 2))
467
+
427
468
  def percentile(self, p):
428
469
  if not (0 <= p <= 100):
429
470
  raise ValueError("p must be in the range [0; 100]")
@@ -400,7 +400,7 @@ def format_histogram(benchmarks, bins=20, extend=False, lines=None,
400
400
  return lines
401
401
 
402
402
 
403
- def format_checks(bench, lines=None):
403
+ def format_checks(bench, lines=None, check_too_many_processes=False):
404
404
  if lines is None:
405
405
  lines = []
406
406
 
@@ -412,6 +412,7 @@ def format_checks(bench, lines=None):
412
412
  mean = bench.mean()
413
413
  warnings = []
414
414
  warn = warnings.append
415
+ required_nprocesses = None
415
416
 
416
417
  # Display a warning if the standard deviation is greater than 10%
417
418
  # of the mean
@@ -421,6 +422,14 @@ def format_checks(bench, lines=None):
421
422
  if percent >= 10.0:
422
423
  warn("the standard deviation (%s) is %.0f%% of the mean (%s)"
423
424
  % (bench.format_value(stdev), percent, bench.format_value(mean)))
425
+ else:
426
+ # display a warning if the number of samples isn't enough to get a stable result
427
+ required_nprocesses = bench.required_nprocesses()
428
+ if (
429
+ required_nprocesses is not None and
430
+ required_nprocesses > len(bench._runs)
431
+ ):
432
+ warn("Not enough samples to get a stable result (95% certainly of less than 1% variation)")
424
433
 
425
434
  # Minimum and maximum, detect obvious outliers
426
435
  for minimum, value in (
@@ -457,6 +466,19 @@ def format_checks(bench, lines=None):
457
466
  lines.append("Use pyperf stats, pyperf dump and pyperf hist to analyze results.")
458
467
  lines.append("Use --quiet option to hide these warnings.")
459
468
 
469
+ if check_too_many_processes:
470
+ if required_nprocesses is None:
471
+ required_nprocesses = bench.required_nprocesses()
472
+ if (
473
+ required_nprocesses is not None and
474
+ required_nprocesses < len(bench._runs) * 0.75
475
+ ):
476
+ lines.append("Benchmark was run more times than necessary to get a stable result.")
477
+ lines.append(
478
+ "Consider passing processes=%d to the Runner constructor to save time." %
479
+ required_nprocesses
480
+ )
481
+
460
482
  # Warn if nohz_full+intel_pstate combo if found in cpu_config metadata
461
483
  for run in bench._runs:
462
484
  cpu_config = run._metadata.get('cpu_config')
@@ -549,7 +571,7 @@ def format_result(bench):
549
571
 
550
572
  def format_benchmark(bench, checks=True, metadata=False,
551
573
  dump=False, stats=False, hist=False, show_name=False,
552
- result=True, display_runs_args=None):
574
+ result=True, display_runs_args=None, only_checks=False):
553
575
  lines = []
554
576
 
555
577
  if metadata:
@@ -568,7 +590,7 @@ def format_benchmark(bench, checks=True, metadata=False,
568
590
  format_stats(bench, lines=lines)
569
591
 
570
592
  if checks:
571
- format_checks(bench, lines=lines)
593
+ format_checks(bench, lines=lines, check_too_many_processes=only_checks)
572
594
 
573
595
  if result:
574
596
  empty_line(lines)
@@ -5,7 +5,12 @@
5
5
 
6
6
  import abc
7
7
  import importlib.metadata
8
+ import os.path
9
+ import shlex
10
+ import subprocess
8
11
  import sys
12
+ import tempfile
13
+ import uuid
9
14
 
10
15
 
11
16
  def get_hooks():
@@ -108,3 +113,58 @@ class pystats(HookBase):
108
113
 
109
114
  def __exit__(self, _exc_type, _exc_value, _traceback):
110
115
  sys._stats_off()
116
+
117
+
118
+ class perf_record(HookBase):
119
+ """Profile the benchmark using perf-record.
120
+
121
+ Profile data is written to the current directory directory by default, or
122
+ to the value of the `PYPERF_PERF_RECORD_DATA_DIR` environment variable, if
123
+ it is provided.
124
+
125
+ Profile data files have a basename of the form `perf.data.<uuid>`
126
+
127
+ The value of the `PYPERF_PERF_RECORD_EXTRA_OPTS` environment variable is
128
+ appended to the command line of perf-record, if provided.
129
+ """
130
+
131
+ def __init__(self):
132
+ self.tempdir = tempfile.TemporaryDirectory()
133
+ self.ctl_fifo = self.mkfifo(self.tempdir.name, "ctl_fifo")
134
+ self.ack_fifo = self.mkfifo(self.tempdir.name, "ack_fifo")
135
+ perf_data_dir = os.environ.get("PYPERF_PERF_RECORD_DATA_DIR", "")
136
+ perf_data_basename = f"perf.data.{uuid.uuid4()}"
137
+ cmd = ["perf", "record",
138
+ "--pid", str(os.getpid()),
139
+ "--output", os.path.join(perf_data_dir, perf_data_basename),
140
+ "--control", f"fifo:{self.ctl_fifo},{self.ack_fifo}"]
141
+ extra_opts = os.environ.get("PYPERF_PERF_RECORD_EXTRA_OPTS", "")
142
+ cmd += shlex.split(extra_opts)
143
+ self.perf = subprocess.Popen(
144
+ cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
145
+ self.ctl_fd = open(self.ctl_fifo, "w")
146
+ self.ack_fd = open(self.ack_fifo, "r")
147
+
148
+ def __enter__(self):
149
+ self.exec_perf_cmd("enable")
150
+
151
+ def __exit__(self, _exc_type, _exc_value, _traceback):
152
+ self.exec_perf_cmd("disable")
153
+
154
+ def teardown(self, metadata):
155
+ try:
156
+ self.exec_perf_cmd("stop")
157
+ self.perf.wait(timeout=120)
158
+ finally:
159
+ self.ctl_fd.close()
160
+ self.ack_fd.close()
161
+
162
+ def mkfifo(self, tmpdir, basename):
163
+ path = os.path.join(tmpdir, basename)
164
+ os.mkfifo(path)
165
+ return path
166
+
167
+ def exec_perf_cmd(self, cmd):
168
+ self.ctl_fd.write(f"{cmd}\n")
169
+ self.ctl_fd.flush()
170
+ self.ack_fd.readline()
@@ -270,7 +270,10 @@ def create_environ(inherit_environ, locale, copy_all):
270
270
  env = {}
271
271
  copy_env = ["PATH", "HOME", "TEMP", "COMSPEC", "SystemRoot", "SystemDrive",
272
272
  # Python specific variables
273
- "PYTHONPATH", "PYTHON_CPU_COUNT", "PYTHON_GIL"]
273
+ "PYTHONPATH", "PYTHON_CPU_COUNT", "PYTHON_GIL",
274
+ # Pyperf specific variables
275
+ "PYPERF_PERF_RECORD_DATA_DIR", "PYPERF_PERF_RECORD_EXTRA_OPTS",
276
+ ]
274
277
  if locale:
275
278
  copy_env.extend(('LANG', 'LC_ADDRESS', 'LC_ALL', 'LC_COLLATE',
276
279
  'LC_CTYPE', 'LC_IDENTIFICATION', 'LC_MEASUREMENT',
@@ -628,8 +628,18 @@ class TestPerfCLI(BaseTestCase, unittest.TestCase):
628
628
 
629
629
  def test_check_stable(self):
630
630
  stdout = self.run_command('check', TELCO)
631
- self.assertEqual(stdout.rstrip(),
632
- 'The benchmark seems to be stable')
631
+ self.assertIn(
632
+ textwrap.dedent(
633
+ """
634
+ Benchmark was run more times than necessary to get a stable result.
635
+ Consider passing processes=7 to the Runner constructor to save time.
636
+ """
637
+ ).strip(), stdout.rstrip()
638
+ )
639
+ self.assertIn(
640
+ 'The benchmark seems to be stable',
641
+ stdout.rstrip()
642
+ )
633
643
 
634
644
  def test_command(self):
635
645
  command = [sys.executable, '-c', 'pass']
@@ -689,7 +699,7 @@ class TestPerfCLI(BaseTestCase, unittest.TestCase):
689
699
  '[1,2]*1000',
690
700
  '-o', tmp_name)
691
701
  bench = pyperf.Benchmark.load(tmp_name)
692
-
702
+
693
703
  self._check_track_memory_bench(bench, loops=5)
694
704
 
695
705
  def test_track_memory(self):
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: pyperf
3
- Version: 2.8.1
3
+ Version: 2.9.0
4
4
  Summary: Python module to run and analyze benchmarks
5
5
  Author-email: Victor Stinner <vstinner@redhat.com>
6
6
  Maintainer-email: Dong-hee Na <donghee.na@python.org>
@@ -3,4 +3,5 @@ pyperf = pyperf.__main__:main
3
3
 
4
4
  [pyperf.hook]
5
5
  _test_hook = pyperf._hooks:_test_hook
6
+ perf_record = pyperf._hooks:perf_record
6
7
  pystats = pyperf._hooks:pystats
@@ -56,6 +56,7 @@ dev = [
56
56
  pyperf = "pyperf.__main__:main"
57
57
 
58
58
  [project.entry-points."pyperf.hook"]
59
+ perf_record = "pyperf._hooks:perf_record"
59
60
  pystats = "pyperf._hooks:pystats"
60
61
  _test_hook = "pyperf._hooks:_test_hook"
61
62
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes