Skip to content

Commit

Permalink
[processing] Implement Protothreads/Resumable using Fibers
Browse files Browse the repository at this point in the history
- Refactor Fibers implementation and enable by default.
- Much more documentation for fibers.
- Implement Protothreads and Resumable Functions using fibers (optional).
- Adapt peripheral drivers where necessary (mostly SPI).
- Adapt fiber examples.
  • Loading branch information
salkinium committed May 14, 2023
2 parents 725a69e + c1bf519 commit 260143c
Show file tree
Hide file tree
Showing 64 changed files with 2,037 additions and 738 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ git clone --recurse-submodules --jobs 8 https://github.com/modm-io/modm.git
- UART, I<sup>2</sup>C, SPI, CAN and Ethernet.
- Interfaces and drivers for many external I<sup>2</sup>C and SPI sensors and devices.
- Debug/logging system with IOStream and printf interface.
- Lightweight, stackless threads and resumable functions using cooperative multitasking.
- Cooperative, stackless protothreads and resumable functions.
- Cooperative, stackful fibers and scheduler.
- Functional (partial) libstdc++ implementation for AVRs.
- Useful filter, interpolation and geometric algorithms.
- Lightweight unit testing system (suitable for AVRs).
Expand Down
23 changes: 14 additions & 9 deletions examples/avr/fiber/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,10 @@ struct Test
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); });
modm::Fiber<> fiber1(fiber_function1);
modm::Fiber<> fiber2(+[](){ fiber_function2(cycles); });
modm::Fiber<> fiber3(+[](){ test.fiber_function3(); });
modm::Fiber<> fiber4([cyc=uint32_t(cycles)]() mutable { cyc++; test.fiber_function4(cyc); });

// ATmega2560@16MHz: 239996 yields in 2492668us, 96280 yields per second, 10386ns per yield
int
Expand All @@ -72,6 +68,11 @@ main()
MODM_LOG_INFO << "Starting fiber modm::yield benchmark..." << modm::endl;
MODM_LOG_INFO.flush();

fiber1.watermark_stack();
fiber2.watermark_stack();
fiber3.watermark_stack();
fiber4.watermark_stack();

const modm::PreciseTimestamp start = modm::PreciseClock::now();
modm::fiber::Scheduler::run();
const auto diff = (modm::PreciseClock::now() - start);
Expand All @@ -82,7 +83,11 @@ main()
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();

MODM_LOG_INFO << "Stack usage 1 = " << fiber1.stack_usage() << modm::endl;
MODM_LOG_INFO << "Stack usage 2 = " << fiber2.stack_usage() << modm::endl;
MODM_LOG_INFO << "Stack usage 3 = " << fiber3.stack_usage() << modm::endl;
MODM_LOG_INFO << "Stack usage 4 = " << fiber4.stack_usage() << modm::endl;

while(1) ;
return 0;
Expand Down
1 change: 0 additions & 1 deletion examples/avr/fiber/project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<!-- <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>
Expand Down
68 changes: 57 additions & 11 deletions examples/generic/fiber/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@
#include <modm/board.hpp>
#include <modm/debug/logger.hpp>
#include <modm/processing.hpp>
#include <modm/driver/time/cycle_counter.hpp>

using namespace Board;
using namespace std::chrono_literals;

constexpr uint32_t cycles = 1'000'000;
constexpr uint32_t cycles = 100'000;
volatile uint32_t f1counter = 0, f2counter = 0;
uint32_t total_counter=0;
modm_fastdata modm::CycleCounter counter;

void
fiber_function1()
Expand Down Expand Up @@ -54,24 +56,57 @@ struct Test
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); });
// Single purpose fibers to time the yield
modm_faststack modm::Fiber<> fiber_y1([](){ modm::fiber::yield(); counter.stop(); });
modm_faststack modm::Fiber<> fiber_y2([](){ counter.start(); modm::fiber::yield(); });

modm_faststack modm::Fiber<> fiber1(fiber_function1, modm::fiber::Start::Later);
modm_faststack modm::Fiber<> fiber2([](){ fiber_function2(cycles); }, modm::fiber::Start::Later);
modm_faststack modm::Fiber<> fiber3([](){ test.fiber_function3(); }, modm::fiber::Start::Later);
modm_faststack modm::Fiber<> fiber4([cyc=uint32_t(0)]() mutable
{ cyc = cycles; test.fiber_function4(cyc); }, modm::fiber::Start::Later);

// Restartable Fibers
extern modm::Fiber<> fiber_pong;
extern modm::Fiber<> fiber_ping;
modm_faststack modm::Fiber<> fiber_ping([](){
MODM_LOG_INFO << "ping = " << fiber_ping.stack_usage() << modm::endl;
modm::fiber::sleep(1s);
fiber_pong.start();
}, modm::fiber::Start::Later);
modm_faststack modm::Fiber<> fiber_pong([](){
MODM_LOG_INFO << "pong = " << fiber_pong.stack_usage() << modm::endl;
modm::fiber::sleep(1s);
fiber_ping.start();
}, modm::fiber::Start::Later);

// 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();
counter.initialize();
MODM_LOG_INFO << "Starting fiber modm::yield benchmark..." << modm::endl;
MODM_LOG_INFO.flush();

fiber_y1.watermark_stack();
fiber_y2.watermark_stack();
// fiber_y1, fiber_y2 were autostarted
{
modm::atomic::Lock l;
modm::fiber::Scheduler::run();
}

MODM_LOG_INFO << "Y1 stack usage: = " << fiber_y1.stack_usage() << modm::endl;
MODM_LOG_INFO << "Y2 stack usage: = " << fiber_y2.stack_usage() << modm::endl;
MODM_LOG_INFO.flush();

// the rest is manually started
fiber1.start(); fiber1.watermark_stack();
fiber2.start(); fiber2.watermark_stack();
fiber3.start(); fiber3.watermark_stack();
fiber4.start(); fiber4.watermark_stack();
const modm::PreciseTimestamp start = modm::PreciseClock::now();
modm::fiber::Scheduler::run();
const auto diff = (modm::PreciseClock::now() - start);
Expand All @@ -81,8 +116,19 @@ main()
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();
MODM_LOG_INFO << "ns per yield slice" << modm::endl;
MODM_LOG_INFO << counter.cycles() << " cycles = " << counter.nanoseconds();
MODM_LOG_INFO << "ns per single yield" << modm::endl;

MODM_LOG_INFO << "F1 stack usage = " << fiber1.stack_usage() << modm::endl;
MODM_LOG_INFO << "F2 stack usage = " << fiber2.stack_usage() << modm::endl;
MODM_LOG_INFO << "F3 stack usage = " << fiber3.stack_usage() << modm::endl;
MODM_LOG_INFO << "F4 stack usage = " << fiber4.stack_usage() << modm::endl;

fiber_ping.watermark_stack();
fiber_pong.watermark_stack();
fiber_ping.start();
modm::fiber::Scheduler::run();

while(1) ;
return 0;
Expand Down
3 changes: 2 additions & 1 deletion examples/generic/fiber/project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
<!-- <extends>modm:nucleo-g071rb</extends> -->
<options>
<option name="modm:build:build.path">../../../build/generic/fiber</option>
<option name="modm:__fibers">yes</option>
<option name="modm:io:with_long_long">yes</option>
</options>
<modules>
<module>modm:build:scons</module>
<module>modm:processing:timer</module>
<module>modm:processing:fiber</module>
<module>modm:driver:cycle_counter</module>
</modules>
</library>
7 changes: 3 additions & 4 deletions examples/linux/fiber/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,14 @@ struct Test
}
} test;

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

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

MODM_LOG_INFO << "Start" << modm::endl;
modm::fiber::Scheduler::run();
Expand Down
1 change: 0 additions & 1 deletion examples/linux/fiber/project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<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>
Expand Down
31 changes: 14 additions & 17 deletions examples/rp_pico/fiber/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,17 @@ fiber_function2(CoreData& d)
}
}

// put cores to mostly equalent environment
modm_core0_data CoreData d0;
modm_core1_data CoreData d1;

modm_core0_noinit modm::fiber::Stack<384> stack01;
modm_core0_noinit modm::fiber::Stack<384> stack02;
modm_core1_noinit modm::fiber::Stack<384> stack11;
modm_core1_noinit modm::fiber::Stack<384> stack12;

modm_core0_data
modm::Fiber fiber01(stack01, []() { fiber_function1(d0); }, 0);
modm_core0_data
modm::Fiber fiber02(stack02, []() { fiber_function2(d0); }, 0);
modm_core1_data
modm::Fiber fiber11(stack11, []() { fiber_function1(d1); }, 1);
modm_core1_data
modm::Fiber fiber12(stack12, []() { fiber_function2(d1); }, 1);
// put cores to mostly equivalent environment
modm_fastdata_core0 CoreData d0;
modm_fastdata_core1 CoreData d1;

modm_faststack_core0 modm::Fiber<256> fiber01([](){fiber_function1(d0);});
modm_faststack_core0 modm::Fiber<256> fiber02([](){fiber_function2(d0);});
// Do not autostart these fibers, otherwise they run on the Core0 scheduler!
modm_faststack_core1
modm::Fiber<256> fiber11([](){fiber_function1(d1);}, modm::fiber::Start::Later);
modm_faststack_core1
modm::Fiber<256> fiber12([](){fiber_function2(d1);}, modm::fiber::Start::Later);

template<typename TimeDiff>
static void
Expand All @@ -92,6 +86,9 @@ print_result(const CoreData& d, TimeDiff diff)
void
core1_main()
{
// Start the fibers on the Core1 scheduler
fiber11.start();
fiber12.start();
const modm::PreciseTimestamp start = modm::PreciseClock::now();
modm::fiber::Scheduler::run();
const auto diff = (modm::PreciseClock::now() - start);
Expand Down
1 change: 0 additions & 1 deletion examples/rp_pico/fiber/project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<extends>modm:rp-pico</extends>
<options>
<option name="modm:build:build.path">../../../build/rp_pico/fiber</option>
<option name="modm:__fibers">yes</option>
</options>
<modules>
<module>modm:debug</module>
Expand Down
6 changes: 1 addition & 5 deletions examples/stm32f3_discovery/accelerometer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,13 @@ class ReaderThread : public modm::pt::Protothread

ReaderThread reader;


int
main()
{
Board::initialize();
Board::initializeLsm3();

while (true)
{
reader.update();
}
modm::fiber::Scheduler::run();

return 0;
}
1 change: 1 addition & 0 deletions examples/stm32f3_discovery/accelerometer/project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<extends>modm:disco-f303vc</extends>
<options>
<option name="modm:build:build.path">../../../build/stm32f3_discovery/accelerometer</option>
<option name="modm:processing:protothread:use_fiber">yes</option>
</options>
<modules>
<module>modm:math:filter</module>
Expand Down
Loading

0 comments on commit 260143c

Please sign in to comment.