LANAI¶
LANguage for Autotuning Infrastructure¶
LANAI is a python based method for specifing the search space and pruning constraints for autotuning programs. This is the basis for the entire BONSAI infrastructure.
General Structure¶
The general structure for a LANAI specification file is
#imports
#iterator constants
#iterator specifications
#constraint constants
#constraint specifications
LANAI allows for outside imports in its iterator files for abstraction purposes. For example, say a file that contains various CUDA constants for different compute capabilities and a file with constants for a particular card. The top of the iterator file would then be
from lanai import *
from cuda_constants import *
from Telsa_K40c import *
Following that may come any other constants that we may wish to specify.
Iterators¶
LANAI supports 2 basic iterator types (expression and deferred) each corresponding to a specific scope (global and local).
Global/Expression Iterators¶
Global/expression iterators take the form of:
dim_x = range(1, max_dim_x+1)
using the standard Python range
syntax. The 3 argument version of
range
is also supported. These are the most basic form of iterator
expressions.
Local/Deferred Iterators¶
Local/deferred iterators are allowed to take other iterators and/or
other constants as arguments. Local iterators must also be decorated
with @iterator
before the iterator definition. This takes the basic
form of
@iterator
def blk_x(dim_x):
return range(dim_x, max_dim_x+1, dim_x)
Deferred iterators are also allowed to contain more complex flow control statements as well. For example
@iterator
def vec_mul(dim_vec):
if dim_vec == 1:
return range(0, 1)
else:
return range(0, 2)
dim_vec
is also an iterator, so vec_mul
can take on different
values depending on what value dim_vec
is currently holding. It is
probably worth mentioning that the iterator definition of dim_vec
must come before any other definition where it is used as an argument.
Conditions¶
LANAI condition statements prune the search space generated by the
iterators. Each condition statement must be decorated with a
@condition
before the definition as so:
@condition
def over_max_threads(threads_per_block):
return threads_per_block > max_threads_per_block
Conditions are always written as a boolean statement that returns ‘true’ when the condition fails. Not following this can lead to unwanted behavior. As an example, look at the following two iterators and pruning condition, where we want both R1 and R2 to be greater than 0.
R1 = range(3)
R2 = range(3)
@condition
def greater_than_zero():
return R1 > 0 and R2 > 0
Without the condition, we get the search space:
R1, R2
0 , 0
0 , 1
0 , 2
1 , 0
1 , 1
1 , 2
2 , 0
2 , 1
2 , 2
Adding the condition prunes the search space to:
R1, R2
0 , 0
0 , 1
0 , 2
1 , 0
2 , 0
This seems to be a bug. The problem lies with how the condition statement was defined. We specified the condition as a statement that we want to always hold, not the condition that we want to fail. To fix this, take the logical complement of the condition:
@condition
def greater_than_zero():
return R1 <= 0 or R2 <= 0
This prunes the search to the space we expected:
R1, R2
1 , 1
1 , 2
2 , 1
2 , 2
Oddities¶
To declare a consant value, it still must be written as an iterator with size one, e.g.
tex_a = range(1,2) #