Skip to content

Commit 96620d8

Browse files
authored
Use nexus Python package (#158)
1 parent 60d5276 commit 96620d8

File tree

4 files changed

+74
-45
lines changed

4 files changed

+74
-45
lines changed

pyproject.toml

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,19 @@ readme = "README.md"
1515
requires-python = ">=3.9"
1616

1717
# Python dependencies
18-
dependencies = ["tomli", "tabulate", "ml_dtypes", "dspy==2.6.27", "pandas", "duckdb", "rich", "pytest", "litellm[proxy]", "rpds-py"]
18+
dependencies = [
19+
"tomli",
20+
"tabulate",
21+
"ml_dtypes",
22+
"dspy==2.6.27",
23+
"pandas",
24+
"duckdb",
25+
"rich",
26+
"pytest",
27+
"litellm[proxy]",
28+
"rpds-py",
29+
"nexus @ git+https://github.com/AMDResearch/nexus.git@main",
30+
]
1931

2032
[tool.setuptools]
2133
package-dir = {"" = "src"}
@@ -39,19 +51,6 @@ python3 -m pip install --ignore-installed blinker &&
3951
python3 -m pip install -r requirements.txt
4052
"""
4153

42-
43-
[tool.nexus]
44-
git = "https://github.com/AMDResearch/nexus.git"
45-
branch = "main"
46-
build_command = """
47-
export CC=${ROCM_PATH}/bin/hipcc
48-
export CXX=${ROCM_PATH}/bin/hipcc
49-
cmake -B build -DCMAKE_PREFIX_PATH=/opt/rocm\
50-
-DLLVM_INSTALL_DIR=/opt/rocm/llvm\
51-
-DCMAKE_BUILD_TYPE=Debug
52-
cmake --build build --parallel 16
53-
"""
54-
5554
[project.optional-dependencies]
5655
dev = [
5756
"ruff==0.3.0",

src/accordo/validator.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,15 @@ def __init__(
139139

140140
# Auto-detect accordo_path if not provided
141141
if accordo_path is None:
142-
# Try to find it relative to this file
142+
# Find it relative to this file (accordo package directory)
143143
accordo_dir = Path(__file__).parent
144144
if (accordo_dir / "build").exists() or (accordo_dir / "CMakeLists.txt").exists():
145145
accordo_path = accordo_dir
146146
else:
147-
# Try environment variable
148-
from intelliperf.utils.env import get_accordo_path
149-
150-
accordo_path = Path(get_accordo_path())
147+
raise RuntimeError(
148+
f"Could not find Accordo build directory. Expected at {accordo_dir}. "
149+
"Please build Accordo first or specify accordo_path explicitly."
150+
)
151151

152152
self.accordo_path = Path(accordo_path)
153153
logging.debug(f"Accordo path: {self.accordo_path}")

src/intelliperf/core/application.py

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
from intelliperf.utils import process
3535
from intelliperf.utils.env import (
3636
get_guided_tuning_path,
37-
get_nexus_path,
3837
get_rocprofiler_path,
3938
)
4039
from intelliperf.utils.process import capture_subprocess_output, exit_on_fail
@@ -224,26 +223,65 @@ def clone(self):
224223
)
225224

226225
def collect_source_code(self):
227-
nexus_directory = get_nexus_path()
228-
lib = os.path.join(nexus_directory, "build", "lib", "libnexus.so")
229-
env = os.environ.copy()
230-
231-
with tempfile.TemporaryDirectory() as tmp:
232-
json_result_file = os.path.join(tmp, "nexus_output.json")
233-
234-
env["HSA_TOOLS_LIB"] = lib
235-
env["NEXUS_LOG_LEVEL"] = "2"
236-
env["NEXUS_OUTPUT_FILE"] = json_result_file
237-
env["TRITON_ALWAYS_COMPILE"] = "1"
238-
env["TRITON_DISABLE_LINE_INFO"] = "0"
239-
capture_subprocess_output(self.get_app_cmd(), new_env=env, working_directory=self.get_project_directory())
240-
241-
if os.path.exists(json_result_file):
242-
df_results = json.loads(open(json_result_file).read())
226+
"""
227+
Collect source code for GPU kernels using Nexus.
228+
229+
Returns:
230+
dict: Dictionary containing kernel information with assembly, HIP source, files, and line numbers
231+
"""
232+
try:
233+
from nexus import Nexus
234+
except ImportError:
235+
logging.error("Nexus Python API not found. Please install it: pip install git+https://github.com/AMDResearch/nexus.git@main")
236+
return {"kernels": {}}
237+
238+
try:
239+
# Map Python logging level to Nexus log level
240+
# Python: NOTSET=0, DEBUG=10, INFO=20, WARNING=30, ERROR=40, CRITICAL=50
241+
# Nexus: 0=none, 1=info, 2=warning, 3=error, 4=detail
242+
current_level = logging.getLogger().getEffectiveLevel()
243+
if current_level <= logging.DEBUG:
244+
nexus_log_level = 4 # detail (most verbose)
245+
elif current_level <= logging.INFO:
246+
nexus_log_level = 1 # info
247+
elif current_level <= logging.WARNING:
248+
nexus_log_level = 2 # warning
243249
else:
244-
df_results = {"kernels": {}}
250+
nexus_log_level = 0 # none
251+
252+
# Create Nexus tracer with inherited log level
253+
nexus = Nexus(log_level=nexus_log_level)
254+
255+
# Additional environment for Triton kernels
256+
triton_env = {
257+
"TRITON_ALWAYS_COMPILE": "1",
258+
"TRITON_DISABLE_LINE_INFO": "0",
259+
}
260+
261+
# Run the application and capture kernel trace
262+
trace = nexus.run(
263+
command=self.get_app_cmd(),
264+
env=triton_env,
265+
cwd=self.get_project_directory(),
266+
)
267+
268+
# Convert trace to the expected format
269+
df_results = {"kernels": {}}
270+
for kernel in trace:
271+
df_results["kernels"][kernel.name] = {
272+
"assembly": kernel.assembly,
273+
"hip": kernel.hip,
274+
"files": kernel.files,
275+
"lines": kernel.lines,
276+
"signature": kernel.signature,
277+
}
278+
245279
return df_results
246280

281+
except Exception as e:
282+
logging.error(f"Failed to collect source code with Nexus: {e}")
283+
return {"kernels": {}}
284+
247285
def get_binary_absolute_path(self):
248286
if self.get_project_directory() != "":
249287
binary = self.get_app_cmd_without_args()

src/intelliperf/utils/env.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,10 @@ def get_guided_tuning_path():
3434
return (Path(__file__).resolve().parent / "../../../external/guided-tuning").resolve()
3535

3636

37-
def get_accordo_path():
38-
return (Path(__file__).resolve().parent / "../../accordo").resolve()
39-
40-
4137
def get_rocprofiler_path():
4238
return (Path(__file__).resolve().parent / "../../../external/rocprofiler-compute/src").resolve()
4339

4440

45-
def get_nexus_path():
46-
return (Path(__file__).resolve().parent / "../../../external/nexus").resolve()
47-
48-
4941
def get_llm_api_key():
5042
llm_key = os.environ.get("LLM_GATEWAY_KEY")
5143
if not llm_key:

0 commit comments

Comments
 (0)