Contact: [email protected] [email protected]
This uses the mujoco simulator to demonstrate the static scheduler.
-
Install Lingua Franca. Make sure to switch to the
static-schedule
branch first.$ git clone [email protected]:lf-lang/lingua-franca.git $ cd lingua-franca $ git checkout static-schedule $ git submodule update --init --recursive $ ./gradlew assemble
-
Install MuJoCo.
Make sure that the MuJoCo dynamic libraries and header files are in the compiler search path (e.g.,
usr/local/lib
andusr/local/include
). This step can be done if you follow the build from source instructions. -
Install GLFW.
-
Adjust
src/mujoco.cmake
accordingly.On some platforms, you might need to adjust this cmake file so that the dependencies can be located.
For example, here is one possible version
# My mujoco/mujoco.h is in /usr/local/include. include_directories(/usr/local/include) find_package (Threads) find_library(MUJOCO_LIBRARY NAMES mujoco PATHS /usr/local/lib/libmujoco.dylib /usr/local/lib/libmujoco.3.1.1.dylib) if(NOT MUJOCO_LIBRARY) message(FATAL_ERROR "MuJoCo library not found") endif() find_library(GLFW_LIBRARY NAMES glfw PATHS /usr/local/Cellar/glfw/3.3.9/lib/libglfw.dylib /usr/local/Cellar/glfw/3.3.9/lib/libglfw.3.dylib /usr/local/Cellar/glfw/3.3.9/lib/libglfw.3.3.dylib) if(NOT GLFW_LIBRARY) message(FATAL_ERROR "Glfw library not found") endif() target_link_libraries(${LF_MAIN_TARGET} ${CMAKE_THREAD_LIBS_INIT} ${MUJOCO_LIBRARY} ${GLFW_LIBRARY})
-
Compile the LF program using
lfc-dev
.lfc-dev src/ReactionWheel.lf
The following instructions describe the steps to compile and execute
src/CompressFiles.lf
such that execution time and energy are enhanced under
the guidance of Mocasin.
-
Make sure Lingua Franca is installed (as described above) and switched to the
static-schedule
branch. -
Install Mocasin
-
In
src/CompressFiles.lf
, under thescheduler
target property, make sure thattype
is set toSTATIC
andstatic-scheduler
is set toMOCASIN
. DO NOT setmocasin-mapping
yet.scheduler: { type: STATIC, static-scheduler: MOCASIN, // mocasin-mapping: [ // "./mappings/mappings-opt-0.csv", // "./mappings/mappings-subopt-1.csv", // "./mappings/mappings-opt-2.csv", // ], },
-
Compile the program using
lfc-dev
.$ lfc-dev src/CompressFiles.lf
If everything goes well, you should see
--- Generating a static schedule lfc: info: SDF3 files generated. Please invoke `mocasin` to generate mappings and provide paths to them using the `mocasin-mapping` target property under `scheduler`. A sample mocasin command is `mocasin pareto_front graph=sdf3_reader trace=sdf3_reader platform=odroid sdf3.file=<abs_path_to_xml>`
-
Invoke
mocasin
to generate mappings. Insrc-gen/CompressFiles/mocasin/
, there should now be some XML files generated.$ cd src-gen/CompressFiles/mocasin/ $ mocasin pareto_front graph=sdf3_reader trace=sdf3_reader platform=odroid sdf3.file=./sdf_frag_0.xml $ mocasin pareto_front graph=sdf3_reader trace=sdf3_reader platform=odroid sdf3.file=./sdf_frag_1.xml $ mocasin pareto_front graph=sdf3_reader trace=sdf3_reader platform=odroid sdf3.file=./sdf_frag_2.xml
There should now be an
output/
directory undersrc-gen/CompressFiles/mocasin/
with threemappings.csv
inside. -
Choose the best mapping. Open each
mappings.csv
, select your desired mapping by moving it to the first row, under the column headers. -
Register the mappings in the LF program. Now, open
src/CompressFiles.lf
again and set the paths of the modifiedmappings.csv
files undermocasin-mapping
, for example:scheduler: { type: STATIC, static-scheduler: MOCASIN, mocasin-mapping: [ "./mappings/mappings-opt-0.csv", "./mappings/mappings-subopt-1.csv", "./mappings/mappings-opt-2.csv", ], },
-
Invoke
lfc-dev
again.$ lfc-dev src/CompressFiles.lf
If everything goes well, you should see the following
[100%] Built target CompressFiles Install the project... -- Install configuration: "Debug" lfc: info: Compiled binary is in <path-to-satellite-altitude-control>/bin lfc: info: Code generation finished.
-
(Tricky) Identify which core a worker maps to. Open
src-gen/CompressFiles/graphs/dag_partitioned_frag_1.dot
(preferably visualize it using Graphviz) and see where each reaction is mapped. There should be a worker label within each reaction node. Also open the 2nd modified mapping (in the example,./mappings/mappings-subopt-1.csv
, since it describes the periodic phase). In the mapping, see which core the reactions assigned to the same worker runs on. For example, if reaction A and B are both assigned to worker 0 in the dot file, and in the mapping CSV, both mapped to core 7, then we need to remember this mapping (A, B => Core 7) for the later pinning step. -
Now follow the instructions below to pin the workers to the right cores.
Author: @axmmisaka
The following steps were taken:
- Modify
boot.ini
in the first partition in the SD card. Inbootargs
addisolcpus=2,3,4,5,6,7,8
. Note that CPU0 cannot be isolated. Verify by checkingcat /sys/devices/system/cpu/isolated
. - Modify
/etc/systemd/system.conf
, make sureCPUAffinity=0 1
. - Note: Core 0-3 are little cores (Cortex-A7) and core 4-7 are big cores (Cortex-A15).
Note that
-
this ONLY work if the POSIX threading implementation is used.
-
this is a non-portable solution and ONLY works with GCC.
-
Generate source by running the source generator.
-
Modify
src-gen/ProjectName/core/threaded/reactor_threaded.c
, as follows:
> // Again, this assumes the use of glibc POSIX threads. This adds the utilities needed.
> #define _GNU_SOURCE
#include <assert.h>
#include <signal.h>
#include <string.h>
#include <time.h>
> #include <sched.h>
> #include <pthread.h>
> #include <unistd.h>
This pins worker threads to one or more cores:
void* worker(void* arg) {
environment_t *env = (environment_t* ) arg;
assert(env != GLOBAL_ENVIRONMENT);
lf_mutex_lock(&env->mutex);
int worker_number = worker_thread_count++;
LF_PRINT_LOG("Worker thread %d started.", worker_number);
973,992d968
> cpu_set_t cpuset; CPU_ZERO(&cpuset);
> CPU_SET(worker_number + 2 /* Or whichever core you want to use*/ , &cpuset);
> /* You can also pin the thread to multiple cores, by adding more cores to the set.
> CPU_SET(worker_number + 3 , &cpuset);
> */
>
> pthread_t current_thread = pthread_self();
> int rv = pthread_setaffinity_np(current_thread, sizeof(cpu_set_t), &cpuset);
>
> /* The following code could be used to verify which cores is the thread using.
> CPU_ZERO(&cpuset);
> int aff = pthread_getaffinity_np(current_thread, sizeof(cpu_set_t), &cpuset);
> */
>
> printf("I am worker thread %d using ", worker_number);
> for (size_t j = 0; j < CPU_SETSIZE; ++j){ if (CPU_ISSET(j, &cpuset)) { printf(" %zu", j); }}
> printf("\n");
> lf_mutex_unlock(&env->mutex);
>
And you can do similar things in lf_reactor_c_main()
to pin the "main" thread.
- After you finish, remake and run the executable.