Cython fastest way to pass a float numbers for high frequency control loops

Viewed 83

I have a function(func) in a c++ class and want to call it from the python side to invoke the following sequence with the lowest latency possible:

1_on the python side: func(np.array([1,2,3,4,5]) or func([1,2,3,4,5]) or 2D array and any other suggestion you may have for lower latency.

2_on the c++ side: I have a place holder of type franka::RobotState robot_state_ and I want to copy a part of the above array inside it. something that I may do for example like:

for (int i = 0; i < 7; ++i) {
        robot_state_.q     [i] = array_that_came_from_python_side  [i];
        robot_state_.dq    [i] = array_that_came_from_python_side  [i+7];
        robot_state_.tau_J [i] = array_that_came_from_python_side  [i+14];
    }

3_Then next lines which I have already written will update another place holder of type franka::Torques _eff_cmd which I want to return to the python side and imagine to do it like the following:

for (int i = 0; i < 7; ++i) {
    array_to_return[i] = _eff_cmd[i]
    }
    return array_to_return // to be sent to the python side

where the array_to_return can be returned on the python side with any type such as numpy array or list or any other suggestion like the input. and then I will repeat this sequence on the python side with a high frequency since it is basically about a control feedback loop.

my question is how to do this in the fastest way with Cython, what do I define the func with on the c++ side. Following this thread one possible way that provides a lower latency seems Memoryviews, but I couldn't understand it well so far to know what I had better write in the c++ code and in the Cython pyx file. I would appreciate if anyone could guide me about it, and if you also had a suggestions other than memoryviews for lower latency.

1 Answers

When it comes to performance optimizations you have to measure!

First make sure, that you exactly know, where your hotspot is. You can use perf or Intels vTune to make sure you optimize the right location.

Than you can write a google benchmark test for that specific hotspot.

If the snippet is your hotspot, splitting the loop will help you, since you have contiguous memory access.

for (int i = 0; i < 7; ++i) {
        robot_state_.q    [i] = array_that_came_from_python_side  [i+7];
}
for (int i = 0; i < 7; ++i) {
        robot_state_.dq     [i] = array_that_came_from_python_side  [i+7];
}
for (int i = 0; i < 7; ++i) {
        robot_state_.tau_J [i] = array_that_came_from_python_side  [i+14];
}

Or it might not do anything because the compilers are very smart these days.

Perhaps std::memcopy will do a goo job

std::memcpy(robot_state_.q, &array_that_came_from_python_side[0], 7);
std::memcpy(robot_state_.dq, &array_that_came_from_python_side[7], 7);
std::memcpy(robot_state_.tau_J , &array_that_came_from_python_side[14], 7);
Related