Skip to content

Commit e230f4d

Browse files
committed
[rp2040] run fibers on each core
1 parent c1fa2fd commit e230f4d

File tree

9 files changed

+282
-29
lines changed

9 files changed

+282
-29
lines changed

examples/rp_pico/fiber/main.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Copyright (c) 2022, Andrey Kunitsyn
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
// ----------------------------------------------------------------------------
11+
12+
#include <modm/board.hpp>
13+
#include <modm/debug/logger.hpp>
14+
#include <modm/processing.hpp>
15+
#include <modm/platform/core/multicore.hpp>
16+
#include <mutex>
17+
18+
using namespace Board;
19+
using namespace std::chrono_literals;
20+
21+
// Create an IODeviceWrapper around the Uart Peripheral we want to use
22+
modm::IODeviceWrapper< Uart0, modm::IOBuffer::BlockIfFull > loggerDevice;
23+
24+
// Set all four logger streams to use the UART
25+
modm::log::Logger modm::log::debug(loggerDevice);
26+
modm::log::Logger modm::log::info(loggerDevice);
27+
modm::log::Logger modm::log::warning(loggerDevice);
28+
modm::log::Logger modm::log::error(loggerDevice);
29+
30+
constexpr uint32_t cycles = 1'000'000;
31+
32+
static modm::platform::multicore::Mutex log_mutex;
33+
34+
struct CoreData {
35+
uint32_t total_counter = 0;
36+
uint32_t f1counter = 0;
37+
uint32_t f2counter = 0;
38+
};
39+
40+
41+
void
42+
fiber_function1(CoreData& d)
43+
{
44+
while (++d.f1counter < cycles) { modm::fiber::yield(); d.total_counter++; }
45+
}
46+
47+
void
48+
fiber_function2(CoreData& d)
49+
{
50+
while (++d.f2counter < cycles) { modm::fiber::yield(); d.total_counter++; }
51+
}
52+
53+
// put cores to mostly equalent environment
54+
modm_section(".scratch_y_data") static CoreData d0;
55+
modm_section(".scratch_x_data") static CoreData d1;
56+
57+
58+
modm_section(".scratch_y_noinit") modm::fiber::Stack<384> stack01;
59+
modm_section(".scratch_y_noinit") modm::fiber::Stack<384> stack02;
60+
modm_section(".scratch_x_noinit") modm::fiber::Stack<384> stack11;
61+
modm_section(".scratch_x_noinit") modm::fiber::Stack<384> stack12;
62+
63+
modm_section(".scratch_y_data") modm::Fiber<0> fiber01(stack01, [](){ fiber_function1(d0); });
64+
modm_section(".scratch_y_data") modm::Fiber<0> fiber02(stack02, [](){ fiber_function2(d0); });
65+
modm_section(".scratch_x_data") modm::Fiber<1> fiber11(stack11, [](){ fiber_function1(d1); });
66+
modm_section(".scratch_x_data") modm::Fiber<1> fiber12(stack12, [](){ fiber_function2(d1); });
67+
68+
template <typename TimeDiff>
69+
static void print_result(const CoreData& d,TimeDiff diff) {
70+
std::lock_guard<modm::platform::multicore::Mutex> g(log_mutex);
71+
MODM_LOG_INFO << "Benchmark for core" << multicore::Core::getNum() << " done!" << modm::endl;
72+
MODM_LOG_INFO << "Executed " << d.total_counter << " yields in " << diff << modm::endl;
73+
MODM_LOG_INFO << ((d.total_counter * 1'000'000ull) / std::chrono::microseconds(diff).count());
74+
MODM_LOG_INFO << " yields per second, ";
75+
MODM_LOG_INFO << (std::chrono::nanoseconds(diff).count() / d.total_counter);
76+
MODM_LOG_INFO << "ns per yield" << modm::endl;
77+
MODM_LOG_INFO.flush();
78+
}
79+
80+
void core1_main() {
81+
const modm::PreciseTimestamp start = modm::PreciseClock::now();
82+
modm::fiber::Scheduler<1>::run();
83+
const auto diff = (modm::PreciseClock::now() - start);
84+
85+
print_result(d1,diff);
86+
while (true) {}
87+
}
88+
89+
int
90+
main()
91+
{
92+
Board::initialize();
93+
94+
// initialize Uart0 for MODM_LOG_*
95+
Uart0::connect<GpioOutput0::Tx>();
96+
Uart0::initialize<Board::SystemClock, 115200_Bd>();
97+
98+
MODM_LOG_INFO << "Starting fiber modm::yield benchmark..." << modm::endl;
99+
MODM_LOG_INFO.flush();
100+
101+
modm::platform::multicore::Core1::run(core1_main);
102+
103+
const modm::PreciseTimestamp start = modm::PreciseClock::now();
104+
modm::fiber::Scheduler<0>::run();
105+
const auto diff = (modm::PreciseClock::now() - start);
106+
107+
print_result(d0,diff);
108+
while (true) {}
109+
110+
return 0;
111+
}

examples/rp_pico/fiber/project.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<library>
2+
<extends>modm:rp-pico</extends>
3+
<options>
4+
<option name="modm:build:build.path">../../../build/rp_pico/fiber</option>
5+
<option name="modm:__fibers">yes</option>
6+
</options>
7+
<modules>
8+
<module>modm:debug</module>
9+
<module>modm:platform:uart:0</module>
10+
<module>modm:build:scons</module>
11+
<module>modm:processing:timer</module>
12+
<module>modm:processing:fiber</module>
13+
</modules>
14+
</library>

src/modm/board/rp_pico/board.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
<options>
99
<option name="modm:target">rp2040</option>
1010
<option name="modm:platform:core:boot2">w25q080</option>
11+
<option name="modm:platform:multicore:core_storage.0">modm_section(".scratch_y_data")</option>
12+
<option name="modm:platform:multicore:core_storage.1">modm_section(".scratch_x_data")</option>
1113
</options>
1214
<modules>
1315
<module>modm:board:rp-pico</module>

src/modm/platform/core/rp/flash.ld.in

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,45 @@ ASSERT(__boot2_end__ - __boot2_start__ == 256,
5858

5959
%% macro section_mem_bank(memory)
6060
/* Sections in {{memory}} */
61-
.{{memory | lower}} :
61+
.{{memory | lower}}.data :
6262
{
63-
__{{memory | lower}}_start__ = .;
64-
*(.{{memory | lower}}.*)
63+
__{{memory | lower}}_data_load = LOADADDR(.{{memory | lower}}.data);
64+
__{{memory | lower}}_data_start = .;
65+
*(.{{memory | lower}}_data)
66+
*(.{{memory | lower}}_data.*)
6567
. = ALIGN(4);
66-
__{{memory | lower}}_end__ = .;
68+
__{{memory | lower}}_data_end = .;
6769
} >{{memory}} AT > FLASH
68-
__{{memory | lower}}_source__ = LOADADDR(.{{memory | lower}});
70+
%% do table_copy.append( memory.lower() + '_data' )
71+
72+
.{{memory | lower}}.text :
73+
{
74+
__{{memory | lower}}_text_load = LOADADDR(.{{memory | lower}}.text);
75+
__{{memory | lower}}_text_start = .;
76+
*(.{{memory | lower}}_text)
77+
*(.{{memory | lower}}_text.*)
78+
. = ALIGN(4);
79+
__{{memory | lower}}_text_end = .;
80+
} >{{memory}} AT > FLASH
81+
%% do table_copy.append( memory.lower() + '_text' )
82+
83+
.{{memory | lower}}.bss (NOLOAD) :
84+
{
85+
__{{memory | lower}}_bss_start = . ;
86+
*(.{{memory | lower}}_bss)
87+
*(.{{memory | lower}}_bss.*)
88+
. = ALIGN(4);
89+
__{{memory | lower}}_bss_end = . ;
90+
} >{{memory}}
91+
%% do table_zero.append(memory.lower() + "_bss")
92+
.{{memory | lower}}.noinit (NOLOAD) :
93+
{
94+
__{{memory | lower}}_noinit_start = . ;
95+
*(.{{memory | lower}}_noinit)
96+
*(.{{memory | lower}}_noinit.*)
97+
. = ALIGN(4);
98+
__{{memory | lower}}_noinit_end = . ;
99+
} >{{memory}}
69100
%% endmacro
70101

71102
{{ section_mem_bank("SCRATCH_X") }}

src/modm/platform/core/rp/multicore.lb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ def init(module):
1919
def prepare(module, options):
2020
if options[":target"].identifier.platform != "rp":
2121
return False
22+
for i in range(int(options[":target"].identifier.cores)):
23+
module.add_option(
24+
StringOption(
25+
name="core_storage.{}".format(i),
26+
description="Storage for Core{}".format(i),
27+
default=''))
2228
return True
2329

2430

src/modm/processing/fiber/fiber.hpp renamed to src/modm/processing/fiber/fiber.hpp.in

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515
#include "stack.hpp"
1616
#include <memory>
1717

18+
%% if multicore
19+
%% set Instance = "<Core>"
20+
%% set TemplateInstance = "template <size_t Core>"
21+
%% else
22+
%% set Instance = ""
23+
%% set TemplateInstance = ""
24+
%% endif
25+
1826
namespace modm
1927
{
2028

@@ -23,6 +31,11 @@ namespace fiber
2331

2432
void yield();
2533

34+
%% if multicore
35+
template <size_t>
36+
void yieldCore();
37+
template <size_t>
38+
%% endif
2639
class Scheduler;
2740
class Waitable;
2841
template<class Data_t>
@@ -40,13 +53,20 @@ class Channel;
4053
* @author Niklas Hauser
4154
* @ingroup modm_processing_fiber
4255
*/
56+
%% if multicore
57+
template <size_t Core = 0>
58+
%% endif
4359
class Fiber
4460
{
45-
friend class fiber::Scheduler;
61+
friend class fiber::Scheduler{{Instance}};
4662
template<class>
4763
friend class fiber::Channel;
4864
friend class fiber::Waitable;
65+
%% if multicore
66+
friend void fiber::yieldCore<Core>();
67+
%% else
4968
friend void fiber::yield();
69+
%% endif
5070

5171
public:
5272
template<size_t Size>
@@ -75,21 +95,22 @@ class Fiber
7595

7696
namespace modm
7797
{
78-
98+
{{TemplateInstance}}
7999
template<size_t Size>
80-
Fiber::Fiber(fiber::Stack<Size>& stack, void(*fn)())
100+
Fiber{{Instance}}::Fiber(fiber::Stack<Size>& stack, void(*fn)())
81101
{
82102
ctx = modm_context_init((uintptr_t) stack.memory,
83103
(uintptr_t) stack.memory + stack.size,
84104
(uintptr_t) fn,
85-
(uintptr_t) fiber::Scheduler::deregisterFiber);
105+
(uintptr_t) fiber::Scheduler{{Instance}}::deregisterFiber);
86106
// register this fiber to be scheduled
87-
fiber::Scheduler::registerFiber(this);
107+
fiber::Scheduler{{Instance}}::registerFiber(this);
88108
}
89109

110+
{{TemplateInstance}}
90111
template<size_t Size, class T>
91112
requires requires { &std::decay_t<T>::operator(); }
92-
Fiber::Fiber(fiber::Stack<Size>& stack, T&& closure)
113+
Fiber{{Instance}}::Fiber(fiber::Stack<Size>& stack, T&& closure)
93114
{
94115
// Find a suitable aligned area at the top of stack to allocate the closure
95116
uintptr_t ptr = uintptr_t(stack.memory) + stack.size;
@@ -104,15 +125,16 @@ Fiber::Fiber(fiber::Stack<Size>& stack, T&& closure)
104125
auto function = (uintptr_t) +[](std::decay_t<T>* closure) { (*closure)(); };
105126
// format the stack below the allocated closure
106127
ctx = modm_context_init((uintptr_t) stack.memory, ptr, function,
107-
(uintptr_t) fiber::Scheduler::deregisterFiber);
128+
(uintptr_t) fiber::Scheduler{{Instance}}::deregisterFiber);
108129
// register this fiber to be scheduled
109-
fiber::Scheduler::registerFiber(this);
130+
fiber::Scheduler{{Instance}}::registerFiber(this);
110131
}
111132

133+
{{TemplateInstance}}
112134
void
113-
Fiber::jump(Fiber& other)
135+
Fiber{{Instance}}::jump(Fiber& other)
114136
{
115-
fiber::Scheduler::current = &other;
137+
fiber::Scheduler{{Instance}}::current = &other;
116138
modm_context_jump(&(ctx.sp), other.ctx.sp);
117139
}
118140

src/modm/processing/fiber/module.lb

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@ def build(env):
2929
env.outbasepath = "modm/src/modm/processing/fiber"
3030
env.copy("../fiber.hpp")
3131

32-
env.copy("fiber.hpp")
33-
env.copy("scheduler.hpp")
34-
3532
env.copy("context.h")
3633

3734
core = env[":target"].get_driver("core")["type"]
@@ -41,7 +38,17 @@ def build(env):
4138
"with_fpu": env.get(":platform:cortex-m:float-abi", "soft") != "soft",
4239
"with_windows": env[":target"].identifier.family == "windows",
4340
"target": env[":target"].identifier,
41+
"multicore": env.has_module(":platform:multicore"),
4442
}
43+
if env.has_module(":platform:multicore"):
44+
cores = int(env[":target"].identifier.cores)
45+
env.substitutions["num_cores"] = cores
46+
core_storage = []
47+
for i in range(cores):
48+
core_storage.append(env.get(":platform:multicore:core_storage.{}".format(i),""))
49+
env.substitutions["core_storage"] = core_storage
50+
env.template("fiber.hpp.in")
51+
env.template("scheduler.hpp.in")
4552

4653
env.template("stack.hpp.in")
4754

0 commit comments

Comments
 (0)