Overview
The purpose of this document is to specify how applications can be created and executed in OpenCPI. The OpenCPI framework supports Component-Based Development, where applications are composed of pre-existing components that may exist in ready-to-run binary form before the application is even defined.
An OpenCPI component is a functional abstraction with a specifically defined control and configuration interface based on configuration properties, and zero or more data ports, each with a defined messaging protocol. An OpenCPI Component Specification (OCS) describes both of these aspects of a component, establishing interface requirements for multiple implementations (workers) of the component. Workers are developed and coded based on an OCS, and when built, are available for applications that are defined in terms of components that meet a spec. An application identifies the components it uses by the name of their spec.
Having one or more libraries of prebuilt, ready-to-run component implementations (a.k.a. workers) is a prerequisite for running OpenCPI applications. The syntax and semantics of component specifications (OCS), and how component implementations are developed, are defined in the OpenCPI Component Development Guide (CDG). Creating and running applications for OpenCPI does not require the knowledge of how components are developed, but it does require some knowledge of how they are specified. Component specifications are discussed briefly in this document, and described in detail in the CDG.
OpenCPI applications are defined as assemblies of component instances with connections among them. They can be specified two different ways:
A standalone XML document (text file).
An XML document embedded in, and manipulated by, a C++ program.
This document specifies:
The format and contents of the XML documents that define applications
A utility program that directly executes the applications defined in XML files
A C++ and Python API for manipulating and executing XML-based applications
There are also related sections describing:
How to use other network-attached systems when executing applications, a.k.a. remote containers.
How to develop and run applications in OpenCPI projects, which are development work areas for groups of assets like components and applications.
How create FPGA artifacts which are HDL assemblies of workers that can implement a subset of an application for execution on an FPGA platform.
OpenCPI uses several terms when describing component-based applications. In particular:
Component: a specific function used to compose applications. Components are described by an XML document called a component specification.
Instance: the use of a component in an application (a part of an application).
Application: the composition of instances
Worker: a concrete implementation of a component, in three contexts: source code, compiled code for some target platform, runtime object executing the compiled code.
Container: the OpenCPI execution environment on some platform that will execute workers (i.e. where they execute).
Port: a communication interface of a component or worker, with which they send and receive messages with other components/workers.
Property: a configuration value applied to a component to control its function. Components have defined properties with defined data types, and workers implement those properties. Workers (specific implementations) may have additional properties beyond those defined by the component (spec) being implemented.
Platform: a particular type of processing hardware and/or software that can host a container for executing OpenCPI workers.
Artifact: a file containing binary code for one or more workers, built for a platform.
Artifact Library: a collection of artifacts in a hierarchical file system directory structure.
PackageID: a globally unique identifier for OpenCPI assets, in this case used to identify component specifications.
System: a collection of platforms usually in a box or on a system bus or fabric.
The OpenCPI execution framework for component-based applications is based on workers executing in containers (on platforms), communicating via their ports, and configured via their properties. The runtime workers are instances of component implementations realized in artifact files. The term artifact is used as a technology neutral term which represents a compiled binary file that is the resulting artifact of compiling and linking (or for FPGAs, synthesizing etc.) some source code that implements some components. We use the term worker both for a specific (coded) implementation of a component, as well as the runtime instances of that implementation.
The component development and build process results in artifacts that can be loaded as needed and used to instantiate the runtime workers. Typical artifacts are “shared object” or “dynamic library” files on UNIX systems for software workers, and “bitstreams” for FPGA workers. While it is typical for artifacts to hold the implementation code for one worker, it is also common to build artifact files that contain multiple worker implementations.
OpenCPI applications are created by specifying which components should be instantiated (using some artifacts), how the resulting workers should be connected, and how they should be configured via their properties. Specifying an instance is based on the package ID of the component specification.
The runtime software uses a package ID to search the available artifact libraries for available implementations in artifacts, and matches those (binary) implementations to the available containers (processors of various types), running on platforms in the system. The result of the search is a set of potential candidate workers for each instance. To be a candidate, an implementation must be able to execute in some available container.
The package ID of a component specification generally has a prefix followed by package name
(followed by a period). This prefix is the name scope in which the component is defined. This allows
components to be specified and implemented by different organizations, while still allowing any
implementation found in a library to satisfy any (other) organization’s component specifications.
E.g., my project can have an additional, alternative implementation of a component specified in
another library, or can define its own specification for a component with the same name in a
different package ID name scope. OpenCPI package naming follows the Java package naming
conventions, with the addition of two special top-level packages: local and ocpi.
To actually run the application, the deployment decision is made for each instance in the application:
which implementation/artifact should be used, and
which container (running on some platform) should it run in.
A set of mutually feasible deployment decisions results in the overall deployment of the application.
Unless a specific implementation is indicated, the OCPI_LIBRARY_PATH environment variable
is used to indicate a list of colon-separated directories or files, which are searched to locate
artifact files containing component implementations. The directories are searched recursively.
During this search, when the deployment decisions are made, there may be multiple possible
deployments. Each possible deployment is scored and the first deployment among those with the best
score is used. If two artifacts are considered equivalent, the one found earlier in
OCPI_LIBRARY_PATH will be used. OCPI_LIBRARY_PATH is used similar to the
LD_LIBRARY_PATH on Linux systems except that it descends recursively into directories
when doing the search.
The relationships between applications, artifacts, containers, workers, platforms etc. is shown in the following diagram:
Figure 4: An Application of Components Deployed on a System