-
Notifications
You must be signed in to change notification settings - Fork 12
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
multi-threading for nuttx #29
Comments
Regarding the stack size, usually calling to micro-ROS functions use "big" stack:
These values are completely experimental and usually depend on the functionality used. The point is that every time I see an inexplicable crash in an embedded application, it usually is the stack. This stack is only the main thread? The other threads share this amount? |
I guess. How do I know? Do you think that 65000 (aka 65kB) is sufficient for all - or should I define an extra STACKSIZE for these threads? If I configure a new thread like this: nuttx_apps/examples/uros_rbs/main_rbs.c Line 138 in 0746a00
the stack-size is exclusive for the thread? |
The worker thread does not have any local data. However the thread gets as parameter this struct (with 4 pointers) The worker thread I wonder, what stacksize for such a thread should be - what would you suggest? |
What is the maximum total STACKSIZE for all threads? How much memory is available for that at the Olimex board? |
I'm not sure about how stack size is set for threads in Nuttx, AFAIK it should follow strictly the POSIX Thread API. These samples that I provide are for threads that execute the whole micro-ROS application. The handling of the available memory depends on the RTOS, for example, FreeRTOS let you create static memory blocks for thread stacks, and Zephyr (by default) use heap for allocating dynamically the thread stack. So I guess that the available memory depends on the heap/bss/data sections defined in the linker script because I guess that the stack section (if exists) will be used to startup code and RTOS initialization. Are you sure that only one thread is accessing the middleware? In some tests that we did time ago, multithreaded access to the XRCE middleware breaks it really easy because of buffer corruption. |
"Are you sure that only one thread is accessing the middleware? In some tests that we did time ago, multithreaded access to the XRCE middleware breaks it really easy because of buffer corruption." Yes. I designed the multi-threaded executor in such a way, that only one thread accesses all calls to XRCE middleware. |
Please explain how the worker thread uses the guard condition. |
The reason for the guard condition is to respond as fast as possible to incoming messages:
In the main-thread
In worker thread:
|
Ok, I'm trying to understand this... Some thoughts:
Let me know what do you think about this approach or if this interferes too much with your implementation. Maybe we can add some kind of concept of "guard condition" to the XRCE middleware in order to abort the session wait... Last thing regarding this
Is possible for you to test the executor under Linux but using the XRCE-DDS middleware? Like we do with micro-ROS demos. This way we should be able to determine if this is a middleware problem and debug and fix it in such that case. |
then I could run the ping-pong example successfully. |
Jan, which one of these points makes the application works? I would like to know it because if it is a stack limitation it would be "ok". But if we are having concurrency issues I would like to investigate a bit about making the library multithreaded because in this use-case it should be working theoretically with the current approach. |
Definitly, this stacksize adjustment make it run. The configured stacksize is the total stacksize of the entire application (with two pthreads). The stacksizes of the threads are not configured - so I assume that they are using the stacksize of their spawning application. The lock in the worker-thread around the the execution of the user-callback, which might call To summarize, this version of a multi-threaded rclc-executor works with the single-threaded micro-ros library. It was designed to demonstrate budget-based scheduling with NuttX, but it can be used to assign priorities on Linux/FreeRTOS/Zephyr as well - assuming creation of pthreads, and assignment of priorities (sched_param) are supported. |
I've followed this on the side since Jan asked me about it earlier. The fact that we needed 65k stack, and now even 69k stack, has puzzled me for a long time and I would love to learn more about what this is for. It doesn't seem to match the memory requirement benchmarks for micro-xrce-dds, but I also don't see another big consumer of memory in this app. |
@pablogs9 The memory consumption measurements show publisher and subscriber in isolation. But what would be the memory for an application with two publishers and two subscribers? Can I just add these values:
Really? The Olimex board STM32-E407 has only 196kB RAM. |
As stated in the document, this high memory consumption is related to middleware buffer configuration and the RMW history. Right now you can tune it to your topic size (by default it is 512 B and both rmw and middleware histories are 4), so for example for subscriptions, by default, you will need 51244 = 8192 B of static memory for each one. You can tune these values for decreasing this. Also, we have planned a refactor of the micro-ROS RMW where the subscription buffer will be shared between every subscription. By now, users that have wanted to tune the memory consumption had found no problem, in fact, we have ports for Arduino Zero where you only have 32 kB of SRAM. |
@pablogs9 I did not understand this sentence: "(by default it is 512 B and both rmw and middleware histories are 4), so for example for subscriptions, by default, you will need 51244 = 8192 B of static memory for each one" |
After enabling sporadic scheduling with kernel variable I increased the STACKSIZE. This is my result:
So until 68600B the application hangs and from 68650 the application is not available from nsh shell:
I guess, because the sporadic scheduling is enabled, a few more functions are in NuttX OS library. Even though, I am not calling any sporadic scheduling functions, this has an impact on the STACKSIZE of the application. Strange. Even though, with luck, I found a configuration that just worked. However, very shaky! |
Let assume one subscription in reliable mode: the middleware has a buffer with 4 slots of 512 B, in total: 2048 B. The RMW layers use that buffer for receiving topics of the subscription, as we want the RMW to store the received data between the So in total, with the default configuration:
If you want to tune this static memory:
This said, I don't know how Nuttx is handling stack, the only thing that we have measured is the maximum stack consumption of a task that runs micro-ROS in FreeRTOS. All the details, procedures, and results are explained carefully in the memory profiling article. In this case the stack is about 10 kB, which is aprox the value that we are using in apps that use FreeRTOS. In Nuttx I'm not aware of the behavior of the memory handling since for me it seems more like a normal OS than an RTOS:
|
Something is not right here. Jan's app is about as stripped down as it gets, there is almost nothing but communication setup and a bit of execution in there. How can this take so much memory? |
The increase from 65kb to 68,6kb stacksize was also due to the worker-threads and activating sporadic scheduling:
|
I had to add another thread in the demonstrator application to create a 100% CPU utilization. And now with three threads the application does not run any more:
I updated
Another reason could be, that the |
I'm not sure about the behavior of RCL but in our RMW you can run the XRCE session (in the Are you able to debug onboard using a JTAG probe and detect where does the application freeze? |
Documentation of rcl_wait regarding empty wait_set: "Passing a wait set with no wait-able items in it will fail." |
I have not setup JTAG debugging on the board yet. |
It will fail at RCL level: https://github.com/micro-ROS/rcl/blob/8eddc13db38bdecdd3089b8c96d13f0df3f5b35d/rcl/src/rcl/wait.c#L538 |
At least it does not crash and comes "only back with an error message" which I could ignore. |
Hi,
@jamoralp @pablogs9 @ralph-lange
I am running into problems for an application with multiple threads for NuttX and Olimex board. You know, that I try to get the multi-threaded executor for NuttX running.
What I have done so far:
When I try to run it on Olimex board, the threads start, but there is no progress in the main thread (aka executor).
The application uses two subscriptions and two publishers and one executor. So I don't need to change anything in the micro-ros configuration, right?
nuttx_apps/examples/uros_rbs/main_rbs.c
Line 216 in 0746a00
The processing just stops after calling rcl_wait
https://github.com/micro-ROS/rclc/blob/7a5d0d254f4dbf744b04f46a14fd05de061bbeb3/rclc/src/rclc/executor.c#L1559
However, rcl_wait might not be the problem - maybe something goes wrong with the other threads and then everything stops.
I configured also the priorities:
So even if the worker threads are executing, the NuttX OS should be able to execute the executor loop.
I also noticed that sometimes the green light on the Olimex board starts blinking. after that not output is seen in the nsh shell (via screen terminal). What does that mean? Something really went wrong?
I wrote a simple program a main thread and two worker threads, which seems to works fine (without micro-ros functions used).
Is there anything regarding STACKSIZE I have to consider? Currently it is set to 65000 in the Makefile
When spawning threads (pthread_create), then no stack size is configured. What is the default stack size. Is it maybe too small, too large?
rclc executor:
https://github.com/micro-ROS/rclc/tree/feature/rbs-nuttx
application on olimex:
https://github.com/micro-ROS/nuttx_apps/tree/feature/foxy_rbs_executor_demo/examples/uros_rbs
The text was updated successfully, but these errors were encountered: