Files
triton/python/autotune/pysrc/autotune.py

264 lines
14 KiB
Python
Raw Normal View History

2014-09-02 22:03:20 -04:00
from __future__ import division
import argparse, itertools, os, sys, json
2014-10-28 01:10:14 -04:00
import misc_tools, optimize, dataset
2014-09-02 22:03:20 -04:00
import pyopencl as cl
import pyviennacl as vcl
import pyatidlas as atd
import numpy as np
2014-09-02 22:03:20 -04:00
from numpy import random
from model import train_model
TYPES = { 'vector-axpy': {'template':atd.VectorAxpyTemplate,
2014-11-02 10:05:14 -05:00
'perf-index':lambda x: 3*x[0]*x[1][0]/x[2]*1e-9,
2014-09-06 00:39:38 -04:00
'perf-measure':'GB/s'},
2014-09-29 03:01:33 +02:00
'matrix-axpy': {'template':atd.MatrixAxpyTemplate,
2014-11-02 10:05:14 -05:00
'perf-index':lambda x: 3*x[0]*x[1][0]*x[1][1]/x[2]*1e-9,
2014-09-06 00:39:38 -04:00
'perf-measure':'GB/s'},
2014-09-29 03:01:33 +02:00
'reduction': {'template':atd.ReductionTemplate,
2014-10-05 06:33:50 +02:00
'perf-index':lambda x: 2*x[0]*x[1][0]/x[2]*1e-9,
2014-09-06 00:39:38 -04:00
'perf-measure':'GB/s'},
2014-09-29 03:01:33 +02:00
'row-wise-reduction': {'template':atd.RowWiseReductionTemplate,
2014-09-06 00:39:38 -04:00
'perf-index':lambda x: x[0]*x[1][0]*x[1][1]/x[2]*1e-9,
'perf-measure':'GB/s'},
2014-09-29 03:01:33 +02:00
'matrix-product': {'template': atd.MatrixProductTemplate,
2014-09-06 00:39:38 -04:00
'perf-index': lambda x: 2*x[1][0]*x[1][1]*x[1][2]/x[2]*1e-9,
'perf-measure': 'GFLOP/s'} }
2014-09-29 03:01:33 +02:00
2014-10-31 18:12:55 -04:00
def do_tuning(args):
2014-10-31 18:56:33 -04:00
device = args.device
2014-10-29 17:01:57 +01:00
2014-10-31 18:56:33 -04:00
if os.path.isfile(args.json_file):
json_out = json.load(open(args.json_file, 'r'))
else:
json_out = {}
json_out["version"] = "1.0"
2014-10-03 09:29:45 +02:00
def map_to_list(T, x):
return list(map(T, x if isinstance(x, list) else [x]))
2014-10-31 18:56:33 -04:00
if(args.method=='simple'):
default_tuning_sizes = {'vector-axpy': args.blas1_size, 'reduction': args.blas1_size,
'matrix-axpy' : args.blas2_size, 'row-wise-reduction' : args.blas2_size,
'matrix-product': args.blas3_size}
2014-10-29 17:01:57 +01:00
2014-10-29 12:45:20 -04:00
for operation in ['vector-axpy', 'reduction', 'matrix-axpy', 'row-wise-reduction', 'matrix-product']:
for datatype in [vcl.float32, vcl.float64]:
if operation not in args.operations and operation + '-' + datatype.__name__ not in args.operations:
2014-10-29 17:01:57 +01:00
continue
ctx = cl.Context([device])
ctx = vcl.backend.Context(ctx)
#Check data-type
if datatype is vcl.float64 and not device.double_fp_config:
sys.stderr.write('Warning : The device ' + device.name + ' does not support double precision! Skipping ...')
continue
#Helper for execution
def execute(device, node, other_params, sizes, fname = os.devnull, parameters = None):
with vcl.Statement(node) as statement:
2014-10-29 17:01:57 +01:00
if parameters is not None:
TemplateType = TYPES[operation]['template']
return misc_tools.benchmark(TemplateType(TemplateType.Parameters(*parameters),*other_params), statement, device)
with open(fname, "w+") as archive:
return optimize.genetic(statement, device, TYPES[operation]['template'], lambda p: TYPES[operation]['template'](p, *other_params),
lambda t: TYPES[operation]['perf-index']([datatype().itemsize, sizes, t]), TYPES[operation]['perf-measure'], archive)
def log_uniform_sample(a,b):
return np.exp(np.random.uniform(low=np.log(a), high=np.log(b), size=1)).astype(int)
def space_gen_product(a,b,N,dim,method):
N = int(N**(1.0/dim))
def space_gen(a,b,method):
for i in range(N):
if method == 'linear':
v = int(a + (b-a)*i/N)
if method == 'log':
v = int(np.exp(np.log(a) + (np.log(b) - np.log(a))*i/N))
yield (v//64 + 1)*64
return tuple(itertools.product(*[space_gen(a,b,method) for i in range(dim)]))
#Helper for tuning
def tune(execution_handler, a, b, dimsample, layouts, sample_method_profiles, sample_method_dataset):
print args.build_model
2014-10-29 17:01:57 +01:00
print('-----')
print(' '.join(map(str, ("Now tuning:", datatype.__name__, '-', operation, '-'.join(layouts), '[' + device.name, '(' + device.platform.name + ')]'))))
#Update JSON
full_operation = operation + ''.join(layouts)
if full_operation not in json_out:
json_out[full_operation] = {}
json_out[full_operation][datatype.__name__] = {}
D = json_out[full_operation][datatype.__name__]
2014-10-31 18:56:33 -04:00
if args.method == 'simple':
2014-10-29 17:01:57 +01:00
print default_tuning_sizes[operation]
profiles = [execution_handler(map(int,default_tuning_sizes[operation]))]
else:
def compute_perf(x, t):
return TYPES[operation]['perf-index']([datatype().itemsize, x, t])
profiles_generator = space_gen_product(a, b, args.sample_size, dimsample, sample_method_profiles)
profiles = dataset.sample_profiles(execution_handler, profiles_generator)
2014-10-31 18:56:33 -04:00
if args.build_model:
dataset_generator = space_gen_product(a, b, 1000, dimsample, sample_method_dataset)
X, Y, profiles = dataset.sample_dataset(os.path.join(full_operation,datatype.__name__), profiles, execution_handler, dataset_generator)
# profiles = np.loadtxt('data/'+full_operation+'/'+datatype.__name__+'/profiles.csv')
# X = np.loadtxt('data/'+full_operation+'/'+datatype.__name__+'/X.csv',ndmin=2)
# Y = np.loadtxt('data/'+full_operation+'/'+datatype.__name__+'/Y.csv',ndmin=2)
2014-10-28 01:10:14 -04:00
clf = train_model(X, Y, profiles, TYPES[operation]['perf-measure'])
D['predictor'] = [{'children_left': e.tree_.children_left.tolist(),
'children_right': e.tree_.children_right.tolist(),
2014-10-31 18:12:55 -04:00
'threshold': e.tree_.threshold.astype('float64').tolist(),
'feature': e.tree_.feature.astype('float64').tolist(),
'value': e.tree_.value[:,:,0].astype('float64').tolist()} for e in clf.estimators_]
2014-10-31 18:56:33 -04:00
if args.viennacl_src_path:
misc_tools.update_viennacl_headers(args.viennacl_src_path, device,datatype,operation,layouts,profiles[0])
2014-10-29 17:01:57 +01:00
D['profiles'] = [map(int, x) for x in profiles]
#Vector AXPY
if operation=='vector-axpy':
def execution_handler(sizes, fname=os.devnull, parameters=None):
x = vcl.Vector(sizes[0], context=ctx, dtype=datatype)
2014-11-02 10:05:14 -05:00
y = vcl.Vector(sizes[0], context=ctx, dtype=datatype)
return execute(device, vcl.Assign(y, x + y), (), sizes, fname, parameters)
tune(execution_handler, 1e3, 2e7, 1, (),'log', 'log')
#Reduction
if operation=='reduction':
def execution_handler(sizes, fname=os.devnull, parameters=None):
x = vcl.Vector(sizes[0], context=ctx, dtype=datatype)
y = vcl.Vector(sizes[0], context=ctx, dtype=datatype)
s = vcl.Scalar(0, context=ctx, dtype=datatype)
return execute(device, vcl.Assign(s, vcl.Dot(x,y)), (), sizes, fname, parameters)
tune(execution_handler, 1e3, 2e7, 1, (),'log', 'log')
#Matrix AXPY
if operation=='matrix-axpy':
def execution_handler(sizes, fname=os.devnull, parameters=None):
A = vcl.Matrix(sizes, context=ctx, dtype=datatype, layout=vcl.COL_MAJOR)
C = vcl.Matrix(sizes, context=ctx, dtype=datatype, layout=vcl.COL_MAJOR)
2014-11-02 10:05:14 -05:00
return execute(device, vcl.Assign(C,A + C), (), sizes, fname, parameters)
tune(execution_handler, 100, 5000, 2, (),'log', 'log')
#Row-wise reduction
if operation=='row-wise-reduction':
2014-10-31 18:56:33 -04:00
for A_trans in args.gemv_layouts:
def execution_handler(sizes, fname=os.devnull, parameters=None):
A = vcl.Matrix(sizes if A_trans=='N' else sizes[::-1], context=ctx, dtype=datatype, layout=vcl.COL_MAJOR)
2014-10-29 17:01:57 +01:00
x = vcl.Vector(sizes[1], context=ctx, dtype=datatype)
y = vcl.Vector(sizes[0], context=ctx, dtype=datatype)
LHS = A if A_trans=='N' else A.T
return execute(device, vcl.Assign(y, LHS*x), (), sizes, fname, parameters)
tune(execution_handler, 100, 5000, 2, (A_trans,),'log', 'log')
#Matrix Product
if operation=='matrix-product':
2014-10-31 18:56:33 -04:00
for L in args.gemm_layouts:
2014-10-31 18:12:55 -04:00
A_trans = L[0]
B_trans = L[1]
def execution_handler(sizes, fname=os.devnull, parameters=None):
2014-10-31 18:12:55 -04:00
A = vcl.Matrix((sizes[0], sizes[2]) if A_trans=='N' else (sizes[2],sizes[0]), context=ctx, dtype=datatype, layout=vcl.COL_MAJOR)
B = vcl.Matrix((sizes[2], sizes[1]) if B_trans=='N' else (sizes[1],sizes[2]), context=ctx, dtype=datatype, layout=vcl.COL_MAJOR)
LHS = A if A_trans=='N' else A.T
RHS = B if B_trans=='N' else B.T
alpha = vcl.HostScalar(1.0, context=ctx, dtype = datatype)
beta = vcl.HostScalar(1.0, context=ctx, dtype = datatype)
C = vcl.Matrix((sizes[0], sizes[1]), context=ctx, dtype = datatype, layout=vcl.COL_MAJOR)
2014-10-31 18:12:55 -04:00
return execute(device, vcl.Assign(C,LHS*RHS*alpha + C*beta),(A_trans,B_trans), sizes, fname, parameters)
tune(execution_handler, 100, 2000, 3,(A_trans,B_trans), 'linear')
2014-10-29 17:01:57 +01:00
2014-10-31 18:56:33 -04:00
json.dump(json_out, open(args.json_file,'w'))
2014-10-29 17:01:57 +01:00
2014-09-29 03:01:33 +02:00
2014-10-31 18:56:33 -04:00
class ArgumentsHandler:
2014-09-29 03:01:33 +02:00
2014-10-31 18:56:33 -04:00
def __init__(self):
2014-11-02 10:05:14 -05:00
#No action argument -> interactive tuning
if len(sys.argv)==1:
def add_input(help, default):
return raw_input(help + "[" + default + "] : ") or default
self.device = add_input('Device to tune for','0')
self.operations = add_input('Operations to tune for','vector-axpy,matrix-axpy,reduction,row-wise-reduction,matrix-product-float32').split(',')
self.gemm_layouts = add_input('GEMV Layouts', 'NN,NT,TN,TT')
self.gemv_layouts = add_input('GEMV Layouts', 'N,T')
2014-11-02 10:05:14 -05:00
self.json_file = add_input('JSON File', misc_tools.sanitize_string(devices[int(self.device)].name) + '.json')
self.method = add_input('Tuning type', 'simple')
if self.method == 'simple':
self.blas1_size = add_input('BLAS1 size', '10e6')
self.blas2_size = add_input('BLAS2 sizes (M,N)', '2560,2560').split(',')
self.blas3_size = add_input('BLAS3 sizes (M,N,K)', '1024,1024,1024').split(',')
else:
self.build_model = True
self.sample_size = 30
self.viennacl_src_path= add_input('ViennaCL src path', '')
else:
#Command line arguments
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='action')
print_devices_parser = subparsers.add_parser('list-devices', help='List the devices available')
tune_parser = subparsers.add_parser('tune', help='Auto-tuning')
tune_parser.add_argument("--device", default=0, type=int)
tune_parser.add_argument("--operations", default = 'vector-axpy,matrix-axpy,reduction,row-wise-reduction,matrix-product-float32', type=str)
tune_parser.add_argument("--gemm-layouts", default='NN,NT,TN,TT', type=str)
tune_parser.add_argument("--gemv-layouts", default='N,T', type=str)
tune_parser.add_argument("--json-file", default='', type=str)
tune_parser.add_argument("--viennacl-src-path", default='', type=str)
tune_subparsers = tune_parser.add_subparsers(dest='method')
simple_parser = tune_subparsers.add_parser('simple', help = 'Tune each operation for unique sizes')
simple_parser.add_argument("--blas1-size", default = 10e6, type=int)
simple_parser.add_argument("--blas2-size", nargs=2, default=[2560,2560], type=int)
simple_parser.add_argument("--blas3-size", nargs=3, default=[1536,1536,1536],type=int)
full_parser = tune_subparsers.add_parser('full', help = 'Tune each operation for randomly chosen sizes')
full_parser.add_argument("--build-model", default=True, type=bool)
full_parser.add_argument("--sample-size", default=30, type=int)
args = parser.parse_args()
self.__dict__ = args.__dict__.copy()
2014-10-31 18:56:33 -04:00
#Retypes
self.operations = [self.operations] if not isinstance(self.operations, list) else self.operations
2014-10-31 18:56:33 -04:00
self.device = devices[int(self.device)]
if not self.json_file:
self.json_file = misc_tools.sanitize_string(self.device.name) + '.json'
2014-10-31 18:56:33 -04:00
self.gemm_layouts = self.gemm_layouts.split(',')
self.gemv_layouts = self.gemv_layouts.split(',')
if self.method == 'simple':
self.blas1_size = [int(float(self.blas1_size))]
self.blas2_size = map(int, self.blas2_size)
self.blas3_size = map(int, self.blas3_size)
2014-09-02 22:03:20 -04:00
if __name__ == "__main__":
2014-10-31 18:56:33 -04:00
devices = [d for platform in cl.get_platforms() for d in platform.get_devices()]
2014-10-31 18:12:55 -04:00
print("----------------")
print("Devices available:")
print("----------------")
for (i, d) in enumerate(devices):
print 'Device', i, '|', cl.device_type.to_string(d.type), '|', d.name, 'on', d.platform.name
print("----------------")
2014-10-31 18:56:33 -04:00
args = ArgumentsHandler()
2014-10-31 18:12:55 -04:00
print("------")
print("Auto-tuning")
print("------")
2014-10-31 18:56:33 -04:00
2014-10-31 18:12:55 -04:00
do_tuning(args)