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) #