Added partial support for synthetic matrices
This commit is contained in:
parent
6bf301e9b7
commit
66b0699fa8
@ -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
|
||||||
|
@ -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'
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
matrix = torch.sparse_coo_tensor(
|
||||||
np.vstack((matrix.row, matrix.col)),
|
np.vstack((matrix.row, matrix.col)),
|
||||||
matrix.data, matrix.shape,
|
matrix.data, matrix.shape,
|
||||||
device=device
|
device=device, dtype=torch.float32)
|
||||||
).to_sparse_csr().type(torch.float)
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user