def tune_blocksize(data, params, func_regs):
    #info = DeviceInfo()

    max_smem = info.shared_mem * 0.9
    max_threads = int(info.max_block_threads * 0.5)
    max_regs = info.max_registers
    max_grid = int(info.max_grid_dim[0])

    params_per = 64#max_threads
    if (len(params) < params_per):
        params_per = _next_pow2(len(params), info.max_block_threads)

    min_data_per = data.shape[0] / max_grid;
    data_per0 = _next_pow2( max( max_threads / params_per, min_data_per ), 512);
    data_per = data_per0

    def _can_fit(data_per, params_per):
        ok = compute_shmem(data, params, data_per, params_per) <= max_smem
        ok = ok and data_per*params_per <= max_threads
        return ok and func_regs*data_per*params_per <= max_regs

    while True:
        while not _can_fit(data_per, params_per):
            if data_per <= min_data_per:
                break

            if params_per > 1:
                # reduce number of parameters first
                params_per /= 2
            else:
                # can't go any further, have to do less data
                data_per /= 2

        if data_per <= min_data_per:
            # we failed somehow. start over
            data_per = 2 * data_per0
            params_per /= 2
            continue
        else:
            break

    while _can_fit(2 * data_per, params_per):
        #if 2 * data_per * params_per < max_threads:
            data_per *= 2
        #else:
            # hit block size limit
        #    break

    #import pdb; pdb.set_trace()
    return data_per, params_per
For multivariate distributions-- what's the optimal block size given the
dataset/ETHPy150Open dukestats/gpustats/gpustats/util.py/tune_blocksize