ci : fix parsing of vgpr counts in hip-quality-check (#20987)
* scripts: hip: gcn-cdna-vgpr-check: fix parsing of vgpr counts when an amdclang Remark block is interlieved with another from a different process * Return warning ignore * obay pep8 inline double space before inline commets * add # noqa: NP100 for other prints too * Add script changes to cause autotrigger
This commit is contained in:
@@ -8,7 +8,8 @@ on:
|
|||||||
paths: [
|
paths: [
|
||||||
'.github/workflows/hip-quality-check.yml',
|
'.github/workflows/hip-quality-check.yml',
|
||||||
'**/*.cu',
|
'**/*.cu',
|
||||||
'**/*.cuh'
|
'**/*.cuh',
|
||||||
|
'scripts/hip/gcn-cdna-vgpr-check.py'
|
||||||
]
|
]
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -16,7 +17,8 @@ on:
|
|||||||
paths: [
|
paths: [
|
||||||
'.github/workflows/hip-quality-check.yml',
|
'.github/workflows/hip-quality-check.yml',
|
||||||
'**/*.cu',
|
'**/*.cu',
|
||||||
'**/*.cuh'
|
'**/*.cuh',
|
||||||
|
'scripts/hip/gcn-cdna-vgpr-check.py'
|
||||||
]
|
]
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
|
|||||||
@@ -2,37 +2,51 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
def parse_log_file(filepath):
|
def parse_log_file(filepath):
|
||||||
"""Parse log file and extract function VGPR usage."""
|
|
||||||
import re
|
|
||||||
|
|
||||||
functions = defaultdict(lambda: {'vgprs': 0, 'spill': 0, 'location': ''})
|
functions = defaultdict(lambda: {'vgprs': 0, 'spill': 0, 'location': ''})
|
||||||
|
func_stack = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(filepath, 'r') as f:
|
with open(filepath, 'r') as f:
|
||||||
content = f.read()
|
for line in f:
|
||||||
# Find all function entries with VGPR usage including location
|
# Match function name lines
|
||||||
pattern = r'([^:]+:\d+):.*?Function Name: (\S+).*?VGPRs: (\d+).*?VGPRs Spill: (\d+)'
|
func_match = re.search(r'remark: ([^:]+):(\d+):\d+: Function Name: (\S+)', line)
|
||||||
matches = re.findall(pattern, content, re.DOTALL)
|
if func_match:
|
||||||
|
location = func_match.group(1) + ':' + func_match.group(2)
|
||||||
|
func_name = func_match.group(3)
|
||||||
|
# Extract just the filename and line number
|
||||||
|
parts = location.split('/')
|
||||||
|
short_location = parts[-1] if len(parts) > 0 else location
|
||||||
|
functions[func_name]['location'] = short_location
|
||||||
|
# Push function onto stack with its location
|
||||||
|
func_stack.append({'name': func_name, 'location': location})
|
||||||
|
continue
|
||||||
|
|
||||||
for location, func_name, vgprs, spill in matches:
|
# Match VGPR usage lines (only if we have functions in stack)
|
||||||
functions[func_name]['vgprs'] = int(vgprs)
|
vgpr_match = re.search(r'remark: ([^:]+):(\d+):\d+:\s+VGPRs: (\d+)', line)
|
||||||
functions[func_name]['spill'] = int(spill)
|
if vgpr_match:
|
||||||
# Extract just the filename and line number
|
location = vgpr_match.group(1) + ':' + vgpr_match.group(2)
|
||||||
parts = location.split('/')
|
# Find the most recent function with matching location
|
||||||
if len(parts) > 0:
|
for i in range(len(func_stack) - 1, -1, -1):
|
||||||
short_location = parts[-1] # Get last part (filename)
|
if func_stack[i]['location'] == location:
|
||||||
# Check if there's a line number after filename
|
functions[func_stack[i]['name']]['vgprs'] = int(vgpr_match.group(3))
|
||||||
if ':' in short_location:
|
break
|
||||||
functions[func_name]['location'] = short_location
|
continue
|
||||||
else:
|
|
||||||
functions[func_name]['location'] = location
|
spill_match = re.search(r'remark: ([^:]+):(\d+):\d+:\s+VGPRs Spill: (\d+)', line)
|
||||||
else:
|
if spill_match:
|
||||||
functions[func_name]['location'] = location
|
location = spill_match.group(1) + ':' + spill_match.group(2)
|
||||||
|
# Find the most recent function with matching location
|
||||||
|
for i in range(len(func_stack) - 1, -1, -1):
|
||||||
|
if func_stack[i]['location'] == location:
|
||||||
|
functions[func_stack[i]['name']]['spill'] = int(spill_match.group(3))
|
||||||
|
break
|
||||||
|
continue
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print(f"Error: File {filepath} not found", file=sys.stderr) # noqa: NP100
|
print(f"Error: File {filepath} not found", file=sys.stderr) # noqa: NP100
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
return functions
|
return functions
|
||||||
@@ -40,7 +54,7 @@ def parse_log_file(filepath):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
print("Usage: ./vgpr_check.py <log_file>", file=sys.stderr) # noqa: NP100
|
print("Usage: ./vgpr_check.py <log_file>", file=sys.stderr) # noqa: NP100
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
log_file = sys.argv[1]
|
log_file = sys.argv[1]
|
||||||
@@ -123,6 +137,9 @@ def main():
|
|||||||
'_ZL18flash_attn_ext_f16ILi128ELi128ELi32ELi2ELb1ELb0EEvPKcS1_S1_S1_S1_PKiPfP15HIP_vector_typeIfLj2EEffffjfiS5_IjLj3EEiiiiiiiiiiiliiliiiiil',
|
'_ZL18flash_attn_ext_f16ILi128ELi128ELi32ELi2ELb1ELb0EEvPKcS1_S1_S1_S1_PKiPfP15HIP_vector_typeIfLj2EEffffjfiS5_IjLj3EEiiiiiiiiiiiliiliiiiil',
|
||||||
'_ZL18flash_attn_ext_f16ILi128ELi128ELi4ELi8ELb1ELb0EEvPKcS1_S1_S1_S1_PKiPfP15HIP_vector_typeIfLj2EEffffjfiS5_IjLj3EEiiiiiiiiiiiliiliiiiil',
|
'_ZL18flash_attn_ext_f16ILi128ELi128ELi4ELi8ELb1ELb0EEvPKcS1_S1_S1_S1_PKiPfP15HIP_vector_typeIfLj2EEffffjfiS5_IjLj3EEiiiiiiiiiiiliiliiiiil',
|
||||||
'_ZL18flash_attn_ext_f16ILi96ELi96ELi4ELi8ELb0ELb0EEvPKcS1_S1_S1_S1_PKiPfP15HIP_vector_typeIfLj2EEffffjfiS5_IjLj3EEiiiiiiiiiiiliiliiiiil',
|
'_ZL18flash_attn_ext_f16ILi96ELi96ELi4ELi8ELb0ELb0EEvPKcS1_S1_S1_S1_PKiPfP15HIP_vector_typeIfLj2EEffffjfiS5_IjLj3EEiiiiiiiiiiiliiliiiiil',
|
||||||
|
'_ZL18flash_attn_ext_vecILi128ELi2EL9ggml_type2ELS0_2ELb0EEvPKcS2_S2_S2_S2_PKiPfP15HIP_vector_typeIfLj2EEffffjfiS6_IjLj3EEiiiiiiiiiiiliiliiiiil',
|
||||||
|
'_ZL9mul_mat_qIL9ggml_type10ELi16ELb1EEvPKcPKiS4_S4_PfS5_iiiiiiiiiiiiiiiii',
|
||||||
|
'_ZL9mul_mat_qIL9ggml_type12ELi128ELb1EEvPKcPKiS4_S4_PfS5_iiiiiiiiiiiiiiiii'
|
||||||
}
|
}
|
||||||
|
|
||||||
functions = parse_log_file(log_file)
|
functions = parse_log_file(log_file)
|
||||||
@@ -134,7 +151,7 @@ def main():
|
|||||||
total_vgprs = int(data['vgprs']) + int(data['spill'])
|
total_vgprs = int(data['vgprs']) + int(data['spill'])
|
||||||
if total_vgprs > 256 and func_name in ignored and func_name not in printed_ignored:
|
if total_vgprs > 256 and func_name in ignored and func_name not in printed_ignored:
|
||||||
location = data.get('location', log_file)
|
location = data.get('location', log_file)
|
||||||
print(f"{location}: {func_name} - Total VGPRs: {total_vgprs} ({data['vgprs']} + {data['spill']}) [IGNORED]") # noqa: NP100
|
print(f"{location}: {func_name} - Total VGPRs: {total_vgprs} ({data['vgprs']} + {data['spill']}) [IGNORED]") # noqa: NP100
|
||||||
printed_ignored.add(func_name)
|
printed_ignored.add(func_name)
|
||||||
|
|
||||||
# Then print new functions with issues in red
|
# Then print new functions with issues in red
|
||||||
@@ -146,7 +163,7 @@ def main():
|
|||||||
# Print in red if not ignored
|
# Print in red if not ignored
|
||||||
color_code = "\033[91m" if func_name not in ignored else ""
|
color_code = "\033[91m" if func_name not in ignored else ""
|
||||||
reset_code = "\033[0m" if func_name not in ignored else ""
|
reset_code = "\033[0m" if func_name not in ignored else ""
|
||||||
print(f"{color_code}{location}: {func_name} - Total VGPRs: {total_vgprs} ({data['vgprs']} + {data['spill']}) {status}{reset_code}") # noqa: NP100
|
print(f"{color_code}{location}: {func_name} - Total VGPRs: {total_vgprs} ({data['vgprs']} + {data['spill']}) {status}{reset_code}") # noqa: NP100
|
||||||
if func_name not in ignored:
|
if func_name not in ignored:
|
||||||
found_issues = True
|
found_issues = True
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user