Skip to content

Commit a47cb8a

Browse files
committed
script addition
Signed-off-by: Akshay Tondak <aktondak@amd.com>
1 parent 2747cae commit a47cb8a

3 files changed

Lines changed: 225 additions & 29 deletions

File tree

archive/README.md

Lines changed: 78 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,103 @@
1-
# Runner Directory Archive Creation Guide
1+
# Archive Directory - NPU Platform Test Archives
22

3-
This directory contains test runners and benchmarks for different NPU platforms: `npu3`, `phx`, and `strx`. Each platform has its own subdirectory with specific test configurations and binaries.
3+
This directory contains test runners and benchmarks for different NPU platforms: `npu3`, `phx`, `strx`, and `ve2`. Each platform has its own subdirectory with specific test configurations and binaries.
44

55
## Directory Structure
66

77
```
8-
runner/
9-
├── npu3/ # NPU3 platform tests
10-
├── phx/ # Phoenix platform tests
11-
├── Strx/ # Strix platform tests
12-
└── ve2/ # Telluride platform tests
8+
archive/
9+
├── npu3/ # NPU3 platform tests
10+
│ └── xrt_smi_npu3.a # Generated archive
11+
├── phx/ # Phoenix platform tests
12+
│ └── xrt_smi_phx.a # Generated archive
13+
├── strx/ # Strix platform tests
14+
│ └── xrt_smi_strx.a # Generated archive
15+
├── ve2/ # Telluride platform tests
16+
│ └── xrt_smi_ve2.a # Generated archive
17+
└── build_archives.py # Archive creation script
1318
```
1419

15-
## Creating Archives
20+
## Creating Archives (Recommended)
1621

17-
Use the `ar` utility to create archives. **Note**: The `ar` utility preserves directory paths by default and does NOT automatically flatten file structure.
22+
Use the provided Python script for automated archive creation:
1823

19-
### Platform Archives
24+
### Basic Usage
2025

2126
```bash
22-
# Archive all NPU3 subdirectories
23-
(cd npu3 && find . -type f -print0 | xargs -0 ar -cr xrt_smi_npu3.a)
27+
# Create archives for all platforms
28+
python build_archives.py
2429

25-
# Archive all PHX subdirectories
26-
(cd phx && find . -type f -print0 | xargs -0 ar -cr xrt_smi_phx.a)
30+
# Create archive for specific platform
31+
python build_archives.py strx
2732

28-
# Archive all STRX subdirectories
29-
(cd strx && find . -type f -print0 | xargs -0 ar -cr xrt_smi_strx.a)
33+
# Create archives for multiple platforms
34+
python build_archives.py phx ve2 strx
35+
```
36+
37+
### Script Features
38+
39+
- **Recursive file collection**: Automatically includes files from subdirectories
40+
- **Flattened structure**: Creates archives with all files at root level
41+
- **Smart updates**: Only updates files newer than existing archive
42+
- **Change tracking**: Shows added, removed, and updated files
43+
- **Automatic exclusion**: Skips `.a` files to prevent self-inclusion
44+
45+
### Example Output
3046

31-
# Archive all VE2 subdirectories
32-
(cd ve2 && find . -type f -print0 | xargs -0 ar -cr xrt_smi_ve2.a)
47+
```
48+
Processing 1 folder(s)...
49+
Updating xrt_smi_strx.a from 25 files...
50+
✓ Updated: strx/xrt_smi_strx.a
51+
➕ New files added (2):
52+
+ firmware_log.json
53+
+ trace_events.json
54+
🔄 Files updated (3):
55+
~ config.json
56+
~ nop.elf
57+
~ validate.xclbin
58+
59+
SUMMARY:
60+
Archives processed: 1/1
61+
Total new files: 2
62+
Total updated files: 3
63+
```
64+
65+
## Manual Archive Creation (Alternative)
66+
67+
If you need to create archives manually without the script:
68+
69+
```bash
70+
# Archive all STRX subdirectories manually
71+
(cd strx && find . -type f ! -name "*.a" -print0 | xargs -0 ar -cr xrt_smi_strx.a)
72+
73+
# Archive all PHX subdirectories manually
74+
(cd phx && find . -type f ! -name "*.a" -print0 | xargs -0 ar -cr xrt_smi_phx.a)
3375
```
3476

3577
## File Types in Archives
3678

37-
Each test category typically contains:
79+
Each platform directory typically contains:
3880
- **ELF files** (`.elf`): Executable binaries for the NPU
39-
- **JSON files** (`.json`): Configuration profiles and recipes
81+
- **JSON files** (`.json`): Configuration profiles, recipes, and firmware logs
4082
- **XCLBIN files** (`.xclbin`): FPGA bitstream files
41-
- **Archive files** (`.a`): Static library files (XRT SMI)
83+
- **Other test files**: Various test configurations and data
4284

43-
## Archive Command Options
85+
## Archive Management
4486

45-
- `c`: Create archive
46-
- `r`: Insert files (replace if already exists)
47-
- The `ar` utility creates archives with all files flattened at the root level
87+
```bash
88+
# List contents of an archive
89+
ar -t strx/xrt_smi_strx.a
90+
91+
# Extract all files from an archive
92+
ar -x strx/xrt_smi_strx.a
93+
94+
# Get help for the Python script
95+
python build_archives.py --help
96+
```
4897

4998
## Notes
5099

51-
- Archives are created in the current working directory
52-
- Use `ar -t archive_name.a` to list contents of an archive
53-
- Use `ar -x archive_name.a` to extract all files from an archive
54-
- All files will be extracted to the current directory without preserving subdirectory structure
100+
- Archives are stored in their respective platform directories (e.g., `strx/xrt_smi_strx.a`)
101+
- All files are flattened to root level in archives (no directory structure preserved)
102+
- The Python script automatically excludes existing `.a` files to prevent circular inclusion
103+
- Use the Python script for consistent and automated archive management

archive/build_archives.py

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#!/usr/bin/env python3
2+
3+
import subprocess
4+
import argparse
5+
import shutil
6+
from pathlib import Path
7+
8+
def check_ar_utility():
9+
if not shutil.which('ar'):
10+
print("Error: 'ar' utility not found. Please install binutils package.")
11+
exit(1)
12+
13+
def get_archive_contents(archive_path):
14+
if not archive_path.exists():
15+
return set()
16+
result = subprocess.run(['ar', 't', str(archive_path)], capture_output=True, text=True)
17+
return set(f.strip() for f in result.stdout.strip().split('\n') if f.strip()) if result.returncode == 0 else set()
18+
19+
def create_archive(folder_path):
20+
if not folder_path.exists():
21+
print(f"Error: Folder {folder_path} does not exist")
22+
return False, [], []
23+
24+
# Get all files recursively from the folder and its subdirectories, excluding .a files
25+
files = list(folder_path.rglob('*'))
26+
files = [f for f in files if f.is_file() and f.suffix != '.a']
27+
28+
if not files:
29+
print(f"Error: Folder {folder_path} has no files")
30+
return False, [], []
31+
32+
output_name = f"xrt_smi_{folder_path.name}.a"
33+
output_path = folder_path / output_name # Store archive inside the folder itself
34+
old_files, archive_existed = get_archive_contents(output_path), output_path.exists()
35+
36+
print(f"{'Updating' if archive_existed else 'Creating'} {output_name} from {len(files)} files...")
37+
38+
file_paths = [str(f.absolute()) for f in files]
39+
40+
if archive_existed:
41+
# Check which files are newer than the archive before updating
42+
archive_mtime = output_path.stat().st_mtime
43+
updated_files = [f.name for f in files if f.name in old_files and f.stat().st_mtime > archive_mtime]
44+
45+
# Use 'ar u' (update) to only add files newer than those in archive
46+
result = subprocess.run(['ar', 'rus', str(output_path)] + file_paths,
47+
capture_output=True, text=True)
48+
action = "Updated"
49+
else:
50+
updated_files = []
51+
# Create new archive
52+
result = subprocess.run(['ar', 'rcs', str(output_path)] + file_paths,
53+
capture_output=True, text=True)
54+
action = "Created"
55+
56+
if result.returncode != 0:
57+
print(f"✗ Failed: {result.stderr}")
58+
return False, [], []
59+
60+
print(f"✓ {action}: {output_path}")
61+
62+
# Show what actually changed by comparing before/after
63+
new_files_set = get_archive_contents(output_path)
64+
added = new_files_set - old_files
65+
removed = old_files - new_files_set
66+
67+
if archive_existed:
68+
for files_list, symbol, label, emoji in [
69+
(added, "+", "New files added", "➕"),
70+
(removed, "-", "Files removed", "➖"),
71+
(updated_files, "~", "Files updated", "🔄")
72+
]:
73+
if files_list:
74+
print(f" {emoji} {label} ({len(files_list)}):")
75+
[print(f" {symbol} {file}") for file in sorted(files_list)]
76+
77+
if not added and not removed and not updated_files:
78+
print(f" 📄 No changes detected")
79+
80+
return True, list(added), updated_files
81+
else:
82+
print(f" 📦 Files added to new archive ({len(new_files_set)}):")
83+
[print(f" + {file}") for file in sorted(new_files_set)]
84+
return True, list(new_files_set), []
85+
86+
def print_help():
87+
print("""Archive Builder - Create .a archives from folders
88+
89+
USAGE: python build_archives.py [folders...]
90+
ARGUMENTS: folders - List of folder names (default: all folders in current directory)
91+
92+
EXAMPLES:
93+
python build_archives.py # Create archives for all folders
94+
python build_archives.py phx # Create archive for specific folder
95+
python build_archives.py phx ve2 # Create archives for multiple folders
96+
97+
OUTPUT: Archives created as xrt_smi_<foldername>.a""")
98+
99+
def main():
100+
check_ar_utility()
101+
parser = argparse.ArgumentParser(add_help=False)
102+
parser.add_argument('-h', '--help', action='store_true')
103+
parser.add_argument('folders', nargs='*', help='Folder names to create archives for')
104+
args = parser.parse_args()
105+
106+
if args.help:
107+
print_help()
108+
return 0
109+
110+
current_dir = Path(".")
111+
folder_names = args.folders or [d.name for d in current_dir.iterdir() if d.is_dir()]
112+
if not args.folders:
113+
print(f"No folders specified, processing all: {', '.join(folder_names)}")
114+
115+
folders = [current_dir / name for name in folder_names if (current_dir / name).exists()]
116+
[print(f"Warning: Folder {name} not found, skipping") for name in folder_names if not (current_dir / name).exists()]
117+
118+
if not folders:
119+
print("No valid folders found")
120+
return 1
121+
122+
print(f"Processing {len(folders)} folder(s)...")
123+
success, total_new, total_updated, archives_info = 0, 0, 0, []
124+
125+
for folder in folders:
126+
success_status, new_files, updated_files = create_archive(folder)
127+
if success_status:
128+
success += 1
129+
total_new += len(new_files)
130+
total_updated += len(updated_files)
131+
archives_info.append((f"xrt_smi_{folder.name}.a", new_files, updated_files))
132+
print()
133+
134+
print("=" * 60)
135+
print(f"SUMMARY:\nArchives processed: {success}/{len(folders)}\nTotal new files: {total_new}\nTotal updated files: {total_updated}")
136+
137+
if archives_info:
138+
print("\nArchive changes:")
139+
for archive_name, new_files, updated_files in archives_info:
140+
status = [f"{len(new_files)} new"] if new_files else []
141+
status += [f"{len(updated_files)} updated"] if updated_files else []
142+
print(f" {archive_name}: {', '.join(status) or 'no changes'}")
143+
144+
return 0 if success == len(folders) else 1
145+
146+
if __name__ == "__main__":
147+
exit(main())

archive/strx/xrt_smi_strx.a

27.3 KB
Binary file not shown.

0 commit comments

Comments
 (0)