Improvement of allocation of big python list to custom message data field
Short explanation:
I am trying to use ROS2 to publish sensor data that I have stored on disk that I "acquired" from a simulator. The sensor data frame is in the form of a protobuf RepeatedScalarContainer. I have no problem in parsing and deserializing the data from protobuf (.bin). I already cast this data into a python list (let's call it sensor_data_list
) and this works just fine and it is not my problem.
The problem is when I try to allocate a sensor dataframe (a quite big list of size ~4 million elements which is equivalent to 18 MB, when I use sys.getsizeof()
) into a field of a custom message. I think that this is not a ROS2 problem but rather how I handle data in python. However, I thought that someone in the ROS community might have had the same problem or some similar experience.
Detailed explanation:
I needed to create my own sensor custom data to handle a specific sensor data (no, I could not use already available sensor data msgs available in ROS, but this is not the point of my question anyway). Let's call this custome message sensor_data_custom_msg
.
My data handling workflow in my ROS2 sensor node is the following:
- deserialize protobuf sensor data and preload it into a big python list. This is done at the beginning of the node initialization on purpose since we don't care about "spending/wasting" some time in the initialization phase of the node.
- create the actual sensor publisher node by passing to it the preloaded data in previous point
in thetimer_callback
of the node I initialize asensor_data_custom_msg
and I pass to the callback the preloaded data. - The problem is at this step: At each time step what I would like to do is to fill the
sensor_data_custom_msg
fielddata
with a specific element of the listsensor_data_list
to then publish mysensor_data_custom_msg
filled with sensor data stored on disk. This operation however is taking a lot of time (~0.4 seconds). Therefore, from here I started investigating a bit the problem. What I found is:
If I print the length and type of the data I am trying to fill the sensor_data_custom_msg.data
I get respectively:
length: 4608000; type: <class 'list'>
. You can then understand that my sensor data is quite big and here comes my question: is there a better way to deal with such big lists in python? Can I optimize or change the way I allocate such big chunk of data in python?
Another thing that I would like to point out is about computational resources. I have a rather powerful machine. I am working on ubuntu 20.04 (pop_os) and I have an i9 processor with 32GB of RAM. I am using ROS2 inside a Docker container and the container is not the problem. Indeed, if you are asking yourself: "does the container have enough resources from the host computer?" I think that the answer is yes. Indeed:
if I don't run the sensor data publisher node I have the following performance from
docker stats
:CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
908be47fcb43 ros2sensorserver 0.63% 1.423GiB / 31.03GiB 4.58% 8.19MB / 468kB 685MB / 2.24MB 137if I start the sensor data publisher node I have the following performance from
docker stats
:CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
908be47fcb43 ros2sensorserver 102.02% 2.342GiB / 31.03GiB 7.55% 8.19MB / 454kB 685MB / 2.24MB 163
so, you see that some resources are used but nowhere close to the maximum of my machine.
FYI: CPU over 100% is not an issue since docker stats
treats 100% as 1 core (I have a CPU with 16 cores)as it is also specified here and also somewhere else.
Asked by fabbro on 2022-08-30 03:10:44 UTC
Answers
I think you can try to use a Python generator for getting elements from your list.
Next thing would be numpy
- its implementation under Python API is in C, considerably faster than Python. It will take some time to learn it, but basics for numpy.array
can be learned in 1-2 hours if you know Python well. You should check it :)
Asked by ljaniec on 2022-08-30 03:30:40 UTC
Comments
Thanks for your answer. Generators are indeed the first thing I am investigating since that's what I found browsing the web, I should have mentioned it in my question. I also already tried to use NumPy. I tried to instead of using a list to convert the parsed data to a NumPy array but I did not see any improvements. I will try again to understand if I missed something.
Asked by fabbro on 2022-08-30 03:44:45 UTC
If you can add your code as chunks in the question edit, we could then check it and perhaps suggest some improvements. If you are familiar with pandas, you could try loading sensor data as chunks (e.g. https://www.geeksforgeeks.org/how-to-load-a-massive-file-as-small-chunks-in-pandas/)
Asked by ljaniec on 2022-08-30 03:56:50 UTC
After looking a bit more into generators I understood that this is not the place to use them. Generators help when you have a memory problem and you don't want to load the whole data into memory. In my case this is not the issue. My issue is the "copy" of a big list (class <list>
in pyton) into a custom ROS2 message field which is defined as a float32[] data
in its .msg
file. I confirm that I also tried to change the type of the preloaded data from list to numpy array and it did not improve performance either.
Asked by fabbro on 2022-08-30 11:20:15 UTC
Well, you could try implementing this particular node in C++ to see if it helps with speed.
In general, it seems that perhaps you need a different approach/architecture for your case - eliminating that single list with 460k elements would be a priority. Usually some kind of batching/multithreading/data fusion and/or compression is needed to process such large data faster.
Asked by ljaniec on 2022-08-30 13:38:55 UTC
Yes, this is another possibility indeed. I wanted to leave it as a last option since I am not super familiar with C++. I would like to add also another information: the size of the data I am trying to allocate is 18MB, so it is not that small. Another option is that maybe this is the maximum speed I can achieve with the architecture I have.
Asked by fabbro on 2022-08-30 14:29:31 UTC
Comments