Skip to content

perf: clear generated primitive arrays with slice deletion#260

Open
Lidang-Jiang wants to merge 1 commit intoros2:rollingfrom
Lidang-Jiang:fix/sequence-clear-del-slice
Open

perf: clear generated primitive arrays with slice deletion#260
Lidang-Jiang wants to merge 1 commit intoros2:rollingfrom
Lidang-Jiang:fix/sequence-clear-del-slice

Conversation

@Lidang-Jiang
Copy link
Copy Markdown

Summary

Replace the generated Python array reset loop with PySequence_DelSlice() when converting primitive sequences to Python, and add regression coverage for bounded and unbounded primitive sequence conversion.

Closes #255

Before
$ git show upstream/rolling:rosidl_generator_py/resource/_msg_support.c.em | sed -n "675,705p"
@(bi)    Py_DECREF(itemsize_attr);
@(bi)    if (itemsize != sizeof(@primitive_msg_type_to_c(member.type.value_type))) {
@(bi)      PyErr_SetString(PyExc_RuntimeError, "itemsize doesn't match expectation");
@(bi)      Py_DECREF(field);
@(bi)      return NULL;
@(bi)    }
@(bi)    // clear the array, poor approach to remove potential default values
@(bi)    Py_ssize_t length = PyObject_Length(field);
@(bi)    if (-1 == length) {
@(bi)      Py_DECREF(field);
@(bi)      return NULL;
@(bi)    }
@(bi)    if (length > 0) {
@(bi)      PyObject * pop = PyObject_GetAttrString(field, "pop");
@(bi)      assert(pop != NULL);
@(bi)      for (Py_ssize_t i = 0; i < length; ++i) {
@(bi)        PyObject * ret = PyObject_CallFunctionObjArgs(pop, NULL);
@(bi)        if (!ret) {
@(bi)          Py_DECREF(pop);
@(bi)          Py_DECREF(field);
@(bi)          return NULL;
@(bi)        }
@(bi)        Py_DECREF(ret);
@(bi)      }
@(bi)      Py_DECREF(pop);
@(bi)    }
@(bi)    if (ros_message->@(member.name).size > 0) {
@(bi)      // populating the array.array using the frombytes method
@(bi)      PyObject * frombytes = PyObject_GetAttrString(field, "frombytes");
@(bi)      assert(frombytes != NULL);
@(bi)      @primitive_msg_type_to_c(member.type.value_type) * src = &(ros_message->@(member.name).data[0]);

$ git show upstream/rolling:rosidl_generator_py/test/test_interfaces.py | rg -n "convert_to_py|PyCapsule|primitive_sequences_convert" || true
After
$ git diff --check

$ python3 -m py_compile rosidl_generator_py/test/test_interfaces.py
$WORKSPACE/python310_torch25_cuda/lib/python3.10/site-packages/xpytorch_import_hook.py:6: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
  import pkg_resources

$ ruff check rosidl_generator_py/test/test_interfaces.py
All checks passed!

$ rg -n "PySequence_DelSlice|primitive_sequences_convert_to_py|PyCapsule_GetPointer" rosidl_generator_py/resource/_msg_support.c.em rosidl_generator_py/test/test_interfaces.py
rosidl_generator_py/test/test_interfaces.py:44:_PY_CAPSULE_GET_POINTER = ctypes.pythonapi.PyCapsule_GetPointer
rosidl_generator_py/test/test_interfaces.py:823:def test_primitive_sequences_convert_to_py(
rosidl_generator_py/resource/_msg_support.c.em:687:@(bi)    if (PySequence_DelSlice(field, 0, length) == -1) {

$ python -m pytest -q rosidl_generator_py/test/test_interfaces.py::test_primitive_sequences_convert_to_py
ERROR: found no collectors for $WORKSPACE/ros2-contrib/worktrees/rosidl_python-255/rosidl_generator_py/test/test_interfaces.py::test_primitive_sequences_convert_to_py


==================================== ERRORS ====================================
___________________ ERROR collecting test/test_interfaces.py ___________________
ImportError while importing test module '$WORKSPACE/ros2-contrib/worktrees/rosidl_python-255/rosidl_generator_py/test/test_interfaces.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
../../../python310_torch25_cuda/lib/python3.10/importlib/__init__.py:126: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
rosidl_generator_py/test/test_interfaces.py:24: in <module>
    from rosidl_generator_py.msg import Arrays
E   ModuleNotFoundError: No module named 'rosidl_generator_py.msg'
=========================== short test summary info ============================
ERROR rosidl_generator_py/test/test_interfaces.py
1 error in 0.10s

Test plan

  • git diff --check
  • python3 -m py_compile rosidl_generator_py/test/test_interfaces.py
  • ruff check rosidl_generator_py/test/test_interfaces.py
  • Target pytest cannot complete in this local environment because rosidl_generator_py.msg is generated by the ROS build/test setup and is not present in this source checkout

Signed-off-by: Lidang Jiang <lidangjiang@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Eliminate array resetting loop in _msg_support.c.em

1 participant