4 changed files with 699 additions and 0 deletions
@ -1,3 +1,6 @@
@@ -1,3 +1,6 @@
|
||||
build |
||||
.vs |
||||
.clangd |
||||
test |
||||
settings.json |
||||
launch.json |
||||
|
@ -0,0 +1,215 @@
@@ -0,0 +1,215 @@
|
||||
## Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved. |
||||
## |
||||
## Redistribution and use in source and binary forms, with or without |
||||
## modification, are permitted provided that the following conditions |
||||
## are met: |
||||
## * Redistributions of source code must retain the above copyright |
||||
## notice, this list of conditions and the following disclaimer. |
||||
## * Redistributions in binary form must reproduce the above copyright |
||||
## notice, this list of conditions and the following disclaimer in the |
||||
## documentation and/or other materials provided with the distribution. |
||||
## * Neither the name of NVIDIA CORPORATION nor the names of its |
||||
## contributors may be used to endorse or promote products derived |
||||
## from this software without specific prior written permission. |
||||
## |
||||
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY |
||||
## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
||||
## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
## |
||||
## For additional information on the license terms, see the CUDA EULA at |
||||
## https://docs.nvidia.com/cuda/eula/index.html |
||||
|
||||
import os |
||||
import sys |
||||
import json |
||||
import subprocess |
||||
import argparse |
||||
from pathlib import Path |
||||
|
||||
def normalize_exe_name(name): |
||||
"""Normalize executable name across platforms by removing .exe if present""" |
||||
return Path(name).stem |
||||
|
||||
def load_args_config(config_file): |
||||
"""Load arguments configuration from JSON file""" |
||||
if not config_file or not os.path.exists(config_file): |
||||
return {} |
||||
|
||||
try: |
||||
with open(config_file, 'r') as f: |
||||
config = json.load(f) |
||||
|
||||
# Validate the config format |
||||
if not isinstance(config, dict): |
||||
print("Warning: Config file must contain a dictionary/object") |
||||
return {} |
||||
|
||||
return config |
||||
except json.JSONDecodeError: |
||||
print("Warning: Failed to parse config file as JSON") |
||||
return {} |
||||
except Exception as e: |
||||
print(f"Warning: Error reading config file: {str(e)}") |
||||
return {} |
||||
|
||||
def find_executables(root_dir): |
||||
"""Find all executable files recursively""" |
||||
executables = [] |
||||
|
||||
for path in Path(root_dir).rglob('*'): |
||||
# Skip directories |
||||
if not path.is_file(): |
||||
continue |
||||
|
||||
# Check if file is executable |
||||
if os.access(path, os.X_OK): |
||||
# Skip if it's a library file |
||||
if path.suffix.lower() in ('.dll', '.so', '.dylib'): |
||||
continue |
||||
executables.append(path) |
||||
|
||||
return executables |
||||
|
||||
def run_test(executable, output_dir, args_config, global_args=None): |
||||
"""Run a single test and capture output""" |
||||
exe_path = str(executable) |
||||
exe_name = executable.name |
||||
base_name = normalize_exe_name(exe_name) |
||||
|
||||
# Check if this executable should be skipped |
||||
if base_name in args_config and args_config[base_name].get("skip", False): |
||||
print(f"Skipping {exe_name} (marked as skip in config)") |
||||
return 0 |
||||
|
||||
# Get argument sets for this executable |
||||
arg_sets = [] |
||||
if base_name in args_config: |
||||
config = args_config[base_name] |
||||
if "args" in config: |
||||
# Single argument set (backwards compatibility) |
||||
if isinstance(config["args"], list): |
||||
arg_sets.append(config["args"]) |
||||
else: |
||||
print(f"Warning: Arguments for {base_name} must be a list") |
||||
elif "runs" in config: |
||||
# Multiple argument sets |
||||
for run in config["runs"]: |
||||
if isinstance(run.get("args", []), list): |
||||
arg_sets.append(run.get("args", [])) |
||||
else: |
||||
print(f"Warning: Arguments for {base_name} run must be a list") |
||||
|
||||
# If no specific args defined, run once with no args |
||||
if not arg_sets: |
||||
arg_sets.append([]) |
||||
|
||||
# Run for each argument set |
||||
failed = False |
||||
run_number = 1 |
||||
for args in arg_sets: |
||||
# Create output file name with run number if multiple runs |
||||
if len(arg_sets) > 1: |
||||
output_file = os.path.abspath(f"{output_dir}/APM_{exe_name}.run{run_number}.txt") |
||||
print(f"Running {exe_name} (run {run_number}/{len(arg_sets)})") |
||||
else: |
||||
output_file = os.path.abspath(f"{output_dir}/APM_{exe_name}.txt") |
||||
print(f"Running {exe_name}") |
||||
|
||||
try: |
||||
# Prepare command with arguments |
||||
cmd = [f"./{exe_name}"] |
||||
cmd.extend(args) |
||||
|
||||
# Add global arguments if provided |
||||
if global_args: |
||||
cmd.extend(global_args) |
||||
|
||||
print(f" Command: {' '.join(cmd)}") |
||||
|
||||
# Store current directory |
||||
original_dir = os.getcwd() |
||||
|
||||
try: |
||||
# Change to executable's directory |
||||
os.chdir(os.path.dirname(exe_path)) |
||||
|
||||
# Run the executable and capture output |
||||
with open(output_file, 'w') as f: |
||||
result = subprocess.run( |
||||
cmd, |
||||
stdout=f, |
||||
stderr=subprocess.STDOUT, |
||||
timeout=300 # 5 minute timeout |
||||
) |
||||
|
||||
if result.returncode != 0: |
||||
failed = True |
||||
print(f" Test completed with return code {result.returncode}") |
||||
|
||||
finally: |
||||
# Always restore original directory |
||||
os.chdir(original_dir) |
||||
|
||||
except subprocess.TimeoutExpired: |
||||
print(f"Error: {exe_name} timed out after 5 minutes") |
||||
failed = True |
||||
except Exception as e: |
||||
print(f"Error running {exe_name}: {str(e)}") |
||||
failed = True |
||||
|
||||
run_number += 1 |
||||
|
||||
return 1 if failed else 0 |
||||
|
||||
def main(): |
||||
parser = argparse.ArgumentParser(description='Run all executables and capture output') |
||||
parser.add_argument('--dir', default='.', help='Root directory to search for executables') |
||||
parser.add_argument('--config', help='JSON configuration file for executable arguments') |
||||
parser.add_argument('--output', default='.', # Default to current directory |
||||
help='Output directory for test results') |
||||
parser.add_argument('--args', nargs=argparse.REMAINDER, |
||||
help='Global arguments to pass to all executables') |
||||
args = parser.parse_args() |
||||
|
||||
# Create output directory if it doesn't exist |
||||
if args.output: |
||||
os.makedirs(args.output, exist_ok=True) |
||||
|
||||
# Load arguments configuration |
||||
args_config = load_args_config(args.config) |
||||
|
||||
executables = find_executables(args.dir) |
||||
if not executables: |
||||
print("No executables found!") |
||||
return 1 |
||||
|
||||
print(f"Found {len(executables)} executables") |
||||
|
||||
failed = [] |
||||
for exe in executables: |
||||
ret_code = run_test(exe, args.output, args_config, args.args) |
||||
if ret_code != 0: |
||||
failed.append((exe.name, ret_code)) |
||||
|
||||
# Print summary |
||||
print("\nTest Summary:") |
||||
print(f"Ran {len(executables)} tests") |
||||
if failed: |
||||
print(f"Failed tests ({len(failed)}):") |
||||
for name, code in failed: |
||||
print(f" {name}: returned {code}") |
||||
return failed[0][1] # Return first failure code |
||||
else: |
||||
print("All tests passed!") |
||||
return 0 |
||||
|
||||
if __name__ == '__main__': |
||||
sys.exit(main()) |
@ -0,0 +1,329 @@
@@ -0,0 +1,329 @@
|
||||
{ |
||||
"simpleCUDA2GL": { |
||||
"skip": true |
||||
}, |
||||
"simpleTexture3D": { |
||||
"args": [ |
||||
"--file=ref_texture3D.bin" |
||||
] |
||||
}, |
||||
"ptxgen": { |
||||
"args": [ |
||||
"test.ll", |
||||
"-arch=compute_75" |
||||
] |
||||
}, |
||||
"volumeRender": { |
||||
"args": [ |
||||
"--file=ref_volume.ppm" |
||||
] |
||||
}, |
||||
"fluidsGL": { |
||||
"skip": true |
||||
}, |
||||
"simpleD3D11Texture": { |
||||
"skip": true |
||||
}, |
||||
"recursiveGaussian": { |
||||
"runs": [ |
||||
{ |
||||
"args": [ |
||||
"-sigma=10", |
||||
"-file=data/ref_10.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-sigma=14", |
||||
"-file=data/ref_14.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-sigma=18", |
||||
"-file=data/ref_18.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-sigma=22", |
||||
"-file=data/ref_22.ppm" |
||||
] |
||||
} |
||||
] |
||||
}, |
||||
"simpleGL": { |
||||
"args": [ |
||||
"-file=data/ref_simpleGL.bin" |
||||
] |
||||
}, |
||||
"bicubicTexture": { |
||||
"runs": [ |
||||
{ |
||||
"args": [ |
||||
"-mode=0", |
||||
"-file=data/0_nearest.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-mode=1", |
||||
"-file=data/1_bilinear.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-mode=2", |
||||
"-file=data/2_bicubic.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-mode=3", |
||||
"-file=data/3_fastcubic.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-mode=4", |
||||
"-file=data/4_catmull-rom.ppm" |
||||
] |
||||
} |
||||
] |
||||
}, |
||||
"simpleVulkan": { |
||||
"skip": true |
||||
}, |
||||
"smokeParticles": { |
||||
"args": [ |
||||
"-qatest" |
||||
] |
||||
}, |
||||
"Mandelbrot": { |
||||
"runs": [ |
||||
{ |
||||
"args": [ |
||||
"-mode=0", |
||||
"-file=data/Mandelbrot_fp32.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-mode=1", |
||||
"-file=data/referenceJulia_fp32.ppm" |
||||
] |
||||
} |
||||
] |
||||
}, |
||||
"vulkanImageCUDA": { |
||||
"skip": true |
||||
}, |
||||
"SobelFilter": { |
||||
"runs": [ |
||||
{ |
||||
"args": [ |
||||
"-mode=0", |
||||
"-file=data/ref_orig.pgm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-mode=1", |
||||
"-file=data/ref_tex.pgm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-mode=2", |
||||
"-file=data/ref_shared.pgm" |
||||
] |
||||
} |
||||
] |
||||
}, |
||||
"bilateralFilter": { |
||||
"runs": [ |
||||
{ |
||||
"args": [ |
||||
"-radius=5", |
||||
"-file=data/ref_05.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-radius=6", |
||||
"-file=data/ref_06.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-radius=7", |
||||
"-file=data/ref_07.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-radius=8", |
||||
"-file=data/ref_08.ppm" |
||||
] |
||||
} |
||||
] |
||||
}, |
||||
"nbody": { |
||||
"args": [ |
||||
"-benchmark", |
||||
"-compare", |
||||
"-cpu" |
||||
] |
||||
}, |
||||
"volumeFiltering": { |
||||
"args": [ |
||||
"-file=data/ref_volumefilter.ppm" |
||||
] |
||||
}, |
||||
"simpleVulkanMMAP": { |
||||
"skip": true |
||||
}, |
||||
"postProcessGL": { |
||||
"skip": true |
||||
}, |
||||
"marchingCubes": { |
||||
"runs": [ |
||||
{ |
||||
"args": [ |
||||
"-dump=0", |
||||
"-file=data/posArray.bin" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-dump=1", |
||||
"-file=data/normalArray.bin" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-dump=2", |
||||
"-file=data/compVoxelArray.bin" |
||||
] |
||||
} |
||||
] |
||||
}, |
||||
"bindlessTexture": { |
||||
"args": [ |
||||
"-file=data/ref_bindlessTexture.bin" |
||||
] |
||||
}, |
||||
"cuSolverSp_LinearSolver": { |
||||
"runs": [ |
||||
{ |
||||
"args": [ |
||||
"-R=qr" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-R=chol" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-R=qr", |
||||
"-P=symamd" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-R=chol", |
||||
"-P=symamd" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-R=lu", |
||||
"-P=symamd" |
||||
] |
||||
} |
||||
] |
||||
}, |
||||
"randomFog": { |
||||
"args": [ |
||||
"-qatest" |
||||
] |
||||
}, |
||||
"oceanFFT": { |
||||
"args": [ |
||||
"-qatest" |
||||
] |
||||
}, |
||||
"FunctionPointers": { |
||||
"runs": [ |
||||
{ |
||||
"args": [ |
||||
"-mode=0", |
||||
"-file=data/ref_orig.pgm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-mode=1", |
||||
"-file=data/ref_tex.pgm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-mode=2", |
||||
"-file=data/ref_shared.pgm" |
||||
] |
||||
} |
||||
] |
||||
}, |
||||
"particles": { |
||||
"args": [ |
||||
"-file=data/ref_particles.bin" |
||||
] |
||||
}, |
||||
"imageDenoising": { |
||||
"runs": [ |
||||
{ |
||||
"args": [ |
||||
"-kernel=0", |
||||
"-file=data/ref_passthru.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-kernel=1", |
||||
"-file=data/ref_knn.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-kernel=2", |
||||
"-file=data/ref_nlm.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-kernel=3", |
||||
"-file=data/ref_nlm2.ppm" |
||||
] |
||||
} |
||||
] |
||||
}, |
||||
"boxFilter": { |
||||
"runs": [ |
||||
{ |
||||
"args": [ |
||||
"-radius=14", |
||||
"-file=data/ref_14.ppm" |
||||
] |
||||
}, |
||||
{ |
||||
"args": [ |
||||
"-radius=22", |
||||
"-file=data/ref_22.ppm" |
||||
] |
||||
} |
||||
] |
||||
} |
||||
} |
Loading…
Reference in new issue