Skip to content

Commit

Permalink
sw: Add doitgen kernel
Browse files Browse the repository at this point in the history
  • Loading branch information
colluca committed Aug 20, 2024
1 parent 5401e44 commit ed2b667
Show file tree
Hide file tree
Showing 9 changed files with 498 additions and 0 deletions.
1 change: 1 addition & 0 deletions sw/apps/doitgen/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
data/data.h
12 changes: 12 additions & 0 deletions sw/apps/doitgen/data/params.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// 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

{
"r": 32,
"q": 32,
"s": 8,
"r_tiles": 2,
"q_tiles": 2,
"funcptr": "doitgen_baseline"
}
90 changes: 90 additions & 0 deletions sw/apps/doitgen/scripts/datagen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/env python3
# 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]>

import numpy as np

from snitch.util.sim import data_utils
from snitch.util.sim.data_utils import format_array_definition, format_struct_definition, DataGen

np.random.seed(42)

DOUBLE_BUFFER = True


class DoitgenDataGen(DataGen):

# Function pointers to alternative implementations
FUNCPTRS = ["doitgen_naive", "doitgen_baseline", "doitgen_opt"]

def golden_model(self, A, x):
R, Q, S = A.shape
P, _ = x.shape
Aout = np.ndarray((R, Q, P))
for r in range(R):
for q in range(Q):
for p in range(P):
Aout[r, q, p] = 0
for s in range(S):
Aout[r, q, p] += A[r, q, s] * x[p, s]
return Aout

def validate(self, **kwargs):
n_cores = 8
assert (kwargs['r'] % kwargs['r_tiles']) == 0, "r must be an integer multiple of r_tiles"
assert (kwargs['q'] % kwargs['q_tiles']) == 0, "q must be an integer multiple of q_tiles"
if kwargs['funcptr'] != 'doitgen_naive':
assert (kwargs['s'] % 4) == 0, "s must be an integer multiple of unrolling factor"
r_per_tile = kwargs['r'] / kwargs['r_tiles']
q_per_tile = kwargs['q'] / kwargs['q_tiles']
assert (r_per_tile % n_cores) == 0, "r_per_tile must be an integer multiple of n_cores"
assert kwargs['funcptr'] in self.FUNCPTRS, f"Function pointer must be among {self.FUNCPTRS}"

# Calculate total TCDM occupation
a_tile_size = r_per_tile * q_per_tile * kwargs['s'] * 8
x_size = kwargs['s'] * kwargs['s'] * 8
total_size = 2 * a_tile_size + x_size
if DOUBLE_BUFFER:
total_size *= 2
data_utils.validate_tcdm_footprint(total_size)

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

self.validate(**kwargs)

A = np.random.randint(-100, 100, size=(kwargs['r'], kwargs['q'], kwargs['s']))
x = np.random.randint(-100, 100, size=(kwargs['s'], kwargs['s']))

_ = self.golden_model(A, x)

A = A.flatten()
x = x.flatten()

A_uid = 'A'
x_uid = 'x'

cfg = {
'r': kwargs['r'],
'q': kwargs['q'],
's': kwargs['s'],
'A': A_uid,
'x': x_uid,
'r_tiles': kwargs['r_tiles'],
'q_tiles': kwargs['q_tiles'],
'funcptr': kwargs['funcptr']
}

header += [format_array_definition('double', A_uid, A)]
header += [format_array_definition('double', x_uid, x)]
header += [format_struct_definition('doitgen_args_t', 'args', cfg)]
header = '\n\n'.join(header)

return header


if __name__ == '__main__':
DoitgenDataGen().main()
48 changes: 48 additions & 0 deletions sw/apps/doitgen/scripts/verify.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env python3
# 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
#
# Luca Colagrande <[email protected]>

import numpy as np
import sys
from datagen import DoitgenDataGen

from snitch.util.sim.verif_utils import Verifier


class DoitgenVerifier(Verifier):

OUTPUT_UIDS = ['A']

def __init__(self):
super().__init__()
self.func_args = {
'r': 'I',
'q': 'I',
's': 'I',
'A': 'I',
'x': 'I',
'r_tiles': 'I',
'q_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(self.OUTPUT_UIDS[0], 'double')

def get_expected_results(self):
A = self.get_input_from_symbol('A', 'double')
A = np.reshape(A, (self.func_args['r'], self.func_args['q'], self.func_args['s']))
x = self.get_input_from_symbol('x', 'double')
x = np.reshape(x, (self.func_args['s'], self.func_args['s']))
return DoitgenDataGen().golden_model(A, x).flatten()

def check_results(self, *args):
return super().check_results(*args, rtol=1e-10)


if __name__ == "__main__":
sys.exit(DoitgenVerifier().main())
22 changes: 22 additions & 0 deletions sw/apps/doitgen/src/args.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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 (*doitgen_fp_t)(uint32_t r, uint32_t q, uint32_t s,
double *A, double *x, double *Aout);

typedef struct {
uint32_t r;
uint32_t q;
uint32_t s;
double *A;
double *x;
uint32_t r_tiles;
uint32_t q_tiles;
doitgen_fp_t funcptr;
} doitgen_args_t;
Loading

0 comments on commit ed2b667

Please sign in to comment.