Added partial support for synthetic matrices

This commit is contained in:
cephi 2024-12-12 01:18:26 -05:00
parent 6bf301e9b7
commit 66b0699fa8
4 changed files with 79 additions and 21 deletions

View File

@ -16,7 +16,7 @@ class Stat(Enum):
MATRIX_SHAPE = 'matrix shape' MATRIX_SHAPE = 'matrix shape'
MATRIX_SIZE = 'matrix size' MATRIX_SIZE = 'matrix size'
MATRIX_NNZ = 'matrix nnz' MATRIX_NNZ = 'matrix nnz'
MATRIX_DENSITY = 'matrix density %' MATRIX_DENSITY = 'matrix density'
#POWER_BEFORE = 'power before' #POWER_BEFORE = 'power before'
#POWER = 'power' #POWER = 'power'
@ -65,6 +65,10 @@ class Stat(Enum):
L2D_CACHE_MISS_RATE = 'L2D cache miss rate' L2D_CACHE_MISS_RATE = 'L2D cache miss rate'
LL_CACHE_MISS_RATE = 'LL cache miss rate' LL_CACHE_MISS_RATE = 'LL cache miss rate'
class Format(Enum):
CSR = 'csr'
COO = 'coo'
class Cpu(Enum): class Cpu(Enum):
#ALTRA = altra_names #ALTRA = altra_names
#XEON = xeon_names #XEON = xeon_names

View File

@ -1,4 +1,4 @@
from data_stat import Cpu from data_stat import Cpu, Format
import argparse import argparse
import glob import glob
@ -10,7 +10,10 @@ parser = argparse.ArgumentParser()
parser.add_argument('cpu', choices=[x.name.lower() for x in Cpu]) parser.add_argument('cpu', choices=[x.name.lower() for x in Cpu])
parser.add_argument('output_dir') parser.add_argument('output_dir')
parser.add_argument('matrix_dir') parser.add_argument('matrix_dir')
parser.add_argument('iterations', type=int) parser.add_argument('format', type=str,
choices=[fmt.name.lower() for fmt in Format])
parser.add_argument('base_iterations', type=int)
parser.add_argument('min_time_s', type=int)
parser.add_argument('baseline_time_s', type=int) parser.add_argument('baseline_time_s', type=int)
parser.add_argument('baseline_delay_s', type=int) parser.add_argument('baseline_delay_s', type=int)
parser.add_argument('--perf', action='store_const', const='--perf') parser.add_argument('--perf', action='store_const', const='--perf')
@ -18,6 +21,7 @@ parser.add_argument('--power', action='store_const', const='--power')
parser.add_argument('--distribute', action='store_true') parser.add_argument('--distribute', action='store_true')
args = parser.parse_args() args = parser.parse_args()
args.cpu = Cpu[args.cpu.upper()] args.cpu = Cpu[args.cpu.upper()]
args.format = Format[args.format.upper()]
srun_args = { srun_args = {
Cpu.ALTRA: [ Cpu.ALTRA: [
@ -40,18 +44,29 @@ srun_args = {
'--cpus-per-task', '16', '--cpus-per-task', '16',
'--ntasks-per-node', '1', '--ntasks-per-node', '1',
'--prefer', 'EPYC-7313P' '--prefer', 'EPYC-7313P'
],
Cpu.XEON_4216: [
'--account', 'nexus',
'--partition', 'tron',
'--qos', 'tron-exempt',
'--cpus-per-task', '32',
'--ntasks-per-node', '1',
'--prefer', 'Xeon,4216'
] ]
} }
python = { python = {
Cpu.ALTRA: 'python3', Cpu.ALTRA: 'python3',
Cpu.EPYC_7313P: 'python3.11' Cpu.EPYC_7313P: 'python3.11',
Cpu.XEON_4216: 'python3.11'
} }
def srun(srun_args_list: list, run_args, matrix_file: str) -> list: def srun(srun_args_list: list, run_args, matrix_file: str) -> list:
run_args_list = [ run_args_list = [
args.cpu.name.lower(), args.cpu.name.lower(),
matrix_file, matrix_file,
str(args.iterations), args.format.name.lower(),
str(args.base_iterations),
str(args.min_time_s),
str(args.baseline_time_s), str(args.baseline_time_s),
str(args.baseline_delay_s)] str(args.baseline_delay_s)]
if args.perf is not None: if args.perf is not None:
@ -74,10 +89,10 @@ for i, matrix in enumerate(glob.glob(f'{args.matrix_dir.rstrip("/")}/*.mtx')):
output_filename = '_'.join([ output_filename = '_'.join([
args.cpu.name.lower(), args.cpu.name.lower(),
str(args.min_time_s),
str(args.baseline_time_s), str(args.baseline_time_s),
str(args.baseline_delay_s), str(args.baseline_delay_s),
os.path.splitext(os.path.basename(matrix))[0], os.path.splitext(os.path.basename(matrix))[0]])
str(args.iterations)])
json_filepath = f'{args.output_dir.rstrip("/")}/{output_filename}.json' json_filepath = f'{args.output_dir.rstrip("/")}/{output_filename}.json'
raw_filepath = f'{args.output_dir.rstrip("/")}/{output_filename}.output' raw_filepath = f'{args.output_dir.rstrip("/")}/{output_filename}.output'

View File

@ -1,5 +1,5 @@
import data_stat import data_stat
from data_stat import Stat, Cpu from data_stat import Stat, Cpu, Format
import argparse import argparse
import os, sys import os, sys
@ -10,6 +10,8 @@ import time
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('cpu', choices=[x.name.lower() for x in Cpu]) parser.add_argument('cpu', choices=[x.name.lower() for x in Cpu])
parser.add_argument('matrix_file') parser.add_argument('matrix_file')
parser.add_argument('format', type=str,
choices=[fmt.name.lower() for fmt in Format])
parser.add_argument('base_iterations', type=int) parser.add_argument('base_iterations', type=int)
parser.add_argument('min_time_s', type=int) parser.add_argument('min_time_s', type=int)
parser.add_argument('baseline_time_s', type=int) parser.add_argument('baseline_time_s', type=int)
@ -19,6 +21,7 @@ parser.add_argument('--power', action='store_true')
parser.add_argument('-d', '--debug', action='store_true') parser.add_argument('-d', '--debug', action='store_true')
args = parser.parse_args() args = parser.parse_args()
args.cpu = Cpu[args.cpu.upper()] args.cpu = Cpu[args.cpu.upper()]
args.format = Format[args.format.upper()]
python = { python = {
Cpu.ALTRA: 'python3', Cpu.ALTRA: 'python3',
@ -40,16 +43,16 @@ def program(cpu: Cpu, matrix_file: str, iterations: int) -> list:
return [ return [
'apptainer', 'run', 'pytorch-altra.sif', '-c', 'apptainer', 'run', 'pytorch-altra.sif', '-c',
'numactl --cpunodebind=0 --membind=0 ' 'numactl --cpunodebind=0 --membind=0 '
+ f'python3 spmv.py {matrix_file} {iterations}'] + f'python3 spmv.py {iterations} csr -m {matrix_file}']
elif cpu == Cpu.EPYC_7313P: elif cpu == Cpu.EPYC_7313P:
return [ return [
'apptainer', 'run', 'pytorch-epyc_7313p.sif', 'apptainer', 'run', 'pytorch-epyc_7313p.sif',
'python3', 'spmv.py', f'{matrix_file}', f'{iterations}'] 'python3', 'spmv.py', f'{iterations}', 'csr', '-m', f'{matrix_file}']
elif cpu == Cpu.XEON_4216: elif cpu == Cpu.XEON_4216:
return [ return [
'apptainer', 'run', 'pytorch-xeon_4216.sif', 'apptainer', 'run', 'pytorch-xeon_4216.sif',
'numactl', '--cpunodebind=0', '--membind=0', 'numactl', '--cpunodebind=0', '--membind=0',
'python3', 'spmv.py', f'{matrix_file}', f'{iterations}'] 'python3', 'spmv.py', f'{iterations}', 'csr', '-m', f'{matrix_file}']
def baseline_power(cpu: Cpu, baseline_time_s: int) -> list: def baseline_power(cpu: Cpu, baseline_time_s: int) -> list:
power_process = subprocess.Popen(['./power.sh', str(baseline_time_s)], power_process = subprocess.Popen(['./power.sh', str(baseline_time_s)],
@ -88,7 +91,7 @@ iterations = args.base_iterations
program_result = run_program(program(args.cpu, args.matrix_file, iterations)) program_result = run_program(program(args.cpu, args.matrix_file, iterations))
while program_result[0][Stat.TIME_S.name] < args.min_time_s: while program_result[0][Stat.TIME_S.name] < args.min_time_s:
# Increase the number of iterations by difference between the current time taken and the desired time. # Increase the number of iterations by difference between the current time taken and the desired time.
iterations *= 1 / ((args.min_time_s - program_result[0][Stat.TIME_S.name]) / args.min_time_s) iterations *= 1 / (program_result[0][Stat.TIME_S.name] / args.min_time_s)
# Add another 5% for safety. # Add another 5% for safety.
iterations += iterations * 0.05 iterations += iterations * 0.05
iterations = int(iterations) iterations = int(iterations)
@ -157,6 +160,9 @@ if args.power:
args.baseline_time_s) args.baseline_time_s)
) )
baseline_wattage = baseline_joules / (args.baseline_time_s * 2) baseline_wattage = baseline_joules / (args.baseline_time_s * 2)
if args.debug:
print(baseline_joules)
print(baseline_wattage)
result[Stat.J_1KI.name] = ( result[Stat.J_1KI.name] = (
(result[Stat.J.name] / result[Stat.ITERATIONS.name]) * 1000 (result[Stat.J.name] / result[Stat.ITERATIONS.name]) * 1000

View File

@ -1,4 +1,4 @@
from data_stat import Stat from data_stat import Stat, Format
import torch, scipy import torch, scipy
import numpy as np import numpy as np
@ -8,18 +8,48 @@ import json
import sys, os import sys, os
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('matrix_file', help='the input matrix (.mtx) file')
parser.add_argument('iterations', type=int, help='the number of iterations of multiplication to perform') parser.add_argument('iterations', type=int, help='the number of iterations of multiplication to perform')
parser.add_argument('format', type=str,
choices=[fmt.name.lower() for fmt in Format],
help='the sparse format to use')
parser.add_argument('-m', '--matrix_file', help='the input matrix (.mtx) file')
parser.add_argument('-ss', '--synthetic_size', type=int,
help='the synthetic matrix parameters size (rows)')
parser.add_argument('-sd', '--synthetic_density', type=float,
help='the synthetic matrix density (%)')
args = parser.parse_args() args = parser.parse_args()
args.format = Format[args.format.upper()]
device = 'cpu' device = 'cpu'
matrix = scipy.io.mmread(args.matrix_file) if args.matrix_file is not None:
matrix = torch.sparse_coo_tensor( matrix = scipy.io.mmread(args.matrix_file)
np.vstack((matrix.row, matrix.col)), matrix = torch.sparse_coo_tensor(
matrix.data, matrix.shape, np.vstack((matrix.row, matrix.col)),
device=device matrix.data, matrix.shape,
).to_sparse_csr().type(torch.float) device=device, dtype=torch.float32)
elif args.synthetic_size is not None and args.synthetic_density is not None:
nnz = int((args.synthetic_size ** 2) * (args.synthetic_density / 100))
row_indices = torch.randint(0, args.synthetic_size, (nnz,))
col_indices = torch.randint(0, args.synthetic_size, (nnz,))
indices = torch.stack([row_indices, col_indices])
values = torch.randn(nnz)
matrix = torch.sparse_coo_tensor(
indices, values,
size=(args.synthetic_size, args.synthetic_size),
device=device, dtype=torch.float32)
else:
print("No matrix specified!")
exit(1)
if args.format == Format.CSR:
matrix = matrix.to_sparse_csr().type(torch.float32)
elif args.format == Format.COO:
pass
else:
print("Unrecognized format!")
exit(1)
vector = torch.rand(matrix.shape[1], device=device) vector = torch.rand(matrix.shape[1], device=device)
@ -35,7 +65,10 @@ end = time.time()
result = dict() result = dict()
result[Stat.MATRIX_FILE.name] = os.path.splitext(os.path.basename(args.matrix_file))[0] if args.matrix_file is not None:
result[Stat.MATRIX_FILE.name] = os.path.splitext(os.path.basename(args.matrix_file))[0]
else:
result[Stat.MATRIX_FILE.name] = "synthetic"
print(f"Matrix: {result[Stat.MATRIX_FILE.name]}", file=sys.stderr) print(f"Matrix: {result[Stat.MATRIX_FILE.name]}", file=sys.stderr)
result[Stat.MATRIX_SHAPE.name] = matrix.shape result[Stat.MATRIX_SHAPE.name] = matrix.shape