Skip to content

Commit 47c7c03

Browse files
illsilinassistant-librarian[bot]
authored andcommitted
[rocm-libraries] ROCm/rocm-libraries#4525 (commit 7f34b22)
[CK] Fix the launch_tests script. ## Motivation Fix the script that filters the tests. ## Technical Details There were several places where the paths had to be updated for the launch_tests script to work correctly. ## Test Plan <!-- Explain any relevant testing done to verify this PR. --> ## Test Result <!-- Briefly summarize test outcomes. --> ## Submission Checklist - [ ] Look over the contributing guidelines at https://github.com/ROCm/ROCm/blob/develop/CONTRIBUTING.md#pull-requests.
1 parent e1e2f7a commit 47c7c03

5 files changed

Lines changed: 297 additions & 212 deletions

File tree

script/dependency-parser/README.md

Lines changed: 123 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -8,166 +8,200 @@ The parser:
88
- Identifies all executables in the Ninja build.
99
- Maps object files to their source and header dependencies using `ninja -t deps`.
1010
- Constructs a reverse mapping from each file to all dependent executables.
11-
- Handles multi-executable dependencies and supports parallel processing for scalability.
11+
- Automatically detects monorepo structure (`projects/<name>/`) and scopes analysis accordingly.
1212
- Exports results in CSV and JSON formats for integration with other tools.
1313

1414
## Features
1515

1616
- **Comprehensive Dependency Tracking**: Captures direct source file dependencies and, critically, all included header files via `ninja -t deps`.
1717
- **Executable to Object Mapping**: Parses the `build.ninja` file to understand how executables are linked from object files.
18-
- **Object to Source/Header Mapping**: Uses `ninja -t deps` for each object file to get a complete list of its dependencies.
18+
- **Batch Dependency Extraction**: Runs a single `ninja -t deps` call (no arguments) to dump all dependency information at once, then filters in-memory. This avoids the massive overhead of per-object subprocess calls on large build files (e.g., a 246MB `build.ninja` with 29K+ objects completes in ~2 seconds instead of ~54 minutes).
19+
- **Monorepo Awareness**: Automatically detects `projects/<project>/` paths, strips them to project-relative paths, and scopes `git diff` to only the relevant subtree.
1920
- **File to Executable Inversion**: Inverts the dependency graph to map each file to the set of executables that depend on it.
20-
- **Parallel Processing**: Utilizes a `ThreadPoolExecutor` to run `ninja -t deps` commands in parallel, significantly speeding up analysis for projects with many object files.
21-
- **Filtering**: Option to filter out system files and focus on project-specific dependencies.
21+
- **Filtering**: Filters out system files (`/usr/`, `/opt/rocm/`, etc.) and focuses on project-specific dependencies.
2222
- **Multiple Output Formats**:
23-
- **CSV**: `enhanced_file_executable_mapping.csv` - A comma-separated values file where each row lists a file and a semicolon-separated list of executables that depend on it.
24-
- **JSON**: `enhanced_dependency_mapping.json` - A JSON file representing a dictionary where keys are file paths and values are lists of dependent executables.
23+
- **CSV**: `enhanced_file_executable_mapping.csv` - Each row lists a file and a semicolon-separated list of dependent executables.
24+
- **JSON**: `enhanced_dependency_mapping.json` - Includes file-to-executable mapping, executable-to-file mapping, repo metadata, and statistics.
2525
- **Robust Error Handling**: Includes error handling for missing files and failed subprocess commands.
2626

2727
## Prerequisites
2828

2929
- **Python 3.7+**
3030
- **Ninja build system**: The `ninja` executable must be in the system's PATH or its path provided as an argument.
31-
- A **Ninja build directory** containing a `build.ninja` file and the compiled object files. The project should have been built at least once.
31+
- A **Ninja build directory** containing a `build.ninja` file. The project should have been built at least once (even partially) so that `ninja -t deps` has dependency data.
32+
33+
## Quick Start with launch_tests.sh
34+
35+
The easiest way to use this tool is via the `launch_tests.sh` wrapper script:
36+
37+
```bash
38+
# From the monorepo root (or anywhere):
39+
script/launch_tests.sh /path/to/build-dir
40+
41+
# Uses default build dir (<CK_ROOT>/build) if no argument given:
42+
script/launch_tests.sh
43+
```
44+
45+
This script:
46+
1. Discovers the git root (monorepo root) automatically.
47+
2. Runs the dependency parser against `build.ninja`.
48+
3. Runs `git diff` between `origin/develop` and the current branch (scoped to CK files only).
49+
4. Maps changed files to affected tests/examples.
50+
5. Runs the affected tests via `ctest` in chunks.
51+
52+
Environment variables:
53+
- `CTEST_CHUNK_SIZE`: Number of tests per ctest invocation (default: 10).
54+
- `CTEST_FAIL_FAST`: Set to `true` to stop on first failure (default: `false`).
3255

3356
## Using CMake with Ninja
3457

35-
To use this tool effectively, your C++ project should be configured with CMake to generate Ninja build files and dependency information. Follow these steps:
58+
To use this tool effectively, your C++ project should be configured with CMake to generate Ninja build files:
3659

37-
1. **Configure CMake to use Ninja and generate dependencies:**
60+
1. **Configure CMake to use Ninja:**
3861
```bash
39-
cmake -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Release /path/to/your/source
62+
cmake -G Ninja \
63+
-DCMAKE_PREFIX_PATH=/opt/rocm \
64+
-DCMAKE_CXX_COMPILER=/opt/rocm/bin/hipcc \
65+
-DCMAKE_BUILD_TYPE=Release \
66+
-DGPU_TARGETS="gfx942" \
67+
/path/to/composablekernel
4068
```
41-
- The `-G Ninja` flag tells CMake to generate Ninja build files.
42-
- `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON` is optional but useful for other tooling.
43-
- Ensure your CMakeLists.txt uses `target_include_directories` and proper dependency declarations for accurate results.
4469

45-
2. **Build your project with Ninja:**
70+
2. **Build your project (full or partial):**
4671
```bash
72+
# Full build
4773
ninja
74+
75+
# Or build specific targets
76+
ninja example_gemm_xdl_fp16 example_gemm_xdl_fp16_v3
4877
```
49-
- This step is required to generate all object files and dependency information (`.d` files) that the parser relies on.
78+
The parser only extracts dependencies for objects that were actually built.
5079

51-
3. **Run the dependency parser tool:**
80+
3. **Run the dependency parser:**
5281
```bash
53-
python main.py parse /path/to/build.ninja --workspace-root /path/to/your/workspace
82+
python main.py parse /path/to/build/build.ninja --workspace-root /path/to/monorepo-root
5483
```
5584

56-
**Note:** Always run Ninja to ensure all dependencies are up to date before invoking the parser. If you change source files or headers, re-run Ninja first.
85+
**Note:** `--workspace-root` should point to the **git root** (monorepo root) for correct monorepo detection. If omitted, it defaults to `..` relative to the build directory.
5786

5887
## Usage
5988

60-
All features are available via the unified main.py CLI:
89+
All features are available via the unified `main.py` CLI:
6190

6291
```bash
63-
# Dependency parsing (now supports --workspace-root)
64-
python main.py parse examples/build-ninja/build.ninja --workspace-root /path/to/your/workspace
92+
# Dependency parsing
93+
python main.py parse /path/to/build.ninja --workspace-root /path/to/monorepo-root
6594
66-
# Selective test filtering
95+
# Selective test filtering (between git refs)
6796
python main.py select enhanced_dependency_mapping.json <ref1> <ref2> [--all | --test-prefix] [--output <output_json>]
6897
69-
# Code auditing
98+
# Code auditing (list all files and their dependent executables)
7099
python main.py audit enhanced_dependency_mapping.json
71100
72-
# Build optimization
101+
# Build optimization (list affected executables for specific changed files)
73102
python main.py optimize enhanced_dependency_mapping.json <changed_file1> [<changed_file2> ...]
74103
```
75104
76-
**Arguments:**
77-
78-
1. `<path_to_build.ninja>`: (Required) The full path to the `build.ninja` file within your Ninja build directory.
79-
2. `[--workspace-root <workspace_root>]`: (Optional, recommended) The root directory of your workspace.
80-
3. `[path_to_ninja_executable]`: (Optional) The path to the `ninja` executable if it's not in your system's PATH. Defaults to `ninja`.
105+
### Parse arguments
81106
82-
**Example:**
107+
| Argument | Required | Description |
108+
|----------|----------|-------------|
109+
| `build_ninja` | Yes | Path to the `build.ninja` file |
110+
| `--workspace-root` | No | Root of the workspace/monorepo (default: `..`) |
111+
| `--ninja` | No | Path to the ninja executable (default: `ninja`) |
83112
84-
```bash
85-
# Assuming your build directory is 'build-ninja' and it contains 'build.ninja'
86-
python src/enhanced_ninja_parser.py build-ninja/build.ninja
87-
88-
# With custom workspace root
89-
python src/enhanced_ninja_parser.py build-ninja/build.ninja ninja /path/to/your/workspace
113+
### Select arguments
90114
91-
# If ninja is installed in a custom location
92-
python src/enhanced_ninja_parser.py /path/to/project/build/build.ninja /usr/local/bin/ninja
93-
```
115+
| Argument | Required | Description |
116+
|----------|----------|-------------|
117+
| `depmap_json` | Yes | Path to `enhanced_dependency_mapping.json` |
118+
| `ref1` | Yes | Source git ref (branch or commit SHA) |
119+
| `ref2` | Yes | Target git ref (branch or commit SHA) |
120+
| `--all` | No | Include all affected executables (default) |
121+
| `--test-prefix` | No | Only include executables starting with `test_` |
122+
| `--output` | No | Output JSON file (default: `tests_to_run.json`) |
94123
95124
## How It Works
96125
97-
1. **Initialization**:
98-
* Takes the path to `build.ninja` and optionally the `ninja` executable.
99-
* Sets up internal data structures to store mappings.
100-
101-
2. **Build File Parsing (`_parse_build_file`)**:
102-
* Reads the `build.ninja` file.
103-
* Uses regular expressions to identify rules for linking executables (e.g., `build my_exe: link main.o utils.o`) and compiling object files (e.g., `build main.o: cxx ../src/main.cpp`).
104-
* Populates `executable_to_objects` (mapping an executable name to a list of its .o files) and `object_to_source` (mapping an object file to its primary source file).
105-
106-
3. **Object Dependency Extraction (`_extract_all_object_dependencies`)**:
107-
* Iterates through all unique object files identified in the previous step.
108-
* For each object file, it calls `_get_object_dependencies`.
109-
* This process is parallelized using `ThreadPoolExecutor` for efficiency. Each call to `ninja -t deps` runs in a separate thread.
110-
111-
4. **Individual Object Dependencies (`_get_object_dependencies`)**:
112-
* For a given object file (e.g., `main.o`), it runs the command: `ninja -t deps main.o` in the build directory.
113-
* This command outputs a list of all files that `main.o` depends on, including its primary source (`main.cpp`) and all headers (`*.h`, `*.hpp`) it includes directly or indirectly.
114-
* The output is parsed, cleaned, and returned as a list of file paths.
115-
116-
5. **Building Final File-to-Executable Mapping (`_build_file_to_executable_mapping`)**:
117-
* This is the core inversion step. It iterates through each executable and its associated object files.
118-
* For each object file, it looks up the full list of its dependencies (source and headers) obtained in step 3 & 4.
119-
* For every dependent file found, it adds the current executable to that file's entry in the `file_to_executables` dictionary.
120-
* If `filter_project_files` is enabled, it checks each dependency against a list of common system paths (e.g., `/usr/include`, `_deps/`) and excludes them if they match.
121-
122-
6. **Filtering (`_is_project_file`)**:
123-
* A helper function to determine if a given file path is likely a project file or a system/external library file. This helps in focusing the dependency map on the user's own codebase.
124-
125-
7. **Output Generation**:
126-
* **`export_to_csv(csv_file)`**: Writes the `file_to_executables` mapping to a CSV file. Each row contains a file path and a semicolon-delimited string of executable names.
127-
* **`export_to_json(json_file)`**: Dumps the `file_to_executables` mapping (where the set of executables is converted to a list) into a JSON file.
128-
* **`print_summary()`**: Prints a summary of the findings, including the number of executables, object files, source files, and header files mapped.
126+
1. **Build File Parsing (`_parse_build_file`)**:
127+
* Reads the `build.ninja` file (~246MB for the full CK monorepo build).
128+
* Uses regular expressions to identify executable link rules and object compilation rules.
129+
* Populates `executable_to_objects` and `object_to_source` mappings.
130+
131+
2. **Batch Dependency Extraction (`_extract_object_dependencies`)**:
132+
* Runs a single `ninja -t deps` command (no arguments) which dumps all dependency information for every built object file.
133+
* Parses the output and filters to only the objects found in `object_to_source`.
134+
* Strips the workspace root prefix from absolute paths to produce project-relative paths.
135+
136+
3. **Monorepo Path Detection (`_build_file_to_executable_mapping`)**:
137+
* Applies a regex to detect `projects/<project_name>/` in dependency paths.
138+
* Strips the monorepo prefix so paths are relative to the CK project root (e.g., `include/ck/ck.hpp`).
139+
* Records the detected project name for use by the selective test filter.
140+
141+
4. **File Filtering (`_is_project_file`)**:
142+
* Excludes system files (`/usr/`, `/opt/rocm/`, etc.).
143+
* Includes files in known CK directories (`include/`, `library/`, `test/`, `example/`, etc.).
144+
* Also recognizes monorepo-prefixed paths (`projects/composablekernel/include/`, etc.).
145+
146+
5. **Selective Test Filtering (`selective_test_filter.py`)**:
147+
* Loads the dependency mapping JSON.
148+
* Runs `git diff --name-only` between two refs, scoped to `projects/<project>/` when in monorepo mode.
149+
* Strips the monorepo prefix from changed file paths.
150+
* Looks up each changed file in the dependency map to find affected executables.
151+
* Exports the list of tests to run as JSON.
129152
130153
## Output Files
131154
132-
Running the script will generate two files in the same directory as the input `build.ninja` file:
155+
Running the parser generates two files in the build directory:
133156
134157
- **`enhanced_file_executable_mapping.csv`**:
135158
```csv
136-
File,Executables
137-
/path/to/project/src/main.cpp,my_exe_1;my_exe_2
138-
/path/to/project/include/utils.h,my_exe_1;another_test
139-
...
159+
source_file,executables
160+
"include/ck/ck.hpp","bin/example_gemm_xdl_fp16;bin/example_gemm_xdl_fp16_v3"
161+
"example/01_gemm/gemm_xdl_fp16.cpp","bin/example_gemm_xdl_fp16"
140162
```
141163
142164
- **`enhanced_dependency_mapping.json`**:
143165
```json
144166
{
145-
"/path/to/project/src/main.cpp": ["my_exe_1", "my_exe_2"],
146-
"/path/to/project/include/utils.h": ["my_exe_1", "another_test"],
147-
...
167+
"repo": {
168+
"type": "monorepo",
169+
"project": "composablekernel"
170+
},
171+
"file_to_executables": {
172+
"include/ck/ck.hpp": ["bin/example_gemm_xdl_fp16", "bin/example_gemm_xdl_fp16_v3"],
173+
"example/01_gemm/gemm_xdl_fp16.cpp": ["bin/example_gemm_xdl_fp16"]
174+
},
175+
"executable_to_files": {
176+
"bin/example_gemm_xdl_fp16": ["include/ck/ck.hpp", "example/01_gemm/gemm_xdl_fp16.cpp"]
177+
},
178+
"statistics": {
179+
"total_files": 180,
180+
"total_executables": 20403,
181+
"total_object_files": 29530,
182+
"files_with_multiple_executables": 140
183+
}
148184
}
149185
```
150186
151187
## Use Cases
152188
153-
- **Impact Analysis**: Determine which executables (especially tests) need to be rebuilt or re-run when a specific source or header file changes.
154-
- **Build Optimization**: Understand the dependency structure to potentially optimize build times.
189+
- **Selective CI/CD Testing**: Run only the tests affected by a PR's changes, cutting CI time dramatically.
190+
- **Impact Analysis**: Determine which executables need to be rebuilt when a header changes.
191+
- **Build Optimization**: Identify which targets are affected by a set of file changes.
155192
- **Code Auditing**: Get a clear overview of how files are used across different executables.
156-
- **Selective Testing**: Integrate with CI/CD systems to run only the tests affected by a given set of changes.
157193
158194
## Limitations
159195
160196
- Relies on the accuracy of Ninja's dependency information (`ninja -t deps`). If the build system doesn't correctly generate `.d` (dependency) files, the header information might be incomplete.
161-
- The definition of "project file" vs. "system file" is based on a simple path-based heuristic and might need adjustment for specific project structures.
162-
- Performance for extremely large projects (tens of thousands of object files) might still be a consideration, though parallelization helps significantly.
197+
- Only objects that have been **actually built** will have dependency data. A partial build means partial coverage of the dependency map.
198+
- The definition of "project file" vs. "system file" is based on a path-based heuristic and might need adjustment for other project structures.
163199
164200
## Troubleshooting
165201
166-
- **"ninja: command not found"**: Ensure `ninja` is installed and in your PATH, or provide the full path to the executable as the second argument.
202+
- **"ninja: command not found"**: Ensure `ninja` is installed and in your PATH, or provide the full path via `--ninja`.
167203
- **"build.ninja not found"**: Double-check the path to your `build.ninja` file.
168204
- **Empty or Incomplete Output**:
169205
* Make sure the project has been successfully built at least once. `ninja -t deps` relies on information generated during the build.
170-
* Verify that your CMake (or other meta-build system) is configured to generate dependency files for Ninja.
171-
- **Slow Performance**: For very large projects, the number of `ninja -t deps` calls can be substantial. While parallelized, it can still take time. Consider if all object files truly need to be analyzed or if a subset is sufficient for your needs.
172-
173-
This tool provides a powerful way to gain deep insights into your Ninja project's dependency structure, enabling more intelligent build and test workflows.
206+
* Verify that your CMake is configured to generate dependency files for Ninja (`-G Ninja`).
207+
- **JSON shows `"type": "component"` instead of `"monorepo"`**: Ensure `--workspace-root` points to the **git/monorepo root**, not the CK project root. The parser needs to see `projects/<name>/` in the dependency paths to detect monorepo mode.

0 commit comments

Comments
 (0)