acprof 0.3.0__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.
- acprof/__init__.py +3 -0
- acprof/__main__.py +5 -0
- acprof/_bundle/.dockerignore +20 -0
- acprof/_bundle/LICENSE +202 -0
- acprof/_bundle/NOTICE +43 -0
- acprof/_bundle/acprof/__init__.py +3 -0
- acprof/_bundle/acprof/__main__.py +5 -0
- acprof/_bundle/acprof/analysis/__init__.py +1 -0
- acprof/_bundle/acprof/analysis/audit.py +276 -0
- acprof/_bundle/acprof/analysis/comparison.py +364 -0
- acprof/_bundle/acprof/analysis/compatibility.py +223 -0
- acprof/_bundle/acprof/analysis/conditions.py +185 -0
- acprof/_bundle/acprof/analysis/independent_comparison.py +191 -0
- acprof/_bundle/acprof/analysis/latency_model.py +1106 -0
- acprof/_bundle/acprof/analysis/latency_report.py +577 -0
- acprof/_bundle/acprof/analysis/model.py +276 -0
- acprof/_bundle/acprof/analysis/precision.py +51 -0
- acprof/_bundle/acprof/analysis/uncertainty.py +144 -0
- acprof/_bundle/acprof/application/__init__.py +1 -0
- acprof/_bundle/acprof/application/download.py +14 -0
- acprof/_bundle/acprof/application/errors.py +5 -0
- acprof/_bundle/acprof/application/notifications.py +302 -0
- acprof/_bundle/acprof/application/preparation.py +333 -0
- acprof/_bundle/acprof/application/resources.py +66 -0
- acprof/_bundle/acprof/application/run.py +462 -0
- acprof/_bundle/acprof/application/terminal_log.py +136 -0
- acprof/_bundle/acprof/artifact_layout.py +261 -0
- acprof/_bundle/acprof/artifacts.py +161 -0
- acprof/_bundle/acprof/capabilities.py +404 -0
- acprof/_bundle/acprof/cli/__init__.py +1 -0
- acprof/_bundle/acprof/cli/audit.py +74 -0
- acprof/_bundle/acprof/cli/auto.py +41 -0
- acprof/_bundle/acprof/cli/backfill_compute.py +498 -0
- acprof/_bundle/acprof/cli/compare.py +34 -0
- acprof/_bundle/acprof/cli/coverage.py +70 -0
- acprof/_bundle/acprof/cli/doctor.py +47 -0
- acprof/_bundle/acprof/cli/inspect.py +101 -0
- acprof/_bundle/acprof/cli/load.py +190 -0
- acprof/_bundle/acprof/cli/main.py +64 -0
- acprof/_bundle/acprof/cli/model_store.py +22 -0
- acprof/_bundle/acprof/cli/plot.py +211 -0
- acprof/_bundle/acprof/cli/posthoc.py +113 -0
- acprof/_bundle/acprof/cli/probe.py +186 -0
- acprof/_bundle/acprof/cli/report.py +35 -0
- acprof/_bundle/acprof/cli/results.py +37 -0
- acprof/_bundle/acprof/cli/run.py +54 -0
- acprof/_bundle/acprof/cli/stats.py +94 -0
- acprof/_bundle/acprof/cli/tui.py +65 -0
- acprof/_bundle/acprof/config.py +177 -0
- acprof/_bundle/acprof/container/__init__.py +1 -0
- acprof/_bundle/acprof/container/compat/__init__.py +1 -0
- acprof/_bundle/acprof/container/compat/transformers_dynamic.py +54 -0
- acprof/_bundle/acprof/container/compat/transformers_model_types.json +1091 -0
- acprof/_bundle/acprof/container/compute_profile_runner.py +392 -0
- acprof/_bundle/acprof/container/download_model.py +165 -0
- acprof/_bundle/acprof/container/execution.py +73 -0
- acprof/_bundle/acprof/container/handlers/__init__.py +298 -0
- acprof/_bundle/acprof/container/handlers/audio.py +743 -0
- acprof/_bundle/acprof/container/handlers/custom_pipeline.py +74 -0
- acprof/_bundle/acprof/container/handlers/cv.py +321 -0
- acprof/_bundle/acprof/container/handlers/diffusion.py +728 -0
- acprof/_bundle/acprof/container/handlers/moss.py +64 -0
- acprof/_bundle/acprof/container/handlers/multimodal.py +609 -0
- acprof/_bundle/acprof/container/handlers/nlp.py +747 -0
- acprof/_bundle/acprof/container/handlers/onnx_tasks.py +231 -0
- acprof/_bundle/acprof/container/handlers/onnxruntime.py +90 -0
- acprof/_bundle/acprof/container/handlers/structured.py +185 -0
- acprof/_bundle/acprof/container/handlers/timeseries.py +178 -0
- acprof/_bundle/acprof/container/load_policy.py +81 -0
- acprof/_bundle/acprof/container/loading_quality.py +48 -0
- acprof/_bundle/acprof/container/local_pipeline.py +31 -0
- acprof/_bundle/acprof/container/model_files.py +280 -0
- acprof/_bundle/acprof/container/model_probe.py +80 -0
- acprof/_bundle/acprof/container/onnx_session.py +150 -0
- acprof/_bundle/acprof/container/runtime_manifest.py +150 -0
- acprof/_bundle/acprof/container/runtime_validate.py +156 -0
- acprof/_bundle/acprof/container/server.py +209 -0
- acprof/_bundle/acprof/container/torch_execution.py +55 -0
- acprof/_bundle/acprof/container/validation.py +172 -0
- acprof/_bundle/acprof/cpu_affinity.py +35 -0
- acprof/_bundle/acprof/dependency_locks.py +129 -0
- acprof/_bundle/acprof/experiment.py +356 -0
- acprof/_bundle/acprof/extensions/__init__.py +294 -0
- acprof/_bundle/acprof/extensions/builtin/manifest.json +3591 -0
- acprof/_bundle/acprof/extensions/onnxruntime/manifest.json +191 -0
- acprof/_bundle/acprof/extensions/schema.py +238 -0
- acprof/_bundle/acprof/extensions/transformers/4.57.6.json +1639 -0
- acprof/_bundle/acprof/extensions/transformers/5.10.4.json +1812 -0
- acprof/_bundle/acprof/failures.py +115 -0
- acprof/_bundle/acprof/hardware_conditions.py +18 -0
- acprof/_bundle/acprof/hf_download.py +143 -0
- acprof/_bundle/acprof/hf_endpoints.py +62 -0
- acprof/_bundle/acprof/hf_transport.py +238 -0
- acprof/_bundle/acprof/host/__init__.py +1 -0
- acprof/_bundle/acprof/host/automation.py +161 -0
- acprof/_bundle/acprof/host/client.py +520 -0
- acprof/_bundle/acprof/host/collection_history.py +77 -0
- acprof/_bundle/acprof/host/collection_workflow.py +285 -0
- acprof/_bundle/acprof/host/command.py +119 -0
- acprof/_bundle/acprof/host/container_lifecycle.py +225 -0
- acprof/_bundle/acprof/host/container_state.py +128 -0
- acprof/_bundle/acprof/host/coverage_state.py +259 -0
- acprof/_bundle/acprof/host/detect.py +669 -0
- acprof/_bundle/acprof/host/docker_runtime.py +359 -0
- acprof/_bundle/acprof/host/doctor.py +158 -0
- acprof/_bundle/acprof/host/env_utils.py +233 -0
- acprof/_bundle/acprof/host/execution_conditions.py +87 -0
- acprof/_bundle/acprof/host/gpu_device.py +66 -0
- acprof/_bundle/acprof/host/hardware_conditions.py +130 -0
- acprof/_bundle/acprof/host/images/__init__.py +1 -0
- acprof/_bundle/acprof/host/images/dependencies.py +169 -0
- acprof/_bundle/acprof/host/images/environment.py +313 -0
- acprof/_bundle/acprof/host/images/graph.py +143 -0
- acprof/_bundle/acprof/host/images/identity.py +6 -0
- acprof/_bundle/acprof/host/images/inventory.py +445 -0
- acprof/_bundle/acprof/host/images/runtime.py +457 -0
- acprof/_bundle/acprof/host/images/scan.py +154 -0
- acprof/_bundle/acprof/host/input_plan.py +1056 -0
- acprof/_bundle/acprof/host/interface_probe.py +141 -0
- acprof/_bundle/acprof/host/largest_scale_probe.py +566 -0
- acprof/_bundle/acprof/host/matrix_plan.py +98 -0
- acprof/_bundle/acprof/host/measurement/__init__.py +1 -0
- acprof/_bundle/acprof/host/measurement/boundary.py +162 -0
- acprof/_bundle/acprof/host/measurement/capture.py +139 -0
- acprof/_bundle/acprof/host/measurement/checkpoint.py +275 -0
- acprof/_bundle/acprof/host/measurement/config.py +212 -0
- acprof/_bundle/acprof/host/measurement/diagnostics.py +247 -0
- acprof/_bundle/acprof/host/measurement/energy_validation.py +172 -0
- acprof/_bundle/acprof/host/measurement/errors.py +25 -0
- acprof/_bundle/acprof/host/measurement/execution.py +396 -0
- acprof/_bundle/acprof/host/measurement/load.py +237 -0
- acprof/_bundle/acprof/host/measurement/metrics.py +975 -0
- acprof/_bundle/acprof/host/measurement/monitors.py +143 -0
- acprof/_bundle/acprof/host/measurement/publication.py +171 -0
- acprof/_bundle/acprof/host/measurement/requests.py +97 -0
- acprof/_bundle/acprof/host/measurement/types.py +82 -0
- acprof/_bundle/acprof/host/model_coverage.py +337 -0
- acprof/_bundle/acprof/host/model_errors.py +116 -0
- acprof/_bundle/acprof/host/model_inspection.py +107 -0
- acprof/_bundle/acprof/host/model_schema.py +35 -0
- acprof/_bundle/acprof/host/model_store.py +733 -0
- acprof/_bundle/acprof/host/network_preflight.py +229 -0
- acprof/_bundle/acprof/host/orchestrator.py +1133 -0
- acprof/_bundle/acprof/host/permissions.py +117 -0
- acprof/_bundle/acprof/host/platform_metadata.py +63 -0
- acprof/_bundle/acprof/host/posthoc/__init__.py +12 -0
- acprof/_bundle/acprof/host/posthoc/backfill.py +415 -0
- acprof/_bundle/acprof/host/posthoc/context.py +400 -0
- acprof/_bundle/acprof/host/posthoc/plans.py +597 -0
- acprof/_bundle/acprof/host/posthoc/service.py +303 -0
- acprof/_bundle/acprof/host/posthoc/storage.py +491 -0
- acprof/_bundle/acprof/host/preflight.py +370 -0
- acprof/_bundle/acprof/host/profiling/__init__.py +1 -0
- acprof/_bundle/acprof/host/profiling/compute.py +436 -0
- acprof/_bundle/acprof/host/profiling/compute_plan.py +261 -0
- acprof/_bundle/acprof/host/profiling/execution.py +547 -0
- acprof/_bundle/acprof/host/profiling/execution_plan.py +576 -0
- acprof/_bundle/acprof/host/profiling/progress.py +83 -0
- acprof/_bundle/acprof/host/profiling/support.py +252 -0
- acprof/_bundle/acprof/host/profiling/tools/__init__.py +1 -0
- acprof/_bundle/acprof/host/profiling/tools/advisor.py +164 -0
- acprof/_bundle/acprof/host/profiling/tools/compute_parsers.py +409 -0
- acprof/_bundle/acprof/host/profiling/tools/execution_environment.py +135 -0
- acprof/_bundle/acprof/host/profiling/tools/execution_parsers.py +364 -0
- acprof/_bundle/acprof/host/profiling/tools/massif.py +418 -0
- acprof/_bundle/acprof/host/profiling/tools/ncu.py +696 -0
- acprof/_bundle/acprof/host/profiling/tools/nsys.py +326 -0
- acprof/_bundle/acprof/host/profiling/tools/tool_discovery.py +229 -0
- acprof/_bundle/acprof/host/profiling/tools/torch.py +158 -0
- acprof/_bundle/acprof/host/result_cleanup.py +65 -0
- acprof/_bundle/acprof/host/run_state.py +639 -0
- acprof/_bundle/acprof/host/runtime_settings.py +10 -0
- acprof/_bundle/acprof/host/runtime_validation.py +302 -0
- acprof/_bundle/acprof/host/source_bundle.py +96 -0
- acprof/_bundle/acprof/host/startup_probe.py +95 -0
- acprof/_bundle/acprof/host/static_metadata.py +936 -0
- acprof/_bundle/acprof/host/task_support.py +121 -0
- acprof/_bundle/acprof/installation.py +26 -0
- acprof/_bundle/acprof/latency_slo.py +62 -0
- acprof/_bundle/acprof/messages.py +26 -0
- acprof/_bundle/acprof/metric_registry.py +315 -0
- acprof/_bundle/acprof/model_candidates.py +297 -0
- acprof/_bundle/acprof/model_contract.py +234 -0
- acprof/_bundle/acprof/model_dependencies.py +93 -0
- acprof/_bundle/acprof/model_dependency_domain.py +45 -0
- acprof/_bundle/acprof/model_dependency_eval.py +438 -0
- acprof/_bundle/acprof/model_dependency_flow.py +200 -0
- acprof/_bundle/acprof/model_evidence.py +115 -0
- acprof/_bundle/acprof/model_metadata_analysis.py +156 -0
- acprof/_bundle/acprof/model_repository.py +149 -0
- acprof/_bundle/acprof/model_resolution.py +129 -0
- acprof/_bundle/acprof/model_review.py +155 -0
- acprof/_bundle/acprof/model_source_analysis.py +299 -0
- acprof/_bundle/acprof/model_spec.py +204 -0
- acprof/_bundle/acprof/model_support.py +105 -0
- acprof/_bundle/acprof/model_transforms.py +81 -0
- acprof/_bundle/acprof/monitors/__init__.py +1 -0
- acprof/_bundle/acprof/monitors/common.py +63 -0
- acprof/_bundle/acprof/monitors/energy_cpu.py +651 -0
- acprof/_bundle/acprof/monitors/energy_nvml.py +381 -0
- acprof/_bundle/acprof/monitors/gpu_metrics.py +123 -0
- acprof/_bundle/acprof/monitors/interfaces.py +74 -0
- acprof/_bundle/acprof/monitors/perf_mips.py +617 -0
- acprof/_bundle/acprof/monitors/rapl_topology.py +100 -0
- acprof/_bundle/acprof/monitors/resource_metrics.py +472 -0
- acprof/_bundle/acprof/monitors/resource_readers.py +435 -0
- acprof/_bundle/acprof/monitors/resource_usage.py +450 -0
- acprof/_bundle/acprof/monitors/sampling.py +79 -0
- acprof/_bundle/acprof/network_policy.py +182 -0
- acprof/_bundle/acprof/notifications.py +279 -0
- acprof/_bundle/acprof/packet/__init__.py +1 -0
- acprof/_bundle/acprof/packet/merge_packet_latency.py +369 -0
- acprof/_bundle/acprof/packet/sniff_parse_pcap.py +240 -0
- acprof/_bundle/acprof/pixel_metrics.py +103 -0
- acprof/_bundle/acprof/platform.py +180 -0
- acprof/_bundle/acprof/plotting/__init__.py +1 -0
- acprof/_bundle/acprof/plotting/config.py +487 -0
- acprof/_bundle/acprof/plotting/data.py +236 -0
- acprof/_bundle/acprof/plotting/diagnostics.py +747 -0
- acprof/_bundle/acprof/plotting/latency.py +638 -0
- acprof/_bundle/acprof/plotting/metrics.py +648 -0
- acprof/_bundle/acprof/plotting/plotly-LICENSE.txt +21 -0
- acprof/_bundle/acprof/plotting/report.py +66 -0
- acprof/_bundle/acprof/plotting/styles.py +111 -0
- acprof/_bundle/acprof/precision.py +42 -0
- acprof/_bundle/acprof/preparation_events.py +78 -0
- acprof/_bundle/acprof/progress_events.py +105 -0
- acprof/_bundle/acprof/quality.py +153 -0
- acprof/_bundle/acprof/resource_budget.py +29 -0
- acprof/_bundle/acprof/result_csv.py +263 -0
- acprof/_bundle/acprof/result_layers.py +365 -0
- acprof/_bundle/acprof/run_args.py +223 -0
- acprof/_bundle/acprof/run_options.py +225 -0
- acprof/_bundle/acprof/runtime_dependencies.py +195 -0
- acprof/_bundle/acprof/runtime_profiles.py +258 -0
- acprof/_bundle/acprof/runtime_settings.py +72 -0
- acprof/_bundle/acprof/source_identity.py +68 -0
- acprof/_bundle/acprof/telemetry.py +225 -0
- acprof/_bundle/acprof/testing/__init__.py +1 -0
- acprof/_bundle/acprof/testing/evidence.py +117 -0
- acprof/_bundle/acprof/testing/plugin.py +126 -0
- acprof/_bundle/acprof/testing/provenance.py +53 -0
- acprof/_bundle/acprof/testing/sharding.py +14 -0
- acprof/_bundle/acprof/tui/__init__.py +1 -0
- acprof/_bundle/acprof/tui/app.py +934 -0
- acprof/_bundle/acprof/tui/app_contracts.py +43 -0
- acprof/_bundle/acprof/tui/catalog_controller.py +120 -0
- acprof/_bundle/acprof/tui/commands.py +209 -0
- acprof/_bundle/acprof/tui/configuration_controller.py +436 -0
- acprof/_bundle/acprof/tui/diagnostics.py +340 -0
- acprof/_bundle/acprof/tui/downloads.py +56 -0
- acprof/_bundle/acprof/tui/environment.py +248 -0
- acprof/_bundle/acprof/tui/experiment_catalog.py +279 -0
- acprof/_bundle/acprof/tui/experiment_controller.py +132 -0
- acprof/_bundle/acprof/tui/experiment_picker.py +273 -0
- acprof/_bundle/acprof/tui/field_validation.py +62 -0
- acprof/_bundle/acprof/tui/i18n.py +57 -0
- acprof/_bundle/acprof/tui/image_controller.py +525 -0
- acprof/_bundle/acprof/tui/images.py +737 -0
- acprof/_bundle/acprof/tui/input.py +191 -0
- acprof/_bundle/acprof/tui/localization_controller.py +110 -0
- acprof/_bundle/acprof/tui/log.py +310 -0
- acprof/_bundle/acprof/tui/model_candidates.py +278 -0
- acprof/_bundle/acprof/tui/model_controller.py +111 -0
- acprof/_bundle/acprof/tui/model_input.py +12 -0
- acprof/_bundle/acprof/tui/model_store.py +166 -0
- acprof/_bundle/acprof/tui/preflight_controller.py +271 -0
- acprof/_bundle/acprof/tui/preparation.py +269 -0
- acprof/_bundle/acprof/tui/presentation.py +46 -0
- acprof/_bundle/acprof/tui/process.py +111 -0
- acprof/_bundle/acprof/tui/process_controller.py +218 -0
- acprof/_bundle/acprof/tui/profile_controller.py +109 -0
- acprof/_bundle/acprof/tui/progress.py +195 -0
- acprof/_bundle/acprof/tui/recovery.py +114 -0
- acprof/_bundle/acprof/tui/recovery_controller.py +169 -0
- acprof/_bundle/acprof/tui/rendering.py +75 -0
- acprof/_bundle/acprof/tui/reports.py +303 -0
- acprof/_bundle/acprof/tui/result_controller.py +279 -0
- acprof/_bundle/acprof/tui/review_inputs.py +54 -0
- acprof/_bundle/acprof/tui/run_form.py +125 -0
- acprof/_bundle/acprof/tui/run_planning.py +97 -0
- acprof/_bundle/acprof/tui/run_results.py +175 -0
- acprof/_bundle/acprof/tui/scrollbar.py +65 -0
- acprof/_bundle/acprof/tui/settings.py +203 -0
- acprof/_bundle/acprof/tui/slash_controller.py +95 -0
- acprof/_bundle/acprof/tui/stages.py +97 -0
- acprof/_bundle/acprof/tui/storage.py +150 -0
- acprof/_bundle/acprof/tui/table.py +213 -0
- acprof/_bundle/acprof/tui/themes.py +112 -0
- acprof/_bundle/acprof/tui/translation_catalog.py +1861 -0
- acprof/_bundle/acprof/tui/tui.tcss +373 -0
- acprof/_bundle/acprof/tui/views.py +706 -0
- acprof/_bundle/acprof/window_records.py +165 -0
- acprof/_bundle/acprof/workloads/__init__.py +222 -0
- acprof/_bundle/acprof/workloads/audio.py +621 -0
- acprof/_bundle/acprof/workloads/contract.py +116 -0
- acprof/_bundle/acprof/workloads/cv.py +240 -0
- acprof/_bundle/acprof/workloads/diffusion.py +410 -0
- acprof/_bundle/acprof/workloads/multimodal.py +329 -0
- acprof/_bundle/acprof/workloads/nlp.py +151 -0
- acprof/_bundle/acprof/workloads/structured.py +151 -0
- acprof/_bundle/acprof/workloads/timeseries.py +69 -0
- acprof/_bundle/assets/audio/librispeech-clean-test-en-30s/audio.wav +0 -0
- acprof/_bundle/assets/audio/librispeech-clean-test-en-30s/source.json +81 -0
- acprof/_bundle/dockerfiles/environment_tools.py +314 -0
- acprof/_bundle/dockerfiles/locks/audio-cpu.artifacts.json +503 -0
- acprof/_bundle/dockerfiles/locks/audio-cpu.txt +143 -0
- acprof/_bundle/dockerfiles/locks/audio-cu124.artifacts.json +600 -0
- acprof/_bundle/dockerfiles/locks/audio-cu124.txt +171 -0
- acprof/_bundle/dockerfiles/locks/audio-cu128.artifacts.json +544 -0
- acprof/_bundle/dockerfiles/locks/audio-cu128.txt +155 -0
- acprof/_bundle/dockerfiles/locks/custom-multimodal-cpu.artifacts.json +510 -0
- acprof/_bundle/dockerfiles/locks/custom-multimodal-cpu.txt +145 -0
- acprof/_bundle/dockerfiles/locks/custom-multimodal-cu124.artifacts.json +607 -0
- acprof/_bundle/dockerfiles/locks/custom-multimodal-cu124.txt +173 -0
- acprof/_bundle/dockerfiles/locks/custom-multimodal-cu128.artifacts.json +642 -0
- acprof/_bundle/dockerfiles/locks/custom-multimodal-cu128.txt +183 -0
- acprof/_bundle/dockerfiles/locks/cv-cpu.artifacts.json +279 -0
- acprof/_bundle/dockerfiles/locks/cv-cpu.txt +79 -0
- acprof/_bundle/dockerfiles/locks/cv-cu124.artifacts.json +376 -0
- acprof/_bundle/dockerfiles/locks/cv-cu124.txt +107 -0
- acprof/_bundle/dockerfiles/locks/cv-cu128.artifacts.json +411 -0
- acprof/_bundle/dockerfiles/locks/cv-cu128.txt +117 -0
- acprof/_bundle/dockerfiles/locks/diffusion-cpu.artifacts.json +335 -0
- acprof/_bundle/dockerfiles/locks/diffusion-cpu.txt +95 -0
- acprof/_bundle/dockerfiles/locks/diffusion-cu124.artifacts.json +432 -0
- acprof/_bundle/dockerfiles/locks/diffusion-cu124.txt +123 -0
- acprof/_bundle/dockerfiles/locks/diffusion-cu128.artifacts.json +467 -0
- acprof/_bundle/dockerfiles/locks/diffusion-cu128.txt +133 -0
- acprof/_bundle/dockerfiles/locks/moss-transformers5104.artifacts.json +621 -0
- acprof/_bundle/dockerfiles/locks/moss-transformers5104.txt +177 -0
- acprof/_bundle/dockerfiles/locks/multimodal-transformers4576.artifacts.json +635 -0
- acprof/_bundle/dockerfiles/locks/multimodal-transformers4576.txt +181 -0
- acprof/_bundle/dockerfiles/locks/nlp-cpu.artifacts.json +363 -0
- acprof/_bundle/dockerfiles/locks/nlp-cpu.txt +103 -0
- acprof/_bundle/dockerfiles/locks/nlp-cu124.artifacts.json +460 -0
- acprof/_bundle/dockerfiles/locks/nlp-cu124.txt +131 -0
- acprof/_bundle/dockerfiles/locks/nlp-cu128.artifacts.json +495 -0
- acprof/_bundle/dockerfiles/locks/nlp-cu128.txt +141 -0
- acprof/_bundle/dockerfiles/locks/onnxruntime-cpu.artifacts.json +261 -0
- acprof/_bundle/dockerfiles/locks/onnxruntime-cpu.txt +73 -0
- acprof/_bundle/dockerfiles/locks/platform-cpu.artifacts.json +99 -0
- acprof/_bundle/dockerfiles/locks/platform-cpu.txt +27 -0
- acprof/_bundle/dockerfiles/locks/platform-cu124.artifacts.json +196 -0
- acprof/_bundle/dockerfiles/locks/platform-cu124.txt +55 -0
- acprof/_bundle/dockerfiles/locks/platform-cu128.artifacts.json +231 -0
- acprof/_bundle/dockerfiles/locks/platform-cu128.txt +65 -0
- acprof/_bundle/dockerfiles/locks/platform-python-cpu.artifacts.json +37 -0
- acprof/_bundle/dockerfiles/locks/platform-python-cpu.txt +9 -0
- acprof/_bundle/dockerfiles/locks/structured-cpu.artifacts.json +279 -0
- acprof/_bundle/dockerfiles/locks/structured-cpu.txt +79 -0
- acprof/_bundle/dockerfiles/locks/structured-cu124.artifacts.json +376 -0
- acprof/_bundle/dockerfiles/locks/structured-cu124.txt +107 -0
- acprof/_bundle/dockerfiles/locks/structured-cu128.artifacts.json +411 -0
- acprof/_bundle/dockerfiles/locks/structured-cu128.txt +117 -0
- acprof/_bundle/dockerfiles/locks/system-trixie-amd64.json +620 -0
- acprof/_bundle/dockerfiles/locks/timeseries-cpu.artifacts.json +314 -0
- acprof/_bundle/dockerfiles/locks/timeseries-cpu.txt +89 -0
- acprof/_bundle/dockerfiles/locks/timeseries-cu124.artifacts.json +411 -0
- acprof/_bundle/dockerfiles/locks/timeseries-cu124.txt +117 -0
- acprof/_bundle/dockerfiles/locks/timeseries-cu128.artifacts.json +446 -0
- acprof/_bundle/dockerfiles/locks/timeseries-cu128.txt +127 -0
- acprof/_bundle/dockerfiles/locks/transformers5104-cpu.artifacts.json +594 -0
- acprof/_bundle/dockerfiles/locks/transformers5104-cpu.txt +169 -0
- acprof/_bundle/dockerfiles/locks/transformers5104-cu124.artifacts.json +691 -0
- acprof/_bundle/dockerfiles/locks/transformers5104-cu124.txt +197 -0
- acprof/_bundle/dockerfiles/locks/transformers5104-cu128.artifacts.json +726 -0
- acprof/_bundle/dockerfiles/locks/transformers5104-cu128.txt +207 -0
- acprof/_bundle/dockerfiles/platform.Dockerfile +22 -0
- acprof/_bundle/dockerfiles/requirements/audio.in +5 -0
- acprof/_bundle/dockerfiles/requirements/custom-multimodal.in +2 -0
- acprof/_bundle/dockerfiles/requirements/cv.in +4 -0
- acprof/_bundle/dockerfiles/requirements/diffusion.in +6 -0
- acprof/_bundle/dockerfiles/requirements/moss-transformers5104.in +9 -0
- acprof/_bundle/dockerfiles/requirements/multimodal-transformers4576.in +3 -0
- acprof/_bundle/dockerfiles/requirements/nlp.in +7 -0
- acprof/_bundle/dockerfiles/requirements/onnxruntime.in +9 -0
- acprof/_bundle/dockerfiles/requirements/service.in +8 -0
- acprof/_bundle/dockerfiles/requirements/structured.in +4 -0
- acprof/_bundle/dockerfiles/requirements/timeseries.in +2 -0
- acprof/_bundle/dockerfiles/requirements/timm.in +1 -0
- acprof/_bundle/dockerfiles/requirements/transformers5104.in +4 -0
- acprof/_bundle/dockerfiles/runtime-final.Dockerfile +34 -0
- acprof/_bundle/dockerfiles/runtime-model.Dockerfile +19 -0
- acprof/_bundle/dockerfiles/runtime.Dockerfile +23 -0
- acprof/_bundle/examples/coverage/regression.json +17 -0
- acprof/_bundle/examples/hardware-validation.json +19 -0
- acprof/_bundle/examples/multimodal/ultravox.model.json +29 -0
- acprof/_bundle/examples/nlp/smoke.py +111 -0
- acprof/_bundle/examples/onnxruntime/fixtures.py +164 -0
- acprof/_bundle/examples/onnxruntime/iris.json +16 -0
- acprof/_bundle/examples/onnxruntime/iris.model.json +7 -0
- acprof/_bundle/examples/onnxruntime/real_models.py +155 -0
- acprof/_bundle/examples/onnxruntime/smoke.py +68 -0
- acprof/_bundle/examples/structured/chronos_smoke.py +56 -0
- acprof/_bundle/examples/structured/export_models.py +71 -0
- acprof/_bundle/examples/structured/smoke.py +71 -0
- acprof/_bundle/licenses/CC-BY-4.0.txt +156 -0
- acprof/analysis/__init__.py +1 -0
- acprof/analysis/audit.py +276 -0
- acprof/analysis/comparison.py +364 -0
- acprof/analysis/compatibility.py +223 -0
- acprof/analysis/conditions.py +185 -0
- acprof/analysis/independent_comparison.py +191 -0
- acprof/analysis/latency_model.py +1106 -0
- acprof/analysis/latency_report.py +577 -0
- acprof/analysis/model.py +276 -0
- acprof/analysis/precision.py +51 -0
- acprof/analysis/uncertainty.py +144 -0
- acprof/application/__init__.py +1 -0
- acprof/application/download.py +14 -0
- acprof/application/errors.py +5 -0
- acprof/application/notifications.py +302 -0
- acprof/application/preparation.py +333 -0
- acprof/application/resources.py +66 -0
- acprof/application/run.py +462 -0
- acprof/application/terminal_log.py +136 -0
- acprof/artifact_layout.py +261 -0
- acprof/artifacts.py +161 -0
- acprof/capabilities.py +404 -0
- acprof/cli/__init__.py +1 -0
- acprof/cli/audit.py +74 -0
- acprof/cli/auto.py +41 -0
- acprof/cli/backfill_compute.py +498 -0
- acprof/cli/compare.py +34 -0
- acprof/cli/coverage.py +70 -0
- acprof/cli/doctor.py +47 -0
- acprof/cli/inspect.py +101 -0
- acprof/cli/load.py +190 -0
- acprof/cli/main.py +64 -0
- acprof/cli/model_store.py +22 -0
- acprof/cli/plot.py +211 -0
- acprof/cli/posthoc.py +113 -0
- acprof/cli/probe.py +186 -0
- acprof/cli/report.py +35 -0
- acprof/cli/results.py +37 -0
- acprof/cli/run.py +54 -0
- acprof/cli/stats.py +94 -0
- acprof/cli/tui.py +65 -0
- acprof/config.py +177 -0
- acprof/container/__init__.py +1 -0
- acprof/container/compat/__init__.py +1 -0
- acprof/container/compat/transformers_dynamic.py +54 -0
- acprof/container/compat/transformers_model_types.json +1091 -0
- acprof/container/compute_profile_runner.py +392 -0
- acprof/container/download_model.py +165 -0
- acprof/container/execution.py +73 -0
- acprof/container/handlers/__init__.py +298 -0
- acprof/container/handlers/audio.py +743 -0
- acprof/container/handlers/custom_pipeline.py +74 -0
- acprof/container/handlers/cv.py +321 -0
- acprof/container/handlers/diffusion.py +728 -0
- acprof/container/handlers/moss.py +64 -0
- acprof/container/handlers/multimodal.py +609 -0
- acprof/container/handlers/nlp.py +747 -0
- acprof/container/handlers/onnx_tasks.py +231 -0
- acprof/container/handlers/onnxruntime.py +90 -0
- acprof/container/handlers/structured.py +185 -0
- acprof/container/handlers/timeseries.py +178 -0
- acprof/container/load_policy.py +81 -0
- acprof/container/loading_quality.py +48 -0
- acprof/container/local_pipeline.py +31 -0
- acprof/container/model_files.py +280 -0
- acprof/container/model_probe.py +80 -0
- acprof/container/onnx_session.py +150 -0
- acprof/container/runtime_manifest.py +150 -0
- acprof/container/runtime_validate.py +156 -0
- acprof/container/server.py +209 -0
- acprof/container/torch_execution.py +55 -0
- acprof/container/validation.py +172 -0
- acprof/cpu_affinity.py +35 -0
- acprof/dependency_locks.py +129 -0
- acprof/experiment.py +356 -0
- acprof/extensions/__init__.py +294 -0
- acprof/extensions/builtin/manifest.json +3591 -0
- acprof/extensions/onnxruntime/manifest.json +191 -0
- acprof/extensions/schema.py +238 -0
- acprof/extensions/transformers/4.57.6.json +1639 -0
- acprof/extensions/transformers/5.10.4.json +1812 -0
- acprof/failures.py +115 -0
- acprof/hardware_conditions.py +18 -0
- acprof/hf_download.py +143 -0
- acprof/hf_endpoints.py +62 -0
- acprof/hf_transport.py +238 -0
- acprof/host/__init__.py +1 -0
- acprof/host/automation.py +161 -0
- acprof/host/client.py +520 -0
- acprof/host/collection_history.py +77 -0
- acprof/host/collection_workflow.py +285 -0
- acprof/host/command.py +119 -0
- acprof/host/container_lifecycle.py +225 -0
- acprof/host/container_state.py +128 -0
- acprof/host/coverage_state.py +259 -0
- acprof/host/detect.py +669 -0
- acprof/host/docker_runtime.py +359 -0
- acprof/host/doctor.py +158 -0
- acprof/host/env_utils.py +233 -0
- acprof/host/execution_conditions.py +87 -0
- acprof/host/gpu_device.py +66 -0
- acprof/host/hardware_conditions.py +130 -0
- acprof/host/images/__init__.py +1 -0
- acprof/host/images/dependencies.py +169 -0
- acprof/host/images/environment.py +313 -0
- acprof/host/images/graph.py +143 -0
- acprof/host/images/identity.py +6 -0
- acprof/host/images/inventory.py +445 -0
- acprof/host/images/runtime.py +457 -0
- acprof/host/images/scan.py +154 -0
- acprof/host/input_plan.py +1056 -0
- acprof/host/interface_probe.py +141 -0
- acprof/host/largest_scale_probe.py +566 -0
- acprof/host/matrix_plan.py +98 -0
- acprof/host/measurement/__init__.py +1 -0
- acprof/host/measurement/boundary.py +162 -0
- acprof/host/measurement/capture.py +139 -0
- acprof/host/measurement/checkpoint.py +275 -0
- acprof/host/measurement/config.py +212 -0
- acprof/host/measurement/diagnostics.py +247 -0
- acprof/host/measurement/energy_validation.py +172 -0
- acprof/host/measurement/errors.py +25 -0
- acprof/host/measurement/execution.py +396 -0
- acprof/host/measurement/load.py +237 -0
- acprof/host/measurement/metrics.py +975 -0
- acprof/host/measurement/monitors.py +143 -0
- acprof/host/measurement/publication.py +171 -0
- acprof/host/measurement/requests.py +97 -0
- acprof/host/measurement/types.py +82 -0
- acprof/host/model_coverage.py +337 -0
- acprof/host/model_errors.py +116 -0
- acprof/host/model_inspection.py +107 -0
- acprof/host/model_schema.py +35 -0
- acprof/host/model_store.py +733 -0
- acprof/host/network_preflight.py +229 -0
- acprof/host/orchestrator.py +1133 -0
- acprof/host/permissions.py +117 -0
- acprof/host/platform_metadata.py +63 -0
- acprof/host/posthoc/__init__.py +12 -0
- acprof/host/posthoc/backfill.py +415 -0
- acprof/host/posthoc/context.py +400 -0
- acprof/host/posthoc/plans.py +597 -0
- acprof/host/posthoc/service.py +303 -0
- acprof/host/posthoc/storage.py +491 -0
- acprof/host/preflight.py +370 -0
- acprof/host/profiling/__init__.py +1 -0
- acprof/host/profiling/compute.py +436 -0
- acprof/host/profiling/compute_plan.py +261 -0
- acprof/host/profiling/execution.py +547 -0
- acprof/host/profiling/execution_plan.py +576 -0
- acprof/host/profiling/progress.py +83 -0
- acprof/host/profiling/support.py +252 -0
- acprof/host/profiling/tools/__init__.py +1 -0
- acprof/host/profiling/tools/advisor.py +164 -0
- acprof/host/profiling/tools/compute_parsers.py +409 -0
- acprof/host/profiling/tools/execution_environment.py +135 -0
- acprof/host/profiling/tools/execution_parsers.py +364 -0
- acprof/host/profiling/tools/massif.py +418 -0
- acprof/host/profiling/tools/ncu.py +696 -0
- acprof/host/profiling/tools/nsys.py +326 -0
- acprof/host/profiling/tools/tool_discovery.py +229 -0
- acprof/host/profiling/tools/torch.py +158 -0
- acprof/host/result_cleanup.py +65 -0
- acprof/host/run_state.py +639 -0
- acprof/host/runtime_settings.py +10 -0
- acprof/host/runtime_validation.py +302 -0
- acprof/host/source_bundle.py +96 -0
- acprof/host/startup_probe.py +95 -0
- acprof/host/static_metadata.py +936 -0
- acprof/host/task_support.py +121 -0
- acprof/installation.py +26 -0
- acprof/latency_slo.py +62 -0
- acprof/messages.py +26 -0
- acprof/metric_registry.py +315 -0
- acprof/model_candidates.py +297 -0
- acprof/model_contract.py +234 -0
- acprof/model_dependencies.py +93 -0
- acprof/model_dependency_domain.py +45 -0
- acprof/model_dependency_eval.py +438 -0
- acprof/model_dependency_flow.py +200 -0
- acprof/model_evidence.py +115 -0
- acprof/model_metadata_analysis.py +156 -0
- acprof/model_repository.py +149 -0
- acprof/model_resolution.py +129 -0
- acprof/model_review.py +155 -0
- acprof/model_source_analysis.py +299 -0
- acprof/model_spec.py +204 -0
- acprof/model_support.py +105 -0
- acprof/model_transforms.py +81 -0
- acprof/monitors/__init__.py +1 -0
- acprof/monitors/common.py +63 -0
- acprof/monitors/energy_cpu.py +651 -0
- acprof/monitors/energy_nvml.py +381 -0
- acprof/monitors/gpu_metrics.py +123 -0
- acprof/monitors/interfaces.py +74 -0
- acprof/monitors/perf_mips.py +617 -0
- acprof/monitors/rapl_topology.py +100 -0
- acprof/monitors/resource_metrics.py +472 -0
- acprof/monitors/resource_readers.py +435 -0
- acprof/monitors/resource_usage.py +450 -0
- acprof/monitors/sampling.py +79 -0
- acprof/network_policy.py +182 -0
- acprof/notifications.py +279 -0
- acprof/packet/__init__.py +1 -0
- acprof/packet/merge_packet_latency.py +369 -0
- acprof/packet/sniff_parse_pcap.py +240 -0
- acprof/pixel_metrics.py +103 -0
- acprof/platform.py +180 -0
- acprof/plotting/__init__.py +1 -0
- acprof/plotting/config.py +487 -0
- acprof/plotting/data.py +236 -0
- acprof/plotting/diagnostics.py +747 -0
- acprof/plotting/latency.py +638 -0
- acprof/plotting/metrics.py +648 -0
- acprof/plotting/plotly-LICENSE.txt +21 -0
- acprof/plotting/report.css +61 -0
- acprof/plotting/report.html +68 -0
- acprof/plotting/report.js +295 -0
- acprof/plotting/report.py +66 -0
- acprof/plotting/styles.py +111 -0
- acprof/plotting/view_model.js +145 -0
- acprof/precision.py +42 -0
- acprof/preparation_events.py +78 -0
- acprof/progress_events.py +105 -0
- acprof/quality.py +153 -0
- acprof/resource_budget.py +29 -0
- acprof/result_csv.py +263 -0
- acprof/result_layers.py +365 -0
- acprof/run_args.py +223 -0
- acprof/run_options.py +225 -0
- acprof/runtime_dependencies.py +195 -0
- acprof/runtime_profiles.py +258 -0
- acprof/runtime_settings.py +72 -0
- acprof/source_identity.py +68 -0
- acprof/telemetry.py +225 -0
- acprof/testing/__init__.py +1 -0
- acprof/testing/evidence.py +117 -0
- acprof/testing/plugin.py +126 -0
- acprof/testing/provenance.py +53 -0
- acprof/testing/sharding.py +14 -0
- acprof/tui/__init__.py +1 -0
- acprof/tui/app.py +934 -0
- acprof/tui/app_contracts.py +43 -0
- acprof/tui/catalog_controller.py +120 -0
- acprof/tui/commands.py +209 -0
- acprof/tui/configuration_controller.py +436 -0
- acprof/tui/diagnostics.py +340 -0
- acprof/tui/downloads.py +56 -0
- acprof/tui/environment.py +248 -0
- acprof/tui/experiment_catalog.py +279 -0
- acprof/tui/experiment_controller.py +132 -0
- acprof/tui/experiment_picker.py +273 -0
- acprof/tui/field_validation.py +62 -0
- acprof/tui/i18n.py +57 -0
- acprof/tui/image_controller.py +525 -0
- acprof/tui/images.py +737 -0
- acprof/tui/input.py +191 -0
- acprof/tui/localization_controller.py +110 -0
- acprof/tui/log.py +310 -0
- acprof/tui/model_candidates.py +278 -0
- acprof/tui/model_controller.py +111 -0
- acprof/tui/model_input.py +12 -0
- acprof/tui/model_store.py +166 -0
- acprof/tui/preflight_controller.py +271 -0
- acprof/tui/preparation.py +269 -0
- acprof/tui/presentation.py +46 -0
- acprof/tui/process.py +111 -0
- acprof/tui/process_controller.py +218 -0
- acprof/tui/profile_controller.py +109 -0
- acprof/tui/progress.py +195 -0
- acprof/tui/recovery.py +114 -0
- acprof/tui/recovery_controller.py +169 -0
- acprof/tui/rendering.py +75 -0
- acprof/tui/reports.py +303 -0
- acprof/tui/result_controller.py +279 -0
- acprof/tui/review_inputs.py +54 -0
- acprof/tui/run_form.py +125 -0
- acprof/tui/run_planning.py +97 -0
- acprof/tui/run_results.py +175 -0
- acprof/tui/scrollbar.py +65 -0
- acprof/tui/settings.py +203 -0
- acprof/tui/slash_controller.py +95 -0
- acprof/tui/stages.py +97 -0
- acprof/tui/storage.py +150 -0
- acprof/tui/table.py +213 -0
- acprof/tui/themes.py +112 -0
- acprof/tui/translation_catalog.py +1861 -0
- acprof/tui/tui.tcss +373 -0
- acprof/tui/views.py +706 -0
- acprof/window_records.py +165 -0
- acprof/workloads/__init__.py +222 -0
- acprof/workloads/audio.py +621 -0
- acprof/workloads/contract.py +116 -0
- acprof/workloads/cv.py +240 -0
- acprof/workloads/diffusion.py +410 -0
- acprof/workloads/multimodal.py +329 -0
- acprof/workloads/nlp.py +151 -0
- acprof/workloads/structured.py +151 -0
- acprof/workloads/timeseries.py +69 -0
- acprof-0.3.0.dist-info/METADATA +117 -0
- acprof-0.3.0.dist-info/RECORD +704 -0
- acprof-0.3.0.dist-info/WHEEL +4 -0
- acprof-0.3.0.dist-info/entry_points.txt +2 -0
- acprof-0.3.0.dist-info/licenses/LICENSE +202 -0
- acprof-0.3.0.dist-info/licenses/NOTICE +43 -0
- acprof-0.3.0.dist-info/licenses/licenses/CC-BY-4.0.txt +156 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
"""只读比较已有实验条件;不替代严格的续跑身份或模型质量验收。"""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import hashlib
|
|
5
|
+
import json
|
|
6
|
+
from collections import Counter
|
|
7
|
+
from fractions import Fraction
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from acprof.analysis.audit import audit_result, number
|
|
11
|
+
from acprof.analysis.conditions import (
|
|
12
|
+
ALLOWED_RESOURCE_DIMENSIONS,
|
|
13
|
+
PURPOSES,
|
|
14
|
+
compare_profiles,
|
|
15
|
+
compare_workload_profiles,
|
|
16
|
+
comparison_profile,
|
|
17
|
+
workload_case_profile,
|
|
18
|
+
)
|
|
19
|
+
from acprof.artifacts import read_json_object
|
|
20
|
+
from acprof.hardware_conditions import HARDWARE_FIELDS, conditions_path
|
|
21
|
+
from acprof.metric_registry import METRICS
|
|
22
|
+
from acprof.platform import recorded_identity
|
|
23
|
+
from acprof.quality import QUALITY_FIELDS
|
|
24
|
+
from acprof.result_csv import measurement_key, read_result_csv
|
|
25
|
+
from acprof.runtime_settings import RUNTIME_ENV_NAMES
|
|
26
|
+
|
|
27
|
+
MEASUREMENT_OPTIONS = (
|
|
28
|
+
"profiling_mode", "warmup", "repeat", "repeat_in_window", "repeat_window_seconds",
|
|
29
|
+
"request_timeout_seconds", "sample_hz", "sampling_policy", "raw_sample_limit",
|
|
30
|
+
"idle_seconds", "idle_cooldown_seconds",
|
|
31
|
+
"compute_profile_tool", "execution_profile_tool", "prune_startup_oom",
|
|
32
|
+
"matrix_order", "matrix_seed", "dram_energy",
|
|
33
|
+
)
|
|
34
|
+
RUNTIME_ENVIRONMENT = (set(RUNTIME_ENV_NAMES) - {"ACPROF_REQUEST_TIMEOUT_S"}) | {"OMP_NUM_THREADS", "MKL_NUM_THREADS"}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _canonical(value) -> str:
|
|
38
|
+
return json.dumps(value, sort_keys=True, ensure_ascii=False, allow_nan=False, separators=(",", ":"))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _digest(value) -> str:
|
|
42
|
+
return hashlib.sha256(_canonical(value).encode()).hexdigest()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _unknown(value) -> bool:
|
|
46
|
+
if value is None or value == "unknown":
|
|
47
|
+
return True
|
|
48
|
+
if isinstance(value, dict):
|
|
49
|
+
return not value or any(_unknown(item) for item in value.values())
|
|
50
|
+
if isinstance(value, list):
|
|
51
|
+
return not value or any(_unknown(item) for item in value)
|
|
52
|
+
return False
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _condition(left, right) -> dict:
|
|
56
|
+
if isinstance(left, dict) and isinstance(right, dict) and left and right:
|
|
57
|
+
statuses = {_condition(left.get(key), right.get(key))["status"] for key in left.keys() | right.keys()}
|
|
58
|
+
status = ("incompatible" if "incompatible" in statuses
|
|
59
|
+
else "unknown" if "unknown" in statuses else "compatible")
|
|
60
|
+
elif _unknown(left) or _unknown(right):
|
|
61
|
+
status = "unknown"
|
|
62
|
+
else:
|
|
63
|
+
status = "compatible" if left == right else "incompatible"
|
|
64
|
+
return {"status": status, "left": left, "right": right}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _actual_workload(rows: list[dict]) -> dict | None:
|
|
68
|
+
"""Pool observed request counts per case without losing the mixture weights."""
|
|
69
|
+
facts: dict[str, Counter] = {}
|
|
70
|
+
for row in rows:
|
|
71
|
+
row_key = measurement_key(row)
|
|
72
|
+
if row.get("status") not in {"ok", "warn"} or row_key[4] != "0":
|
|
73
|
+
continue
|
|
74
|
+
raw = row.get("workload_contract")
|
|
75
|
+
if not raw or raw.lower() in {"nan", "null", "none"}:
|
|
76
|
+
return None
|
|
77
|
+
summary = json.loads(raw)
|
|
78
|
+
if not isinstance(summary, dict) or summary.get("schema_version") != 1:
|
|
79
|
+
return None
|
|
80
|
+
variants, total = summary.get("variants"), summary.get("request_count")
|
|
81
|
+
if not isinstance(variants, list) or not variants or type(total) is not int or total <= 0:
|
|
82
|
+
return None
|
|
83
|
+
counts: list[int] = []
|
|
84
|
+
for variant in variants:
|
|
85
|
+
count = variant.get("count") if isinstance(variant, dict) else None
|
|
86
|
+
if type(count) is not int or count <= 0:
|
|
87
|
+
return None
|
|
88
|
+
counts.append(count)
|
|
89
|
+
if sum(counts) != total:
|
|
90
|
+
return None
|
|
91
|
+
key = _canonical(row_key[:4])
|
|
92
|
+
for variant in variants:
|
|
93
|
+
contract = variant.get("contract")
|
|
94
|
+
if not isinstance(contract, dict) or contract.get("schema_version") != 1:
|
|
95
|
+
return None
|
|
96
|
+
# Backend parameters are identity evidence, not workload semantics.
|
|
97
|
+
contract = {name: item for name, item in contract.items() if name != "runtime"}
|
|
98
|
+
facts.setdefault(key, Counter())[_canonical(contract)] += variant["count"]
|
|
99
|
+
return {key: {"request_count": sum(counts.values()), "variants": [
|
|
100
|
+
{"contract": json.loads(contract), "count": count,
|
|
101
|
+
"proportion": str(Fraction(count, sum(counts.values())))}
|
|
102
|
+
for contract, count in sorted(counts.items())]}
|
|
103
|
+
for key, counts in sorted(facts.items())} or None
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _distribution(case, projection=lambda contract: contract):
|
|
107
|
+
counts: Counter[str] = Counter()
|
|
108
|
+
for variant in case["variants"]:
|
|
109
|
+
counts[_canonical(projection(variant["contract"]))] += variant["count"]
|
|
110
|
+
total = case["request_count"]
|
|
111
|
+
return {value: str(Fraction(count, total)) for value, count in sorted(counts.items())}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _dimensions(contract, prefix=""):
|
|
115
|
+
result = {}
|
|
116
|
+
for key, value in contract.items():
|
|
117
|
+
name = f"{prefix}.{key}" if prefix else key
|
|
118
|
+
if isinstance(value, dict):
|
|
119
|
+
result.update(_dimensions(value, name))
|
|
120
|
+
else:
|
|
121
|
+
result[name] = value
|
|
122
|
+
return result
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _workload_condition(left, right):
|
|
126
|
+
result = {"status": "unknown", "left": left, "right": right,
|
|
127
|
+
"request_counts_changed": None, "changed_dimensions": {},
|
|
128
|
+
"reason": "actual_workload_evidence_missing"}
|
|
129
|
+
if left is None or right is None:
|
|
130
|
+
return result
|
|
131
|
+
if left.keys() != right.keys():
|
|
132
|
+
return {**result, "status": "incompatible", "reason": "workload_cases_changed"}
|
|
133
|
+
result["request_counts_changed"] = any(left[key]["request_count"] != right[key]["request_count"] for key in left)
|
|
134
|
+
incomplete = any(_unknown(v["contract"]) for cases in (left, right) for case in cases.values() for v in case["variants"])
|
|
135
|
+
changed: dict[str, dict[str, dict[str, dict[str, str]]]] = {}
|
|
136
|
+
differing_cases = [key for key in left if _distribution(left[key]) != _distribution(right[key])]
|
|
137
|
+
if not differing_cases:
|
|
138
|
+
return {**result, "status": "unknown" if incomplete else "compatible",
|
|
139
|
+
"reason": "actual_workload_evidence_incomplete" if incomplete else "same_per_request_distribution"}
|
|
140
|
+
profile_status = compare_workload_profiles(*({key: workload_case_profile(case) for key, case in cases.items()}
|
|
141
|
+
for cases in (left, right)))
|
|
142
|
+
for key in differing_cases:
|
|
143
|
+
a, b = left[key], right[key]
|
|
144
|
+
names = set().union(*(_dimensions(v["contract"]).keys() for c in (a, b) for v in c["variants"]))
|
|
145
|
+
for name in sorted(names):
|
|
146
|
+
lhs = _distribution(a, lambda c, name=name: _dimensions(c).get(name))
|
|
147
|
+
rhs = _distribution(b, lambda c, name=name: _dimensions(c).get(name))
|
|
148
|
+
if lhs != rhs:
|
|
149
|
+
changed.setdefault(name, {})[key] = {"left": lhs, "right": rhs}
|
|
150
|
+
# Equal marginal distributions may still hide different joint mixtures.
|
|
151
|
+
if not changed:
|
|
152
|
+
changed["joint_distribution"] = {key: {"left": _distribution(left[key]), "right": _distribution(right[key])}
|
|
153
|
+
for key in differing_cases}
|
|
154
|
+
return {**result, "status": profile_status, "changed_dimensions": changed,
|
|
155
|
+
"reason": ("per_request_distribution_changed" if profile_status == "incompatible" else
|
|
156
|
+
"actual_workload_evidence_incomplete" if incomplete else "output_distribution_equivalence_unverified")}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def load_comparison_snapshot(source: str | Path) -> dict:
|
|
160
|
+
source = Path(source)
|
|
161
|
+
directory = source if source.is_dir() else source.parent
|
|
162
|
+
audit = audit_result(source)
|
|
163
|
+
issues = []
|
|
164
|
+
|
|
165
|
+
def read_json(name):
|
|
166
|
+
try:
|
|
167
|
+
from acprof.artifact_layout import ArtifactLayout
|
|
168
|
+
layout = ArtifactLayout.discover(source) if source.is_dir() else ArtifactLayout.from_csv(source)
|
|
169
|
+
path = layout.path(name)
|
|
170
|
+
if not path.exists():
|
|
171
|
+
return {}
|
|
172
|
+
return read_json_object(path, label=name)
|
|
173
|
+
except (OSError, ValueError) as error:
|
|
174
|
+
issues.append(f"{name}: {error}")
|
|
175
|
+
return {}
|
|
176
|
+
|
|
177
|
+
state = read_json("run_state.json")
|
|
178
|
+
metadata = read_json("static_meta.json")
|
|
179
|
+
plan = read_json("input_scale_plan.json")
|
|
180
|
+
from acprof.artifact_layout import ArtifactLayout
|
|
181
|
+
layout = ArtifactLayout.discover(source) if source.is_dir() else ArtifactLayout.from_csv(source)
|
|
182
|
+
hardware_payload = read_json(str(conditions_path(layout).relative_to(layout.root)))
|
|
183
|
+
hardware_cases = hardware_payload.get("cases", {})
|
|
184
|
+
if hardware_payload and (hardware_payload.get("schema_version") != 1 or not isinstance(hardware_cases, dict)):
|
|
185
|
+
issues.append("hardware_conditions.json: unsupported schema")
|
|
186
|
+
hardware_cases = {}
|
|
187
|
+
for case_id, record in list(hardware_cases.items()):
|
|
188
|
+
if not isinstance(record, dict):
|
|
189
|
+
issues.append(f"hardware_conditions.json: invalid case {case_id}")
|
|
190
|
+
hardware_cases[case_id] = {}
|
|
191
|
+
|
|
192
|
+
def object_field(parent, name):
|
|
193
|
+
value = parent.get(name, {})
|
|
194
|
+
if not isinstance(value, dict):
|
|
195
|
+
issues.append(f"{name}: 应为 JSON 对象")
|
|
196
|
+
return {}
|
|
197
|
+
return value
|
|
198
|
+
|
|
199
|
+
options = object_field(state, "options")
|
|
200
|
+
environment = object_field(options, "measurement_environment") if "measurement_environment" in options else None
|
|
201
|
+
runtime_environment = {key: value for key, value in (environment or {}).items() if key in RUNTIME_ENVIRONMENT}
|
|
202
|
+
measurement_environment = (_digest({key: value for key, value in environment.items()
|
|
203
|
+
if key not in RUNTIME_ENVIRONMENT})
|
|
204
|
+
if isinstance(environment, dict) else None)
|
|
205
|
+
entries = plan.get("entries")
|
|
206
|
+
inputs = None
|
|
207
|
+
if plan.get("schema_version") == 2 and isinstance(entries, list) and entries:
|
|
208
|
+
if all(isinstance(entry, dict) and isinstance(entry.get("payload"), dict)
|
|
209
|
+
and entry.get("input_scale") is not None for entry in entries):
|
|
210
|
+
try:
|
|
211
|
+
inputs = _digest([{key: entry[key] for key in ("input_scale", "payload")} for entry in entries])
|
|
212
|
+
except (ValueError, TypeError) as error:
|
|
213
|
+
issues.append(f"input_scale_plan.json: {error}")
|
|
214
|
+
threads = {}
|
|
215
|
+
validation = object_field(metadata, "runtime_validation")
|
|
216
|
+
devices = object_field(validation, "devices")
|
|
217
|
+
# The independent probe injects quota-derived TORCH_NUM_THREADS, while the
|
|
218
|
+
# ordinary server preserves runtime defaults. Its effective count only
|
|
219
|
+
# establishes a shared setting when this run explicitly requested threads.
|
|
220
|
+
thread_names: tuple[str, ...] = (("ACPROF_ONNX_INTRA_OP_THREADS",) if metadata.get("runtime_backend") == "onnxruntime" else ())
|
|
221
|
+
thread_names += ("ACPROF_RUNTIME_THREADS", "TORCH_NUM_THREADS")
|
|
222
|
+
thread_request = next(((environment or {})[name] for name in thread_names if name in (environment or {})), None)
|
|
223
|
+
try:
|
|
224
|
+
explicit_threads = thread_request is not None and not isinstance(thread_request, bool) and int(thread_request) > 0
|
|
225
|
+
except (TypeError, ValueError):
|
|
226
|
+
explicit_threads = False
|
|
227
|
+
for device in devices:
|
|
228
|
+
result = object_field(devices, device)
|
|
229
|
+
parameters = object_field(result, "runtime_parameters")
|
|
230
|
+
effective = object_field(parameters, "effective")
|
|
231
|
+
observed = effective.get("threads")
|
|
232
|
+
threads[device] = (observed if explicit_threads and result.get("status") == "ok"
|
|
233
|
+
and type(observed) is int and observed > 0 else None)
|
|
234
|
+
case_ids = set()
|
|
235
|
+
rows: list[dict[str, str]] = []
|
|
236
|
+
try:
|
|
237
|
+
_, rows = read_result_csv(directory / "result_layers.json" if source.is_dir() else source)
|
|
238
|
+
actual = _actual_workload(rows)
|
|
239
|
+
case_ids = {f"{int(float(row['cpu_cores']))}c_{int(float(row['mem_cap_gb']))}g_{row['gpu_mode']}"
|
|
240
|
+
for row in rows if row.get("status") in {"ok", "warn"}}
|
|
241
|
+
|
|
242
|
+
except (OSError, ValueError, TypeError, AttributeError) as error:
|
|
243
|
+
actual = None
|
|
244
|
+
issues.append(f"actual workload: {error}")
|
|
245
|
+
# Only the input payload and semantic conditions are compared. Model/export,
|
|
246
|
+
# packages and backend hashes continue to belong to the existing run identity.
|
|
247
|
+
host = object_field(state, "host")
|
|
248
|
+
measured_rows = [row for row in rows if row.get("status") == "ok" and measurement_key(row)[4] == "0"]
|
|
249
|
+
return {
|
|
250
|
+
**recorded_identity(metadata),
|
|
251
|
+
"metric_availability": {name: any(number(row.get(name)) is not None
|
|
252
|
+
for row in measured_rows)
|
|
253
|
+
for name, metric in METRICS.items() if metric.kind == "number"},
|
|
254
|
+
"run_id": state.get("run_id"), "result_csv": audit["result_csv"],
|
|
255
|
+
"run_status": audit["run_status"], "measurement_status": audit["measurement_status"],
|
|
256
|
+
"missing_metrics": audit["missing_metrics"],
|
|
257
|
+
**{key: audit[key] for key in QUALITY_FIELDS},
|
|
258
|
+
"valid": audit["valid"] and not issues, "issues": issues,
|
|
259
|
+
"planned_input_entries": ([{key: entry[key] for key in ("input_scale", "payload")} for entry in entries]
|
|
260
|
+
if inputs is not None else None),
|
|
261
|
+
"conditions": {
|
|
262
|
+
"comparability_class": recorded_identity(metadata)["comparability_class"],
|
|
263
|
+
"task_semantics": {key: plan.get(key) for key in ("task_family", "pipeline_tag", "scenario")},
|
|
264
|
+
"planned_inputs": inputs,
|
|
265
|
+
"resources": {**{key: options.get(key) for key in ("cpus", "mems", "gpus", "batch_size")},
|
|
266
|
+
**{key: metadata.get(key) for key in ("cgroup_version", "cgroup_collection_mode")}},
|
|
267
|
+
"runtime_threads": threads or None,
|
|
268
|
+
"measurement_protocol": {**{key: options.get(key) for key in MEASUREMENT_OPTIONS},
|
|
269
|
+
"measurement_environment": measurement_environment,
|
|
270
|
+
"static_schema_version": metadata.get("schema_version")},
|
|
271
|
+
"quality_constraints": plan.get("quality_constraints"),
|
|
272
|
+
"actual_workload": actual,
|
|
273
|
+
},
|
|
274
|
+
"hardware": {
|
|
275
|
+
name: {case_id: hardware_cases.get(case_id, {}).get(name) for case_id in sorted(case_ids)} or None
|
|
276
|
+
for name in HARDWARE_FIELDS
|
|
277
|
+
},
|
|
278
|
+
"identity": {**{key: metadata.get(key) for key in (
|
|
279
|
+
"model_name", "model_revision", "runtime_backend", "image_id", "runtime_environment")},
|
|
280
|
+
"model_source": metadata.get("model_source", "huggingface"),
|
|
281
|
+
"runtime_requested_environment": runtime_environment,
|
|
282
|
+
**{key: host.get(key) for key in ("source_sha256", "packages_sha256")}},
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def compare_results(left: str | Path, right: str | Path, *, purpose: str = "same-hardware") -> dict:
|
|
287
|
+
"""Return compatible/incompatible/unknown for recorded comparison conditions.
|
|
288
|
+
|
|
289
|
+
Quality constraints describe a shared target, not proof that either model
|
|
290
|
+
meets it. Missing legacy evidence is unknown and never reconstructed.
|
|
291
|
+
"""
|
|
292
|
+
if purpose not in PURPOSES:
|
|
293
|
+
raise ValueError(f"comparison purpose must be one of {PURPOSES}")
|
|
294
|
+
snapshots = {"left": load_comparison_snapshot(left), "right": load_comparison_snapshot(right)}
|
|
295
|
+
lhs, rhs = snapshots.values()
|
|
296
|
+
conditions = {name: _condition(value, rhs["conditions"][name])
|
|
297
|
+
for name, value in lhs["conditions"].items()}
|
|
298
|
+
conditions["actual_workload"] = _workload_condition(lhs["conditions"]["actual_workload"],
|
|
299
|
+
rhs["conditions"]["actual_workload"])
|
|
300
|
+
if purpose == "resource-scaling":
|
|
301
|
+
def resource_workload(cases):
|
|
302
|
+
if cases is None:
|
|
303
|
+
return None
|
|
304
|
+
normalized: dict[str, dict] = {}
|
|
305
|
+
for key, value in cases.items():
|
|
306
|
+
projected = _canonical(json.loads(key)[2:])
|
|
307
|
+
if projected in normalized and workload_case_profile(normalized[projected]) != workload_case_profile(value):
|
|
308
|
+
return None
|
|
309
|
+
normalized[projected] = value
|
|
310
|
+
return normalized
|
|
311
|
+
conditions["actual_workload"] = _workload_condition(resource_workload(lhs["conditions"]["actual_workload"]),
|
|
312
|
+
resource_workload(rhs["conditions"]["actual_workload"]))
|
|
313
|
+
for name in HARDWARE_FIELDS:
|
|
314
|
+
left_value, right_value = lhs["hardware"].get(name), rhs["hardware"].get(name)
|
|
315
|
+
item = _condition(left_value, right_value)
|
|
316
|
+
if purpose == "cross-hardware" and name != "runtime_threads":
|
|
317
|
+
# A known model difference cannot turn an unknown power policy into
|
|
318
|
+
# verified evidence. Complete but different CPU-ID maps are expected.
|
|
319
|
+
item["status"] = ("unknown" if _unknown(left_value) or _unknown(right_value)
|
|
320
|
+
else "compatible" if left_value == right_value else "expected_difference")
|
|
321
|
+
conditions[f"hardware_{name}"] = item
|
|
322
|
+
# Observed formal-server threads supersede independent-probe approximations.
|
|
323
|
+
if not _unknown(lhs["hardware"].get("runtime_threads")) and not _unknown(rhs["hardware"].get("runtime_threads")):
|
|
324
|
+
conditions["runtime_threads"] = conditions["hardware_runtime_threads"]
|
|
325
|
+
profiles = {side: comparison_profile(snapshot, purpose=purpose) for side, snapshot in snapshots.items()}
|
|
326
|
+
qualification = compare_profiles(profiles["left"], profiles["right"])
|
|
327
|
+
for name, item in conditions.items():
|
|
328
|
+
statuses = {value for key, value in qualification["checks"].items() if key == name or key.startswith(name + ".")}
|
|
329
|
+
item["status"] = ("incompatible" if "incompatible" in statuses else "unknown" if "unknown" in statuses else
|
|
330
|
+
"expected_difference" if "expected_difference" in statuses else "compatible")
|
|
331
|
+
valid = lhs["valid"] and rhs["valid"]
|
|
332
|
+
status = qualification["status"]
|
|
333
|
+
differences = {name: {"left": value, "right": rhs["identity"][name]}
|
|
334
|
+
for name, value in lhs["identity"].items() if value != rhs["identity"][name]}
|
|
335
|
+
environment_condition = conditions["comparability_class"]
|
|
336
|
+
warnings = []
|
|
337
|
+
if environment_condition["status"] != "compatible":
|
|
338
|
+
warnings.append(f"Environment comparison blocked: {lhs['comparability_class']} vs "
|
|
339
|
+
f"{rhs['comparability_class']}. WSL measurements must not be treated as "
|
|
340
|
+
"native Linux measurements; unknown provenance cannot enter a Native baseline.")
|
|
341
|
+
metric_comparability = {}
|
|
342
|
+
for name in lhs["metric_availability"]:
|
|
343
|
+
available = lhs["metric_availability"][name] and rhs["metric_availability"][name]
|
|
344
|
+
metric_comparability[name] = {
|
|
345
|
+
"status": "comparable" if status == "compatible" and available else "not comparable",
|
|
346
|
+
"reason": ("missing_measurement" if not available else
|
|
347
|
+
"environment_" + environment_condition["status"]
|
|
348
|
+
if environment_condition["status"] != "compatible" else
|
|
349
|
+
"conditions_" + status if status != "compatible" else ""),
|
|
350
|
+
}
|
|
351
|
+
return {"schema_version": 2, "purpose": purpose, "status": status, "valid": valid,
|
|
352
|
+
"allowed_resource_dimensions": ALLOWED_RESOURCE_DIMENSIONS if purpose == "resource-scaling" else [],
|
|
353
|
+
"comparison_reasons": qualification["reasons"],
|
|
354
|
+
"warnings": warnings, "metric_comparability": metric_comparability,
|
|
355
|
+
"native_baseline_eligible": status == "compatible" and lhs["comparability_class"] == "native_linux",
|
|
356
|
+
"scope": "recorded_comparison_conditions_not_model_quality_or_resume_identity",
|
|
357
|
+
"limitations": ["hardware conditions are boundary observations, not proof of continuous isolation or identical thermal state",
|
|
358
|
+
"resource-scaling allows CPU and memory quotas; changing both cannot isolate either causal effect",
|
|
359
|
+
"missing hardware or effective thread evidence remains unknown; affinity does not prove exclusive CPU use",
|
|
360
|
+
"matching quality constraints do not prove either model meets them"],
|
|
361
|
+
"conditions": conditions, "expected_differences": differences,
|
|
362
|
+
"experiments": {side: {key: snapshot[key] for key in ("run_id", "result_csv", "valid", "issues", "environment_class",
|
|
363
|
+
"run_status", "measurement_status", "missing_metrics", *QUALITY_FIELDS)}
|
|
364
|
+
for side, snapshot in snapshots.items()}}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"""Render compatibility evidence without reinterpreting exception messages."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import csv
|
|
6
|
+
import io
|
|
7
|
+
import json
|
|
8
|
+
import math
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import TextIO
|
|
11
|
+
|
|
12
|
+
from acprof.artifacts import atomic_write
|
|
13
|
+
from acprof.failures import Failure, compatibility_status
|
|
14
|
+
from acprof.model_repository import MODEL_SOURCES
|
|
15
|
+
from acprof.quality import combine_quality, read_quality, summarize_quality
|
|
16
|
+
|
|
17
|
+
MAX_COMPATIBILITY_ARTIFACT_BYTES = 4 * 1024 * 1024
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _finite_json_number(raw: str) -> float:
|
|
21
|
+
value = float(raw)
|
|
22
|
+
if not math.isfinite(value):
|
|
23
|
+
raise ValueError("non-finite number")
|
|
24
|
+
return value
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _read_recorded_object(path: Path) -> dict:
|
|
28
|
+
with path.open("rb") as stream:
|
|
29
|
+
content = stream.read(MAX_COMPATIBILITY_ARTIFACT_BYTES + 1)
|
|
30
|
+
if len(content) > MAX_COMPATIBILITY_ARTIFACT_BYTES:
|
|
31
|
+
raise ValueError("artifact exceeds the 4 MiB read limit")
|
|
32
|
+
payload = json.loads(content, parse_float=_finite_json_number,
|
|
33
|
+
parse_constant=_finite_json_number)
|
|
34
|
+
if not isinstance(payload, dict):
|
|
35
|
+
raise ValueError("top-level JSON value must be an object")
|
|
36
|
+
return payload
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _recorded_evidence_failure(path: Path, error: Exception) -> dict:
|
|
40
|
+
return Failure(
|
|
41
|
+
"compatibility_report", "recorded_evidence_invalid", f"{path.name}: {error}",
|
|
42
|
+
evidence={"artifact": str(path.resolve()), "artifact_name": path.name},
|
|
43
|
+
exception_type=type(error).__name__,
|
|
44
|
+
).to_dict()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class _RecordedSourceError(ValueError):
|
|
48
|
+
def __init__(self, artifact: str, detail: str):
|
|
49
|
+
super().__init__(detail)
|
|
50
|
+
self.artifact = artifact
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _recorded_model_source(metadata: dict, resolution: dict) -> str:
|
|
54
|
+
provenance = resolution.get("provenance", {})
|
|
55
|
+
if not isinstance(provenance, dict):
|
|
56
|
+
raise _RecordedSourceError("model_resolution.json", "model provenance must be an object")
|
|
57
|
+
sources = provenance.get("sources", {})
|
|
58
|
+
if not isinstance(sources, dict):
|
|
59
|
+
raise _RecordedSourceError("model_resolution.json", "model provenance sources must be an object")
|
|
60
|
+
snapshot = sources.get("repository_snapshot", {})
|
|
61
|
+
if not isinstance(snapshot, dict):
|
|
62
|
+
raise _RecordedSourceError("model_resolution.json", "repository snapshot provenance must be an object")
|
|
63
|
+
source = metadata.get("model_source", snapshot.get("source", "huggingface"))
|
|
64
|
+
if not isinstance(source, str) or source not in MODEL_SOURCES:
|
|
65
|
+
raise _RecordedSourceError("static_meta.json" if "model_source" in metadata else "model_resolution.json",
|
|
66
|
+
"recorded model source must be huggingface/modelscope")
|
|
67
|
+
if "source" in snapshot and snapshot["source"] != source:
|
|
68
|
+
raise _RecordedSourceError("model_resolution.json", "recorded source conflicts with static_meta.json")
|
|
69
|
+
return source
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def result_status(row):
|
|
73
|
+
if row.get("failure"):
|
|
74
|
+
return compatibility_status(row["failure"])
|
|
75
|
+
if row.get("full_profile_complete"):
|
|
76
|
+
if row.get("quality_status") == "unknown":
|
|
77
|
+
return "full_success_quality_unknown"
|
|
78
|
+
return "full_success_with_warnings" if any(check["severity"] == "warning" for check in row.get("quality_checks", [])) else "full_success"
|
|
79
|
+
return row.get("runtime_status", "unverified")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def write_compatibility_report(root: Path, rows: list[dict]):
|
|
83
|
+
fields = ("model_id", "revision", "status", "stage", "reason_code", "detail", "device",
|
|
84
|
+
"runtime_profile", "retryability", "evidence", "full_profile_complete", "quality_status", "quality_checks",
|
|
85
|
+
"quality_reasons", "auto_selection_eligible", "attempt_id", "attempt_path", "configuration_sha256", "source")
|
|
86
|
+
stream = io.StringIO(newline="")
|
|
87
|
+
writer = csv.DictWriter(stream, fieldnames=fields)
|
|
88
|
+
writer.writeheader()
|
|
89
|
+
lines = ["# Compatibility report", "", "状态仅适用于所记录的 source、revision、设备、环境和验证范围。", "",
|
|
90
|
+
"| Source | Model | Revision | Status | reason_code | Detail |", "| --- | --- | --- | --- | --- | --- |"]
|
|
91
|
+
for row in rows:
|
|
92
|
+
failure = row.get("failure") or {}
|
|
93
|
+
quality = summarize_quality(row.get("quality_checks"))
|
|
94
|
+
if row.get("quality_status") == "unknown":
|
|
95
|
+
quality = combine_quality([quality, summarize_quality(None)])
|
|
96
|
+
if "quality_reasons" in row:
|
|
97
|
+
quality.update({key: row[key] for key in quality if key in row})
|
|
98
|
+
row = {"source": "huggingface", **row, **quality}
|
|
99
|
+
checks = row["quality_checks"]
|
|
100
|
+
values = {key: failure.get(key, row.get(key, "")) for key in fields}
|
|
101
|
+
values.update(status=result_status(row), evidence=json.dumps(failure.get("evidence", row.get("evidence", {})), ensure_ascii=False),
|
|
102
|
+
quality_checks=json.dumps(checks, ensure_ascii=False),
|
|
103
|
+
quality_reasons=json.dumps(row["quality_reasons"], ensure_ascii=False))
|
|
104
|
+
writer.writerow(values)
|
|
105
|
+
def cell(value):
|
|
106
|
+
return str(value).replace("|", "\\|").replace("\n", " ")
|
|
107
|
+
detail = failure.get("detail", "") or ", ".join(check["code"] for check in checks)
|
|
108
|
+
lines.append("| " + " | ".join(cell(value) for value in (
|
|
109
|
+
row["source"], row["model_id"], values["revision"], values["status"], values["reason_code"], detail)) + " |")
|
|
110
|
+
csv_text = stream.getvalue()
|
|
111
|
+
report_text = "\n".join(lines) + "\n"
|
|
112
|
+
def write_text(stream: TextIO, content: str) -> None:
|
|
113
|
+
stream.write(content)
|
|
114
|
+
|
|
115
|
+
atomic_write(root / "models.csv", lambda output: write_text(output, csv_text))
|
|
116
|
+
atomic_write(root / "REPORT.md", lambda output: write_text(output, report_text))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def report_results(sources: list[Path], output: Path) -> dict:
|
|
120
|
+
"""Read recorded results, including failed preflight directories; never rerun."""
|
|
121
|
+
from acprof.artifact_layout import ArtifactLayout
|
|
122
|
+
from acprof.artifacts import atomic_write_json
|
|
123
|
+
rows = []
|
|
124
|
+
for source in sources:
|
|
125
|
+
layout = ArtifactLayout.discover(source)
|
|
126
|
+
invalid = []
|
|
127
|
+
|
|
128
|
+
def read(name):
|
|
129
|
+
path = layout.path(name)
|
|
130
|
+
if not path.is_file():
|
|
131
|
+
return {}
|
|
132
|
+
try:
|
|
133
|
+
return _read_recorded_object(path)
|
|
134
|
+
except (OSError, UnicodeError, ValueError, RecursionError) as error:
|
|
135
|
+
invalid.append(_recorded_evidence_failure(path, error))
|
|
136
|
+
return {}
|
|
137
|
+
|
|
138
|
+
def invalid_shape(name, detail):
|
|
139
|
+
invalid.append(_recorded_evidence_failure(layout.path(name), ValueError(detail)))
|
|
140
|
+
|
|
141
|
+
def validated_failure(name, value, location):
|
|
142
|
+
try:
|
|
143
|
+
if not isinstance(value, dict):
|
|
144
|
+
raise ValueError("must be an object")
|
|
145
|
+
failure = Failure(**value)
|
|
146
|
+
if (not isinstance(failure.stage, str) or not failure.stage
|
|
147
|
+
or not isinstance(failure.detail, str)
|
|
148
|
+
or not isinstance(failure.evidence, dict)):
|
|
149
|
+
raise ValueError("has invalid typed failure fields")
|
|
150
|
+
return failure.to_dict()
|
|
151
|
+
except (TypeError, ValueError) as error:
|
|
152
|
+
invalid_shape(name, f"{location} must be a valid typed failure: {error}")
|
|
153
|
+
return None
|
|
154
|
+
|
|
155
|
+
metadata, resolution = read("static_meta.json"), read("model_resolution.json")
|
|
156
|
+
capability = read("capability_report.json")
|
|
157
|
+
validation = read("runtime_validation.json")
|
|
158
|
+
failure_report = read("runtime_failures.json")
|
|
159
|
+
if not any((metadata, resolution, capability, validation, failure_report, invalid)):
|
|
160
|
+
raise ValueError(f"No recorded compatibility evidence: {source}")
|
|
161
|
+
|
|
162
|
+
invalid_identity = any(problem["evidence"]["artifact_name"] in {
|
|
163
|
+
"static_meta.json", "model_resolution.json"} for problem in invalid)
|
|
164
|
+
try:
|
|
165
|
+
# Corrupt identity evidence is not a historical document with missing fields.
|
|
166
|
+
model_source = "unknown" if invalid_identity else _recorded_model_source(metadata, resolution)
|
|
167
|
+
except _RecordedSourceError as error:
|
|
168
|
+
invalid_shape(error.artifact, str(error))
|
|
169
|
+
model_source = "unknown"
|
|
170
|
+
|
|
171
|
+
recorded_failures = failure_report.get("failures", [])
|
|
172
|
+
if not isinstance(recorded_failures, list):
|
|
173
|
+
invalid_shape("runtime_failures.json", "failures must be a list")
|
|
174
|
+
recorded_failures = []
|
|
175
|
+
else:
|
|
176
|
+
recorded_failures = [
|
|
177
|
+
failure for index, value in enumerate(recorded_failures)
|
|
178
|
+
if (failure := validated_failure(
|
|
179
|
+
"runtime_failures.json", value, f"failures[{index}]",
|
|
180
|
+
)) is not None
|
|
181
|
+
]
|
|
182
|
+
|
|
183
|
+
devices = validation.get("devices", {})
|
|
184
|
+
if not isinstance(devices, dict):
|
|
185
|
+
invalid_shape("runtime_validation.json", "devices must be an object")
|
|
186
|
+
devices = {}
|
|
187
|
+
device_failures = []
|
|
188
|
+
for device, value in devices.items():
|
|
189
|
+
if not isinstance(value, dict):
|
|
190
|
+
invalid_shape("runtime_validation.json", f"device {device!r} must be an object")
|
|
191
|
+
continue
|
|
192
|
+
failure = value.get("failure")
|
|
193
|
+
if failure is None:
|
|
194
|
+
continue
|
|
195
|
+
failure = validated_failure(
|
|
196
|
+
"runtime_validation.json", failure, f"device {device!r} failure",
|
|
197
|
+
)
|
|
198
|
+
if failure is not None:
|
|
199
|
+
device_failures.append(failure)
|
|
200
|
+
|
|
201
|
+
resolution_failure = resolution.get("failure")
|
|
202
|
+
if resolution_failure is not None:
|
|
203
|
+
resolution_failure = validated_failure(
|
|
204
|
+
"model_resolution.json", resolution_failure, "failure",
|
|
205
|
+
)
|
|
206
|
+
failures = [*recorded_failures, *device_failures]
|
|
207
|
+
if resolution_failure:
|
|
208
|
+
failures.append(resolution_failure)
|
|
209
|
+
failures.extend(invalid)
|
|
210
|
+
|
|
211
|
+
quality = read_quality(source)
|
|
212
|
+
rows.append({"source": model_source, "model_id": metadata.get("model_id", resolution.get("model_id", source.name)),
|
|
213
|
+
"revision": metadata.get("model_revision", resolution.get("model_revision", "unknown")),
|
|
214
|
+
"runtime_profile": metadata.get("runtime_profile_id", resolution.get("runtime_profile", "")),
|
|
215
|
+
"full_profile_complete": capability.get("full_profile_complete") is True,
|
|
216
|
+
"runtime_status": validation.get("status", "unverified"),
|
|
217
|
+
**quality, "failure": failures[0] if failures else None,
|
|
218
|
+
"failures": failures, "evidence": {"result_directory": str(source.resolve())}})
|
|
219
|
+
output.mkdir(parents=True, exist_ok=False)
|
|
220
|
+
report = {"schema_version": 1, "scope": "recorded_results; no_reexecution", "rows": rows}
|
|
221
|
+
atomic_write_json(output / "coverage.json", report)
|
|
222
|
+
write_compatibility_report(output, rows)
|
|
223
|
+
return report
|