[Openembedded-architecture] Heterogeneous System Proposal

Mark Hatle mark.hatle at kernel.crashing.org
Mon Dec 2 21:37:15 UTC 2019


Problem Statement
-----------------
In the current world there is an increasing number of heterogeneous
systems being developed.  Currently these components can be built
independently of each other, and then combined later.  For ease of use,
it would be nice to be able to build these systems with a single build,
including generating a final bootable image.  A heterogeneous system may
simply be different configurations for different components, different
operating systems for different components, or a system made up of
diverse processor architectures.  Recently the Yocto Project has added
multiconfig in order to enable these types of configurations, but
suggested workflows for various configurations are needed to avoid
confusion and to avoid developers implementing their own schemes.

Proposal
--------
During the course of discussing this with other people a number of terms
have been involved, and after numerous discussions it is clear that
people have a different definition for the various components.  The
purpose of this document is to explain the various pieces of this
proposal, so that we can all be using the same items for the various
components necessary to build a heterogeneous system.

For a homogeneous build, the traditional Open Embedded/Yocto Project
components that are used include:

* Build Configuration (local.conf)
* MACHINE
   * Specifies target device information, including hardware
     capabilities, console settings, boot image configurations, etc.
     These settings are used by MACHINE packages, as well as image
     generation.
   * Define MACHINE in the conf/local.conf file in the Build Directory.
* SOC_FAMILY (optional, but implied by the machine)
   * Way to group together machines based upon common System On Chip
     components.
   * A SOC_FAMILY by itself is not a fully configured and bootable
     machine, but may be used by a series of machines to specify the
     common components.
* TUNE (typically specified implicitly by the machine)
   * Specifies the CPU (instruction set), and ABI settings available to
     the user
   * DEFAULTTUNE then selects which of the available tunes is to be used.
     This is usually set by the machine.
* DISTRO (Distribution Configuration)
   * Specifies cross recipe configurations that together result in an
     overall distribution configuration.
   * Define DISTRO in the conf/local.conf file in the Build Directory.
     If not specified, a default "nodistro" distribution is used.
* Recipes (.bb files)
   * Specify how to generically build individual items.  These recipes
     will inherit the system wide settings from the distribution
     configuration, and tune.  For MACHINE specific packages they can
     also inherit machine specific settings as well.
* Image Recipes
   * Specify a series of dependencies that cause recipes to be built and
     a list of resulting packages to be installed into a target image.
   * Image recipes are responsible for constructing a filesystem image.
     Further the system can extend these into a bootable disc image
     format.

In any sort of heterogeneous configuration we want to use and build upon
the existing homogeneous components.  A heterogeneous solution is really
comprised of a number of homogeneous configurations that when deployed
together result in a fully functional device.  In other words, each of
individual parts of the heterogeneous build are standalone and not tied
to the assembly of a specific system.

Based on this, we want to avoid any changes that complicate the existing
homogeneous build components or even adding additional levels of
configuration as this will complicate existing and future uses.  For
example, in the past there have been suggestions for SUBMACHINE or other
levels of hierarchy between SOC_FAMILY and MACHINE.  Adding this level
of indirection can make it more difficult to combine different
configurations into new heterogeneous solutions.  For example, if
someone has already defined a heterogeneous solution using a MACHINE,
SUBMACHINE, and SOC_FAMILY heirachy and you wish to extend it the
existing MACHINE / SUBMACHINE may interfear with your own systems unique
configuration.

There are a few types of heterogenous systems that I have seen.  Each of
them can be constructed by combining the output of homogeneous
configurations.  The most basic heterogenous systems I have seen include
either a collection of containers or different OSes, a primary CPU +
co-processors, or all of the CPUs are independent of each other but
share resources.  It is also possible to combine these heterogenous
configurations such as a multiple CPU system, with some CPUs having
co-processors with one or more CPU running containers.

In the case of the container based system, you really want a master
homogeneous machine configuration along with a few additional
configurations that can be incorporated into that image.  Using a
multilib configuration you would have something like:

build (build directory)
  conf
   local.conf:
    MACHINE = "genericx86_64"
    DISTRO = "poky"
    BBMULTICONFIG = "container1 containter2"
   multiconfig
    container1.conf:
     MACHINE = "genericx86_64"
     DISTRO = "mydistro1"
     TMPDIR = "${TOPDIR}/tmp/multi/container1"
    container2.conf:
     MACHINE = "genericx86_64"
     DISTRO = "mydistro2"
     TMPDIR = "${TOPDIR}/tmp/multi/container2"
layers
  meta-<custom_layer>
    conf
     distro
      mydistro1.conf
      mydistro2.conf
    recipes-images
     microservices
      service-image-1.bb
      service-image-2.bb
     other
      my-custom-image-recipe.bb:
       do_image[mcdepends] = "mc:container1:service-image1:do_rootfs \
                       mc:container2:service-image2:do_rootfs"
       do_image() { ... instructions for combining stuff ... }


This configuration allows for individual configurations for each
container and changes to the multiconfigs, but general re-use of much of
the system.  Especially if the distros in each one are same or similar.

Similar to the above, you could use a multiconfig system to combine
different operating systems.  For instance, instead of building a
standard-alone bare-metal style bootloader as part of the OS
configuration, you could think of it as an external non-OS application.
A configuration might look like:

build
  conf
   local.conf:
    MACHINE = "genericx86_64"
    DISTRO = "poky"
    BBMULTICONFIG = "bootloader"
   multiconfig
    bootloader.conf:
     MACHINE = "genericx86_64"
     DISTRO = "baremetal"
     TMPDIR = "${TOPDIR}/tmp/multi/bootloader"
layers
  meta-mybootloader
   conf
    distro
     baremetal.conf
   recipes
    newlib
     newlib_ver.bb
    first_stage
     first_stage.bb
    second_stage
     second_stage.bb
    bootloader
     bootloader.bb
      DEPENDS = "newlib first_stage second_stage"
  meta-<custom_layer>
   recipes
    bootloader
     mybootloader.bb
      depend on mc:bootloader:second_stage:....


For a simple heterogeneous solution, where the main CPU may need to load
software for co-processors, the configuration would be similar to the
above bare-metal example.  The difference would be that the MACHINE and
DISTRO settings for a DSP would need to have the necessary
configurations to properly build applications for the DSP.  Then the
Linux side of things can take this baremetal software and package it up
independently or in conjunction with software to actually configure and
load that software:

build
  conf
   local.conf:
    MACHINE = "myarmccpu"
    DISTRO = "poky"
    BBMULTICONFIG = "dsp"
   multiconfig
    dsp.conf:
     MACHINE = "magic-dsp"
     DISTRO = "baremetal"
     TMPDIR = "${TOPDIR}/tmp/multi/dsp"
layers
  meta-dsp
   conf
    distro
     baremetal.conf
    machine
     dsp.conf
   recipes-dsp
    newlib
     newlib_ver.bb
    library
     library.bb
    application
     application.bb
      DEPENDS = "newlib library application"
   recipes-linux
    dsp-application
     ...depends on application...

Note: in the above, separating the distro, machine and application
components into individual layers may be needed for Yocto Project
compliance.


In all of the above examples, the user has manually configured the
multiconfig within their project.  There is a simple way to move that
configuration to a layer, simply place it in a conf/multiconfig
directory within that layer.

This ability suggests to be that there should be a standard way to
specify a layer above that of machine, which defines the overall
characteristics of the system.

I'm proposing calling this new layer type as a system layer and it's
configuration variable "SYSTEM".  It will be used instead of MACHINE
when there is no single machine to quantify the contents of the produced
system image.  When implementing a system, we do not want to make major
changes to any other components.  Due to the existing implementation
requiring MACHINE and certain TUNE parameters, this will require us to
provide a special MACHINE value that can be used for a heterogeneous
system.  I suggest we create a new 'nomachine' system that only
defines/uses an equivalent noarch style tune.  This will instruct the
system that this configuration can be used to noarch software and create
images (including with wic), but it is not able to compile specific
applications.  Each of these applications or images must come from a
defined MACHINE.

The SYSTEM level multiconfig could be used to combine any homogeneous or
heterogeneous configuration.  For example:

build
  conf
   local.conf:
    SYSTEM = "mysystem"
layers
  meta-<system>
   conf
    system
     mysystem.conf
      MACHINE = "nomachine"
      BBMULTICONFIG = "bootloader fpga linux"
     mysystem.wks
    multiconfig
     bootloader.conf:
      MACHINE = "zcu102_microblaze"
      DISTRO = "baremetal"
      TMPDIR = "${TOPDIR}/tmp/multi/bootloader"
     fpga.conf:
      MACHINE = "zcu_fpga"
      DISTRO = "baremetal"
      TMPDIR = "${TOPDIR}/tmp/multi/fpga"
     linux.conf:
      MACHINE = "zcu_cortex-a72"
      DISTRO = "poky"
      TMPDIR = "${TOPDIR}/tmp/multi/linux"
   recipes
    images
     system-images.bb
      do_image[mcdepends] = "mc:bootloader:application:do_deploy \
                             mc:fpga:application:do_deploy \
                             mc:linux:core-image-minimal:do_rootfs"
      do_image() { ... instructions for combining stuff ... }
  meta-<machine>
   conf
    machine
     zcu_microblaze.conf
     zcu_fpga.conf
     zcu_cortext-a72.conf
  meta-mybootloader
   conf
    distro
     baremetal.conf
   recipes
    newlib
     newlib_ver.bb
    first_stage
     first_stage.bb
    second_stage
     second_stage.bb
    bootloader
     bootloader.bb
      DEPENDS = "newlib first_stage second_stage"
  meta-fpga
   conf
    distro
     baremetal.conf
   recipes-baremetal
    newlib
     newlib_ver.bb
    library
     library.bb
    application
     application.bb
      DEPENDS = "newlib library application"

So proposal:

Introduce a new OPTIONAL "SYSTEM" variable.  Which, like machine, would
automatically "include conf/${SYSTEM}.conf", if defined.

Introduce nomachine and notune, and adjust system components to know how
to deal with these properly.  I.e. recipes that are NOT noarch would be
be rejected in this configuration.

Introduce system layers to the yocto check script, and layer index.

Add documentation explaining the new SYSTEM variable and it's usage for
building complex heterogeneous systems.

Option:

If SYSTEM (as described above) does not make sense, then we could re-use
MACHINE instead, but I would still like a notune option for a 'machine'
that shouldn't have software compiled for it.

--Mark
This email and any attachments are intended for the sole use of the named
recipient(s) and contain(s) confidential information that may be proprietary,
privileged or copyrighted under applicable law. If you are not the intended
recipient, do not read, copy, or forward this email message or any attachments.
Delete this email message and any attachments immediately.


More information about the Openembedded-architecture mailing list