diff --git a/ComputeGraph/README.md b/ComputeGraph/README.md index 9c8def7d..24e71808 100644 --- a/ComputeGraph/README.md +++ b/ComputeGraph/README.md @@ -12,11 +12,11 @@ 3. ### [Examples](examples/README.md) -4. ### [Python API](documentation/PythonAPI.md) +4. ### [Python API for creating graphs and schedulers](documentation/PythonAPI.md) -5. ### [C++ Default nodes](documentation/CPPNodes.md) +5. ### [C++ default nodes for C++ schedulers](documentation/CPPNodes.md) -6. ### [Python default nodes](documentation/PythonNodes.md) +6. ### [Python default nodes for Python schedulers](documentation/PythonNodes.md) 7. ### [Memory optimizations](documentation/Memory.md) diff --git a/ComputeGraph/documentation/CCodeGen.md b/ComputeGraph/documentation/CCodeGen.md index 8d13b978..364ae380 100644 --- a/ComputeGraph/documentation/CCodeGen.md +++ b/ComputeGraph/documentation/CCodeGen.md @@ -1,4 +1,4 @@ -# C Code generation +# C++ Code generation ## API @@ -21,12 +21,18 @@ Optional arguments to pass to the C API of the scheduler function It can either use a `string` or a list of `string` where an element is an argument of the function (and should be valid `C`). -For instance: +For instance, with: ```Python conf.cOptionalArgs=["int someVariable"] ``` +The API of the generated scheduler function would be: + +```C++ +uint32_t scheduler(int *error,int someVariable) +``` + ### codeArray (default = True) When true, the scheduling is defined as an array. Otherwise, a list of function calls is generated. diff --git a/ComputeGraph/documentation/CPPNodes.md b/ComputeGraph/documentation/CPPNodes.md index 08912f54..121d9686 100644 --- a/ComputeGraph/documentation/CPPNodes.md +++ b/ComputeGraph/documentation/CPPNodes.md @@ -4,7 +4,7 @@ Those classes are defined in `GenericNodes.h` a header that is always included by the scheduler. -As consequence, the definition for those classes is always included : that's the meaning of mandatory. +As consequence, the definition for those classes is always included. ### FIFO @@ -82,7 +82,7 @@ template class FIFO: public FIFOBase ``` -This implementation is a bit more heavy and is providing implementations of following function that is doing something useful : +This implementation is a bit more heavy and is providing implementations of following function : ```C++ bool willUnderflowWith(int nb) const; @@ -92,7 +92,7 @@ int nbSamplesInFIFO() const; ### Nodes -Nodes are inheriting from the virtual class: +All nodes are inheriting from the virtual class `NodeBase`: ```C++ class NodeBase @@ -269,7 +269,7 @@ class InterleavedStereoToMono; For specialization `q15_t` and `q31_t`, the inputs are divided by 2 before being added to avoid any overflow. -For specialization `float32_t` : The output is multiplied by `0.5f` for consistency for the fixed point version. +For specialization `float32_t` : The output is multiplied by `0.5f` for consistency with the fixed point version. ### MFCC @@ -317,7 +317,7 @@ The implementation is generic but will only build for a type `IN` having an addi This node is using a little memory (C++ vector) of size `overlap` that is allocated during creation of the node. -This node will overlap input data by `overlap` samples and add the common overlapping samples. +This node will overlap input data by `overlap` samples and sum the common overlapping samples. ### SlidingBuffer @@ -443,9 +443,9 @@ template class FileSource; There is only one specialization for the `float32_t` type. -It is reading text file with one float per file and generating a stream of float. +It is reading text file with one float per line and generating a stream of float. -At the end of file, 0s are generated on the output indefinitely. +At the end of file, 0.0f are generated on the output indefinitely. The constructor has an additional argument : the name/path of the input file: diff --git a/ComputeGraph/documentation/Generic.md b/ComputeGraph/documentation/Generic.md index d54f70e3..b10f3af3 100644 --- a/ComputeGraph/documentation/Generic.md +++ b/ComputeGraph/documentation/Generic.md @@ -1,26 +1,26 @@ -# Generic and functions nodes +# Description of the nodes The generic and function nodes are the basic nodes that you use to create other kind of nodes in the graph. -There are 3 generic classes provided by the framework to be used to create new nodes : +There are 3 generic classes provided by the framework to be used to create new nodes. + +To create a new kind of node, you inherit from one of those classes: * `GenericSource` * `GenericNode` * `GenericSink` -They are defined in `cmsisdsp.cg.scheduler` +They are defined in `cmsisdsp.cg.scheduler`. -There are 3 other classes that can be used to create new nodes from functions: +There are 3 other classes that can be used to create new nodes from functions. A function has no state and a C++ wrapper is not required. In this case, the tool is generating code for calling the function directly rather than using a C++ wrapper. -* `Unary` -* `Binary` -* `Dsp` +* `Unary` (unary operators like `negate`, `inverse` ...) +* `Binary` (binary operators like `add`, `mul` ...) +* `Dsp` (Some CMSIS-DSP function either binary or unary) # Generic Nodes -Any new kind of node must inherit from one of those classes. Those classes are providing the methods `addInput` and/or `addOutput` to define new IOs. - -The method `typeName` from the parent class must be overridden. +When you define a new kind of node, it must inherit from one of those classes. Those classes are providing the methods `addInput` and/or `addOutput` to define new inputs / outputs. A new kind of node is generally defined as: @@ -36,6 +36,20 @@ class ProcessingNode(GenericNode): return "ProcessingNode" ``` +The method `typeName` from the parent class must be overridden and provide the name of the `C++` wrapper to be used for this node. + +The object constructor is defining the inputs / outputs : number of samples and datatype. + +The object constructor is also defining the name used to identity this node in the generated code (so it must be a valid C variable name). + +`GenericSink` is only providing the `addInput` function. + +`GenericSource` is only providing the `addOutput` function + +`GenericNode` is providing both. + +You can use each function as much as you want to create several inputs and / or several outputs for a node. + See the [simple](../examples/simple/README.md) example for more explanation about how to define a new node. ## Methods @@ -46,7 +60,7 @@ The constructor of the node is using the `addInput` and/or `addOutput` to define def addInput(self,name,theType,theLength): ``` -* `name` is the name of the input. It will becomes a property of the Python object so it must not conflict with existing properties. If `name` is, for instance, "i" then it can be accessed with `node.i` in the code +* `name` is the name of the input. It will becomes a property of the Python object so it must not conflict with existing properties. If `name` is, for instance, `"i"` then it can be accessed with `node.i` in the code * `theType` is the datatype of the IO. It must inherit from `CGStaticType` (see below for more details about defining the types) * `theLength` is the amount of **samples** consumed by this IO at each execution of the node @@ -54,7 +68,7 @@ def addInput(self,name,theType,theLength): def addOutput(self,name,theType,theLength): ``` -* `name` is the name of the input. It will becomes a property of the Python object so it must not conflict with existing properties. If `name` is, for instance, "o" then it can be accessed with `node.o` in the code +* `name` is the name of the output. It will becomes a property of the Python object so it must not conflict with existing properties. If `name` is, for instance, `"o"` then it can be accessed with `node.o` in the code * `theType` is the datatype of the IO. It must inherit from `CGStaticType` (see below for more details about defining the types) * `theLength` is the amount of **samples** produced by this IO at each execution of the node @@ -70,9 +84,9 @@ This method defines the name of the C++ class implementing the wrapper for this Datatypes for the IOs are inheriting from `CGStaticType`. -Currently there are 3 classes defined: +Currently there are 3 classes defined in the project: -* `CType` for the standard CMSIS-DSP types +* `CType` for the standard CMSIS-DSP types like `q15_t`, `float32_t` ... * `CStructType` for a C struct * `PythonClassType` to create structured datatype for the Python scheduler @@ -104,7 +118,7 @@ def __init__(self,name,size_in_bytes): ``` * `name` is the name of the C struct -* `size_in_bytes` is the size of the struct. It should take into account padding. It is used in case of buffer sharing since the datatype of the shared buffer is `int8_t`. The Python script must be able to compute the size of those buffers and needs to know the size of the structure including padding. +* `size_in_bytes` is the size of the C struct. It should take into account padding. It is used when the compute graph memory optimization is used since size of the datatype is needed. ## PythonClassType @@ -125,9 +139,17 @@ Most CMSIS-DSP functions have no state. The compute graph framework is providing This feature is relying on the nodes: * `Unary` + * To use an unary operator like `negate`, `inverse` ... + * `Binary` + * To use a binary operator like `add`, `mul` ... + * `Dsp` + * Should detect if the CMSIS-DSP operator is unary or binary and use the datatype to compute the name of the function. In practice, only a subset of CMSIS-DSP function is supported so you should use `Unary` or `Binary` nodes + * `Constant` + * Special node to be used **only** with function nodes when some arguments cannot be connected to a FIFO. For instance, with `arm_scale_f32` the scaling factor is a scalar value and a FIFO cannot be connected to this argument. The function is a binary operator but between a stream and a scalar. + All of this is explained in detail in the [simple example with CMSIS-DSP](../examples/simpledsp/README.md). diff --git a/ComputeGraph/documentation/Graph.md b/ComputeGraph/documentation/Graph.md index 9ddcd4a8..e456b765 100644 --- a/ComputeGraph/documentation/Graph.md +++ b/ComputeGraph/documentation/Graph.md @@ -1,4 +1,4 @@ -# API of the Graph Class +# Adding nodes to the graph ## Creating a connection @@ -13,13 +13,14 @@ Typically this method is used as: ```python the_graph = Graph() -# Connect the source output to the processing node input +# Connect the source output to the processing node input and add this directed +# edge to the object the_graph the_graph.connect(src.o,processing.i) ``` -There are two optional arguments: +There are two optional arguments for the `connect` function: -* `fifoClass` : To use a different C++ class for implementing the connection between the two IOs. (it is also possible to change the FIFO class globally by setting an option on the graph. See below). Only the `FIFO` class is provided by default. Any new implementation must inherit from `FIFObase` +* `fifoClass` : To use a different C++ class for implementing the connection between the two IOs. (it is also possible to change the FIFO class globally by setting an option on the graph. See below). The `FIFO` class is provided by default. Any new implementation must inherit from `FIFObase` * `fifoScale` : In asynchronous mode, it is a scaling factor to increase the length of the FIFO compared to what has been computed by the synchronous approximation. This setting can also be set globally using the scheduler options. `fifoScale` is overriding the global setting. It must be a `float` (not an `int`). ```python @@ -55,3 +56,7 @@ Class used for FIFO by default. Can also be customized for each connection (`con Prefix used to generate the duplicate node classes like `Duplicate2`, `Duplicate3` ... +Those nodes are inserted automatically to implement one-to-many connections. + +If you need to connect an output to more than 3 nodes, you'll have to create the `Duplicate` nodes. + diff --git a/ComputeGraph/documentation/PythonAPI.md b/ComputeGraph/documentation/PythonAPI.md index 8345a703..7df84008 100644 --- a/ComputeGraph/documentation/PythonAPI.md +++ b/ComputeGraph/documentation/PythonAPI.md @@ -1,24 +1,28 @@ # Python API -Python APIs to describe the nodes and graph and generate the C++, Python or Graphviz code. +When you describe a graph and generate a scheduler there are 4 mandatory steps and one optional one: -1. ## [Graph class](Graph.md) +* Describing the nodes +* Adding the nodes to the graph +* Computing the schedule +* Generating the C++ and/or Python scheduler implementation +* Optional : Generating a graphviz `.dot` file with the graphical representation of the graph -2. ## [Generic, function nodes and datatypes](Generic.md) +1. ## [Description of the nodes](Generic.md) -3. ## Scheduler +2. ## [Adding nodes to the graph](Graph.md) - 1. ### [Schedule computation](SchedOptions.md) +3. ## [Schedule computation](SchedOptions.md) - 2. ### Code generation +4. ## Code generation - 1. #### [C++ Code generation](CCodeGen.md) + 1. #### [C++ Code generation](CCodeGen.md) - 2. #### [Python code generation](PythonGen.md) + 2. #### [Python code generation](PythonGen.md) - 3. #### [Graphviz representation](GraphvizGen.md) - - 4. #### [Common options](CodegenOptions.md) + 3. #### [Graphviz representation](GraphvizGen.md) + + 4. #### [Common options](CodegenOptions.md) diff --git a/ComputeGraph/documentation/PythonNodes.md b/ComputeGraph/documentation/PythonNodes.md index c5f29868..27621d9c 100644 --- a/ComputeGraph/documentation/PythonNodes.md +++ b/ComputeGraph/documentation/PythonNodes.md @@ -1,5 +1,9 @@ # Python Nodes and classes +Python implementation of the nodes to be run from a Python scheduler. + +You don't need this if you're only working with C++ schedulers. + (DOCUMENTATION TO BE WRITTEN) ## Mandatory classes