oscura 0.0.1__py3-none-any.whl → 0.1.1__py3-none-any.whl
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.
- oscura/__init__.py +813 -8
- oscura/__main__.py +392 -0
- oscura/analyzers/__init__.py +37 -0
- oscura/analyzers/digital/__init__.py +177 -0
- oscura/analyzers/digital/bus.py +691 -0
- oscura/analyzers/digital/clock.py +805 -0
- oscura/analyzers/digital/correlation.py +720 -0
- oscura/analyzers/digital/edges.py +632 -0
- oscura/analyzers/digital/extraction.py +413 -0
- oscura/analyzers/digital/quality.py +878 -0
- oscura/analyzers/digital/signal_quality.py +877 -0
- oscura/analyzers/digital/thresholds.py +708 -0
- oscura/analyzers/digital/timing.py +1104 -0
- oscura/analyzers/eye/__init__.py +46 -0
- oscura/analyzers/eye/diagram.py +434 -0
- oscura/analyzers/eye/metrics.py +555 -0
- oscura/analyzers/jitter/__init__.py +83 -0
- oscura/analyzers/jitter/ber.py +333 -0
- oscura/analyzers/jitter/decomposition.py +759 -0
- oscura/analyzers/jitter/measurements.py +413 -0
- oscura/analyzers/jitter/spectrum.py +220 -0
- oscura/analyzers/measurements.py +40 -0
- oscura/analyzers/packet/__init__.py +171 -0
- oscura/analyzers/packet/daq.py +1077 -0
- oscura/analyzers/packet/metrics.py +437 -0
- oscura/analyzers/packet/parser.py +327 -0
- oscura/analyzers/packet/payload.py +2156 -0
- oscura/analyzers/packet/payload_analysis.py +1312 -0
- oscura/analyzers/packet/payload_extraction.py +236 -0
- oscura/analyzers/packet/payload_patterns.py +670 -0
- oscura/analyzers/packet/stream.py +359 -0
- oscura/analyzers/patterns/__init__.py +266 -0
- oscura/analyzers/patterns/clustering.py +1036 -0
- oscura/analyzers/patterns/discovery.py +539 -0
- oscura/analyzers/patterns/learning.py +797 -0
- oscura/analyzers/patterns/matching.py +1091 -0
- oscura/analyzers/patterns/periodic.py +650 -0
- oscura/analyzers/patterns/sequences.py +767 -0
- oscura/analyzers/power/__init__.py +116 -0
- oscura/analyzers/power/ac_power.py +391 -0
- oscura/analyzers/power/basic.py +383 -0
- oscura/analyzers/power/conduction.py +314 -0
- oscura/analyzers/power/efficiency.py +297 -0
- oscura/analyzers/power/ripple.py +356 -0
- oscura/analyzers/power/soa.py +372 -0
- oscura/analyzers/power/switching.py +479 -0
- oscura/analyzers/protocol/__init__.py +150 -0
- oscura/analyzers/protocols/__init__.py +150 -0
- oscura/analyzers/protocols/base.py +500 -0
- oscura/analyzers/protocols/can.py +620 -0
- oscura/analyzers/protocols/can_fd.py +448 -0
- oscura/analyzers/protocols/flexray.py +405 -0
- oscura/analyzers/protocols/hdlc.py +399 -0
- oscura/analyzers/protocols/i2c.py +368 -0
- oscura/analyzers/protocols/i2s.py +296 -0
- oscura/analyzers/protocols/jtag.py +393 -0
- oscura/analyzers/protocols/lin.py +445 -0
- oscura/analyzers/protocols/manchester.py +333 -0
- oscura/analyzers/protocols/onewire.py +501 -0
- oscura/analyzers/protocols/spi.py +334 -0
- oscura/analyzers/protocols/swd.py +325 -0
- oscura/analyzers/protocols/uart.py +393 -0
- oscura/analyzers/protocols/usb.py +495 -0
- oscura/analyzers/signal_integrity/__init__.py +63 -0
- oscura/analyzers/signal_integrity/embedding.py +294 -0
- oscura/analyzers/signal_integrity/equalization.py +370 -0
- oscura/analyzers/signal_integrity/sparams.py +484 -0
- oscura/analyzers/spectral/__init__.py +53 -0
- oscura/analyzers/spectral/chunked.py +273 -0
- oscura/analyzers/spectral/chunked_fft.py +571 -0
- oscura/analyzers/spectral/chunked_wavelet.py +391 -0
- oscura/analyzers/spectral/fft.py +92 -0
- oscura/analyzers/statistical/__init__.py +250 -0
- oscura/analyzers/statistical/checksum.py +923 -0
- oscura/analyzers/statistical/chunked_corr.py +228 -0
- oscura/analyzers/statistical/classification.py +778 -0
- oscura/analyzers/statistical/entropy.py +1113 -0
- oscura/analyzers/statistical/ngrams.py +614 -0
- oscura/analyzers/statistics/__init__.py +119 -0
- oscura/analyzers/statistics/advanced.py +885 -0
- oscura/analyzers/statistics/basic.py +263 -0
- oscura/analyzers/statistics/correlation.py +630 -0
- oscura/analyzers/statistics/distribution.py +298 -0
- oscura/analyzers/statistics/outliers.py +463 -0
- oscura/analyzers/statistics/streaming.py +93 -0
- oscura/analyzers/statistics/trend.py +520 -0
- oscura/analyzers/validation.py +598 -0
- oscura/analyzers/waveform/__init__.py +36 -0
- oscura/analyzers/waveform/measurements.py +943 -0
- oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
- oscura/analyzers/waveform/spectral.py +1689 -0
- oscura/analyzers/waveform/wavelets.py +298 -0
- oscura/api/__init__.py +62 -0
- oscura/api/dsl.py +538 -0
- oscura/api/fluent.py +571 -0
- oscura/api/operators.py +498 -0
- oscura/api/optimization.py +392 -0
- oscura/api/profiling.py +396 -0
- oscura/automotive/__init__.py +73 -0
- oscura/automotive/can/__init__.py +52 -0
- oscura/automotive/can/analysis.py +356 -0
- oscura/automotive/can/checksum.py +250 -0
- oscura/automotive/can/correlation.py +212 -0
- oscura/automotive/can/discovery.py +355 -0
- oscura/automotive/can/message_wrapper.py +375 -0
- oscura/automotive/can/models.py +385 -0
- oscura/automotive/can/patterns.py +381 -0
- oscura/automotive/can/session.py +452 -0
- oscura/automotive/can/state_machine.py +300 -0
- oscura/automotive/can/stimulus_response.py +461 -0
- oscura/automotive/dbc/__init__.py +15 -0
- oscura/automotive/dbc/generator.py +156 -0
- oscura/automotive/dbc/parser.py +146 -0
- oscura/automotive/dtc/__init__.py +30 -0
- oscura/automotive/dtc/database.py +3036 -0
- oscura/automotive/j1939/__init__.py +14 -0
- oscura/automotive/j1939/decoder.py +745 -0
- oscura/automotive/loaders/__init__.py +35 -0
- oscura/automotive/loaders/asc.py +98 -0
- oscura/automotive/loaders/blf.py +77 -0
- oscura/automotive/loaders/csv_can.py +136 -0
- oscura/automotive/loaders/dispatcher.py +136 -0
- oscura/automotive/loaders/mdf.py +331 -0
- oscura/automotive/loaders/pcap.py +132 -0
- oscura/automotive/obd/__init__.py +14 -0
- oscura/automotive/obd/decoder.py +707 -0
- oscura/automotive/uds/__init__.py +48 -0
- oscura/automotive/uds/decoder.py +265 -0
- oscura/automotive/uds/models.py +64 -0
- oscura/automotive/visualization.py +369 -0
- oscura/batch/__init__.py +55 -0
- oscura/batch/advanced.py +627 -0
- oscura/batch/aggregate.py +300 -0
- oscura/batch/analyze.py +139 -0
- oscura/batch/logging.py +487 -0
- oscura/batch/metrics.py +556 -0
- oscura/builders/__init__.py +41 -0
- oscura/builders/signal_builder.py +1131 -0
- oscura/cli/__init__.py +14 -0
- oscura/cli/batch.py +339 -0
- oscura/cli/characterize.py +273 -0
- oscura/cli/compare.py +775 -0
- oscura/cli/decode.py +551 -0
- oscura/cli/main.py +247 -0
- oscura/cli/shell.py +350 -0
- oscura/comparison/__init__.py +66 -0
- oscura/comparison/compare.py +397 -0
- oscura/comparison/golden.py +487 -0
- oscura/comparison/limits.py +391 -0
- oscura/comparison/mask.py +434 -0
- oscura/comparison/trace_diff.py +30 -0
- oscura/comparison/visualization.py +481 -0
- oscura/compliance/__init__.py +70 -0
- oscura/compliance/advanced.py +756 -0
- oscura/compliance/masks.py +363 -0
- oscura/compliance/reporting.py +483 -0
- oscura/compliance/testing.py +298 -0
- oscura/component/__init__.py +38 -0
- oscura/component/impedance.py +365 -0
- oscura/component/reactive.py +598 -0
- oscura/component/transmission_line.py +312 -0
- oscura/config/__init__.py +191 -0
- oscura/config/defaults.py +254 -0
- oscura/config/loader.py +348 -0
- oscura/config/memory.py +271 -0
- oscura/config/migration.py +458 -0
- oscura/config/pipeline.py +1077 -0
- oscura/config/preferences.py +530 -0
- oscura/config/protocol.py +875 -0
- oscura/config/schema.py +713 -0
- oscura/config/settings.py +420 -0
- oscura/config/thresholds.py +599 -0
- oscura/convenience.py +457 -0
- oscura/core/__init__.py +299 -0
- oscura/core/audit.py +457 -0
- oscura/core/backend_selector.py +405 -0
- oscura/core/cache.py +590 -0
- oscura/core/cancellation.py +439 -0
- oscura/core/confidence.py +225 -0
- oscura/core/config.py +506 -0
- oscura/core/correlation.py +216 -0
- oscura/core/cross_domain.py +422 -0
- oscura/core/debug.py +301 -0
- oscura/core/edge_cases.py +541 -0
- oscura/core/exceptions.py +535 -0
- oscura/core/gpu_backend.py +523 -0
- oscura/core/lazy.py +832 -0
- oscura/core/log_query.py +540 -0
- oscura/core/logging.py +931 -0
- oscura/core/logging_advanced.py +952 -0
- oscura/core/memoize.py +171 -0
- oscura/core/memory_check.py +274 -0
- oscura/core/memory_guard.py +290 -0
- oscura/core/memory_limits.py +336 -0
- oscura/core/memory_monitor.py +453 -0
- oscura/core/memory_progress.py +465 -0
- oscura/core/memory_warnings.py +315 -0
- oscura/core/numba_backend.py +362 -0
- oscura/core/performance.py +352 -0
- oscura/core/progress.py +524 -0
- oscura/core/provenance.py +358 -0
- oscura/core/results.py +331 -0
- oscura/core/types.py +504 -0
- oscura/core/uncertainty.py +383 -0
- oscura/discovery/__init__.py +52 -0
- oscura/discovery/anomaly_detector.py +672 -0
- oscura/discovery/auto_decoder.py +415 -0
- oscura/discovery/comparison.py +497 -0
- oscura/discovery/quality_validator.py +528 -0
- oscura/discovery/signal_detector.py +769 -0
- oscura/dsl/__init__.py +73 -0
- oscura/dsl/commands.py +246 -0
- oscura/dsl/interpreter.py +455 -0
- oscura/dsl/parser.py +689 -0
- oscura/dsl/repl.py +172 -0
- oscura/exceptions.py +59 -0
- oscura/exploratory/__init__.py +111 -0
- oscura/exploratory/error_recovery.py +642 -0
- oscura/exploratory/fuzzy.py +513 -0
- oscura/exploratory/fuzzy_advanced.py +786 -0
- oscura/exploratory/legacy.py +831 -0
- oscura/exploratory/parse.py +358 -0
- oscura/exploratory/recovery.py +275 -0
- oscura/exploratory/sync.py +382 -0
- oscura/exploratory/unknown.py +707 -0
- oscura/export/__init__.py +25 -0
- oscura/export/wireshark/README.md +265 -0
- oscura/export/wireshark/__init__.py +47 -0
- oscura/export/wireshark/generator.py +312 -0
- oscura/export/wireshark/lua_builder.py +159 -0
- oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
- oscura/export/wireshark/type_mapping.py +165 -0
- oscura/export/wireshark/validator.py +105 -0
- oscura/exporters/__init__.py +94 -0
- oscura/exporters/csv.py +303 -0
- oscura/exporters/exporters.py +44 -0
- oscura/exporters/hdf5.py +219 -0
- oscura/exporters/html_export.py +701 -0
- oscura/exporters/json_export.py +291 -0
- oscura/exporters/markdown_export.py +367 -0
- oscura/exporters/matlab_export.py +354 -0
- oscura/exporters/npz_export.py +219 -0
- oscura/exporters/spice_export.py +210 -0
- oscura/extensibility/__init__.py +131 -0
- oscura/extensibility/docs.py +752 -0
- oscura/extensibility/extensions.py +1125 -0
- oscura/extensibility/logging.py +259 -0
- oscura/extensibility/measurements.py +485 -0
- oscura/extensibility/plugins.py +414 -0
- oscura/extensibility/registry.py +346 -0
- oscura/extensibility/templates.py +913 -0
- oscura/extensibility/validation.py +651 -0
- oscura/filtering/__init__.py +89 -0
- oscura/filtering/base.py +563 -0
- oscura/filtering/convenience.py +564 -0
- oscura/filtering/design.py +725 -0
- oscura/filtering/filters.py +32 -0
- oscura/filtering/introspection.py +605 -0
- oscura/guidance/__init__.py +24 -0
- oscura/guidance/recommender.py +429 -0
- oscura/guidance/wizard.py +518 -0
- oscura/inference/__init__.py +251 -0
- oscura/inference/active_learning/README.md +153 -0
- oscura/inference/active_learning/__init__.py +38 -0
- oscura/inference/active_learning/lstar.py +257 -0
- oscura/inference/active_learning/observation_table.py +230 -0
- oscura/inference/active_learning/oracle.py +78 -0
- oscura/inference/active_learning/teachers/__init__.py +15 -0
- oscura/inference/active_learning/teachers/simulator.py +192 -0
- oscura/inference/adaptive_tuning.py +453 -0
- oscura/inference/alignment.py +653 -0
- oscura/inference/bayesian.py +943 -0
- oscura/inference/binary.py +1016 -0
- oscura/inference/crc_reverse.py +711 -0
- oscura/inference/logic.py +288 -0
- oscura/inference/message_format.py +1305 -0
- oscura/inference/protocol.py +417 -0
- oscura/inference/protocol_dsl.py +1084 -0
- oscura/inference/protocol_library.py +1230 -0
- oscura/inference/sequences.py +809 -0
- oscura/inference/signal_intelligence.py +1509 -0
- oscura/inference/spectral.py +215 -0
- oscura/inference/state_machine.py +634 -0
- oscura/inference/stream.py +918 -0
- oscura/integrations/__init__.py +59 -0
- oscura/integrations/llm.py +1827 -0
- oscura/jupyter/__init__.py +32 -0
- oscura/jupyter/display.py +268 -0
- oscura/jupyter/magic.py +334 -0
- oscura/loaders/__init__.py +526 -0
- oscura/loaders/binary.py +69 -0
- oscura/loaders/configurable.py +1255 -0
- oscura/loaders/csv.py +26 -0
- oscura/loaders/csv_loader.py +473 -0
- oscura/loaders/hdf5.py +9 -0
- oscura/loaders/hdf5_loader.py +510 -0
- oscura/loaders/lazy.py +370 -0
- oscura/loaders/mmap_loader.py +583 -0
- oscura/loaders/numpy_loader.py +436 -0
- oscura/loaders/pcap.py +432 -0
- oscura/loaders/preprocessing.py +368 -0
- oscura/loaders/rigol.py +287 -0
- oscura/loaders/sigrok.py +321 -0
- oscura/loaders/tdms.py +367 -0
- oscura/loaders/tektronix.py +711 -0
- oscura/loaders/validation.py +584 -0
- oscura/loaders/vcd.py +464 -0
- oscura/loaders/wav.py +233 -0
- oscura/math/__init__.py +45 -0
- oscura/math/arithmetic.py +824 -0
- oscura/math/interpolation.py +413 -0
- oscura/onboarding/__init__.py +39 -0
- oscura/onboarding/help.py +498 -0
- oscura/onboarding/tutorials.py +405 -0
- oscura/onboarding/wizard.py +466 -0
- oscura/optimization/__init__.py +19 -0
- oscura/optimization/parallel.py +440 -0
- oscura/optimization/search.py +532 -0
- oscura/pipeline/__init__.py +43 -0
- oscura/pipeline/base.py +338 -0
- oscura/pipeline/composition.py +242 -0
- oscura/pipeline/parallel.py +448 -0
- oscura/pipeline/pipeline.py +375 -0
- oscura/pipeline/reverse_engineering.py +1119 -0
- oscura/plugins/__init__.py +122 -0
- oscura/plugins/base.py +272 -0
- oscura/plugins/cli.py +497 -0
- oscura/plugins/discovery.py +411 -0
- oscura/plugins/isolation.py +418 -0
- oscura/plugins/lifecycle.py +959 -0
- oscura/plugins/manager.py +493 -0
- oscura/plugins/registry.py +421 -0
- oscura/plugins/versioning.py +372 -0
- oscura/py.typed +0 -0
- oscura/quality/__init__.py +65 -0
- oscura/quality/ensemble.py +740 -0
- oscura/quality/explainer.py +338 -0
- oscura/quality/scoring.py +616 -0
- oscura/quality/warnings.py +456 -0
- oscura/reporting/__init__.py +248 -0
- oscura/reporting/advanced.py +1234 -0
- oscura/reporting/analyze.py +448 -0
- oscura/reporting/argument_preparer.py +596 -0
- oscura/reporting/auto_report.py +507 -0
- oscura/reporting/batch.py +615 -0
- oscura/reporting/chart_selection.py +223 -0
- oscura/reporting/comparison.py +330 -0
- oscura/reporting/config.py +615 -0
- oscura/reporting/content/__init__.py +39 -0
- oscura/reporting/content/executive.py +127 -0
- oscura/reporting/content/filtering.py +191 -0
- oscura/reporting/content/minimal.py +257 -0
- oscura/reporting/content/verbosity.py +162 -0
- oscura/reporting/core.py +508 -0
- oscura/reporting/core_formats/__init__.py +17 -0
- oscura/reporting/core_formats/multi_format.py +210 -0
- oscura/reporting/engine.py +836 -0
- oscura/reporting/export.py +366 -0
- oscura/reporting/formatting/__init__.py +129 -0
- oscura/reporting/formatting/emphasis.py +81 -0
- oscura/reporting/formatting/numbers.py +403 -0
- oscura/reporting/formatting/standards.py +55 -0
- oscura/reporting/formatting.py +466 -0
- oscura/reporting/html.py +578 -0
- oscura/reporting/index.py +590 -0
- oscura/reporting/multichannel.py +296 -0
- oscura/reporting/output.py +379 -0
- oscura/reporting/pdf.py +373 -0
- oscura/reporting/plots.py +731 -0
- oscura/reporting/pptx_export.py +360 -0
- oscura/reporting/renderers/__init__.py +11 -0
- oscura/reporting/renderers/pdf.py +94 -0
- oscura/reporting/sections.py +471 -0
- oscura/reporting/standards.py +680 -0
- oscura/reporting/summary_generator.py +368 -0
- oscura/reporting/tables.py +397 -0
- oscura/reporting/template_system.py +724 -0
- oscura/reporting/templates/__init__.py +15 -0
- oscura/reporting/templates/definition.py +205 -0
- oscura/reporting/templates/index.html +649 -0
- oscura/reporting/templates/index.md +173 -0
- oscura/schemas/__init__.py +158 -0
- oscura/schemas/bus_configuration.json +322 -0
- oscura/schemas/device_mapping.json +182 -0
- oscura/schemas/packet_format.json +418 -0
- oscura/schemas/protocol_definition.json +363 -0
- oscura/search/__init__.py +16 -0
- oscura/search/anomaly.py +292 -0
- oscura/search/context.py +149 -0
- oscura/search/pattern.py +160 -0
- oscura/session/__init__.py +34 -0
- oscura/session/annotations.py +289 -0
- oscura/session/history.py +313 -0
- oscura/session/session.py +445 -0
- oscura/streaming/__init__.py +43 -0
- oscura/streaming/chunked.py +611 -0
- oscura/streaming/progressive.py +393 -0
- oscura/streaming/realtime.py +622 -0
- oscura/testing/__init__.py +54 -0
- oscura/testing/synthetic.py +808 -0
- oscura/triggering/__init__.py +68 -0
- oscura/triggering/base.py +229 -0
- oscura/triggering/edge.py +353 -0
- oscura/triggering/pattern.py +344 -0
- oscura/triggering/pulse.py +581 -0
- oscura/triggering/window.py +453 -0
- oscura/ui/__init__.py +48 -0
- oscura/ui/formatters.py +526 -0
- oscura/ui/progressive_display.py +340 -0
- oscura/utils/__init__.py +99 -0
- oscura/utils/autodetect.py +338 -0
- oscura/utils/buffer.py +389 -0
- oscura/utils/lazy.py +407 -0
- oscura/utils/lazy_imports.py +147 -0
- oscura/utils/memory.py +836 -0
- oscura/utils/memory_advanced.py +1326 -0
- oscura/utils/memory_extensions.py +465 -0
- oscura/utils/progressive.py +352 -0
- oscura/utils/windowing.py +362 -0
- oscura/visualization/__init__.py +321 -0
- oscura/visualization/accessibility.py +526 -0
- oscura/visualization/annotations.py +374 -0
- oscura/visualization/axis_scaling.py +305 -0
- oscura/visualization/colors.py +453 -0
- oscura/visualization/digital.py +337 -0
- oscura/visualization/eye.py +420 -0
- oscura/visualization/histogram.py +281 -0
- oscura/visualization/interactive.py +858 -0
- oscura/visualization/jitter.py +702 -0
- oscura/visualization/keyboard.py +394 -0
- oscura/visualization/layout.py +365 -0
- oscura/visualization/optimization.py +1028 -0
- oscura/visualization/palettes.py +446 -0
- oscura/visualization/plot.py +92 -0
- oscura/visualization/power.py +290 -0
- oscura/visualization/power_extended.py +626 -0
- oscura/visualization/presets.py +467 -0
- oscura/visualization/protocols.py +932 -0
- oscura/visualization/render.py +207 -0
- oscura/visualization/rendering.py +444 -0
- oscura/visualization/reverse_engineering.py +791 -0
- oscura/visualization/signal_integrity.py +808 -0
- oscura/visualization/specialized.py +553 -0
- oscura/visualization/spectral.py +811 -0
- oscura/visualization/styles.py +381 -0
- oscura/visualization/thumbnails.py +311 -0
- oscura/visualization/time_axis.py +351 -0
- oscura/visualization/waveform.py +367 -0
- oscura/workflow/__init__.py +13 -0
- oscura/workflow/dag.py +377 -0
- oscura/workflows/__init__.py +58 -0
- oscura/workflows/compliance.py +280 -0
- oscura/workflows/digital.py +272 -0
- oscura/workflows/multi_trace.py +502 -0
- oscura/workflows/power.py +178 -0
- oscura/workflows/protocol.py +492 -0
- oscura/workflows/reverse_engineering.py +639 -0
- oscura/workflows/signal_integrity.py +227 -0
- oscura-0.1.1.dist-info/METADATA +300 -0
- oscura-0.1.1.dist-info/RECORD +463 -0
- oscura-0.1.1.dist-info/entry_points.txt +2 -0
- {oscura-0.0.1.dist-info → oscura-0.1.1.dist-info}/licenses/LICENSE +1 -1
- oscura-0.0.1.dist-info/METADATA +0 -63
- oscura-0.0.1.dist-info/RECORD +0 -5
- {oscura-0.0.1.dist-info → oscura-0.1.1.dist-info}/WHEEL +0 -0
oscura/api/profiling.py
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
"""Performance profiling for signal analysis operations.
|
|
2
|
+
|
|
3
|
+
This module provides profiling utilities for measuring and analyzing
|
|
4
|
+
performance of signal processing operations.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import functools
|
|
10
|
+
import logging
|
|
11
|
+
import statistics
|
|
12
|
+
import time
|
|
13
|
+
from contextlib import contextmanager
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from typing import TYPE_CHECKING, Any
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from collections.abc import Callable, Iterator
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"OperationProfile",
|
|
24
|
+
"ProfileReport",
|
|
25
|
+
"Profiler",
|
|
26
|
+
"profile",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class OperationProfile:
|
|
32
|
+
"""Profile data for a single operation.
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
name: Operation name
|
|
36
|
+
calls: Number of calls
|
|
37
|
+
total_time: Total time in seconds
|
|
38
|
+
min_time: Minimum time
|
|
39
|
+
max_time: Maximum time
|
|
40
|
+
times: List of individual times
|
|
41
|
+
memory_peak: Peak memory usage (bytes)
|
|
42
|
+
input_size: Input data size
|
|
43
|
+
|
|
44
|
+
References:
|
|
45
|
+
API-012: Performance Profiling API
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
name: str
|
|
49
|
+
calls: int = 0
|
|
50
|
+
total_time: float = 0.0
|
|
51
|
+
min_time: float = float("inf")
|
|
52
|
+
max_time: float = 0.0
|
|
53
|
+
times: list[float] = field(default_factory=list)
|
|
54
|
+
memory_peak: int = 0
|
|
55
|
+
input_size: int = 0
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def mean_time(self) -> float:
|
|
59
|
+
"""Average time per call."""
|
|
60
|
+
return self.total_time / self.calls if self.calls > 0 else 0.0
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def std_time(self) -> float:
|
|
64
|
+
"""Standard deviation of times."""
|
|
65
|
+
if len(self.times) < 2:
|
|
66
|
+
return 0.0
|
|
67
|
+
return statistics.stdev(self.times)
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def throughput(self) -> float:
|
|
71
|
+
"""Throughput in items per second."""
|
|
72
|
+
if self.total_time > 0 and self.input_size > 0:
|
|
73
|
+
return (self.input_size * self.calls) / self.total_time
|
|
74
|
+
return 0.0
|
|
75
|
+
|
|
76
|
+
def record(self, elapsed: float, size: int = 0) -> None:
|
|
77
|
+
"""Record a timing.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
elapsed: Elapsed time in seconds
|
|
81
|
+
size: Input size
|
|
82
|
+
"""
|
|
83
|
+
self.calls += 1
|
|
84
|
+
self.total_time += elapsed
|
|
85
|
+
self.min_time = min(self.min_time, elapsed)
|
|
86
|
+
self.max_time = max(self.max_time, elapsed)
|
|
87
|
+
self.times.append(elapsed)
|
|
88
|
+
if size > 0:
|
|
89
|
+
self.input_size = size
|
|
90
|
+
|
|
91
|
+
def to_dict(self) -> dict[str, Any]:
|
|
92
|
+
"""Convert to dictionary."""
|
|
93
|
+
return {
|
|
94
|
+
"name": self.name,
|
|
95
|
+
"calls": self.calls,
|
|
96
|
+
"total_time": self.total_time,
|
|
97
|
+
"mean_time": self.mean_time,
|
|
98
|
+
"min_time": self.min_time if self.min_time != float("inf") else 0,
|
|
99
|
+
"max_time": self.max_time,
|
|
100
|
+
"std_time": self.std_time,
|
|
101
|
+
"throughput": self.throughput,
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@dataclass
|
|
106
|
+
class ProfileReport:
|
|
107
|
+
"""Complete profiling report.
|
|
108
|
+
|
|
109
|
+
Attributes:
|
|
110
|
+
profiles: Dictionary of operation profiles
|
|
111
|
+
start_time: Report start time
|
|
112
|
+
end_time: Report end time
|
|
113
|
+
total_operations: Total number of operations
|
|
114
|
+
|
|
115
|
+
References:
|
|
116
|
+
API-012: Performance Profiling API
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
profiles: dict[str, OperationProfile] = field(default_factory=dict)
|
|
120
|
+
start_time: float = 0.0
|
|
121
|
+
end_time: float = 0.0
|
|
122
|
+
total_operations: int = 0
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def total_time(self) -> float:
|
|
126
|
+
"""Total profiled time."""
|
|
127
|
+
return sum(p.total_time for p in self.profiles.values())
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def wall_time(self) -> float:
|
|
131
|
+
"""Wall clock time."""
|
|
132
|
+
return self.end_time - self.start_time if self.end_time > 0 else 0.0
|
|
133
|
+
|
|
134
|
+
def get_slowest(self, n: int = 5) -> list[OperationProfile]:
|
|
135
|
+
"""Get slowest operations.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
n: Number of operations
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
List of slowest operation profiles
|
|
142
|
+
"""
|
|
143
|
+
sorted_profiles = sorted(self.profiles.values(), key=lambda p: p.total_time, reverse=True)
|
|
144
|
+
return sorted_profiles[:n]
|
|
145
|
+
|
|
146
|
+
def get_most_called(self, n: int = 5) -> list[OperationProfile]:
|
|
147
|
+
"""Get most frequently called operations.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
n: Number of operations
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
List of most called operation profiles
|
|
154
|
+
"""
|
|
155
|
+
sorted_profiles = sorted(self.profiles.values(), key=lambda p: p.calls, reverse=True)
|
|
156
|
+
return sorted_profiles[:n]
|
|
157
|
+
|
|
158
|
+
def summary(self) -> str:
|
|
159
|
+
"""Generate text summary.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
Summary string
|
|
163
|
+
"""
|
|
164
|
+
lines = [
|
|
165
|
+
"Performance Profile Report",
|
|
166
|
+
"=" * 50,
|
|
167
|
+
f"Total operations: {self.total_operations}",
|
|
168
|
+
f"Total profiled time: {self.total_time:.4f}s",
|
|
169
|
+
f"Wall clock time: {self.wall_time:.4f}s",
|
|
170
|
+
"",
|
|
171
|
+
"Slowest Operations:",
|
|
172
|
+
"-" * 30,
|
|
173
|
+
]
|
|
174
|
+
|
|
175
|
+
for profile in self.get_slowest():
|
|
176
|
+
lines.append(
|
|
177
|
+
f" {profile.name}: "
|
|
178
|
+
f"{profile.total_time:.4f}s ({profile.calls} calls, "
|
|
179
|
+
f"{profile.mean_time * 1000:.2f}ms avg)"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
return "\n".join(lines)
|
|
183
|
+
|
|
184
|
+
def to_dict(self) -> dict[str, Any]:
|
|
185
|
+
"""Convert to dictionary."""
|
|
186
|
+
return {
|
|
187
|
+
"total_time": self.total_time,
|
|
188
|
+
"wall_time": self.wall_time,
|
|
189
|
+
"total_operations": self.total_operations,
|
|
190
|
+
"profiles": {name: profile.to_dict() for name, profile in self.profiles.items()},
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class Profiler:
|
|
195
|
+
"""Performance profiler for signal analysis operations.
|
|
196
|
+
|
|
197
|
+
Tracks timing and performance metrics for operations.
|
|
198
|
+
|
|
199
|
+
Example:
|
|
200
|
+
>>> profiler = Profiler()
|
|
201
|
+
>>> with profiler.profile("fft"):
|
|
202
|
+
... result = np.fft.fft(data)
|
|
203
|
+
>>> report = profiler.report()
|
|
204
|
+
>>> print(report.summary())
|
|
205
|
+
|
|
206
|
+
References:
|
|
207
|
+
API-012: Performance Profiling API
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
_instance: Profiler | None = None
|
|
211
|
+
|
|
212
|
+
def __init__(self) -> None:
|
|
213
|
+
"""Initialize profiler."""
|
|
214
|
+
self._profiles: dict[str, OperationProfile] = {}
|
|
215
|
+
self._start_time: float = 0.0
|
|
216
|
+
self._enabled: bool = True
|
|
217
|
+
self._stack: list[str] = []
|
|
218
|
+
|
|
219
|
+
@classmethod
|
|
220
|
+
def get_instance(cls) -> Profiler:
|
|
221
|
+
"""Get global profiler instance."""
|
|
222
|
+
if cls._instance is None:
|
|
223
|
+
cls._instance = cls()
|
|
224
|
+
return cls._instance
|
|
225
|
+
|
|
226
|
+
def enable(self) -> None:
|
|
227
|
+
"""Enable profiling."""
|
|
228
|
+
self._enabled = True
|
|
229
|
+
|
|
230
|
+
def disable(self) -> None:
|
|
231
|
+
"""Disable profiling."""
|
|
232
|
+
self._enabled = False
|
|
233
|
+
|
|
234
|
+
def reset(self) -> None:
|
|
235
|
+
"""Reset all profiles."""
|
|
236
|
+
self._profiles.clear()
|
|
237
|
+
self._start_time = 0.0
|
|
238
|
+
|
|
239
|
+
@contextmanager
|
|
240
|
+
def profile(self, name: str, input_size: int = 0) -> Iterator[None]:
|
|
241
|
+
"""Context manager for profiling code block.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
name: Operation name
|
|
245
|
+
input_size: Input data size
|
|
246
|
+
|
|
247
|
+
Yields:
|
|
248
|
+
None
|
|
249
|
+
|
|
250
|
+
Example:
|
|
251
|
+
>>> with profiler.profile("fft"):
|
|
252
|
+
... result = compute_fft(data)
|
|
253
|
+
"""
|
|
254
|
+
if not self._enabled:
|
|
255
|
+
yield
|
|
256
|
+
return
|
|
257
|
+
|
|
258
|
+
if self._start_time == 0:
|
|
259
|
+
self._start_time = time.perf_counter()
|
|
260
|
+
|
|
261
|
+
if name not in self._profiles:
|
|
262
|
+
self._profiles[name] = OperationProfile(name)
|
|
263
|
+
|
|
264
|
+
self._stack.append(name)
|
|
265
|
+
start = time.perf_counter()
|
|
266
|
+
|
|
267
|
+
try:
|
|
268
|
+
yield
|
|
269
|
+
finally:
|
|
270
|
+
elapsed = time.perf_counter() - start
|
|
271
|
+
self._profiles[name].record(elapsed, input_size)
|
|
272
|
+
self._stack.pop()
|
|
273
|
+
|
|
274
|
+
def record(self, name: str, elapsed: float, input_size: int = 0) -> None:
|
|
275
|
+
"""Manually record a timing.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
name: Operation name
|
|
279
|
+
elapsed: Elapsed time
|
|
280
|
+
input_size: Input size
|
|
281
|
+
"""
|
|
282
|
+
if not self._enabled:
|
|
283
|
+
return
|
|
284
|
+
|
|
285
|
+
if name not in self._profiles:
|
|
286
|
+
self._profiles[name] = OperationProfile(name)
|
|
287
|
+
|
|
288
|
+
self._profiles[name].record(elapsed, input_size)
|
|
289
|
+
|
|
290
|
+
def get_profile(self, name: str) -> OperationProfile | None:
|
|
291
|
+
"""Get profile for operation.
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
name: Operation name
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
Operation profile or None
|
|
298
|
+
"""
|
|
299
|
+
return self._profiles.get(name)
|
|
300
|
+
|
|
301
|
+
def report(self) -> ProfileReport:
|
|
302
|
+
"""Generate profiling report.
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
Profile report
|
|
306
|
+
"""
|
|
307
|
+
return ProfileReport(
|
|
308
|
+
profiles=self._profiles.copy(),
|
|
309
|
+
start_time=self._start_time,
|
|
310
|
+
end_time=time.perf_counter(),
|
|
311
|
+
total_operations=sum(p.calls for p in self._profiles.values()),
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def profile(name: str | None = None, input_size_arg: str | None = None) -> Callable: # type: ignore[type-arg]
|
|
316
|
+
"""Decorator for profiling functions.
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
name: Profile name (defaults to function name)
|
|
320
|
+
input_size_arg: Argument name for input size
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
Decorated function
|
|
324
|
+
|
|
325
|
+
Example:
|
|
326
|
+
>>> @profile()
|
|
327
|
+
>>> def compute_fft(data, nfft=None):
|
|
328
|
+
... return np.fft.fft(data, n=nfft)
|
|
329
|
+
|
|
330
|
+
References:
|
|
331
|
+
API-012: Performance Profiling API
|
|
332
|
+
"""
|
|
333
|
+
|
|
334
|
+
def decorator(func: Callable) -> Callable: # type: ignore[type-arg]
|
|
335
|
+
profile_name = name or func.__name__
|
|
336
|
+
|
|
337
|
+
@functools.wraps(func)
|
|
338
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
339
|
+
profiler = Profiler.get_instance()
|
|
340
|
+
|
|
341
|
+
# Determine input size
|
|
342
|
+
input_size = 0
|
|
343
|
+
if input_size_arg:
|
|
344
|
+
if input_size_arg in kwargs:
|
|
345
|
+
data = kwargs[input_size_arg]
|
|
346
|
+
elif args:
|
|
347
|
+
data = args[0]
|
|
348
|
+
else:
|
|
349
|
+
data = None
|
|
350
|
+
|
|
351
|
+
if hasattr(data, "__len__"):
|
|
352
|
+
input_size = len(data)
|
|
353
|
+
|
|
354
|
+
with profiler.profile(profile_name, input_size):
|
|
355
|
+
return func(*args, **kwargs)
|
|
356
|
+
|
|
357
|
+
return wrapper
|
|
358
|
+
|
|
359
|
+
return decorator
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
# Convenience functions
|
|
363
|
+
def get_profiler() -> Profiler:
|
|
364
|
+
"""Get global profiler instance.
|
|
365
|
+
|
|
366
|
+
Returns:
|
|
367
|
+
Global Profiler instance
|
|
368
|
+
|
|
369
|
+
References:
|
|
370
|
+
API-012: Performance Profiling API
|
|
371
|
+
"""
|
|
372
|
+
return Profiler.get_instance()
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def enable_profiling() -> None:
|
|
376
|
+
"""Enable global profiling."""
|
|
377
|
+
get_profiler().enable()
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def disable_profiling() -> None:
|
|
381
|
+
"""Disable global profiling."""
|
|
382
|
+
get_profiler().disable()
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def reset_profiling() -> None:
|
|
386
|
+
"""Reset global profiler."""
|
|
387
|
+
get_profiler().reset()
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def get_profile_report() -> ProfileReport:
|
|
391
|
+
"""Get global profile report.
|
|
392
|
+
|
|
393
|
+
Returns:
|
|
394
|
+
Profile report
|
|
395
|
+
"""
|
|
396
|
+
return get_profiler().report()
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Automotive signal analysis and reverse engineering.
|
|
2
|
+
|
|
3
|
+
This module provides comprehensive automotive protocol analysis capabilities
|
|
4
|
+
for CAN, CAN-FD, OBD-II, J1939, UDS, DBC-based signal decoding, and diagnostic
|
|
5
|
+
trouble code (DTC) database.
|
|
6
|
+
|
|
7
|
+
Key features:
|
|
8
|
+
- CAN message analysis and discovery (message inventory, byte entropy, pattern detection)
|
|
9
|
+
- Signal boundary detection and hypothesis testing
|
|
10
|
+
- DBC database parsing and generation
|
|
11
|
+
- OBD-II diagnostic protocol support
|
|
12
|
+
- J1939 heavy-duty vehicle protocol support
|
|
13
|
+
- UDS (ISO 14229) diagnostic services decoding
|
|
14
|
+
- DTC database (200+ codes for Powertrain, Chassis, Body, Network)
|
|
15
|
+
- Discovery documentation with evidence tracking (.tkcan format)
|
|
16
|
+
- Integration with Oscura's CRC reverse engineering and state machine learning
|
|
17
|
+
|
|
18
|
+
Example:
|
|
19
|
+
>>> from oscura.automotive.can import CANSession
|
|
20
|
+
>>> # Load automotive log file
|
|
21
|
+
>>> session = CANSession.from_log("capture.blf")
|
|
22
|
+
>>> # View message inventory
|
|
23
|
+
>>> inventory = session.inventory()
|
|
24
|
+
>>> # Analyze specific message
|
|
25
|
+
>>> msg = session.message(0x280)
|
|
26
|
+
>>> analysis = msg.analyze()
|
|
27
|
+
>>> # Test hypothesis about signal
|
|
28
|
+
>>> hypothesis = msg.test_hypothesis(
|
|
29
|
+
... signal_name="rpm",
|
|
30
|
+
... start_byte=2,
|
|
31
|
+
... bit_length=16,
|
|
32
|
+
... byte_order="big_endian",
|
|
33
|
+
... scale=0.25
|
|
34
|
+
... )
|
|
35
|
+
>>>
|
|
36
|
+
>>> # Look up diagnostic trouble codes
|
|
37
|
+
>>> from oscura.automotive.dtc import DTCDatabase
|
|
38
|
+
>>> info = DTCDatabase.lookup("P0420")
|
|
39
|
+
>>> print(f"{info.code}: {info.description}")
|
|
40
|
+
P0420: Catalyst System Efficiency Below Threshold (Bank 1)
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
from __future__ import annotations
|
|
44
|
+
|
|
45
|
+
__version__ = "0.1.0"
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
"CANMessage",
|
|
49
|
+
"CANSession",
|
|
50
|
+
"DecodedSignal",
|
|
51
|
+
"DiscoveryDocument",
|
|
52
|
+
"plot_bus_timeline",
|
|
53
|
+
"plot_bus_utilization",
|
|
54
|
+
"plot_message_distribution",
|
|
55
|
+
"plot_message_frequency",
|
|
56
|
+
"plot_signal_timeline",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
# Import main classes when module is loaded
|
|
60
|
+
try:
|
|
61
|
+
from oscura.automotive.can.discovery import DiscoveryDocument
|
|
62
|
+
from oscura.automotive.can.models import CANMessage, DecodedSignal
|
|
63
|
+
from oscura.automotive.can.session import CANSession
|
|
64
|
+
from oscura.automotive.visualization import (
|
|
65
|
+
plot_bus_timeline,
|
|
66
|
+
plot_bus_utilization,
|
|
67
|
+
plot_message_distribution,
|
|
68
|
+
plot_message_frequency,
|
|
69
|
+
plot_signal_timeline,
|
|
70
|
+
)
|
|
71
|
+
except ImportError:
|
|
72
|
+
# Optional automotive dependencies not installed
|
|
73
|
+
pass
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""CAN bus analysis and reverse engineering.
|
|
2
|
+
|
|
3
|
+
This submodule provides CAN-specific analysis tools for reverse engineering
|
|
4
|
+
automotive protocols from captured CAN bus data.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"ByteChange",
|
|
11
|
+
"CANMessage",
|
|
12
|
+
"CANMessageList",
|
|
13
|
+
"CANSession",
|
|
14
|
+
"CANStateMachine",
|
|
15
|
+
"DecodedSignal",
|
|
16
|
+
"FrequencyChange",
|
|
17
|
+
"MessageAnalysis",
|
|
18
|
+
"MessagePair",
|
|
19
|
+
"MessageSequence",
|
|
20
|
+
"PatternAnalyzer",
|
|
21
|
+
"SequenceExtraction",
|
|
22
|
+
"SignalDefinition",
|
|
23
|
+
"StimulusResponseAnalyzer",
|
|
24
|
+
"StimulusResponseReport",
|
|
25
|
+
"TemporalCorrelation",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
from oscura.automotive.can.models import (
|
|
30
|
+
CANMessage,
|
|
31
|
+
CANMessageList,
|
|
32
|
+
DecodedSignal,
|
|
33
|
+
MessageAnalysis,
|
|
34
|
+
SignalDefinition,
|
|
35
|
+
)
|
|
36
|
+
from oscura.automotive.can.patterns import (
|
|
37
|
+
MessagePair,
|
|
38
|
+
MessageSequence,
|
|
39
|
+
PatternAnalyzer,
|
|
40
|
+
TemporalCorrelation,
|
|
41
|
+
)
|
|
42
|
+
from oscura.automotive.can.session import CANSession
|
|
43
|
+
from oscura.automotive.can.state_machine import CANStateMachine, SequenceExtraction
|
|
44
|
+
from oscura.automotive.can.stimulus_response import (
|
|
45
|
+
ByteChange,
|
|
46
|
+
FrequencyChange,
|
|
47
|
+
StimulusResponseAnalyzer,
|
|
48
|
+
StimulusResponseReport,
|
|
49
|
+
)
|
|
50
|
+
except ImportError:
|
|
51
|
+
# Optional dependencies not installed
|
|
52
|
+
pass
|