simdref 0.0.19__tar.gz → 0.0.20__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {simdref-0.0.19/src/simdref.egg-info → simdref-0.0.20}/PKG-INFO +1 -1
- {simdref-0.0.19 → simdref-0.0.20}/pyproject.toml +1 -1
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/cli.py +52 -16
- simdref-0.0.20/src/simdref/cuda.py +294 -0
- simdref-0.0.20/src/simdref/cuda_docs.py +1158 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/display.py +15 -14
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/export.py +42 -26
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/filters.py +190 -4
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/ingest_catalog.py +103 -3
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/ingest_sources.py +32 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/ptx.py +279 -17
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/tui.py +549 -24
- simdref-0.0.20/src/simdref/urls.py +46 -0
- {simdref-0.0.19 → simdref-0.0.20/src/simdref.egg-info}/PKG-INFO +1 -1
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref.egg-info/SOURCES.txt +22 -0
- simdref-0.0.20/tests/test_annotate_microarch.py +55 -0
- simdref-0.0.20/tests/test_arm_arch_filter.py +159 -0
- simdref-0.0.20/tests/test_category_filter.py +84 -0
- simdref-0.0.20/tests/test_cli_perf_line.py +37 -0
- simdref-0.0.20/tests/test_cuda_docs_guide.py +140 -0
- simdref-0.0.20/tests/test_cuda_docs_math.py +382 -0
- simdref-0.0.20/tests/test_cuda_floors.py +145 -0
- simdref-0.0.20/tests/test_cuda_join.py +145 -0
- simdref-0.0.20/tests/test_cuda_links.py +75 -0
- simdref-0.0.20/tests/test_cuda_tex.py +72 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_cuda_wiring.py +24 -0
- simdref-0.0.20/tests/test_detail_metadata.py +90 -0
- simdref-0.0.20/tests/test_empty_query_state.py +69 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_export.py +21 -20
- simdref-0.0.20/tests/test_export_sm.py +72 -0
- simdref-0.0.20/tests/test_export_sm_column.py +86 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_filters.py +21 -3
- simdref-0.0.20/tests/test_perf_kind_toggle.py +84 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_presentation.py +10 -0
- simdref-0.0.20/tests/test_preset_chip_sync.py +45 -0
- simdref-0.0.20/tests/test_ptx.py +431 -0
- simdref-0.0.20/tests/test_related_entries.py +121 -0
- simdref-0.0.20/tests/test_result_row_badges.py +71 -0
- simdref-0.0.20/tests/test_sm_filter.py +297 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_tui.py +163 -0
- simdref-0.0.20/tests/test_urls.py +71 -0
- simdref-0.0.19/src/simdref/cuda.py +0 -50
- simdref-0.0.19/tests/test_ptx.py +0 -253
- {simdref-0.0.19 → simdref-0.0.20}/LICENSE +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/README.md +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/setup.cfg +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/__init__.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/__main__.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/annotate.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/arm_instructions.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/asm_identity.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/asmline.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/catkey.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/htmltext.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/ingest.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/ingest_pdf.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/lsp.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/manpages.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/models.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/operands.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/pdfparse/__init__.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/pdfparse/base.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/pdfparse/intel.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/pdfparse/registry.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/pdfparse/types.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/pdfrefs.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/perf.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/perf_sources/__init__.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/perf_sources/amd_swopt.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/perf_sources/arm_swopt.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/perf_sources/cores.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/perf_sources/instlatx64.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/perf_sources/intel_guide.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/perf_sources/intel_optref.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/perf_sources/llvm_mca.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/perf_sources/llvm_scheduling.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/perf_sources/merge.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/queries.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/regtable.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/riscv.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/search.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/storage.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/tablecols.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref/ui_labels.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref.egg-info/dependency_links.txt +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref.egg-info/entry_points.txt +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref.egg-info/requires.txt +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/src/simdref.egg-info/top_level.txt +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_a1_sdm_parser.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_a2_perf_rule.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_a4_arm_pdfrefs.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_a5_offline_aarchmrs.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_amd_match_llvm_mc.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_annotate.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_annotate_positions.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_annotate_scans.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_arrangement_tail.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_asm_identity.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_asm_wire.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_asmline.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_audit_coverage.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_auto_update_on_version_change.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_b1_latency_pairs.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_b2_metadata.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_b3_sdm_forms.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_b4_descriptions_provenance.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_b5_linking.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_b5_perf_family.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_b5_sme.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_c0_perf_priority.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_catkey.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_cli_bare_query.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_cli_bootstrap_progress.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_cli_help.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_cli_llm.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_coverage_live.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_coverage_parity.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_cuda_declaration_parser.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_cuda_intrinsics.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_cuda_td_expansion.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_display.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_display_scanners.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_export_viz.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_fetch_retry.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_fixui_display.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_htmltext.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_ingest_enc_fields.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_ingest_sources.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_int_arm_isa_label.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_int_core_ids.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_int_ingest_registration.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_int_sdm_family_fallback.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_intel_operation_and_url.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_isa_detect_llvm_mc.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue2_fixes.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_51.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_52.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_53_54.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_55.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_56_57a.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_57_cpi.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_60_c1.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_60_contract.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_60_crossarch.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_60_matcher.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_65_arm_alias.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_65_branch_target.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_65_compressed.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_65_foreign_arch.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_65_identity.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_65_m1.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_65_m5.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_65_perfdata.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_65_sme_za.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_65_text.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issue_65_timing.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issues_23_24_25.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_issues_51_57_join.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_leftover_arm_form_pick.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_leftover_arm_postindex.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_leftover_att_movx.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_leftover_autoupdate.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_leftover_catalog_gaps.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_leftover_ingest_isa_merge.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_leftover_intel_size.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_leftover_perf_join.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_leftover_riscv_shared.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_lsp_cuda.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_lsp_ptx.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_lsp_stdio.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_lsp_web.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_models.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_no_catalog_row.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_objdump_listings.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_operands.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_pdfparse.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_perf.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_perf_source_amd_swopt.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_perf_source_arm_swopt.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_perf_source_instlatx64.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_perf_source_intel_guide.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_perf_source_intel_optref.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_perf_sources.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_preset_persistence.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_regtable.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_release_tag_pin.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_riscv_docs_pages.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_search.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_search_pushdown.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_shared_source_helpers.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_source_kind_filter.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_source_validation.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_storage_alnum.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_storage_payload.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_storage_schema.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_tablecols.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_ui_labels_parity.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_update_build_stamp.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_vendor_riscv_categories.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_vendor_riscv_sources.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_version_matches_pyproject.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_x86_key_widths.py +0 -0
- {simdref-0.0.19 → simdref-0.0.20}/tests/test_x86_linking.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "simdref"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.20"
|
|
8
8
|
description = "Searchable SIMD intrinsic and instruction reference with CLI, manpages, TUI, and LSP."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -917,11 +917,13 @@ def _payload_source_kinds(arch_details) -> list[str]:
|
|
|
917
917
|
# ---------------------------------------------------------------------------
|
|
918
918
|
|
|
919
919
|
|
|
920
|
-
def _print_search_results_runtime(
|
|
920
|
+
def _print_search_results_runtime(
|
|
921
|
+
conn, query: str, limit: int = 20, as_json: bool = False, state=None
|
|
922
|
+
) -> int:
|
|
921
923
|
"""Render the ranked search table (or JSON) in the search's own
|
|
922
924
|
relevance order. Returns the number of rows actually printed — callers
|
|
923
925
|
use 0 to fall through to the no-match branch instead of printing an
|
|
924
|
-
empty table."""
|
|
926
|
+
empty table. *state* hides rows the sm filter excludes."""
|
|
925
927
|
results, intrinsic_map, instruction_map = _search_runtime(conn, query, limit=limit)
|
|
926
928
|
prepared_rows = []
|
|
927
929
|
for result in results:
|
|
@@ -934,6 +936,8 @@ def _print_search_results_runtime(conn, query: str, limit: int = 20, as_json: bo
|
|
|
934
936
|
if item is not None:
|
|
935
937
|
if not isa_visible(item.isa, show_fp16=SHOW_FP16_ISAS):
|
|
936
938
|
continue
|
|
939
|
+
if state is not None and not state.matches(item):
|
|
940
|
+
continue
|
|
937
941
|
arch = display_architecture(item.architecture)
|
|
938
942
|
isa = display_isa(item.isa)
|
|
939
943
|
lat, cpi = variant_perf_summary(item.arch_details, perf.record_iclass(item))
|
|
@@ -942,6 +946,8 @@ def _print_search_results_runtime(conn, query: str, limit: int = 20, as_json: bo
|
|
|
942
946
|
if item is not None:
|
|
943
947
|
if not isa_visible(item.isa, show_fp16=SHOW_FP16_ISAS):
|
|
944
948
|
continue
|
|
949
|
+
if state is not None and not state.matches(item):
|
|
950
|
+
continue
|
|
945
951
|
arch = display_architecture(item.architecture)
|
|
946
952
|
isa = display_isa(item.isa)
|
|
947
953
|
lat, cpi = intrinsic_perf_summary_runtime(conn, item, instruction_map)
|
|
@@ -987,18 +993,31 @@ def _smart_lookup(
|
|
|
987
993
|
preset: str | None = None,
|
|
988
994
|
arch: str | None = None,
|
|
989
995
|
as_json: bool = False,
|
|
996
|
+
sm: str | None = None,
|
|
990
997
|
) -> int:
|
|
991
998
|
"""Dispatch a bare query.
|
|
992
999
|
|
|
993
1000
|
Exact intrinsic match prints the intrinsic detail and exits 0. Exact
|
|
994
1001
|
instruction match prints a plain-text (or JSON) summary and exits 0;
|
|
995
1002
|
``--arch`` applies to this branch only. Fuzzy hits print the ranked
|
|
996
|
-
search list (or JSON) and exit 0, on a TTY or not.
|
|
1003
|
+
search list (or JSON) and exit 0, on a TTY or not. ``--sm`` hides the
|
|
1004
|
+
records whose sm floor fails the chosen level. Nothing found opens
|
|
997
1005
|
the TUI on a TTY (never under ``--json``) or exits 2 non-interactively.
|
|
998
1006
|
"""
|
|
999
1007
|
ensure_runtime()
|
|
1008
|
+
from simdref.filters import FilterState, sm_number
|
|
1009
|
+
|
|
1010
|
+
if sm:
|
|
1011
|
+
try:
|
|
1012
|
+
sm_number(sm)
|
|
1013
|
+
except ValueError:
|
|
1014
|
+
err_console.print(f"--sm {sm!r} is not an sm level (want sm_XX)", style="red")
|
|
1015
|
+
return 1
|
|
1016
|
+
state = FilterState(min_sm=sm or "")
|
|
1000
1017
|
with contextlib.closing(open_db()) as conn:
|
|
1001
1018
|
intrinsic = load_intrinsic_from_db(conn, query)
|
|
1019
|
+
if intrinsic is not None and not state.matches(intrinsic):
|
|
1020
|
+
intrinsic = None
|
|
1002
1021
|
if intrinsic is not None and arch is not None:
|
|
1003
1022
|
err_console.print("--arch applies to instruction queries only", style="red")
|
|
1004
1023
|
return 2
|
|
@@ -1008,7 +1027,7 @@ def _smart_lookup(
|
|
|
1008
1027
|
else:
|
|
1009
1028
|
render_intrinsic(None, intrinsic, conn=conn)
|
|
1010
1029
|
return 0
|
|
1011
|
-
records = _find_instructions_fast(query)
|
|
1030
|
+
records = [r for r in _find_instructions_fast(query) if state.matches(r)]
|
|
1012
1031
|
if records:
|
|
1013
1032
|
return _print_non_interactive_summary(
|
|
1014
1033
|
query, records=records, arch=arch, as_json=as_json
|
|
@@ -1016,7 +1035,7 @@ def _smart_lookup(
|
|
|
1016
1035
|
if arch is not None:
|
|
1017
1036
|
err_console.print("--arch applies to instruction queries only", style="red")
|
|
1018
1037
|
return 2
|
|
1019
|
-
printed = _print_search_results_runtime(conn, query, as_json=as_json)
|
|
1038
|
+
printed = _print_search_results_runtime(conn, query, as_json=as_json, state=state)
|
|
1020
1039
|
if printed:
|
|
1021
1040
|
if not as_json and sys.stdin.isatty() and sys.stdout.isatty():
|
|
1022
1041
|
# A fuzzy match on a TTY opens the TUI (preset as passed, like
|
|
@@ -1158,14 +1177,18 @@ def _print_non_interactive_summary(
|
|
|
1158
1177
|
typer.echo(f" {tag}: lat={lat_text}c cpi={_fmt_num(cpi)} ports={ports_str}")
|
|
1159
1178
|
else:
|
|
1160
1179
|
summary = aggregate_perf(rec, mode="avg", include_modeled=False)
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1180
|
+
if summary.n_archs == 0:
|
|
1181
|
+
# The TUI wording (tui._NO_DATA): no arch holds perf data.
|
|
1182
|
+
typer.echo(" performance: no data")
|
|
1183
|
+
else:
|
|
1184
|
+
ports = collect_ports(rec, arch=None, archs_used=summary.archs_used)
|
|
1185
|
+
ports_str = ",".join(ports) if ports else "-"
|
|
1186
|
+
typer.echo(
|
|
1187
|
+
f" avg over {summary.n_archs} arch(s) [{summary.source_kind}]: "
|
|
1188
|
+
f"lat={_fmt_num(summary.latency)}c cpi={_fmt_num(summary.cpi)} ports={ports_str}"
|
|
1189
|
+
)
|
|
1190
|
+
if summary.archs_used:
|
|
1191
|
+
typer.echo(f" archs: {', '.join(summary.archs_used)}")
|
|
1169
1192
|
return 0
|
|
1170
1193
|
|
|
1171
1194
|
|
|
@@ -1992,7 +2015,7 @@ def llm_query(
|
|
|
1992
2015
|
preset: str = typer.Option(
|
|
1993
2016
|
None,
|
|
1994
2017
|
"--preset",
|
|
1995
|
-
help="Apply a named preset (default, intel, arm32, arm64, riscv, none, all).",
|
|
2018
|
+
help="Apply a named preset (default, intel, arm32, arm64, riscv, cuda, none, all).",
|
|
1996
2019
|
),
|
|
1997
2020
|
source_kind: str = typer.Option(
|
|
1998
2021
|
"any", "--source-kind", help="Filter perf rows by provenance: measured, modeled, or any."
|
|
@@ -2120,7 +2143,7 @@ def llm_batch(
|
|
|
2120
2143
|
preset: str = typer.Option(
|
|
2121
2144
|
None,
|
|
2122
2145
|
"--preset",
|
|
2123
|
-
help="Apply a named preset (default, intel, arm32, arm64, riscv, none, all).",
|
|
2146
|
+
help="Apply a named preset (default, intel, arm32, arm64, riscv, cuda, none, all).",
|
|
2124
2147
|
),
|
|
2125
2148
|
source_kind: str = typer.Option(
|
|
2126
2149
|
"any", "--source-kind", help="Filter perf rows by provenance: measured, modeled, or any."
|
|
@@ -2471,6 +2494,7 @@ def main() -> int:
|
|
|
2471
2494
|
# dispatch.
|
|
2472
2495
|
initial_preset: str | None = None
|
|
2473
2496
|
bare_arch: str | None = None
|
|
2497
|
+
bare_sm: str | None = None
|
|
2474
2498
|
bare_json = False
|
|
2475
2499
|
_cleaned: list[str] = []
|
|
2476
2500
|
_i = 0
|
|
@@ -2492,6 +2516,14 @@ def main() -> int:
|
|
|
2492
2516
|
bare_arch = arg.split("=", 1)[1]
|
|
2493
2517
|
_i += 1
|
|
2494
2518
|
continue
|
|
2519
|
+
if arg == "--sm" and _i + 1 < len(argv):
|
|
2520
|
+
bare_sm = argv[_i + 1]
|
|
2521
|
+
_i += 2
|
|
2522
|
+
continue
|
|
2523
|
+
if arg.startswith("--sm="):
|
|
2524
|
+
bare_sm = arg.split("=", 1)[1]
|
|
2525
|
+
_i += 1
|
|
2526
|
+
continue
|
|
2495
2527
|
if arg == "--json":
|
|
2496
2528
|
bare_json = True
|
|
2497
2529
|
_i += 1
|
|
@@ -2531,7 +2563,11 @@ def main() -> int:
|
|
|
2531
2563
|
if len(argv) > 1 and argv[0].lower() in {"show", "lookup", "info"}:
|
|
2532
2564
|
argv = argv[1:]
|
|
2533
2565
|
return _smart_lookup(
|
|
2534
|
-
" ".join(argv),
|
|
2566
|
+
" ".join(argv),
|
|
2567
|
+
preset=initial_preset,
|
|
2568
|
+
arch=bare_arch,
|
|
2569
|
+
as_json=bare_json,
|
|
2570
|
+
sm=bare_sm,
|
|
2535
2571
|
)
|
|
2536
2572
|
if not argv:
|
|
2537
2573
|
ensure_runtime()
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"""CUDA C++ device intrinsics parsing and derived record rows.
|
|
2
|
+
|
|
3
|
+
Parses the JSON bundle produced by tools/vendor_cuda_sources.py, which
|
|
4
|
+
extracts CUDA API names from four clang headers and resolves PTX
|
|
5
|
+
instruction links by parsing LLVM TableGen .td files. Joins the NVIDIA
|
|
6
|
+
documentation pages, parsed by simdref.cuda_docs, into the rows. The
|
|
7
|
+
join runs at build time. No NVIDIA text is stored in git.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from simdref.cuda_docs import declares_name, tex_to_text
|
|
16
|
+
from simdref.models import IntrinsicRecord
|
|
17
|
+
from simdref.urls import resolve_url
|
|
18
|
+
|
|
19
|
+
BUNDLE_FORMAT = "clang-cuda-headers-v2"
|
|
20
|
+
CUDA_INTRINSICS_DOC_URL = "https://docs.nvidia.com/cuda/cuda-c-programming-guide/"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def parse_cuda_intrinsics_payload(text: str) -> list[IntrinsicRecord]:
|
|
24
|
+
"""Parse the CUDA intrinsics JSON bundle into IntrinsicRecord rows."""
|
|
25
|
+
data = json.loads(text)
|
|
26
|
+
if data.get("format") != BUNDLE_FORMAT:
|
|
27
|
+
raise ValueError(f"Unexpected bundle format: {data.get('format')!r}")
|
|
28
|
+
|
|
29
|
+
rows: list[IntrinsicRecord] = []
|
|
30
|
+
for item in data.get("intrinsics", []):
|
|
31
|
+
metadata = item.get("metadata", {})
|
|
32
|
+
classification = metadata.get("classification", "")
|
|
33
|
+
record_metadata = {"classification": classification}
|
|
34
|
+
for key in ("min_sm", "min_ptx", "min_sm_from", "min_ptx_from"):
|
|
35
|
+
value = str(item.get(key) or metadata.get(key) or "").strip()
|
|
36
|
+
if value:
|
|
37
|
+
record_metadata[key] = value
|
|
38
|
+
|
|
39
|
+
row = IntrinsicRecord(
|
|
40
|
+
name=item["name"],
|
|
41
|
+
signature=item.get("signature", ""),
|
|
42
|
+
description=item.get("description", ""),
|
|
43
|
+
header=item.get("header", ""),
|
|
44
|
+
url=item.get("url", ""),
|
|
45
|
+
architecture="cuda",
|
|
46
|
+
isa=["CUDA"],
|
|
47
|
+
category=item.get("category", ""),
|
|
48
|
+
subcategory=item.get("subcategory", ""),
|
|
49
|
+
instructions=item.get("instructions", []),
|
|
50
|
+
instruction_refs=item.get("instruction_refs", []),
|
|
51
|
+
metadata=record_metadata,
|
|
52
|
+
doc_sections=item.get("doc_sections", {}),
|
|
53
|
+
notes=item.get("notes", []),
|
|
54
|
+
aliases=item.get("aliases", []),
|
|
55
|
+
source="clang-cuda-headers",
|
|
56
|
+
)
|
|
57
|
+
rows.append(row)
|
|
58
|
+
|
|
59
|
+
return rows
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def parse_cuda_calls(text: str) -> dict[str, list[str]]:
|
|
63
|
+
"""name to call-name list from the bundle call graph.
|
|
64
|
+
|
|
65
|
+
The vendor step records, per header function, the names its body
|
|
66
|
+
calls. This is the graph the doc join and the SM floors walk.
|
|
67
|
+
"""
|
|
68
|
+
data = json.loads(text)
|
|
69
|
+
if data.get("format") != BUNDLE_FORMAT:
|
|
70
|
+
raise ValueError(f"Unexpected bundle format: {data.get('format')!r}")
|
|
71
|
+
out: dict[str, list[str]] = {}
|
|
72
|
+
for item in data.get("intrinsics", []):
|
|
73
|
+
out[item["name"]] = [str(name) for name in item.get("calls") or []]
|
|
74
|
+
return out
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _signature_params(signature: str) -> str:
|
|
78
|
+
"""The argument list of a signature, its parameter names and types.
|
|
79
|
+
|
|
80
|
+
The math pages carry no Parameters field. The signature does. This
|
|
81
|
+
takes the text between the first "(" and the last ")" of it.
|
|
82
|
+
"""
|
|
83
|
+
start = signature.find("(")
|
|
84
|
+
end = signature.rfind(")")
|
|
85
|
+
if start == -1 or end <= start:
|
|
86
|
+
return ""
|
|
87
|
+
args = " ".join(signature[start + 1 : end].split())
|
|
88
|
+
if not args or args == "void":
|
|
89
|
+
return ""
|
|
90
|
+
return args
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _first_sentence(text: str) -> str:
|
|
94
|
+
"""The first sentence of a description, with its full stop."""
|
|
95
|
+
joined = " ".join(text.split())
|
|
96
|
+
if not joined:
|
|
97
|
+
return ""
|
|
98
|
+
stop = joined.find(". ")
|
|
99
|
+
if stop == -1:
|
|
100
|
+
return joined
|
|
101
|
+
return joined[: stop + 1]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _stripped(name: str) -> str:
|
|
105
|
+
"""A name as one lowercase run of characters, for containment."""
|
|
106
|
+
return name.replace("_", "").lower()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _reachable_builtins(name: str, calls: dict[str, list[str]]) -> set[str]:
|
|
110
|
+
"""The __nvvm_ and __nv_ tokens the name reaches over the call graph."""
|
|
111
|
+
seen = {name}
|
|
112
|
+
stack = [name]
|
|
113
|
+
out: set[str] = set()
|
|
114
|
+
while stack:
|
|
115
|
+
current = stack.pop()
|
|
116
|
+
for token in calls.get(current, []):
|
|
117
|
+
if token.startswith("__nvvm_") or token.startswith("__nv_"):
|
|
118
|
+
out.add(token)
|
|
119
|
+
elif token in calls and token not in seen:
|
|
120
|
+
seen.add(token)
|
|
121
|
+
stack.append(token)
|
|
122
|
+
return out
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _nearest_documented_caller(name: str, calls: dict[str, list[str]], documented: set[str]) -> str:
|
|
126
|
+
"""The nearest documented name that calls this one, else "".
|
|
127
|
+
|
|
128
|
+
Breadth first over the caller side of the call graph. The nearest
|
|
129
|
+
level with a documented name decides. Ties take the shortest name.
|
|
130
|
+
"""
|
|
131
|
+
callers: dict[str, list[str]] = {}
|
|
132
|
+
for caller, callees in calls.items():
|
|
133
|
+
for callee in callees:
|
|
134
|
+
callers.setdefault(callee, []).append(caller)
|
|
135
|
+
seen = {name}
|
|
136
|
+
frontier = [name]
|
|
137
|
+
while frontier:
|
|
138
|
+
next_frontier: list[str] = []
|
|
139
|
+
candidates: list[str] = []
|
|
140
|
+
for current in frontier:
|
|
141
|
+
for caller in callers.get(current, []):
|
|
142
|
+
if caller in documented and caller not in candidates:
|
|
143
|
+
candidates.append(caller)
|
|
144
|
+
if caller not in seen:
|
|
145
|
+
seen.add(caller)
|
|
146
|
+
next_frontier.append(caller)
|
|
147
|
+
if candidates:
|
|
148
|
+
return min(candidates, key=lambda item: (len(item), item))
|
|
149
|
+
frontier = next_frontier
|
|
150
|
+
return ""
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _contained_doc_name(
|
|
154
|
+
name: str, calls: dict[str, list[str]], documented: dict[str, tuple[dict, str]]
|
|
155
|
+
) -> str:
|
|
156
|
+
"""A documented name that this name reaches by name containment.
|
|
157
|
+
|
|
158
|
+
Last join tier. The documented name, without underscores, must sit
|
|
159
|
+
inside the row name or inside one of the builtins the row reaches,
|
|
160
|
+
from a word start of that name. The row name is tried first, so a
|
|
161
|
+
helper such as __iAtomicExch maps to atomicExch and not to the type
|
|
162
|
+
cast its body calls. The longest such name wins. This maps the
|
|
163
|
+
header helpers onto the API names the docs use.
|
|
164
|
+
"""
|
|
165
|
+
for needles in (
|
|
166
|
+
[name],
|
|
167
|
+
sorted(_reachable_builtins(name, calls)),
|
|
168
|
+
):
|
|
169
|
+
best = ""
|
|
170
|
+
best_len = 0
|
|
171
|
+
for doc_name, (doc_entry, _source) in sorted(documented.items()):
|
|
172
|
+
# A tier-3 name must be a documented function, not a word of
|
|
173
|
+
# an example or a feature table cell.
|
|
174
|
+
signature = str(doc_entry.get("signature") or "")
|
|
175
|
+
if not declares_name(signature, doc_name):
|
|
176
|
+
continue
|
|
177
|
+
token = _stripped(doc_name)
|
|
178
|
+
if len(token) < 4:
|
|
179
|
+
continue
|
|
180
|
+
if any(_starts_at_word(token, needle) for needle in needles) and len(token) > best_len:
|
|
181
|
+
best = doc_name
|
|
182
|
+
best_len = len(token)
|
|
183
|
+
if best:
|
|
184
|
+
return best
|
|
185
|
+
return ""
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _starts_at_word(token: str, name: str) -> bool:
|
|
189
|
+
"""The token matches the name from a word start, underscores aside.
|
|
190
|
+
|
|
191
|
+
Word starts are the name start, the letter after an underscore or
|
|
192
|
+
a digit, and a case hump. Matching skips underscores of the name,
|
|
193
|
+
so a multiword builtin name still matches its word run.
|
|
194
|
+
"""
|
|
195
|
+
n = len(name)
|
|
196
|
+
for pos in range(n):
|
|
197
|
+
if pos:
|
|
198
|
+
prev = name[pos - 1]
|
|
199
|
+
hump = name[pos].isupper() and not prev.isupper()
|
|
200
|
+
if prev != "_" and not prev.isdigit() and not hump:
|
|
201
|
+
continue
|
|
202
|
+
i = pos
|
|
203
|
+
ok = True
|
|
204
|
+
for ch in token:
|
|
205
|
+
while i < n and name[i] == "_":
|
|
206
|
+
i += 1
|
|
207
|
+
# A width run in the name, such as the 32 of match32, does
|
|
208
|
+
# not split the word for the doc name.
|
|
209
|
+
if i < n and name[i].isdigit() and name[i].lower() != ch:
|
|
210
|
+
while i < n and (name[i].isdigit() or name[i] == "_"):
|
|
211
|
+
i += 1
|
|
212
|
+
if i >= n or name[i].lower() != ch:
|
|
213
|
+
ok = False
|
|
214
|
+
break
|
|
215
|
+
i += 1
|
|
216
|
+
if ok:
|
|
217
|
+
return True
|
|
218
|
+
return False
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def apply_cuda_docs(
|
|
222
|
+
rows: list[IntrinsicRecord], calls: dict[str, list[str]], docs: dict[str, Any]
|
|
223
|
+
) -> None:
|
|
224
|
+
"""Fill documentation fields of the CUDA rows from the parsed pages.
|
|
225
|
+
|
|
226
|
+
Join tiers per name: an exact doc entry, then the nearest documented
|
|
227
|
+
caller over the header call graph, then a documented name contained
|
|
228
|
+
in the row name or in a builtin it reaches. The chosen entry stores
|
|
229
|
+
its caller in metadata["doc_via"] on the fallback tiers. A name with
|
|
230
|
+
no entry keeps no URL and keeps the header signature.
|
|
231
|
+
"""
|
|
232
|
+
ulp = docs.get("ulp") or {}
|
|
233
|
+
documented: dict[str, tuple[dict, str]] = {}
|
|
234
|
+
for mapping, source in (
|
|
235
|
+
(docs.get("math") or {}, "cuda-math-api"),
|
|
236
|
+
(docs.get("guide") or {}, "cuda-guide"),
|
|
237
|
+
(docs.get("guide_archive") or {}, "cuda-guide-archive"),
|
|
238
|
+
(docs.get("libdevice") or {}, "libdevice"),
|
|
239
|
+
):
|
|
240
|
+
for doc_name, entry in mapping.items():
|
|
241
|
+
if doc_name not in documented:
|
|
242
|
+
documented[doc_name] = (entry, source)
|
|
243
|
+
for row in rows:
|
|
244
|
+
name = row.name
|
|
245
|
+
via = ""
|
|
246
|
+
hit = documented.get(name)
|
|
247
|
+
if hit is None:
|
|
248
|
+
via = _nearest_documented_caller(name, calls, set(documented))
|
|
249
|
+
if via:
|
|
250
|
+
hit = documented[via]
|
|
251
|
+
if hit is None:
|
|
252
|
+
via = _contained_doc_name(name, calls, documented)
|
|
253
|
+
if via:
|
|
254
|
+
hit = documented[via]
|
|
255
|
+
if hit is None:
|
|
256
|
+
row.url = ""
|
|
257
|
+
continue
|
|
258
|
+
entry, source = hit
|
|
259
|
+
anchor = str(entry.get("anchor") or "")
|
|
260
|
+
page = str(entry.get("page") or "")
|
|
261
|
+
row.url = resolve_url(page, "#" + anchor) if anchor else resolve_url(page)
|
|
262
|
+
if entry.get("signature"):
|
|
263
|
+
row.signature = str(entry["signature"])
|
|
264
|
+
description = str(entry.get("description") or "")
|
|
265
|
+
summary = str(entry.get("summary") or "")
|
|
266
|
+
row.description = _first_sentence(summary or description)
|
|
267
|
+
sections: dict[str, str] = {}
|
|
268
|
+
if description:
|
|
269
|
+
sections["Description"] = description
|
|
270
|
+
parameters = str(entry.get("parameters") or "")
|
|
271
|
+
if not parameters:
|
|
272
|
+
parameters = _signature_params(str(entry.get("signature") or ""))
|
|
273
|
+
if parameters:
|
|
274
|
+
sections["Parameters"] = parameters
|
|
275
|
+
if entry.get("return_value"):
|
|
276
|
+
sections["Return"] = str(entry["return_value"])
|
|
277
|
+
ulp_entry = ulp.get(name) or {}
|
|
278
|
+
accuracy = str(ulp_entry.get("accuracy") or "")
|
|
279
|
+
if not accuracy:
|
|
280
|
+
accuracy = str(entry.get("accuracy") or "")
|
|
281
|
+
if accuracy:
|
|
282
|
+
readable = tex_to_text(accuracy)
|
|
283
|
+
sections["Accuracy"] = readable
|
|
284
|
+
# The web renders the original TeX later; keep it verbatim.
|
|
285
|
+
if readable != accuracy:
|
|
286
|
+
row.metadata["doc_math"] = accuracy
|
|
287
|
+
row.doc_sections = sections
|
|
288
|
+
if entry.get("accuracy"):
|
|
289
|
+
row.notes = [str(entry["accuracy"])]
|
|
290
|
+
row.metadata["doc_source"] = source
|
|
291
|
+
if via:
|
|
292
|
+
row.metadata["doc_via"] = via
|
|
293
|
+
if entry.get("return_value"):
|
|
294
|
+
row.metadata["result"] = str(entry["return_value"])
|