Skip to content

Commit 260143c

Browse files
committed
[processing] Implement Protothreads/Resumable using Fibers
- 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.
2 parents 725a69e + c1bf519 commit 260143c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+2037
-738
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ git clone --recurse-submodules --jobs 8 https://github.com/modm-io/modm.git
6161
- UART, I<sup>2</sup>C, SPI, CAN and Ethernet.
6262
- Interfaces and drivers for many external I<sup>2</sup>C and SPI sensors and devices.
6363
- Debug/logging system with IOStream and printf interface.
64-
- Lightweight, stackless threads and resumable functions using cooperative multitasking.
64+
- Cooperative, stackless protothreads and resumable functions.
65+
- Cooperative, stackful fibers and scheduler.
6566
- Functional (partial) libstdc++ implementation for AVRs.
6667
- Useful filter, interpolation and geometric algorithms.
6768
- Lightweight unit testing system (suitable for AVRs).

examples/avr/fiber/main.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,10 @@ struct Test
5454
volatile uint32_t f4counter{0};
5555
} test;
5656

57-
modm::fiber::Stack<128> stack1;
58-
modm::fiber::Stack<128> stack2;
59-
modm::fiber::Stack<128> stack3;
60-
modm::fiber::Stack<128> stack4;
61-
modm::Fiber fiber1(stack1, fiber_function1);
62-
modm::Fiber fiber2(stack2, [](){ fiber_function2(cycles); });
63-
modm::Fiber fiber3(stack3, [](){ test.fiber_function3(); });
64-
modm::Fiber fiber4(stack4, [cyc=uint32_t(cycles)]() mutable { cyc++; test.fiber_function4(cyc); });
57+
modm::Fiber<> fiber1(fiber_function1);
58+
modm::Fiber<> fiber2(+[](){ fiber_function2(cycles); });
59+
modm::Fiber<> fiber3(+[](){ test.fiber_function3(); });
60+
modm::Fiber<> fiber4([cyc=uint32_t(cycles)]() mutable { cyc++; test.fiber_function4(cyc); });
6561

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

71+
fiber1.watermark_stack();
72+
fiber2.watermark_stack();
73+
fiber3.watermark_stack();
74+
fiber4.watermark_stack();
75+
7576
const modm::PreciseTimestamp start = modm::PreciseClock::now();
7677
modm::fiber::Scheduler::run();
7778
const auto diff = (modm::PreciseClock::now() - start);
@@ -82,7 +83,11 @@ main()
8283
MODM_LOG_INFO << " yields per second, ";
8384
MODM_LOG_INFO << uint32_t(std::chrono::nanoseconds(diff).count() / total_counter);
8485
MODM_LOG_INFO << "ns per yield" << modm::endl;
85-
MODM_LOG_INFO.flush();
86+
87+
MODM_LOG_INFO << "Stack usage 1 = " << fiber1.stack_usage() << modm::endl;
88+
MODM_LOG_INFO << "Stack usage 2 = " << fiber2.stack_usage() << modm::endl;
89+
MODM_LOG_INFO << "Stack usage 3 = " << fiber3.stack_usage() << modm::endl;
90+
MODM_LOG_INFO << "Stack usage 4 = " << fiber4.stack_usage() << modm::endl;
8691

8792
while(1) ;
8893
return 0;

examples/avr/fiber/project.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
<!-- <extends>modm:arduino-nano</extends> -->
44
<options>
55
<option name="modm:build:build.path">../../../build/avr/fiber</option>
6-
<option name="modm:__fibers">yes</option>
76
</options>
87
<modules>
98
<module>modm:build:scons</module>

examples/generic/fiber/main.cpp

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@
1212
#include <modm/board.hpp>
1313
#include <modm/debug/logger.hpp>
1414
#include <modm/processing.hpp>
15+
#include <modm/driver/time/cycle_counter.hpp>
1516

1617
using namespace Board;
1718
using namespace std::chrono_literals;
1819

19-
constexpr uint32_t cycles = 1'000'000;
20+
constexpr uint32_t cycles = 100'000;
2021
volatile uint32_t f1counter = 0, f2counter = 0;
2122
uint32_t total_counter=0;
23+
modm_fastdata modm::CycleCounter counter;
2224

2325
void
2426
fiber_function1()
@@ -54,24 +56,57 @@ struct Test
5456
volatile uint32_t f4counter{0};
5557
} test;
5658

57-
modm_faststack modm::fiber::Stack<2048> stack1;
58-
modm_faststack modm::fiber::Stack<2048> stack2;
59-
modm_faststack modm::fiber::Stack<2048> stack3;
60-
modm_faststack modm::fiber::Stack<2048> stack4;
61-
modm_fastdata modm::Fiber fiber1(stack1, fiber_function1);
62-
modm_fastdata modm::Fiber fiber2(stack2, [](){ fiber_function2(cycles); });
63-
modm_fastdata modm::Fiber fiber3(stack3, [](){ test.fiber_function3(); });
64-
modm_fastdata modm::Fiber fiber4(stack4, [cyc=uint32_t(0)]() mutable { cyc++; test.fiber_function4(cyc); });
59+
// Single purpose fibers to time the yield
60+
modm_faststack modm::Fiber<> fiber_y1([](){ modm::fiber::yield(); counter.stop(); });
61+
modm_faststack modm::Fiber<> fiber_y2([](){ counter.start(); modm::fiber::yield(); });
62+
63+
modm_faststack modm::Fiber<> fiber1(fiber_function1, modm::fiber::Start::Later);
64+
modm_faststack modm::Fiber<> fiber2([](){ fiber_function2(cycles); }, modm::fiber::Start::Later);
65+
modm_faststack modm::Fiber<> fiber3([](){ test.fiber_function3(); }, modm::fiber::Start::Later);
66+
modm_faststack modm::Fiber<> fiber4([cyc=uint32_t(0)]() mutable
67+
{ cyc = cycles; test.fiber_function4(cyc); }, modm::fiber::Start::Later);
68+
69+
// Restartable Fibers
70+
extern modm::Fiber<> fiber_pong;
71+
extern modm::Fiber<> fiber_ping;
72+
modm_faststack modm::Fiber<> fiber_ping([](){
73+
MODM_LOG_INFO << "ping = " << fiber_ping.stack_usage() << modm::endl;
74+
modm::fiber::sleep(1s);
75+
fiber_pong.start();
76+
}, modm::fiber::Start::Later);
77+
modm_faststack modm::Fiber<> fiber_pong([](){
78+
MODM_LOG_INFO << "pong = " << fiber_pong.stack_usage() << modm::endl;
79+
modm::fiber::sleep(1s);
80+
fiber_ping.start();
81+
}, modm::fiber::Start::Later);
6582

6683
// Blue pill (M3 72MHz): Executed 1000000 in 1098591us (910256.88 yields per second)
6784
// Feather M0 (M0+ 48MHz): Executed 1000000 in 1944692us (514220.25 yields per second)
6885
int
6986
main()
7087
{
7188
Board::initialize();
89+
counter.initialize();
7290
MODM_LOG_INFO << "Starting fiber modm::yield benchmark..." << modm::endl;
7391
MODM_LOG_INFO.flush();
7492

93+
fiber_y1.watermark_stack();
94+
fiber_y2.watermark_stack();
95+
// fiber_y1, fiber_y2 were autostarted
96+
{
97+
modm::atomic::Lock l;
98+
modm::fiber::Scheduler::run();
99+
}
100+
101+
MODM_LOG_INFO << "Y1 stack usage: = " << fiber_y1.stack_usage() << modm::endl;
102+
MODM_LOG_INFO << "Y2 stack usage: = " << fiber_y2.stack_usage() << modm::endl;
103+
MODM_LOG_INFO.flush();
104+
105+
// the rest is manually started
106+
fiber1.start(); fiber1.watermark_stack();
107+
fiber2.start(); fiber2.watermark_stack();
108+
fiber3.start(); fiber3.watermark_stack();
109+
fiber4.start(); fiber4.watermark_stack();
75110
const modm::PreciseTimestamp start = modm::PreciseClock::now();
76111
modm::fiber::Scheduler::run();
77112
const auto diff = (modm::PreciseClock::now() - start);
@@ -81,8 +116,19 @@ main()
81116
MODM_LOG_INFO << ((total_counter * 1'000'000ull) / std::chrono::microseconds(diff).count());
82117
MODM_LOG_INFO << " yields per second, ";
83118
MODM_LOG_INFO << (std::chrono::nanoseconds(diff).count() / total_counter);
84-
MODM_LOG_INFO << "ns per yield" << modm::endl;
85-
MODM_LOG_INFO.flush();
119+
MODM_LOG_INFO << "ns per yield slice" << modm::endl;
120+
MODM_LOG_INFO << counter.cycles() << " cycles = " << counter.nanoseconds();
121+
MODM_LOG_INFO << "ns per single yield" << modm::endl;
122+
123+
MODM_LOG_INFO << "F1 stack usage = " << fiber1.stack_usage() << modm::endl;
124+
MODM_LOG_INFO << "F2 stack usage = " << fiber2.stack_usage() << modm::endl;
125+
MODM_LOG_INFO << "F3 stack usage = " << fiber3.stack_usage() << modm::endl;
126+
MODM_LOG_INFO << "F4 stack usage = " << fiber4.stack_usage() << modm::endl;
127+
128+
fiber_ping.watermark_stack();
129+
fiber_pong.watermark_stack();
130+
fiber_ping.start();
131+
modm::fiber::Scheduler::run();
86132

87133
while(1) ;
88134
return 0;

examples/generic/fiber/project.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
<!-- <extends>modm:nucleo-g071rb</extends> -->
44
<options>
55
<option name="modm:build:build.path">../../../build/generic/fiber</option>
6-
<option name="modm:__fibers">yes</option>
6+
<option name="modm:io:with_long_long">yes</option>
77
</options>
88
<modules>
99
<module>modm:build:scons</module>
1010
<module>modm:processing:timer</module>
1111
<module>modm:processing:fiber</module>
12+
<module>modm:driver:cycle_counter</module>
1213
</modules>
1314
</library>

examples/linux/fiber/main.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,14 @@ struct Test
3333
}
3434
} test;
3535

36-
modm::fiber::Stack<1024> stack1;
37-
modm::fiber::Stack<1024> stack2;
38-
modm::Fiber fiber1(stack1, hello);
36+
modm::Fiber<> fiber1(hello);
37+
modm::fiber::Stack<> stack2;
3938

4039
int
4140
main(void)
4241
{
4342
const char *arg = "World";
44-
modm::Fiber fiber2(stack2, [=]() { test.world(arg); });
43+
modm::fiber::Task fiber2(stack2, [=]() { test.world(arg); });
4544

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

examples/linux/fiber/project.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
<options>
44
<option name="modm:target">hosted-linux</option>
55
<option name="modm:build:build.path">../../../build/linux/fiber</option>
6-
<option name="modm:__fibers">yes</option>
76
</options>
87
<modules>
98
<module>modm:debug</module>

examples/rp_pico/fiber/main.cpp

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -57,23 +57,17 @@ fiber_function2(CoreData& d)
5757
}
5858
}
5959

60-
// put cores to mostly equalent environment
61-
modm_core0_data CoreData d0;
62-
modm_core1_data CoreData d1;
63-
64-
modm_core0_noinit modm::fiber::Stack<384> stack01;
65-
modm_core0_noinit modm::fiber::Stack<384> stack02;
66-
modm_core1_noinit modm::fiber::Stack<384> stack11;
67-
modm_core1_noinit modm::fiber::Stack<384> stack12;
68-
69-
modm_core0_data
70-
modm::Fiber fiber01(stack01, []() { fiber_function1(d0); }, 0);
71-
modm_core0_data
72-
modm::Fiber fiber02(stack02, []() { fiber_function2(d0); }, 0);
73-
modm_core1_data
74-
modm::Fiber fiber11(stack11, []() { fiber_function1(d1); }, 1);
75-
modm_core1_data
76-
modm::Fiber fiber12(stack12, []() { fiber_function2(d1); }, 1);
60+
// put cores to mostly equivalent environment
61+
modm_fastdata_core0 CoreData d0;
62+
modm_fastdata_core1 CoreData d1;
63+
64+
modm_faststack_core0 modm::Fiber<256> fiber01([](){fiber_function1(d0);});
65+
modm_faststack_core0 modm::Fiber<256> fiber02([](){fiber_function2(d0);});
66+
// Do not autostart these fibers, otherwise they run on the Core0 scheduler!
67+
modm_faststack_core1
68+
modm::Fiber<256> fiber11([](){fiber_function1(d1);}, modm::fiber::Start::Later);
69+
modm_faststack_core1
70+
modm::Fiber<256> fiber12([](){fiber_function2(d1);}, modm::fiber::Start::Later);
7771

7872
template<typename TimeDiff>
7973
static void
@@ -92,6 +86,9 @@ print_result(const CoreData& d, TimeDiff diff)
9286
void
9387
core1_main()
9488
{
89+
// Start the fibers on the Core1 scheduler
90+
fiber11.start();
91+
fiber12.start();
9592
const modm::PreciseTimestamp start = modm::PreciseClock::now();
9693
modm::fiber::Scheduler::run();
9794
const auto diff = (modm::PreciseClock::now() - start);

examples/rp_pico/fiber/project.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
<extends>modm:rp-pico</extends>
33
<options>
44
<option name="modm:build:build.path">../../../build/rp_pico/fiber</option>
5-
<option name="modm:__fibers">yes</option>
65
</options>
76
<modules>
87
<module>modm:debug</module>

examples/stm32f3_discovery/accelerometer/main.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,13 @@ class ReaderThread : public modm::pt::Protothread
7676

7777
ReaderThread reader;
7878

79-
8079
int
8180
main()
8281
{
8382
Board::initialize();
8483
Board::initializeLsm3();
8584

86-
while (true)
87-
{
88-
reader.update();
89-
}
85+
modm::fiber::Scheduler::run();
9086

9187
return 0;
9288
}

0 commit comments

Comments
 (0)