Closed 2lian closed 3 months ago
I do also wonder if my use of the Rate is wrong. Because this seems like a obvious bug.
In rclpy/timer.py, line 142 the following code would fix the issue, and properly destroy the
Timer
.
Well, it definitely should not do that. The timer as passed in there is not owned by the Rate
object, it is owned by whatever is creating that (in this case, the Node is the one that calls create_rate
). Instead, the user should call node.destroy_rate(rate)
to properly destroy a previously created Rate object. Does that work for you?
Ok I understood how to use it now thank you. I did the same benchmark with the code below. Conclusion: Yes this works as intended and the CPU usage stays low.
def tmr_callback(self) -> None:
myRate = self.create_rate(1000)
myRate.sleep()
self.destroy_rate(myRate)
May I suggest to adapt the documentation to avoid users not properly destroying Rate
s in the future?
On the internet the documentation is lacking, and I usually work by opening the objects with my LSP, then having a quick look of the code available inside. Node.create_rate()
and Rate
both never mention the existence of Node.destroy_rate()
, but Rate.destroy()
is here in plain sight.
Suggestions:
Rate.destroy()
method's doc-string.Node.create_rate()
doc-string.Rate.destroy()
to Rate._destroy()
. I know it is not really a private method of Rate, but the user should not use it. It is fairly confusing to have public methods that should not be used, alongside other that should be used like Rate.sleep()
.)Maybe those additions should also be done on objects that are handled the same way: Publisher
Subscription
Client
Service
Timer
GuardCondition
?
Please feel free to open a PR with your 1) and 2) suggestions. I am happy to review that.
Ok got it. I will make the corresponding PR soon. Should I also commit 1) and 2) for similar Publisher Sub etc. objects? Or only Rate?
Thanks a lot for you help.
Ok got it. I will make the corresponding PR soon. Should I also commit 1) and 2) for similar Publisher Sub etc. objects? Or only Rate?
Up to you. I think it would be nice to have it for the other objects as well, but if you don't have time for that it is fine to just do it for Rate.
Bug report
Steps to reproduce issue
Create a
Node
with rclpy. In a callback: create aRate
, wait it thendestroy
it. The more you call this callback the more the cpu usage will increase. CPU usage I report come from$ top
The following code maxes out my CPU in under a second, even though it does nothing but wait. (This code is exaggerated to create the issues, it takes 5-10 minutes to max my robot's cpu)
Expected behavior
This should not use all the cpu. The rates should be properly destroyed when
destroy()
is called. As a proof, here are alternative implementations withoutRate
that only use 7% of CPU:Actual behavior
The CPU usage explodes and ros becomes laggy. I found that
Rate._timer
are not properly destroyed. The code below proves that the timer's destruction is the issue by fixing the problem (resulting in 7% CPU load).Right now the user should call
Rate._timer.destroy()
andRate.destroy()
to properly use/destroy a Rate. Which is very confusing.Additional information
In rclpy/timer.py, line 142 the following code would fix the issue, and properly destroy the
Timer
.Let me know if I should do a pull request for this.