Skip to content

Commit

Permalink
sw: Add optimized AXPY, Covariance, SYRK and Doitgen kernels (#185)
Browse files Browse the repository at this point in the history
  • Loading branch information
colluca authored Aug 29, 2024
1 parent d024b04 commit 3ba276e
Show file tree
Hide file tree
Showing 49 changed files with 1,800 additions and 305 deletions.
1 change: 0 additions & 1 deletion sw/apps/atax/.gitignore

This file was deleted.

23 changes: 11 additions & 12 deletions sw/apps/atax/scripts/datagen.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@

import numpy as np

from snitch.util.sim.data_utils import format_scalar_definition, format_array_definition, \
format_array_declaration, format_ifdef_wrapper, DataGen
import snitch.util.sim.data_utils as du


# AXI splits bursts crossing 4KB address boundaries. To minimize
# the occurrence of these splits the data should be aligned to 4KB
BURST_ALIGNMENT = 4096


class AtaxDataGen(DataGen):
class AtaxDataGen(du.DataGen):

def golden_model(self, A, x):
return np.matmul(A.transpose(), np.matmul(A, x))
Expand All @@ -26,8 +25,8 @@ def emit_header(self, **kwargs):
header = [super().emit_header()]

M, N = kwargs['M'], kwargs['N']
A = np.random.randint(-200, 100, size=(M, N))/100
x = np.random.randint(-200, 100, size=(N, 1))/100
A = du.generate_random_array((M, N))
x = du.generate_random_array((N, 1))
y = self.golden_model(A, x)

assert (M % 8) == 0, "M must be an integer multiple of the number of cores"
Expand All @@ -37,13 +36,13 @@ def emit_header(self, **kwargs):
x = x.flatten()
y = y.flatten()

header += [format_scalar_definition('uint32_t', 'M', M)]
header += [format_scalar_definition('uint32_t', 'N', N)]
header += [format_array_definition('double', 'A', A, alignment=BURST_ALIGNMENT)]
header += [format_array_definition('double', 'x', x, alignment=BURST_ALIGNMENT)]
header += [format_array_declaration('double', 'y', y.shape, alignment=BURST_ALIGNMENT)]
result_def = format_array_definition('double', 'golden', y, alignment=BURST_ALIGNMENT)
header += [format_ifdef_wrapper('BIST', result_def)]
header += [du.format_scalar_definition('uint32_t', 'M', M)]
header += [du.format_scalar_definition('uint32_t', 'N', N)]
header += [du.format_array_definition('double', 'A', A, alignment=BURST_ALIGNMENT)]
header += [du.format_array_definition('double', 'x', x, alignment=BURST_ALIGNMENT)]
header += [du.format_array_declaration('double', 'y', y.shape, alignment=BURST_ALIGNMENT)]
result_def = du.format_array_definition('double', 'golden', y, alignment=BURST_ALIGNMENT)
header += [du.format_ifdef_wrapper('BIST', result_def)]
header = '\n\n'.join(header)

return header
Expand Down
2 changes: 1 addition & 1 deletion sw/apps/common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ DATA_H := $($(APP)_BUILD_DIR)/data.h
DATAGEN_PY = $(SCRIPTS_DIR)/datagen.py

$(APP)_HEADERS := $(DATA_H)
$(APP)_INCDIRS := $(dir $(DATA_H)) $(SRC_DIR)
$(APP)_INCDIRS += $(dir $(DATA_H)) $(SRC_DIR)

$(dir $(DATA_H)):
mkdir -p $@
Expand Down
1 change: 0 additions & 1 deletion sw/apps/correlation/.gitignore

This file was deleted.

22 changes: 11 additions & 11 deletions sw/apps/correlation/scripts/datagen.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@

import numpy as np

from snitch.util.sim.data_utils import format_scalar_definition, format_array_definition, \
format_array_declaration, format_ifdef_wrapper, DataGen
import snitch.util.sim.data_utils as du


# AXI splits bursts crossing 4KB address boundaries. To minimize
# the occurrence of these splits the data should be aligned to 4KB
BURST_ALIGNMENT = 4096


class CorrelationDataGen(DataGen):
class CorrelationDataGen(du.DataGen):

def golden_model(self, data):
return np.corrcoef(data, rowvar=False)
Expand All @@ -26,19 +25,20 @@ def emit_header(self, **kwargs):
header = [super().emit_header()]

M, N = kwargs['M'], kwargs['N']
data = np.random.randint(-200, 100, size=(N, M))/100
data = du.generate_random_array((N, M))
corr = self.golden_model(data)

data = data.flatten()
corr = corr.flatten()

header += [format_scalar_definition('uint32_t', 'M', M)]
header += [format_scalar_definition('uint32_t', 'N', N)]
header += [format_array_definition('double', 'data', data, alignment=BURST_ALIGNMENT)]
header += [format_array_declaration('double', 'corr', corr.shape,
alignment=BURST_ALIGNMENT)]
result_def = format_array_definition('double', 'golden', corr, alignment=BURST_ALIGNMENT)
header += [format_ifdef_wrapper('BIST', result_def)]
header += [du.format_scalar_definition('uint32_t', 'M', M)]
header += [du.format_scalar_definition('uint32_t', 'N', N)]
header += [du.format_array_definition('double', 'data', data, alignment=BURST_ALIGNMENT)]
header += [du.format_array_declaration('double', 'corr', corr.shape,
alignment=BURST_ALIGNMENT)]
result_def = du.format_array_definition('double', 'golden', corr,
alignment=BURST_ALIGNMENT)
header += [du.format_ifdef_wrapper('BIST', result_def)]
header = '\n\n'.join(header)

return header
Expand Down
1 change: 0 additions & 1 deletion sw/apps/covariance/.gitignore

This file was deleted.

6 changes: 4 additions & 2 deletions sw/apps/covariance/data/params.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// SPDX-License-Identifier: Apache-2.0

{
M: 16,
N: 8
"m": 32,
"n": 2,
"m_tiles": 2,
"funcptr": "covariance_opt"
}
64 changes: 47 additions & 17 deletions sw/apps/covariance/scripts/datagen.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,68 @@

import numpy as np

from snitch.util.sim.data_utils import format_scalar_definition, format_array_definition, \
format_array_declaration, format_ifdef_wrapper, DataGen
import snitch.util.sim.data_utils as du

np.random.seed(42)

# AXI splits bursts crossing 4KB address boundaries. To minimize
# the occurrence of these splits the data should be aligned to 4KB
BURST_ALIGNMENT = 4096
DOUBLE_BUFFER = True


class CovarianceDataGen(DataGen):
class CovarianceDataGen(du.DataGen):

# Function pointers to alternative implementations
FUNCPTRS = ["covariance_naive", "covariance_baseline", "covariance_opt"]

def golden_model(self, data):
return np.cov(data, rowvar=False)

def validate(self, **kwargs):
n_cores = 8
assert (kwargs['m'] % kwargs['m_tiles']) == 0, "m must be an integer multiple of m_tiles"
m_per_tile = kwargs['m'] / kwargs['m_tiles']
assert (m_per_tile % n_cores) == 0, \
"m_per_tile must be an integer multiple of the number of cores"
assert (m_per_tile % 4) == 0, "m_per_tile must be an integer multiple of unroll1 = 4"
m_per_core = m_per_tile / n_cores
assert (m_per_core % 2) == 0, "m_per_core must be an integer multiple of the unroll0 = 2"
assert kwargs['funcptr'] in self.FUNCPTRS, f"Function pointer must be among {self.FUNCPTRS}"

# Calculate total TCDM occupation
a_tile_size = m_per_tile * kwargs['n'] * 8
b_tile_size = m_per_tile * m_per_tile * 8
total_size = 2 * a_tile_size + b_tile_size
if DOUBLE_BUFFER:
total_size *= 2
du.validate_tcdm_footprint(total_size)

def emit_header(self, **kwargs):
header = [super().emit_header()]

M, N = kwargs['M'], kwargs['N']
data = np.random.randint(-200, 100, size=(N, M))
cov = self.golden_model(data)
self.validate(**kwargs)

assert (M % 8) == 0, "M must be an integer multiple of the number of cores"
data = du.generate_random_array((kwargs['n'], kwargs['m']))
cov = self.golden_model(data)

data = data.flatten()
data = data.transpose().flatten()
cov = cov.flatten()

header += [format_scalar_definition('uint32_t', 'M', M)]
header += [format_scalar_definition('uint32_t', 'N', N)]
header += [format_array_definition('double', 'data', data, alignment=BURST_ALIGNMENT)]
header += [format_array_declaration('double', 'cov', cov.shape, alignment=BURST_ALIGNMENT)]
result_def = format_array_definition('double', 'golden', cov, alignment=BURST_ALIGNMENT)
header += [format_ifdef_wrapper('BIST', result_def)]
data_uid = 'data'
cov_uid = 'cov'

cfg = {
'm': kwargs['m'],
'n': kwargs['n'],
'inv_n': 1 / kwargs['n'],
'inv_n_m1': 1 / (kwargs['n'] - 1),
'data': data_uid,
'cov': cov_uid,
'm_tiles': kwargs['m_tiles'],
'funcptr': kwargs['funcptr']
}

header += [du.format_array_definition('double', data_uid, data)]
header += [du.format_array_declaration('double', cov_uid, cov.shape)]
header += [du.format_struct_definition('covariance_args_t', 'args', cfg)]
header = '\n\n'.join(header)

return header
Expand Down
20 changes: 16 additions & 4 deletions sw/apps/covariance/scripts/verify.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,26 @@ class CovarianceVerifier(Verifier):

OUTPUT_UIDS = ['cov']

def __init__(self):
super().__init__()
self.func_args = {
'm': 'I',
'n': 'I',
'inv_n': 'd',
'inv_n_m1': 'd',
'data': 'I',
'cov': 'I',
'm_tiles': 'I',
'funcptr': 'I'
}
self.func_args = self.get_input_from_symbol('args', self.func_args)

def get_actual_results(self):
return self.get_output_from_symbol('cov', 'double')
return self.get_output_from_symbol(self.OUTPUT_UIDS[0], 'double')

def get_expected_results(self):
M = self.get_input_from_symbol('M', 'uint32_t')[0]
N = self.get_input_from_symbol('N', 'uint32_t')[0]
data = self.get_input_from_symbol('data', 'double')
data = np.reshape(data, (N, M))
data = np.reshape(data, (self.func_args['m'], self.func_args['n'])).transpose()
return CovarianceDataGen().golden_model(data).flatten()

def check_results(self, *args):
Expand Down
23 changes: 23 additions & 0 deletions sw/apps/covariance/src/args.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2024 ETH Zurich and University of Bologna.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Author: Luca Colagrande <[email protected]>

#pragma once
#include <stdint.h>

typedef void (*covariance_fp_t)(uint32_t m, uint32_t n, double inv_n,
double inv_n_m1, double *data, double *datat,
double *cov);

typedef struct {
uint32_t m;
uint32_t n;
double inv_n;
double inv_n_m1;
double *data;
double *cov;
uint32_t m_tiles;
covariance_fp_t funcptr;
} covariance_args_t;
Loading

0 comments on commit 3ba276e

Please sign in to comment.