Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fiber] Stackful cooperative scheduling via Fibers #743

Merged
merged 7 commits into from
Oct 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ jobs:
- name: Compile AVR Unittests ATmega
if: always()
run: |
(cd test && make compile-mega-2560-pro)
(cd test && make compile-mega-2560-pro_A compile-mega-2560-pro_B)
- name: Quick compile HAL for AVR Devices
if: always()
run: |
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,22 @@ jobs:
git submodule update --init --jobs 8

- name: Hosted Unittests
if: always()
run: |
(cd test && make run-hosted-darwin)

- name: Hosted Examples
if: always()
run: |
(cd examples && ../tools/scripts/examples_compile.py linux)

- name: Compile STM32 Examples
if: always()
run: |
(cd examples && ../tools/scripts/examples_compile.py nucleo_f031k6 nucleo_f103rb nucleo_f303re nucleo_f411re nucleo_f746zg)
(cd examples && ../tools/scripts/examples_compile.py nucleo_g071rb nucleo_l031k6 nucleo_l152re nucleo_l476rg nucleo_g474re)

- name: Compile AVR Examples
if: always()
run: |
(cd examples && ../tools/scripts/examples_compile.py avr)
3 changes: 2 additions & 1 deletion .github/workflows/windows_hosted.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ jobs:
- name: Hosted Examples
shell: bash
run: |
(cd examples && python ../tools/scripts/examples_compile.py linux/assert linux/block_device linux/build_info linux/git linux/logger linux/printf)
(cd examples && python ../tools/scripts/examples_compile.py linux/assert linux/block_device linux/build_info linux/git linux/logger linux/printf linux/etl linux/fiber)

- name: Hosted Unittests
if: always()
shell: bash
run: |
(cd test && make run-hosted-windows)
89 changes: 89 additions & 0 deletions examples/avr/fiber/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2020, Erik Henriksson
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#include <modm/board.hpp>
#include <modm/debug/logger.hpp>
#include <modm/processing.hpp>

using namespace Board;
using namespace std::chrono_literals;

constexpr uint32_t cycles = 100'000;
volatile uint32_t f1counter = 0, f2counter = 0;
uint32_t total_counter=0;

void
fiber_function1()
{
MODM_LOG_INFO << MODM_FILE_INFO << modm::endl;
while (++f1counter < cycles) { modm::fiber::yield(); total_counter++; }
}

void
fiber_function2(uint32_t cyc)
{
MODM_LOG_INFO << MODM_FILE_INFO << modm::endl;
while (++f2counter < cyc) { modm::fiber::yield(); total_counter++; }
}

struct Test
{
void
fiber_function3()
{
MODM_LOG_INFO << MODM_FILE_INFO << modm::endl;
while (++f3counter < cycles) { modm::fiber::yield(); total_counter++; }
}

void
fiber_function4(uint32_t cyc)
{
MODM_LOG_INFO << MODM_FILE_INFO << modm::endl;
while (++f4counter < cyc) { modm::fiber::yield(); total_counter++; }
}

volatile uint32_t f3counter{0};
volatile uint32_t f4counter{0};
} test;

modm::fiber::Stack<128> stack1;
modm::fiber::Stack<128> stack2;
modm::fiber::Stack<128> stack3;
modm::fiber::Stack<128> stack4;
modm::Fiber fiber1(stack1, fiber_function1);
modm::Fiber fiber2(stack2, [](){ fiber_function2(cycles); });
modm::Fiber fiber3(stack3, [](){ test.fiber_function3(); });
modm::Fiber fiber4(stack4, [cyc=uint32_t(cycles)]() mutable { cyc++; test.fiber_function4(cyc); });

// ATmega2560@16MHz: 239996 yields in 2492668us, 96280 yields per second, 10386ns per yield
int
main()
{
Board::initialize();
Board::LedD13::setOutput();
MODM_LOG_INFO << "Starting fiber modm::yield benchmark..." << modm::endl;
MODM_LOG_INFO.flush();

const modm::PreciseTimestamp start = modm::PreciseClock::now();
modm::fiber::Scheduler::run();
const auto diff = (modm::PreciseClock::now() - start);

MODM_LOG_INFO << "Benchmark done!" << modm::endl;
MODM_LOG_INFO << "Executed " << total_counter << " yields in " << diff << modm::endl;
MODM_LOG_INFO << uint32_t((total_counter * 1'000'000ull) / std::chrono::microseconds(diff).count());
MODM_LOG_INFO << " yields per second, ";
MODM_LOG_INFO << uint32_t(std::chrono::nanoseconds(diff).count() / total_counter);
MODM_LOG_INFO << "ns per yield" << modm::endl;
MODM_LOG_INFO.flush();

while(1) ;
return 0;
}
13 changes: 13 additions & 0 deletions examples/avr/fiber/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<library>
<extends>modm:mega-2560-pro</extends>
<!-- <extends>modm:arduino-nano</extends> -->
<options>
<option name="modm:build:build.path">../../../build/avr/fiber</option>
<option name="modm:__fibers">yes</option>
</options>
<modules>
<module>modm:build:scons</module>
<module>modm:processing:timer</module>
<module>modm:processing:fiber</module>
</modules>
</library>
89 changes: 89 additions & 0 deletions examples/generic/fiber/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2020, Erik Henriksson
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#include <modm/board.hpp>
#include <modm/debug/logger.hpp>
#include <modm/processing.hpp>

using namespace Board;
using namespace std::chrono_literals;

constexpr uint32_t cycles = 1'000'000;
volatile uint32_t f1counter = 0, f2counter = 0;
uint32_t total_counter=0;

void
fiber_function1()
{
MODM_LOG_INFO << MODM_FILE_INFO << modm::endl;
while (++f1counter < cycles) { modm::fiber::yield(); total_counter++; }
}

void
fiber_function2(uint32_t cyc)
{
MODM_LOG_INFO << MODM_FILE_INFO << modm::endl;
while (++f2counter < cyc) { modm::fiber::yield(); total_counter++; }
}

struct Test
{
void
fiber_function3()
{
MODM_LOG_INFO << MODM_FILE_INFO << modm::endl;
while (++f3counter < cycles) { modm::fiber::yield(); total_counter++; }
}

void
fiber_function4(uint32_t cyc)
{
MODM_LOG_INFO << MODM_FILE_INFO << modm::endl;
while (++f4counter < cyc) { modm::fiber::yield(); total_counter++; }
}

volatile uint32_t f3counter{0};
volatile uint32_t f4counter{0};
} test;

modm_faststack modm::fiber::Stack<2048> stack1;
modm_faststack modm::fiber::Stack<2048> stack2;
modm_faststack modm::fiber::Stack<2048> stack3;
modm_faststack modm::fiber::Stack<2048> stack4;
modm_fastdata modm::Fiber fiber1(stack1, fiber_function1);
modm_fastdata modm::Fiber fiber2(stack2, [](){ fiber_function2(cycles); });
modm_fastdata modm::Fiber fiber3(stack3, [](){ test.fiber_function3(); });
modm_fastdata modm::Fiber fiber4(stack4, [cyc=uint32_t(0)]() mutable { cyc++; test.fiber_function4(cyc); });

// Blue pill (M3 72MHz): Executed 1000000 in 1098591us (910256.88 yields per second)
// Feather M0 (M0+ 48MHz): Executed 1000000 in 1944692us (514220.25 yields per second)
int
main()
{
Board::initialize();
MODM_LOG_INFO << "Starting fiber modm::yield benchmark..." << modm::endl;
MODM_LOG_INFO.flush();

const modm::PreciseTimestamp start = modm::PreciseClock::now();
modm::fiber::Scheduler::run();
const auto diff = (modm::PreciseClock::now() - start);

MODM_LOG_INFO << "Benchmark done!" << modm::endl;
MODM_LOG_INFO << "Executed " << total_counter << " yields in " << diff << modm::endl;
MODM_LOG_INFO << ((total_counter * 1'000'000ull) / std::chrono::microseconds(diff).count());
MODM_LOG_INFO << " yields per second, ";
MODM_LOG_INFO << (std::chrono::nanoseconds(diff).count() / total_counter);
MODM_LOG_INFO << "ns per yield" << modm::endl;
MODM_LOG_INFO.flush();

while(1) ;
return 0;
}
13 changes: 13 additions & 0 deletions examples/generic/fiber/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<library>
<extends>modm:nucleo-f429zi</extends>
<!-- <extends>modm:nucleo-g071rb</extends> -->
<options>
<option name="modm:build:build.path">../../../build/generic/fiber</option>
<option name="modm:__fibers">yes</option>
</options>
<modules>
<module>modm:build:scons</module>
<module>modm:processing:timer</module>
<module>modm:processing:fiber</module>
</modules>
</library>
51 changes: 51 additions & 0 deletions examples/linux/fiber/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2021, Niklas Hauser
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#include <modm/debug.hpp>
#include <modm/processing.hpp>

void hello()
{
for(int ii=0; ii<10; ii++)
{
MODM_LOG_INFO << "Hello ";
modm::fiber::yield();
}
}

struct Test
{
void world(const char *arg)
{
for(int ii=0; ii<10; ii++)
{
MODM_LOG_INFO << arg << modm::endl;
modm::fiber::yield();
}
}
} test;

modm::fiber::Stack<1024> stack1;
modm::fiber::Stack<1024> stack2;
modm::Fiber fiber1(stack1, hello);

int
main(void)
{
const char *arg = "World";
modm::Fiber fiber2(stack2, [=]() { test.world(arg); });

MODM_LOG_INFO << "Start" << modm::endl;
modm::fiber::Scheduler::run();
MODM_LOG_INFO << "End" << modm::endl;

return 0;
}
14 changes: 14 additions & 0 deletions examples/linux/fiber/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<library>
<!-- CI: run -->
<options>
<option name="modm:target">hosted-linux</option>
<option name="modm:build:build.path">../../../build/linux/fiber</option>
<option name="modm:__fibers">yes</option>
</options>
<modules>
<module>modm:debug</module>
<module>modm:platform:core</module>
<module>modm:processing:fiber</module>
<module>modm:build:scons</module>
</modules>
</library>
4 changes: 4 additions & 0 deletions repo.lb
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@ def init(repo):
description=descr_target,
enumeration=devices))

# Invisible option guarding the Fiber API until it is ready
repo.add_option(BooleanOption(name="__fibers", default=False,
description="Enable unstable fiber API."))

def prepare(repo, options):
repo.add_modules_recursive("ext", modulefile="*.lb")
repo.add_modules_recursive("src", modulefile="*.lb")
Expand Down
11 changes: 11 additions & 0 deletions src/modm/architecture/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@
/// Marks a declaration as deprecated and displays a message.
#define modm_deprecated(msg)

/// Tells the compiler to not generate prologue/epilogue code for this function.
#define modm_naked

/// Places a function in the fastest executable memory:
/// instruction cache, core coupled memory or SRAM as fallback.
#define modm_fastcode
Expand All @@ -81,6 +84,11 @@
/// @note This memory location may not be DMA-able!
#define modm_fastdata

/// Places an array into the fastest accessible memory *with* DMA access:
/// data cache, core coupled memory or SRAM as fallback.
/// @note This memory location is DMA-able, but uninitialized!
#define modm_faststack

/// This branch is more likely to execute.
#define modm_likely(x) (x)

Expand Down Expand Up @@ -129,6 +137,7 @@
#define modm_fallthrough __attribute__((fallthrough))
#define modm_noreturn __attribute__((noreturn))
#define modm_warn_unused_result __attribute__((warn_unused_result))
#define modm_naked __attribute__((naked))

#ifdef MODM_COMPILER_MINGW
// FIXME: Windows Object Format PE does not support weak symbols
Expand All @@ -144,10 +153,12 @@
# define modm_fastcode
# define modm_ramcode
# define modm_fastdata
# define modm_faststack
#else
# define modm_fastcode modm_section(".fastcode")
# define modm_ramcode modm_fastcode
# define modm_fastdata modm_section(".fastdata")
# define modm_faststack modm_section(".faststack")
#endif

#ifdef __cplusplus
Expand Down
Loading