Improvement to compute graph
More customization options New (experimental) scheduling algorithm to improve latencies.pull/53/head
parent
8ed2ef7a7e
commit
5a99a5c5ad
@ -0,0 +1,109 @@
|
||||
/* ----------------------------------------------------------------------
|
||||
* Project: CMSIS DSP Library
|
||||
* Title: AppNodes.h
|
||||
* Description: Application nodes for Example 1
|
||||
*
|
||||
* $Date: 29 July 2021
|
||||
* $Revision: V1.10.0
|
||||
*
|
||||
* Target Processor: Cortex-M and Cortex-A cores
|
||||
* -------------------------------------------------------------------- */
|
||||
/*
|
||||
* Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef _APPNODES_H_
|
||||
#define _APPNODES_H_
|
||||
|
||||
#include <iostream>
|
||||
|
||||
template<typename IN, int inputSize>
|
||||
class Sink: public GenericSink<IN, inputSize>
|
||||
{
|
||||
public:
|
||||
Sink(FIFOBase<IN> &src):GenericSink<IN,inputSize>(src){};
|
||||
|
||||
int run()
|
||||
{
|
||||
IN *b=this->getReadBuffer();
|
||||
printf("Sink\n");
|
||||
for(int i=0;i<inputSize;i++)
|
||||
{
|
||||
std::cout << (int)b[i] << std::endl;
|
||||
}
|
||||
return(0);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template<typename OUT,int outputSize>
|
||||
class Source: GenericSource<OUT,outputSize>
|
||||
{
|
||||
public:
|
||||
Source(FIFOBase<OUT> &dst):GenericSource<OUT,outputSize>(dst),mCounter(0){};
|
||||
|
||||
int run(){
|
||||
OUT *b=this->getWriteBuffer();
|
||||
|
||||
printf("Source\n");
|
||||
for(int i=0;i<outputSize;i++)
|
||||
{
|
||||
b[i] = (OUT)mCounter++;
|
||||
}
|
||||
return(0);
|
||||
};
|
||||
|
||||
int mCounter;
|
||||
|
||||
};
|
||||
|
||||
template<typename IN1, int inputSize1,
|
||||
typename IN2, int inputSize2,
|
||||
typename OUT,int outputSize>
|
||||
class ProcessingNode;
|
||||
|
||||
template<int inputSize>
|
||||
class ProcessingNode<float32_t,inputSize,
|
||||
float32_t,inputSize,
|
||||
float32_t,inputSize>:
|
||||
public GenericNode21<float32_t,inputSize,
|
||||
float32_t,inputSize,
|
||||
float32_t,inputSize>
|
||||
{
|
||||
public:
|
||||
ProcessingNode(FIFOBase<float32_t> &src1,
|
||||
FIFOBase<float32_t> &src2,
|
||||
FIFOBase<float32_t> &dst):
|
||||
GenericNode21<float32_t,inputSize,
|
||||
float32_t,inputSize,
|
||||
float32_t,inputSize>(src1,src2,dst){};
|
||||
|
||||
int run(){
|
||||
printf("ProcessingNode\n");
|
||||
float32_t *a=this->getReadBuffer1();
|
||||
float32_t *b=this->getReadBuffer2();
|
||||
float32_t *c=this->getWriteBuffer();
|
||||
|
||||
for(int i=0;i<inputSize;i++)
|
||||
{
|
||||
c[i] = a[i] + 0.5f*b[i];
|
||||
}
|
||||
return(0);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,13 @@
|
||||
cmake_minimum_required (VERSION 3.14)
|
||||
include(CMakePrintHelpers)
|
||||
|
||||
project(Example9)
|
||||
|
||||
|
||||
add_executable(example9 main.cpp)
|
||||
|
||||
sdf(example9)
|
||||
add_sdf_dir(example9)
|
||||
|
||||
target_include_directories(example9 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_include_directories(example9 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/generated)
|
||||
@ -0,0 +1,3 @@
|
||||
#ifndef _CUSTOM_H_
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,188 @@
|
||||
/*
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "arm_math.h"
|
||||
#include "custom.h"
|
||||
#include "GenericNodes.h"
|
||||
#include "AppNodes.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
#if !defined(CHECKERROR)
|
||||
#define CHECKERROR if (cgStaticError < 0) \
|
||||
{\
|
||||
goto errorHandling;\
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_ITERATION)
|
||||
#define CG_BEFORE_ITERATION
|
||||
#endif
|
||||
|
||||
#if !defined(CG_AFTER_ITERATION)
|
||||
#define CG_AFTER_ITERATION
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_SCHEDULE)
|
||||
#define CG_BEFORE_SCHEDULE
|
||||
#endif
|
||||
|
||||
#if !defined(CG_AFTER_SCHEDULE)
|
||||
#define CG_AFTER_SCHEDULE
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_BUFFER)
|
||||
#define CG_BEFORE_BUFFER
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_FIFO_BUFFERS)
|
||||
#define CG_BEFORE_FIFO_BUFFERS
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_FIFO_INIT)
|
||||
#define CG_BEFORE_FIFO_INIT
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_NODE_INIT)
|
||||
#define CG_BEFORE_NODE_INIT
|
||||
#endif
|
||||
|
||||
#if !defined(CG_AFTER_INCLUDES)
|
||||
#define CG_AFTER_INCLUDES
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_SCHEDULER_FUNCTION)
|
||||
#define CG_BEFORE_SCHEDULER_FUNCTION
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_NODE_EXECUTION)
|
||||
#define CG_BEFORE_NODE_EXECUTION
|
||||
#endif
|
||||
|
||||
#if !defined(CG_AFTER_NODE_EXECUTION)
|
||||
#define CG_AFTER_NODE_EXECUTION
|
||||
#endif
|
||||
|
||||
CG_AFTER_INCLUDES
|
||||
|
||||
/*
|
||||
|
||||
Description of the scheduling.
|
||||
|
||||
*/
|
||||
static unsigned int schedule[4]=
|
||||
{
|
||||
3,1,0,2,
|
||||
};
|
||||
|
||||
CG_BEFORE_FIFO_BUFFERS
|
||||
/***********
|
||||
|
||||
FIFO buffers
|
||||
|
||||
************/
|
||||
#define FIFOSIZE0 5
|
||||
#define FIFOSIZE1 5
|
||||
#define FIFOSIZE2 5
|
||||
#define FIFOSIZE3 5
|
||||
|
||||
#define BUFFERSIZE1 5
|
||||
CG_BEFORE_BUFFER
|
||||
float32_t buf1[BUFFERSIZE1]={0};
|
||||
|
||||
#define BUFFERSIZE2 5
|
||||
CG_BEFORE_BUFFER
|
||||
float32_t buf2[BUFFERSIZE2]={0};
|
||||
|
||||
#define BUFFERSIZE3 5
|
||||
CG_BEFORE_BUFFER
|
||||
float32_t buf3[BUFFERSIZE3]={0};
|
||||
|
||||
#define BUFFERSIZE4 5
|
||||
CG_BEFORE_BUFFER
|
||||
float32_t buf4[BUFFERSIZE4]={0};
|
||||
|
||||
|
||||
CG_BEFORE_SCHEDULER_FUNCTION
|
||||
uint32_t scheduler(int *error,int someVariable)
|
||||
{
|
||||
int cgStaticError=0;
|
||||
uint32_t nbSchedule=0;
|
||||
int32_t debugCounter=2;
|
||||
|
||||
CG_BEFORE_FIFO_INIT;
|
||||
/*
|
||||
Create FIFOs objects
|
||||
*/
|
||||
FIFO<float32_t,FIFOSIZE0,1> fifo0(buf1);
|
||||
FIFO<float32_t,FIFOSIZE1,1> fifo1(buf2);
|
||||
FIFO<float32_t,FIFOSIZE2,1> fifo2(buf3);
|
||||
FIFO<float32_t,FIFOSIZE3,0> fifo3(buf4,5);
|
||||
|
||||
CG_BEFORE_NODE_INIT;
|
||||
/*
|
||||
Create node objects
|
||||
*/
|
||||
Duplicate2<float32_t,5,float32_t,5,float32_t,5> dup0(fifo1,fifo2,fifo3);
|
||||
ProcessingNode<float32_t,5,float32_t,5,float32_t,5> filter(fifo0,fifo3,fifo1);
|
||||
Sink<float32_t,5> sink(fifo2);
|
||||
Source<float32_t,5> source(fifo0);
|
||||
|
||||
/* Run several schedule iterations */
|
||||
CG_BEFORE_SCHEDULE;
|
||||
while((cgStaticError==0) && (debugCounter > 0))
|
||||
{
|
||||
/* Run a schedule iteration */
|
||||
CG_BEFORE_ITERATION;
|
||||
for(unsigned long id=0 ; id < 4; id++)
|
||||
{
|
||||
CG_BEFORE_NODE_EXECUTION;
|
||||
switch(schedule[id])
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
cgStaticError = dup0.run();
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
cgStaticError = filter.run();
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
cgStaticError = sink.run();
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
cgStaticError = source.run();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CG_AFTER_NODE_EXECUTION;
|
||||
CHECKERROR;
|
||||
}
|
||||
debugCounter--;
|
||||
CG_AFTER_ITERATION;
|
||||
nbSchedule++;
|
||||
}
|
||||
|
||||
errorHandling:
|
||||
CG_AFTER_SCHEDULE;
|
||||
*error=cgStaticError;
|
||||
return(nbSchedule);
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _SCHED_H_
|
||||
#define _SCHED_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
extern uint32_t scheduler(int *error,int someVariable);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -0,0 +1,73 @@
|
||||
from cmsisdsp.cg.static.scheduler import *
|
||||
|
||||
### Define new types of Nodes
|
||||
|
||||
class Node(GenericNode):
|
||||
def __init__(self,name,theType,inLength,outLength):
|
||||
GenericNode.__init__(self,name)
|
||||
self.addInput("ia",theType,inLength)
|
||||
self.addInput("ib",theType,inLength)
|
||||
self.addOutput("o",theType,outLength)
|
||||
|
||||
class Sink(GenericSink):
|
||||
def __init__(self,name,theType,inLength):
|
||||
GenericSink.__init__(self,name)
|
||||
self.addInput("i",theType,inLength)
|
||||
|
||||
@property
|
||||
def typeName(self):
|
||||
return "Sink"
|
||||
|
||||
class Source(GenericSource):
|
||||
def __init__(self,name,theType,inLength):
|
||||
GenericSource.__init__(self,name)
|
||||
self.addOutput("o",theType,inLength)
|
||||
|
||||
@property
|
||||
def typeName(self):
|
||||
return "Source"
|
||||
|
||||
class ProcessingNode(Node):
|
||||
@property
|
||||
def typeName(self):
|
||||
return "ProcessingNode"
|
||||
|
||||
|
||||
|
||||
### Define nodes
|
||||
floatType=CType(F32)
|
||||
src=Source("source",floatType,5)
|
||||
b=ProcessingNode("filter",floatType,5,5)
|
||||
sink=Sink("sink",floatType,5)
|
||||
|
||||
g = Graph()
|
||||
|
||||
g.connect(src.o,b.ia)
|
||||
g.connect(b.o,sink.i)
|
||||
# With less than 5, the tool cannot find a possible schedule
|
||||
# and is generating a DeadLock error
|
||||
g.connectWithDelay(b.o,b.ib,5)
|
||||
|
||||
|
||||
print("Generate graphviz and code")
|
||||
|
||||
conf=Configuration()
|
||||
conf.debugLimit=2
|
||||
conf.cOptionalArgs="int someVariable"
|
||||
#conf.displayFIFOSizes=True
|
||||
# Prefix for global FIFO buffers
|
||||
#conf.prefix="sched1"
|
||||
|
||||
#conf.dumpSchedule = True
|
||||
sched = g.computeSchedule(config=conf)
|
||||
#print(sched.schedule)
|
||||
print("Schedule length = %d" % sched.scheduleLength)
|
||||
print("Memory usage %d bytes" % sched.memory)
|
||||
#
|
||||
|
||||
#conf.codeArray=True
|
||||
sched.ccode("generated",conf)
|
||||
|
||||
with open("test.dot","w") as f:
|
||||
sched.graphviz(f)
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include "scheduler.h"
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
int error;
|
||||
printf("Start\n");
|
||||
uint32_t nbSched=scheduler(&error,1);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
|
||||
|
||||
|
||||
|
||||
digraph structs {
|
||||
node [shape=plaintext]
|
||||
rankdir=LR
|
||||
edge [arrowsize=0.5]
|
||||
fontname="times"
|
||||
|
||||
|
||||
dup0 [shape=point,label=dup0]
|
||||
|
||||
|
||||
filter [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD PORT="ia"><FONT POINT-SIZE="9.0">ia</FONT></TD>
|
||||
<TD ALIGN="CENTER" ROWSPAN="2">filter<BR/>(ProcessingNode)</TD>
|
||||
<TD PORT="o"><FONT POINT-SIZE="9.0">o</FONT></TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD PORT="ib"><FONT POINT-SIZE="9.0">ib</FONT></TD>
|
||||
|
||||
|
||||
<TD></TD></TR>
|
||||
|
||||
</TABLE>>];
|
||||
|
||||
sink [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">sink<BR/>(Sink)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
source [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">source<BR/>(Source)</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
|
||||
|
||||
source:i -> filter:ia [label="f32(5)"
|
||||
,headlabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
|
||||
</TD></TR></TABLE>>
|
||||
,taillabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
|
||||
</TD></TR></TABLE>>]
|
||||
|
||||
filter:o ->
|
||||
dup0 [label="f32(5)"
|
||||
|
||||
,taillabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
|
||||
</TD></TR></TABLE>>]
|
||||
|
||||
|
||||
dup0 -> sink:i [label="f32(5)"
|
||||
,headlabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
|
||||
</TD></TR></TABLE>>
|
||||
]
|
||||
dup0Delay [label=<
|
||||
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
|
||||
<TR>
|
||||
<TD ALIGN="CENTER" PORT="i">5</TD>
|
||||
</TR>
|
||||
</TABLE>>];
|
||||
|
||||
|
||||
|
||||
dup0 -> dup0Delay:i [label=""]
|
||||
|
||||
dup0Delay:i -> filter:ib [label="f32(5)"
|
||||
,headlabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
|
||||
</TD></TR></TABLE>>]
|
||||
|
||||
|
||||
|
||||
}
|
||||
Binary file not shown.
@ -0,0 +1,55 @@
|
||||
#if !defined(CHECKERROR)
|
||||
#define CHECKERROR if (cgStaticError < 0) \
|
||||
{\
|
||||
goto errorHandling;\
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_ITERATION)
|
||||
#define CG_BEFORE_ITERATION
|
||||
#endif
|
||||
|
||||
#if !defined(CG_AFTER_ITERATION)
|
||||
#define CG_AFTER_ITERATION
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_SCHEDULE)
|
||||
#define CG_BEFORE_SCHEDULE
|
||||
#endif
|
||||
|
||||
#if !defined(CG_AFTER_SCHEDULE)
|
||||
#define CG_AFTER_SCHEDULE
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_BUFFER)
|
||||
#define CG_BEFORE_BUFFER
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_FIFO_BUFFERS)
|
||||
#define CG_BEFORE_FIFO_BUFFERS
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_FIFO_INIT)
|
||||
#define CG_BEFORE_FIFO_INIT
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_NODE_INIT)
|
||||
#define CG_BEFORE_NODE_INIT
|
||||
#endif
|
||||
|
||||
#if !defined(CG_AFTER_INCLUDES)
|
||||
#define CG_AFTER_INCLUDES
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_SCHEDULER_FUNCTION)
|
||||
#define CG_BEFORE_SCHEDULER_FUNCTION
|
||||
#endif
|
||||
|
||||
#if !defined(CG_BEFORE_NODE_EXECUTION)
|
||||
#define CG_BEFORE_NODE_EXECUTION
|
||||
#endif
|
||||
|
||||
#if !defined(CG_AFTER_NODE_EXECUTION)
|
||||
#define CG_AFTER_NODE_EXECUTION
|
||||
#endif
|
||||
@ -1,2 +1,2 @@
|
||||
# Python wrapper version
|
||||
__version__ = "1.8.1"
|
||||
__version__ = "1.9.0"
|
||||
|
||||
Loading…
Reference in New Issue