Sparse-checkout from NVIDIA/cccl main branch to complete cccl_upstream: Added: - python/cuda_cccl/ (226 files) — Python bindings for device-level algorithms Critical for muh toolchain: cuda.compute.reduce_into, scan, radix_sort, etc. Includes 204 .py files with full test coverage for all 27 algorithms - ci/ (163 files) — Build/test infrastructure build_cub.sh, test_cub.sh, build_and_test_targets.sh, matrix.yaml Directly maps to our [INFRA-CI] and [INFRA-BUILD] items - .agent/skills/ (7 files) — NVIDIA's own agent skills for CCCL cccl-style/SKILL.md, cccl-test/SKILL.md, sass-diff/SKILL.md - docs/ (491 files) — Official CCCL documentation CI references, CMake guides, Python compute docs, libcudacxx PTX docs - test/ (12 files) — Top-level integration tests (cuda_smoke, stdpar) - Root configs: .clang-format, .clang-tidy, CONTRIBUTING.md, pyproject.toml - CLAUDE.md symlink → AGENTS.md (NVIDIA's standard) cccl_upstream now mirrors full NVIDIA/cccl structure: Before: 42M (cub + thrust + libcudacxx + cudax + c + examples + benchmarks) After: 53M (+python +ci +docs +.agent +test +configs) This completes the CCCL base needed for: - [muh-bench] items: ci/util/build_and_test_targets.sh for targeted builds - [CCCL-verify] items: python/cuda_cccl/tests/ as reference implementations - [CCCL-test] items: ci/test_cub.sh, ci/test_thrust.sh - Agent workflow: .agent/skills/ for consistent style and test patterns
334 lines
11 KiB
Plaintext
334 lines
11 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "903704f7",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Compile-Time Analytics\n",
|
|
"\n",
|
|
"This notebook helps you:\n",
|
|
"\n",
|
|
"1. Run `ci/build_compile_time_bench.sh` from the repo root.\n",
|
|
"2. Load and inspect an all-header processing CSV.\n",
|
|
"3. Explore high-impact headers by TU coverage and average processing time.\n",
|
|
"4. Build combined ranking scores to identify optimization targets.\n",
|
|
"\n",
|
|
"Expected CSV columns include:\n",
|
|
"- `header_path`\n",
|
|
"- `include_tu_count`\n",
|
|
"- `avg_process_time_s`\n",
|
|
"- `total_process_time_s`\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "ad58db28",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"%pip install pandas matplotlib plotly nbformat"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "16ba6808",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import os\n",
|
|
"import shlex\n",
|
|
"import sys\n",
|
|
"from pathlib import Path\n",
|
|
"\n",
|
|
"import pandas as pd\n",
|
|
"\n",
|
|
"pd.set_option(\"display.max_colwidth\", 160)\n",
|
|
"pd.set_option(\"display.width\", 200)\n",
|
|
"pd.set_option(\"display.max_columns\", 20)\n",
|
|
"\n",
|
|
"REPO_ROOT = Path.cwd()\n",
|
|
"while REPO_ROOT != REPO_ROOT.parent and not (REPO_ROOT / \".git\").exists():\n",
|
|
" REPO_ROOT = REPO_ROOT.parent\n",
|
|
"\n",
|
|
"if not (REPO_ROOT / \".git\").exists():\n",
|
|
" raise RuntimeError(\n",
|
|
" \"Could not locate repo root (.git). Start notebook from inside the CCCL repo.\"\n",
|
|
" )\n",
|
|
"\n",
|
|
"print(f\"Repo root: {REPO_ROOT}\")\n",
|
|
"print(f\"Python executable: {sys.executable}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "373652c8",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# --- Run build_compile_time_bench.sh (file-processing mode) ---\n",
|
|
"import subprocess\n",
|
|
"from pathlib import Path\n",
|
|
"\n",
|
|
"if \"REPO_ROOT\" not in globals():\n",
|
|
" REPO_ROOT = Path.cwd()\n",
|
|
" while REPO_ROOT != REPO_ROOT.parent and not (REPO_ROOT / \".git\").exists():\n",
|
|
" REPO_ROOT = REPO_ROOT.parent\n",
|
|
"\n",
|
|
"output_csv = Path(os.environ.get(\"COMPILE_TIME_CSV\", \"/tmp/compile_time.csv\"))\n",
|
|
"cmd = [\n",
|
|
" \"bash\",\n",
|
|
" str(REPO_ROOT / \"ci\" / \"build_compile_time_bench.sh\"),\n",
|
|
" *shlex.split(os.environ.get(\"COMPILE_TIME_BUILD_ARGS\", \"\")),\n",
|
|
" \"--\",\n",
|
|
" \"-f\",\n",
|
|
" \"file-processing\",\n",
|
|
" \"-e\",\n",
|
|
" \"-n\",\n",
|
|
" os.environ.get(\"COMPILE_TIME_TOP_N\", \"5000\"),\n",
|
|
" \"--sort\",\n",
|
|
" \"total\",\n",
|
|
" \"--output-csv\",\n",
|
|
" str(output_csv),\n",
|
|
"]\n",
|
|
"\n",
|
|
"print(\"Command:\")\n",
|
|
"print(\" \" + \" \".join(shlex.quote(x) for x in cmd))\n",
|
|
"\n",
|
|
"subprocess.run(cmd, cwd=REPO_ROOT, check=True)\n",
|
|
"print(f\"\\nWrote: {output_csv}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "12ad4c5c",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# --- Load CSV ---\n",
|
|
"csv_path = Path(os.environ.get(\"COMPILE_TIME_CSV\", \"/tmp/compile_time.csv\"))\n",
|
|
"if not csv_path.exists():\n",
|
|
" raise FileNotFoundError(f\"Missing CSV: {csv_path}. Run the script first.\")\n",
|
|
"\n",
|
|
"df = pd.read_csv(csv_path)\n",
|
|
"\n",
|
|
"event_summary_cols = {\n",
|
|
" \"event_name\",\n",
|
|
" \"event_key\",\n",
|
|
" \"root_tu_count\",\n",
|
|
" \"selected_avg_per_root_tu_s\",\n",
|
|
" \"selected_total_s\",\n",
|
|
"}\n",
|
|
"required_cols = [\n",
|
|
" \"header_path\",\n",
|
|
" \"include_tu_count\",\n",
|
|
" \"avg_process_time_s\",\n",
|
|
" \"total_process_time_s\",\n",
|
|
"]\n",
|
|
"\n",
|
|
"if event_summary_cols.issubset(df.columns):\n",
|
|
" df[\"header_path\"] = df[\"event_key\"]\n",
|
|
" df[\"include_tu_count\"] = df[\"root_tu_count\"]\n",
|
|
" if (\n",
|
|
" \"avg_inclusive_per_root_tu_s\" in df.columns\n",
|
|
" and \"total_inclusive_s\" in df.columns\n",
|
|
" ):\n",
|
|
" df[\"avg_process_time_s\"] = df[\"avg_inclusive_per_root_tu_s\"]\n",
|
|
" df[\"total_process_time_s\"] = df[\"total_inclusive_s\"]\n",
|
|
" else:\n",
|
|
" df[\"avg_process_time_s\"] = df[\"selected_avg_per_root_tu_s\"]\n",
|
|
" df[\"total_process_time_s\"] = df[\"selected_total_s\"]\n",
|
|
"\n",
|
|
"missing = [c for c in required_cols if c not in df.columns]\n",
|
|
"if missing:\n",
|
|
" raise ValueError(\n",
|
|
" f\"CSV is not all-header processing output. Missing columns: {missing}. \"\n",
|
|
" \"Run the script cell above to regenerate /tmp/compile_time.csv.\"\n",
|
|
" )\n",
|
|
"\n",
|
|
"for col in [\"include_tu_count\", \"avg_process_time_s\", \"total_process_time_s\"]:\n",
|
|
" df[col] = pd.to_numeric(df[col], errors=\"coerce\").fillna(0)\n",
|
|
"\n",
|
|
"print(f\"Rows: {len(df):,}\")\n",
|
|
"print(f\"Columns: {list(df.columns)}\")\n",
|
|
"df.head(5)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "1a9b36a8",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# --- Quick top-N views ---\n",
|
|
"TOP_N = 5\n",
|
|
"\n",
|
|
"print(\"Top by avg_process_time_s\")\n",
|
|
"display(\n",
|
|
" df.nlargest(TOP_N, \"avg_process_time_s\")[\n",
|
|
" [\n",
|
|
" \"header_path\",\n",
|
|
" \"avg_process_time_s\",\n",
|
|
" \"include_tu_count\",\n",
|
|
" \"total_process_time_s\",\n",
|
|
" ]\n",
|
|
" ]\n",
|
|
")\n",
|
|
"\n",
|
|
"print(\"\\nTop by include_tu_count\")\n",
|
|
"display(\n",
|
|
" df.nlargest(TOP_N, \"include_tu_count\")[\n",
|
|
" [\n",
|
|
" \"header_path\",\n",
|
|
" \"include_tu_count\",\n",
|
|
" \"avg_process_time_s\",\n",
|
|
" \"total_process_time_s\",\n",
|
|
" ]\n",
|
|
" ]\n",
|
|
")\n",
|
|
"\n",
|
|
"print(\"\\nTop by impact score (include_tu_count * avg_process_time_s)\")\n",
|
|
"df_score = df.copy()\n",
|
|
"df_score[\"impact_score\"] = df_score[\"include_tu_count\"] * df_score[\"avg_process_time_s\"]\n",
|
|
"display(\n",
|
|
" df_score.nlargest(TOP_N, \"impact_score\")[\n",
|
|
" [\n",
|
|
" \"header_path\",\n",
|
|
" \"impact_score\",\n",
|
|
" \"include_tu_count\",\n",
|
|
" \"avg_process_time_s\",\n",
|
|
" \"total_process_time_s\",\n",
|
|
" ]\n",
|
|
" ]\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "174eabd4",
|
|
"metadata": {},
|
|
"source": [
|
|
"### How to read this plot\n",
|
|
"\n",
|
|
"- Each point is one header seen in all-mode profiling.\n",
|
|
"- **X axis (`include_tu_count`)**: how many generated public-header TUs include this header at least once.\n",
|
|
"- **Y axis (`avg_process_time_s`)**: average time spent processing that header per including TU.\n",
|
|
"- Headers near the **upper-right** are usually the best optimization candidates because they are both widespread and expensive per include."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "9ddc0725",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# --- Interactive scatter (hover shows header name) ---\n",
|
|
"\n",
|
|
"import plotly.express as px\n",
|
|
"\n",
|
|
"plot_df = df.copy()\n",
|
|
"\n",
|
|
"total_headers = len(plot_df)\n",
|
|
"total_public_headers = int(plot_df[\"include_tu_count\"].max())\n",
|
|
"\n",
|
|
"fig = px.scatter(\n",
|
|
" plot_df,\n",
|
|
" x=\"include_tu_count\",\n",
|
|
" y=\"avg_process_time_s\",\n",
|
|
" hover_name=\"header_path\",\n",
|
|
" hover_data={\n",
|
|
" \"include_tu_count\": True,\n",
|
|
" \"avg_process_time_s\": \":.6f\",\n",
|
|
" \"total_process_time_s\": \":.3f\",\n",
|
|
" \"header_path\": False,\n",
|
|
" },\n",
|
|
" opacity=0.6,\n",
|
|
" title=(\n",
|
|
" f\"Header include count vs avg processing time ({total_headers:,} total headers; \"\n",
|
|
" f\"coverage measured across {total_public_headers} public headers)\"\n",
|
|
" ),\n",
|
|
")\n",
|
|
"\n",
|
|
"fig.update_layout(\n",
|
|
" xaxis_title=(\n",
|
|
" \"TU coverage: number of public headers that include this header \"\n",
|
|
" f\"(out of {total_public_headers})\"\n",
|
|
" ),\n",
|
|
" yaxis_title=\"Average processing time per including TU (seconds)\",\n",
|
|
" height=900,\n",
|
|
")\n",
|
|
"fig.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "f429b934",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# --- Optional: run ctadvisor and parse expensive headers ---\n",
|
|
"run_ctadvisor = os.environ.get(\"COMPILE_TIME_RUN_CTADVISOR\") == \"1\"\n",
|
|
"CTADVISOR_ENTRIES = 10\n",
|
|
"CTADVISOR_THREADS = os.cpu_count() or 8\n",
|
|
"\n",
|
|
"trace_root = (\n",
|
|
" REPO_ROOT\n",
|
|
" / \"build\"\n",
|
|
" / os.environ.get(\"CCCL_BUILD_INFIX\", \"cuda13.1-gcc14\")\n",
|
|
" / os.environ.get(\"CCCL_COMPILE_TIME_PRESET\", \"all-dev\")\n",
|
|
" / \"compile_time\"\n",
|
|
" / \"raw_traces\"\n",
|
|
")\n",
|
|
"ctadvisor_cmd = [\n",
|
|
" \"ctadvisor\",\n",
|
|
" \"--trace-file-path\",\n",
|
|
" str(trace_root),\n",
|
|
" \"--header-advisor-entries\",\n",
|
|
" str(CTADVISOR_ENTRIES),\n",
|
|
" \"--thread-number\",\n",
|
|
" str(CTADVISOR_THREADS),\n",
|
|
"]\n",
|
|
"\n",
|
|
"if run_ctadvisor:\n",
|
|
" print(\"Command:\")\n",
|
|
" print(\" \" + \" \".join(shlex.quote(x) for x in ctadvisor_cmd))\n",
|
|
"\n",
|
|
" result = subprocess.run(\n",
|
|
" ctadvisor_cmd, cwd=REPO_ROOT, check=True, capture_output=True, text=True\n",
|
|
" )\n",
|
|
" print(result.stdout)\n",
|
|
"else:\n",
|
|
" print(\"Skipping ctadvisor. Set COMPILE_TIME_RUN_CTADVISOR=1 to run it.\")"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "cccl",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.12.3"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|