Coverage for tests/benchmark/benchmark.py: 0%
7 statements
« prev ^ index » next coverage.py v7.4.3, created at 2024-04-21 11:16 +0000
« prev ^ index » next coverage.py v7.4.3, created at 2024-04-21 11:16 +0000
1"""The files at `tests/benchmark` provide an example script to do profiling that can be customized for different
2scenarios, it relies on `line_profiler <https://github.com/pyutils/line_profiler>`_ package.
4The code snippet below shows how to run the benchmark script from a PowerShell terminal and save the results to file:
6.. code-block:: powershell
8 kernprof --line-by-line --builtin --outfile './tests/benchmark/benchmark.lprof' './tests/benchmark/benchmark.py';
9 $output = python -m line_profiler -rmt "./tests/benchmark/benchmark.lprof";
10 $output = $output -join [System.Environment]::NewLine;
11 Set-Content -Path "./tests/benchmark/benchmark.txt" -Value "$output" -Force;
13The following shows benchmarks for signals of different types using these scripts:
15.. code-block::
17 ~100k samples with ~500 edges:
18 Filtering: 0.00 seconds, State Levels: 0.01 seconds, Edges: 0.06 seconds
19 ~100k samples with ~5k edges:
20 Filtering: 0.00 seconds, State Levels: 0.01 seconds, Edges: 0.61 seconds
21 ~1M samples with ~5k edges:
22 Filtering: 0.03 seconds, State Levels: 0.03 seconds, Edges: 0.58 seconds
23 ~1M samples with ~50k edges:
24 Filtering: 0.02 seconds, State Levels: 0.03 seconds, Edges: 4.86 seconds
25 ~10M samples with ~50k edges:
26 Filtering: 0.23 seconds, State Levels: 0.25 seconds, Edges: 5.32 seconds
27 ~10M samples with ~500k edges:
28 Filtering: 0.24 seconds, State Levels: 0.31 seconds, Edges: 52.75 seconds
29 ~30M samples with ~25k edges:
30 Filtering: 0.68 seconds, State Levels: 1.83 seconds, Edges: 4.50 seconds
31 ~30M samples with ~2k edges:
32 Filtering: 0.08 seconds, State Levels: 0.52 seconds, Edges: 0.88 seconds
33 ~30M samples with ~150k edges:
34 Filtering: 0.66 seconds, State Levels: 0.87 seconds, Edges: 19.44 seconds
36Below some notes are listed in terms of performance:
38- If the full range of the signal calculated from the state levels, :class:`.StateLevels`, is below an expected value
39 for the user system, then a processing to extract edges can be skipped as there isn't any.
41- Runt edges, :class:`~.edges.definitions.Type` are more time consuming to extract than normal edges, a signal with
42 an excessive amount of runt edges can be a symptom of issues in the system or in the acquisition and a better
43 signal conditioning could reduce their number.
45- The intermediate point policy for edges, :class:`.IntPointPolicy`, can be adjusted to avoid calculation of
46 intermediate points, forcing the use of the ``begin`` or ``end`` values as ``intermediate``. This can be convenient
47 when the rising or falling times of the system are fast for the acquisition system to acquire samples during
48 that period.
50- For specific scenarios, disabling logging and the garbage collector temporarily during the processing."""
52# pylint: skip-file
54import gc
55import os
56import sys
58# Add path to 'signal-edges' package and perform imports.
59sys.path.append(os.path.normpath(os.path.join(os.path.dirname(__file__), "..", "..", "src")))
61from signal_edges.signal import VoltageSignal
62from signal_edges.signal.edges import IntPointPolicy
63from signal_edges.signal.generator import SignalGenerator
65if __name__ == "__main__":
66 # Disable garbage collection and enable profiling.
67 gc.disable()
68 profile.enable() # type: ignore
70 # Create generator with initial values.
71 sampling_frequency = 100000
72 generator = SignalGenerator(0, 1 / sampling_frequency, 100, 0, 100)
74 # Build signal with multiple pulses.
75 generator.add_flat(10)
76 generator.add_edge("falling", 0, 10)
77 generator.add_flat(10)
78 generator.add_edge("rising", 10, 10)
79 generator.repeat((1000000 - 40) // 40)
81 # Generate signal with some noise.
82 (signal_x, signal_y) = generator.generate(noise=(0, 5))
84 # Create voltage signal from sample.
85 signal = VoltageSignal(signal_x, signal_y, "s", "V")
87 # Create filtered signal.
88 profile(signal.filters_elliptic) # type: ignore
89 filtered_signal = signal.filters_elliptic(sampling_frequency, 4, sampling_frequency / 2.5)
90 # Calculate state levels.
91 profile(filtered_signal.state_levels) # type: ignore
92 (state_levels, (_, _)) = filtered_signal.state_levels()
93 # Calculate edges.
94 profile(filtered_signal.edges) # type: ignore
95 edges = filtered_signal.edges(state_levels, IntPointPolicy.POLICY_0)
97 # Print some data.
98 print(f"Number of samples: {len(signal.timestamps)}.")
99 print(f"Number of edges extracted: {len(edges)}.")
101 # End profile and resume garbage collection.
102 profile.disable() # type: ignore
103 gc.enable()