Improvement to compute graph

New cyclo static scheduler
New code generation mode using switch / case to decrease code size.
pull/53/head
Christophe Favergeon 3 years ago
parent 1edf36dff6
commit c91c8d6cec

@ -0,0 +1,36 @@
# Reference statistics
The different examples should return following schedule statistics:
## Example 1
Schedule length = 17
Memory usage 64 bytes
## Example 2
Schedule length = 302
Memory usage 10720 bytes
## Example 3
Schedule length = 25
Memory usage 11264 bytes
## Example 4
Schedule length = 25
Memory usage 11264 bytes
## Example 5
Schedule length = 292
Memory usage 6614 bytes
## Example 6
Schedule length = 17
Memory usage 2204 bytes
## Example 7
Schedule length = 3
Memory usage 512 bytes
## Example 8
Schedule length = 37
Memory usage 288 bytes

@ -14,6 +14,17 @@ The support classes and code is covered by CMSIS-DSP license.
#include "AppNodes.h"
#include "scheduler.h"
/*
Description of the scheduling. It is a list of nodes to call.
The values are indexes in the previous array.
*/
static unsigned int schedule[17]=
{
2,2,0,1,2,0,1,2,2,0,1,2,0,1,2,0,1,
};
/***********
FIFO buffers
@ -51,45 +62,40 @@ uint32_t scheduler(int *error,int someVariable)
/* Run several schedule iterations */
while((cgStaticError==0) && (debugCounter > 0))
{
/* Run a schedule iteration */
cgStaticError = source.run();
CHECKERROR;
cgStaticError = source.run();
CHECKERROR;
cgStaticError = filter.run();
CHECKERROR;
cgStaticError = sink.run();
CHECKERROR;
cgStaticError = source.run();
CHECKERROR;
cgStaticError = filter.run();
CHECKERROR;
cgStaticError = sink.run();
CHECKERROR;
cgStaticError = source.run();
CHECKERROR;
cgStaticError = source.run();
CHECKERROR;
cgStaticError = filter.run();
CHECKERROR;
cgStaticError = sink.run();
CHECKERROR;
cgStaticError = source.run();
CHECKERROR;
cgStaticError = filter.run();
CHECKERROR;
cgStaticError = sink.run();
CHECKERROR;
cgStaticError = source.run();
CHECKERROR;
cgStaticError = filter.run();
CHECKERROR;
cgStaticError = sink.run();
CHECKERROR;
/* Run a schedule iteration */
for(unsigned long id=0 ; id < 17; id++)
{
switch(schedule[id])
{
case 0:
{
cgStaticError = filter.run();
CHECKERROR;
}
break;
case 1:
{
cgStaticError = sink.run();
CHECKERROR;
}
break;
case 2:
{
cgStaticError = source.run();
CHECKERROR;
}
break;
default:
break;
}
}
debugCounter--;
nbSchedule++;
}
*error=cgStaticError;
return(nbSchedule);
}

File diff suppressed because it is too large Load Diff

@ -14,6 +14,17 @@ The support classes and code is covered by CMSIS-DSP license.
#include "AppNodes.h"
#include "scheduler.h"
/*
Description of the scheduling. It is a list of nodes to call.
The values are indexes in the previous array.
*/
static unsigned int schedule[25]=
{
6,2,0,7,3,4,8,1,6,2,0,7,3,4,8,2,0,7,3,4,1,5,8,1,5,
};
/***********
FIFO buffers
@ -86,12 +97,14 @@ uint32_t scheduler(int *error)
/* Run several schedule iterations */
while((cgStaticError==0) && (debugCounter > 0))
{
/* Run a schedule iteration */
cgStaticError = src.run();
CHECKERROR;
cgStaticError = audioWin.run();
CHECKERROR;
{
/* Run a schedule iteration */
for(unsigned long id=0 ; id < 25; id++)
{
switch(schedule[id])
{
case 0:
{
{
float32_t* i0;
float32_t* o2;
i0=fifo1.getReadBuffer(256);
@ -99,69 +112,74 @@ uint32_t scheduler(int *error)
arm_mult_f32(i0,HANN,o2,256);
cgStaticError = 0;
}
CHECKERROR;
cgStaticError = toCmplx.run();
CHECKERROR;
cgStaticError = cfft.run();
CHECKERROR;
cgStaticError = icfft.run();
CHECKERROR;
cgStaticError = toReal.run();
CHECKERROR;
cgStaticError = audioOverlap.run();
CHECKERROR;
cgStaticError = src.run();
CHECKERROR;
cgStaticError = audioWin.run();
CHECKERROR;
{
float32_t* i0;
float32_t* o2;
i0=fifo1.getReadBuffer(256);
o2=fifo2.getWriteBuffer(256);
arm_mult_f32(i0,HANN,o2,256);
cgStaticError = 0;
}
CHECKERROR;
cgStaticError = toCmplx.run();
CHECKERROR;
cgStaticError = cfft.run();
CHECKERROR;
cgStaticError = icfft.run();
CHECKERROR;
cgStaticError = toReal.run();
CHECKERROR;
cgStaticError = audioWin.run();
CHECKERROR;
{
float32_t* i0;
float32_t* o2;
i0=fifo1.getReadBuffer(256);
o2=fifo2.getWriteBuffer(256);
arm_mult_f32(i0,HANN,o2,256);
cgStaticError = 0;
}
CHECKERROR;
cgStaticError = toCmplx.run();
CHECKERROR;
cgStaticError = cfft.run();
CHECKERROR;
cgStaticError = icfft.run();
CHECKERROR;
cgStaticError = audioOverlap.run();
CHECKERROR;
cgStaticError = sink.run();
CHECKERROR;
cgStaticError = toReal.run();
CHECKERROR;
cgStaticError = audioOverlap.run();
CHECKERROR;
cgStaticError = sink.run();
CHECKERROR;
CHECKERROR;
}
break;
case 1:
{
cgStaticError = audioOverlap.run();
CHECKERROR;
}
break;
case 2:
{
cgStaticError = audioWin.run();
CHECKERROR;
}
break;
case 3:
{
cgStaticError = cfft.run();
CHECKERROR;
}
break;
case 4:
{
cgStaticError = icfft.run();
CHECKERROR;
}
break;
case 5:
{
cgStaticError = sink.run();
CHECKERROR;
}
break;
case 6:
{
cgStaticError = src.run();
CHECKERROR;
}
break;
case 7:
{
cgStaticError = toCmplx.run();
CHECKERROR;
}
break;
case 8:
{
cgStaticError = toReal.run();
CHECKERROR;
}
break;
default:
break;
}
}
debugCounter--;
nbSchedule++;
}
*error=cgStaticError;
return(nbSchedule);
}

@ -14,6 +14,17 @@ The support classes and code is covered by CMSIS-DSP license.
#include "AppNodes.h"
#include "scheduler.h"
/*
Description of the scheduling. It is a list of nodes to call.
The values are indexes in the previous array.
*/
static unsigned int schedule[17]=
{
4,0,1,2,3,3,4,0,1,2,3,3,0,1,2,3,3,
};
/***********
FIFO buffers
@ -63,45 +74,54 @@ uint32_t scheduler(int *error,arm_mfcc_instance_f32 *mfccConfig)
/* Run several schedule iterations */
while((cgStaticError==0) && (debugCounter > 0))
{
/* Run a schedule iteration */
cgStaticError = src.run();
CHECKERROR;
cgStaticError = audioWin.run();
CHECKERROR;
cgStaticError = mfcc.run();
CHECKERROR;
cgStaticError = mfccWin.run();
CHECKERROR;
cgStaticError = sink.run();
CHECKERROR;
cgStaticError = sink.run();
CHECKERROR;
cgStaticError = src.run();
CHECKERROR;
cgStaticError = audioWin.run();
CHECKERROR;
cgStaticError = mfcc.run();
CHECKERROR;
cgStaticError = mfccWin.run();
CHECKERROR;
cgStaticError = sink.run();
CHECKERROR;
cgStaticError = sink.run();
CHECKERROR;
cgStaticError = audioWin.run();
CHECKERROR;
cgStaticError = mfcc.run();
CHECKERROR;
cgStaticError = mfccWin.run();
CHECKERROR;
cgStaticError = sink.run();
CHECKERROR;
cgStaticError = sink.run();
CHECKERROR;
/* Run a schedule iteration */
for(unsigned long id=0 ; id < 17; id++)
{
switch(schedule[id])
{
case 0:
{
cgStaticError = audioWin.run();
CHECKERROR;
}
break;
case 1:
{
cgStaticError = mfcc.run();
CHECKERROR;
}
break;
case 2:
{
cgStaticError = mfccWin.run();
CHECKERROR;
}
break;
case 3:
{
cgStaticError = sink.run();
CHECKERROR;
}
break;
case 4:
{
cgStaticError = src.run();
CHECKERROR;
}
break;
default:
break;
}
}
debugCounter--;
nbSchedule++;
}
*error=cgStaticError;
return(nbSchedule);
}

@ -14,6 +14,17 @@ The support classes and code is covered by CMSIS-DSP license.
#include "AppNodes.h"
#include "scheduler.h"
/*
Description of the scheduling. It is a list of nodes to call.
The values are indexes in the previous array.
*/
static unsigned int schedule[37]=
{
6,6,1,5,0,4,3,2,6,1,6,5,0,4,3,2,6,1,5,0,4,3,2,6,1,6,5,0,4,3,2,1,5,0,4,3,2,
};
/***********
FIFO buffers
@ -75,85 +86,68 @@ uint32_t scheduler(int *error,int someVariable)
/* Run several schedule iterations */
while((cgStaticError==0) && (debugCounter > 0))
{
/* Run a schedule iteration */
cgStaticError = source.run();
CHECKERROR;
cgStaticError = source.run();
CHECKERROR;
cgStaticError = filter.run();
CHECKERROR;
cgStaticError = sd.run();
CHECKERROR;
cgStaticError = dup0.run();
CHECKERROR;
cgStaticError = sc.run();
CHECKERROR;
cgStaticError = sb.run();
CHECKERROR;
cgStaticError = sa.run();
CHECKERROR;
cgStaticError = source.run();
CHECKERROR;
cgStaticError = filter.run();
CHECKERROR;
cgStaticError = source.run();
CHECKERROR;
cgStaticError = sd.run();
CHECKERROR;
cgStaticError = dup0.run();
CHECKERROR;
cgStaticError = sc.run();
CHECKERROR;
cgStaticError = sb.run();
CHECKERROR;
cgStaticError = sa.run();
CHECKERROR;
cgStaticError = source.run();
CHECKERROR;
cgStaticError = filter.run();
CHECKERROR;
cgStaticError = sd.run();
CHECKERROR;
cgStaticError = dup0.run();
CHECKERROR;
cgStaticError = sc.run();
CHECKERROR;
cgStaticError = sb.run();
CHECKERROR;
cgStaticError = sa.run();
CHECKERROR;
cgStaticError = source.run();
CHECKERROR;
cgStaticError = filter.run();
CHECKERROR;
cgStaticError = source.run();
CHECKERROR;
cgStaticError = sd.run();
CHECKERROR;
cgStaticError = dup0.run();
CHECKERROR;
cgStaticError = sc.run();
CHECKERROR;
cgStaticError = sb.run();
CHECKERROR;
cgStaticError = sa.run();
CHECKERROR;
cgStaticError = filter.run();
CHECKERROR;
cgStaticError = sd.run();
CHECKERROR;
cgStaticError = dup0.run();
CHECKERROR;
cgStaticError = sc.run();
CHECKERROR;
cgStaticError = sb.run();
CHECKERROR;
cgStaticError = sa.run();
CHECKERROR;
/* Run a schedule iteration */
for(unsigned long id=0 ; id < 37; id++)
{
switch(schedule[id])
{
case 0:
{
cgStaticError = dup0.run();
CHECKERROR;
}
break;
case 1:
{
cgStaticError = filter.run();
CHECKERROR;
}
break;
case 2:
{
cgStaticError = sa.run();
CHECKERROR;
}
break;
case 3:
{
cgStaticError = sb.run();
CHECKERROR;
}
break;
case 4:
{
cgStaticError = sc.run();
CHECKERROR;
}
break;
case 5:
{
cgStaticError = sd.run();
CHECKERROR;
}
break;
case 6:
{
cgStaticError = source.run();
CHECKERROR;
}
break;
default:
break;
}
}
debugCounter--;
nbSchedule++;
}
*error=cgStaticError;
return(nbSchedule);
}

@ -42,7 +42,10 @@ def gencode(sched,directory,config):
schedDescription=""
if config.codeArray:
ctemplate = env.get_template("codeArray.cpp")
if config.switchCase:
ctemplate = env.get_template("codeSwitch.cpp")
else:
ctemplate = env.get_template("codeArray.cpp")
nb = 0
for s in sched.schedule:
schedDescription = schedDescription + ("%d," % sched.nodes[s].codeID)

@ -63,7 +63,10 @@ class Configuration:
# When codeArray is true, instead of using
# function calls we parse un array giving
# the index of functions to call in another array
self.codeArray = False
self.codeArray = True
# If users do not want to use function pointers,
# we can generate a switch/case instead
self.switchCase = True
# True for an horizontal graphviz layout
self.horizontal = True

@ -505,6 +505,10 @@ class Graph():
def topologyMatrix(self):
self.checkGraph()
# For cyclo static scheduling : compute the node periods
for n in self.nodes:
n.computeCyclePeriod()
rows=[]
# This is used in schedule generation
# and all functions must use the same node ordering
@ -522,21 +526,27 @@ class Graph():
ib=self._sortedNodes.index(nb.owner)
# Produced by na on the edge
currentRow[ia] = na.nbSamples
# for execution of one cycle of the na.owner node
totalProduced = na.cycleTotal * na.owner.cyclePeriod // na.cyclePeriod
currentRow[ia] = totalProduced
# Consumed by nb on the edge
currentRow[ib] = -nb.nbSamples
# for execution of a full cycle of the node
totalProduced = nb.cycleTotal * nb.owner.cyclePeriod // nb.cyclePeriod
currentRow[ib] = -totalProduced
rows.append(currentRow)
return(np.array(rows))
def nullVector(self):
m = self.topologyMatrix()
def nullVector(self,m):
#print("Null vector")
# m is topology matrix computed with toplogyMatrix
r=Matrix(m).nullspace()
if len(r) != 1:
raise NotSchedulableError
result=list(r[0])
#print(result)
denominators = [x.q for x in result]
# Remove denominators
ppcm = ilcm(*denominators)
@ -544,17 +554,72 @@ class Graph():
intValues = [x * ppcm for x in result]
# Convert intValues to the smallest possible values
gcd = igcd(*intValues)
return([x / gcd for x in intValues])
return([x // gcd for x in intValues])
@property
def initEvolutionVector(self):
"""Initial FIFO state taking into account delays"""
return(np.array([self.getDelay(x) for x in self.edges]))
def evolutionVectorForNode(self,nodeID):
def evolutionVectorForNode(self,nodeID,test=True):
"""Return the evolution vector corresponding to a selected node"""
v = np.zeros(len(self._sortedNodes))
v[nodeID] = 1
# For a simple static scheduling, the toplogy matrix T
# is enough. If we know which node is executed, we have
# a node vector V where there is a 1 at the position of the
# execute node.
# And the data generated on the fifos is:
# T . V so the new fifo vector B' is given with
# B' = T .V + B
# But in case of cyclo static scheduling the topology
# matrix is for a full period of the node
# so 1 or several periods of each IO.
# And we don't have the granularity corresponding to
# one node execution.
# For one node execution, we need to know where we are
# in the cycle on each IO
# and where we are in the cycle for the node to
# track how many full eriods of the node execution have been
# done.
# So this function is not just returning the node vector
# and letting the main function updating the fifos.
# This function is returning the new fifo state
# Node vector would have been
# v = np.zeros(len(self._sortedNodes))
# v[nodeID] = 1
# for cyclo static scheduling
n = self._sortedNodes[nodeID]
#print(n)
v = np.zeros(len(self._sortedEdges))
# In test mode we are testing several nodes
# to find the best one to schedule.
# So we should not advance the cycle
# of the IOs
for i in n._inputs:
io = n._inputs[i]
edge = io._fifo
# If 0, it is a connection to a constant node
# so there is no FIFO
if len(edge)>0:
pos = self._sortedEdges.index(edge)
v[pos] = -io.cycleValue
if not test:
io.advanceCycle()
for o in n._outputs:
io = n._outputs[o]
edge = io._fifo
# If 0 it is a connection to a constant edge
# so there is no FIFO
if len(edge)>0:
pos = self._sortedEdges.index(edge)
v[pos] = io.cycleValue
if not test:
io.advanceCycle()
#print(v)
return(v)
@ -565,9 +630,21 @@ class Graph():
# After this transform, each output should be connected to
# only one output.
self.insertDuplicates()
networkMatrix = self.topologyMatrix()
# Init values
initB = self.initEvolutionVector
initN = self.nullVector()
initN = self.nullVector(networkMatrix)
#print(initN)
# nullVector is giving the number of repetitions
# for a node cycle.
# So the number of iteration of the node must be multiplied
# by the cycle period for this node.
#for nodeID in range(len(self._sortedNodes)):
# initN[nodeID] = initN[nodeID] * self._sortedNodes[nodeID].cyclePeriod
# Current values (copys)
b = np.array(initB)
@ -579,7 +656,9 @@ class Graph():
print(b)
# Topology matrix
t = np.array(self.topologyMatrix())
t = np.array(networkMatrix)
#print(t)
#print(n)
# Define the list of FIFOs objects
nbFIFOS = t.shape[0]
@ -588,7 +667,18 @@ class Graph():
allFIFOs.append(FIFODesc(i))
# Normalization vector
normV = 1.0*np.apply_along_axis(abs,1,t).max(axis=1)
# For static scheduling it is
#normV = 1.0*np.apply_along_axis(abs,1,t).max(axis=1)
# For cyclo static scheduling we need the max per execution
# and not the accumulated value for the run of a node
# period which may be several periods of an IO
#print(normV)
normV = np.zeros(len(self._sortedEdges))
for e in range(len(self._sortedEdges)):
(src,dst) = self._sortedEdges[e]
normV[e] = max(src.cycleMax, dst.cycleMax)
#print(normV)
# bMax below is used to track maximum FIFO size
# occuring during a run of the schedule
@ -615,8 +705,11 @@ class Graph():
zeroVec = np.zeros(len(self._sortedNodes))
evolutionTime = 0
# While there are remaining nodes to schedule
#print(self._sortedNodes)
# While there are remaining node periods to schedule
while (n != zeroVec).any():
#print("")
#print(n)
# Look for the best node to schedule
# which is the one giving the minimum FIFO increase
@ -629,10 +722,14 @@ class Graph():
for node in self._sortedNodes:
# If the node can be scheduled
if n[nodeID] > 0:
# Evolution vector if this node is selected
v = self.evolutionVectorForNode(nodeID)
# Evolution vector for static scheduling
# v = self.evolutionVectorForNode(nodeID)
# for cyclo static we need the new fifo state
newB = self.evolutionVectorForNode(nodeID) + b
# New fifos size after this evolution
newB = np.dot(t,v) + b
# For static scheduling, fifo update would have been
# newB = np.dot(t,v) + b
#print(newB)
# Check that there is no FIFO underflow:
if np.all(newB >= 0):
@ -656,13 +753,28 @@ class Graph():
# Now we have evaluated all schedulable nodes for this run
# and selected the one giving the smallest FIFO increase
# Implementation for static scheduling
# Real evolution vector for selected node
evol = self.evolutionVectorForNode(selected)
# evol = self.evolutionVectorForNode(selected)
# Keep track that this node has been schedule
n = n - evol
# n = n - evol
# Compute new fifo state
fifoChange = np.dot(t,evol)
# fifoChange = np.dot(t,evol)
# b = fifoChange + b
# Implementation for cyclo static scheduling
#print("selected")
fifoChange = self.evolutionVectorForNode(selected,test=False)
b = fifoChange + b
# For cyclo static, we create an evolution vector
# which contains a 1
# at a node position only if this node has executed
# its period.
# Otherwise the null vector is not decreased
v = np.zeros(len(self._sortedNodes))
v[selected] = self._sortedNodes[selected].executeNode()
n = n - v
if config.displayFIFOSizes:
print(b)

@ -29,6 +29,10 @@
from jinja2 import Environment, FileSystemLoader, PackageLoader,select_autoescape
import pathlib
import os.path
import numpy as np
from sympy.core.numbers import ilcm
class NoFunctionArrayInPython(Exception):
pass
@ -51,12 +55,69 @@ class IO:
"""Class of input / outputs"""
def __init__(self,owner,name,theType,nbSamples):
self._theType = theType
# For cycle static scheduling it may also be
# a list of samples for each iteration of a cycle
self._nbSamples = nbSamples
self._owner = owner
self._name = name
self._fifo = []
self.constantNode = None
# For cyclo static scheduling nbSamples is a list
# and when simulating the schedule we need to know
# where we currently are in the list
self._cyclePosition = 0
# For cyclo static scheduling we advance the position in the
# cycle
def advanceCycle(self):
if isinstance(self.nbSamples,int):
pass
else:
self._cyclePosition = self._cyclePosition + 1
if self._cyclePosition == len(self.nbSamples):
self._cyclePosition = 0
# For cyclo static scheduling, get the value in the current
# cycle position
@property
def cycleValue(self):
if isinstance(self.nbSamples,int):
return(self.nbSamples)
else:
return(self.nbSamples[self._cyclePosition])
# For cyclo static scheduling: we need
# the length of the cycle
@property
def cyclePeriod(self):
if isinstance(self.nbSamples,int):
return(1)
else:
return(len(self.nbSamples))
# For cyclo static scheduling we need the total
# data generated by a run of the cycle
@property
def cycleTotal(self):
if isinstance(self.nbSamples,int):
return(self.nbSamples)
else:
return(np.sum(self.nbSamples))
# For cyclo static we need the max in a period top use
# as a normalization factor to identify the most filled
# FIFO
@property
def cycleMax(self):
if isinstance(self.nbSamples,int):
return(self.nbSamples)
else:
return(np.max(self.nbSamples))
@property
def fifo(self):
return self._fifo
@ -182,6 +243,15 @@ class BaseNode:
# Literal arguments
self.schedArgs=None
# For cyclo static scheduling
# It is the LCM of the cycles of all
# connected edges.
# After this period, the node and its edges
# should be back to the original state
self.cyclePeriod = 1
self._positionInCycle = 0
def __getattr__(self,name):
"""Present inputs / outputs as attributes"""
if name in self._inputs:
@ -198,6 +268,33 @@ class BaseNode:
return(self._outputs[name])
raise IndexError
# For cyclo static scheduling we need to compute
# the cycle period for this node based upon the
# period of the IOs
def computeCyclePeriod(self):
allLengths = []
for k in self._inputs:
allLengths.append(self._inputs[k].cyclePeriod)
for k in self._outputs:
allLengths.append(self._outputs[k].cyclePeriod)
if len(allLengths)>1:
self.cyclePeriod = ilcm(*allLengths)
else:
self.cyclePeriod = allLengths[0]
# For cyclo static scheduling, we need to track the number
# of period execution
# We return 1 when a period has been executed
# and this is used to decrease the period count in
# the null vector of the toplogy matrix
def executeNode(self):
self._positionInCycle = self._positionInCycle + 1
if (self._positionInCycle == self.cyclePeriod):
self._positionInCycle = 0
return(1)
else:
return(0)
def addLiteralArg(self,l):
if self.schedArgs:
self.schedArgs.append(ArgLiteral(l))
@ -279,11 +376,24 @@ class BaseNode:
# Use ordered io names
for io in self.inputNames:
x = self._inputs[io]
ios.append("%s,%d" % (x.ctype,x.nbSamples))
# For cyclo static scheduling, we may have a list
# of samples
if isinstance(x.nbSamples,int):
ios.append("%s,%d" % (x.ctype,x.nbSamples))
else:
# In case of a list of samples
# thne templaet is receiving only the
# max value
m = np.max(x.nbSamples)
ios.append("%s,%d" % (x.ctype,m))
for io in self.outputNames:
x = self._outputs[io]
ios.append("%s,%d" % (x.ctype,x.nbSamples))
if isinstance(x.nbSamples,int):
ios.append("%s,%d" % (x.ctype,x.nbSamples))
else:
m = np.max(x.nbSamples)
ios.append("%s,%d" % (x.ctype,m))
return("".join(joinit(ios,",")))
@ -297,13 +407,24 @@ class BaseNode:
"""
ios=[]
# Use ordered io names
# For cyclo static scheduling, the nbSamples
# may be a list and we use the max value
# for the code generayion
for io in self.inputNames:
x = self._inputs[io]
ios.append("%d" % x.nbSamples)
if isinstance(x.nbSamples,int):
ios.append("%d" % x.nbSamples)
else:
m = np.max(x.nbSamples)
ios.append("%d" % m)
for io in self.outputNames:
x = self._outputs[io]
ios.append("%d" % x.nbSamples)
if isinstance(x.nbSamples,int):
ios.append("%d" % x.nbSamples)
else:
m = np.max(x.nbSamples)
ios.append("%d" % m)
return("".join(joinit(ios,",")))
@ -589,7 +710,12 @@ class GenericFunction(GenericNode):
tempgen.append("%s,input%dSize" % (x.ctype,inputid))
constructortypes.append("FIFOBase<%s> &src%d" % (x.ctype,inputid))
genericconstructorargs.append("src%d" % inputid)
ios.append("%s,%d" % (x.ctype,x.nbSamples))
# For cyclo static scheduling, nbSamples may be a list
if isinstance(x.nbSamples,int):
ios.append("%s,%d" % (x.ctype,x.nbSamples))
else:
m = np.max(x.nbSamples)
ios.append("%s,%d" % (x.ctype,m))
typenameID = typenameID + 1
for io in self.outputNames:
@ -602,7 +728,11 @@ class GenericFunction(GenericNode):
tempgen.append("%s,output%dSize" % (x.ctype,outputid))
constructortypes.append("FIFOBase<%s> &dst%d" % (x.ctype,outputid))
genericconstructorargs.append("dst%d" % outputid)
ios.append("%s,%d" % (x.ctype,x.nbSamples))
if isinstance(x.nbSamples,int):
ios.append("%s,%d" % (x.ctype,x.nbSamples))
else:
m = np.max(x.nbSamples)
ios.append("%s,%d" % (x.ctype,m))
typenameID = typenameID + 1
self._realInputs = inputid
@ -697,7 +827,13 @@ class GenericFunction(GenericNode):
theType=self._inputs[self.inputNames[0]].ctype
else:
theType=self._inputs[self.inputNames[0]].nptype
theLen = self._inputs[self.inputNames[0]].nbSamples
# For cyclo static scheduling, nbSamples may be a list
# and in this case we are uding the mac value
nbSamples = self._inputs[self.inputNames[0]].nbSamples
if isinstance(nbSamples,int):
theLen = self._inputs[self.inputNames[0]].nbSamples
else:
theLen = np.max(nbSamples)
theId = 0
# List of buffer and corresponding fifo to initialize buffers
inputs=[]

@ -1,3 +1,4 @@
{% extends "commonc.cpp" %}
/*
Generated with CMSIS-DSP Compute Graph Scripts.
@ -21,50 +22,10 @@ The support classes and code is covered by CMSIS-DSP license.
{% if config.cOptionalArgs %},{{config.cOptionalArgs}}{% endif %}
{% endmacro -%}
/***********
{% block schedArray %}
{% endblock %}
FIFO buffers
************/
{% for fifo in fifos %}
#define FIFOSIZE{{fifo.fifoID}} {{fifo.length}}
{% endfor %}
{% for buf in sched._graph._allBuffers %}
#define BUFFERSIZE{{buf._bufferID}} {{buf._length}}
{{buf._theType.ctype}} {{config.prefix}}buf{{buf._bufferID}}[BUFFERSIZE{{buf._bufferID}}]={0};
{% endfor %}
uint32_t {{config.schedName}}(int *error{{optionalargs()}})
{
int cgStaticError=0;
uint32_t nbSchedule=0;
{% if config.debug %}
int32_t debugCounter={{config.debugLimit}};
{% endif %}
/*
Create FIFOs objects
*/
{% for id in range(nbFifos) %}
{% if fifos[id].hasDelay %}
FIFO<{{fifos[id].theType.ctype}},FIFOSIZE{{id}},{{fifos[id].isArrayAsInt}}> fifo{{id}}({{config.prefix}}buf{{fifos[id].buffer._bufferID}},{{fifos[id].delay}});
{% else %}
FIFO<{{fifos[id].theType.ctype}},FIFOSIZE{{id}},{{fifos[id].isArrayAsInt}}> fifo{{id}}({{config.prefix}}buf{{fifos[id].buffer._bufferID}});
{% endif %}
{% endfor %}
/*
Create node objects
*/
{% for node in nodes %}
{% if node.hasState %}
{{node.typeName}}<{{node.ioTemplate()}}> {{node.nodeName}}({{node.args}});
{% endif %}
{% endfor %}
/* Run several schedule iterations */
{% block scheduleLoop %}
{% if config.debug %}
while((cgStaticError==0) && (debugCounter > 0))
{% else %}
@ -88,6 +49,5 @@ uint32_t {{config.schedName}}(int *error{{optionalargs()}})
{% endif %}
nbSchedule++;
}
*error=cgStaticError;
return(nbSchedule);
}
{% endblock %}

@ -0,0 +1,46 @@
{% extends "commonc.cpp" %}
{% block schedArray %}
/*
Description of the scheduling. It is a list of nodes to call.
The values are indexes in the previous array.
*/
static unsigned int schedule[{{schedLen}}]=
{
{{schedDescription}}
};
{% endblock %}
{% block scheduleLoop %}
{% if config.debug %}
while((cgStaticError==0) && (debugCounter > 0))
{% else %}
while(cgStaticError==0)
{% endif %}
{
/* Run a schedule iteration */
for(unsigned long id=0 ; id < {{schedLen}}; id++)
{
switch(schedule[id])
{
{% for nodeID in range(nbNodes) -%}
case {{nodeID}}:
{
{{nodes[nodeID].cRun()}}
CHECKERROR;
}
break;
{% endfor %}default:
break;
}
}
{% if config.debug %}
debugCounter--;
{% endif %}
nbSchedule++;
}
{% endblock %}

@ -0,0 +1,75 @@
/*
Generated with CMSIS-DSP Compute Graph Scripts.
The generated code is not covered by CMSIS-DSP license.
The support classes and code is covered by CMSIS-DSP license.
*/
{% if config.dumpFIFO %}
#define DEBUGSCHED 1
{% endif %}
#include "arm_math.h"
#include "custom.h"
#include "GenericNodes.h"
#include "AppNodes.h"
#include "scheduler.h"
{% macro optionalargs() -%}
{% if config.cOptionalArgs %},{{config.cOptionalArgs}}{% endif %}
{% endmacro -%}
{% block schedArray %}
{% endblock %}
/***********
FIFO buffers
************/
{% for fifo in fifos %}
#define FIFOSIZE{{fifo.fifoID}} {{fifo.length}}
{% endfor %}
{% for buf in sched._graph._allBuffers %}
#define BUFFERSIZE{{buf._bufferID}} {{buf._length}}
{{buf._theType.ctype}} {{config.prefix}}buf{{buf._bufferID}}[BUFFERSIZE{{buf._bufferID}}]={0};
{% endfor %}
uint32_t {{config.schedName}}(int *error{{optionalargs()}})
{
int cgStaticError=0;
uint32_t nbSchedule=0;
{% if config.debug %}
int32_t debugCounter={{config.debugLimit}};
{% endif %}
/*
Create FIFOs objects
*/
{% for id in range(nbFifos) %}
{% if fifos[id].hasDelay %}
FIFO<{{fifos[id].theType.ctype}},FIFOSIZE{{id}},{{fifos[id].isArrayAsInt}}> fifo{{id}}({{config.prefix}}buf{{fifos[id].buffer._bufferID}},{{fifos[id].delay}});
{% else %}
FIFO<{{fifos[id].theType.ctype}},FIFOSIZE{{id}},{{fifos[id].isArrayAsInt}}> fifo{{id}}({{config.prefix}}buf{{fifos[id].buffer._bufferID}});
{% endif %}
{% endfor %}
/*
Create node objects
*/
{% for node in nodes %}
{% if node.hasState %}
{{node.typeName}}<{{node.ioTemplate()}}> {{node.nodeName}}({{node.args}});
{% endif %}
{% endfor %}
/* Run several schedule iterations */
{% block scheduleLoop %}
{% endblock %}
*error=cgStaticError;
return(nbSchedule);
}
Loading…
Cancel
Save