Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Improve performance by using Python C API to enter/exit context #627

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

tarasko
Copy link

@tarasko tarasko commented Sep 8, 2024

From perf, callstack before the change:

--54.22%--__pyx_f_6uvloop_4loop___uv_stream_on_read
         |          
          --52.82%--__pyx_f_6uvloop_4loop_run_in_context1
                    |          
                     --51.06%--cfunction_vectorcall_FASTCALL_KEYWORDS
                               context_run
                               |          
                                --50.49%--_PyObject_VectorcallTstate.lto_priv.18
                                          |          
                                           --50.28%--method_vectorcall
                                                     |          
                                                      --49.45%--__pyx_pw_6picows_6picows_10WSProtocol_13data_received


After the change:

--51.71%--__pyx_f_6uvloop_4loop___uv_stream_on_read
         |          
          --50.42%--__pyx_f_6uvloop_4loop_run_in_context1
                    |          
                     --49.13%--__pyx_pw_6picows_6picows_10WSProtocol_13data_received

On a side note, I have removed Py_INCREF/Py_DECREF because cython does it itself when method is called directly.

static CYTHON_INLINE PyObject *__pyx_f_6uvloop_4loop_run_in_context(PyObject *__pyx_v_context, PyObject *__pyx_v_method) {
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  int __pyx_t_1;
  PyObject *__pyx_t_2 = NULL;
  PyObject *__pyx_t_3 = NULL;
  PyObject *__pyx_t_4 = NULL;
  unsigned int __pyx_t_5;
  int __pyx_t_6;
  char const *__pyx_t_7;
  PyObject *__pyx_t_8 = NULL;
  PyObject *__pyx_t_9 = NULL;
  PyObject *__pyx_t_10 = NULL;
  PyObject *__pyx_t_11 = NULL;
  PyObject *__pyx_t_12 = NULL;
  PyObject *__pyx_t_13 = NULL;
  int __pyx_t_14;
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;
  __Pyx_RefNannySetupContext("run_in_context", 1);

  /* "uvloop/loop.pyx":95
 * 
 * cdef inline run_in_context(context, method):
 *     Context_Enter(context)             # <<<<<<<<<<<<<<
 *     try:
 *         return method()
 */
  __pyx_t_1 = Context_Enter(__pyx_v_context); if (unlikely(__pyx_t_1 == ((int)-1))) __PYX_ERR(0, 95, __pyx_L1_error)

  /* "uvloop/loop.pyx":96
 * cdef inline run_in_context(context, method):
 *     Context_Enter(context)
 *     try:             # <<<<<<<<<<<<<<
 *         return method()
 *     finally:
 */
  /*try:*/ {

    /* "uvloop/loop.pyx":97
 *     Context_Enter(context)
 *     try:
 *         return method()             # <<<<<<<<<<<<<<
 *     finally:
 *         Context_Exit(context)
 */
    __Pyx_XDECREF(__pyx_r);
    __Pyx_INCREF(__pyx_v_method);
    __pyx_t_3 = __pyx_v_method; __pyx_t_4 = NULL;
    __pyx_t_5 = 0;
    #if CYTHON_UNPACK_METHODS
    if (unlikely(PyMethod_Check(__pyx_t_3))) {
      __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
      if (likely(__pyx_t_4)) {
        PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
        __Pyx_INCREF(__pyx_t_4);
        __Pyx_INCREF(function);
        __Pyx_DECREF_SET(__pyx_t_3, function);
        __pyx_t_5 = 1;
      }
    }
    #endif
    {
      PyObject *__pyx_callargs[2] = {__pyx_t_4, NULL};
      __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_5, 0+__pyx_t_5);
      __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
      if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 97, __pyx_L4_error)
      __Pyx_GOTREF(__pyx_t_2);
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    }
    __pyx_r = __pyx_t_2;
    __pyx_t_2 = 0;
    goto __pyx_L3_return;
  }
  /* "uvloop/loop.pyx":99
 *         return method()
 *     finally:
 *         Context_Exit(context)             # <<<<<<<<<<<<<<
 * 
 * 
 */
  /*finally:*/ {
    __pyx_L4_error:;
    /*exception exit:*/{
      __Pyx_PyThreadState_declare
      __Pyx_PyThreadState_assign
      __pyx_t_8 = 0; __pyx_t_9 = 0; __pyx_t_10 = 0; __pyx_t_11 = 0; __pyx_t_12 = 0; __pyx_t_13 = 0;
      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
      __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
      if (PY_MAJOR_VERSION >= 3) __Pyx_ExceptionSwap(&__pyx_t_11, &__pyx_t_12, &__pyx_t_13);
      if ((PY_MAJOR_VERSION < 3) || unlikely(__Pyx_GetException(&__pyx_t_8, &__pyx_t_9, &__pyx_t_10) < 0)) __Pyx_ErrFetch(&__pyx_t_8, &__pyx_t_9, &__pyx_t_10);
      __Pyx_XGOTREF(__pyx_t_8);
      __Pyx_XGOTREF(__pyx_t_9);
      __Pyx_XGOTREF(__pyx_t_10);
      __Pyx_XGOTREF(__pyx_t_11);
      __Pyx_XGOTREF(__pyx_t_12);
      __Pyx_XGOTREF(__pyx_t_13);
      __pyx_t_1 = __pyx_lineno; __pyx_t_6 = __pyx_clineno; __pyx_t_7 = __pyx_filename;
      {
        __pyx_t_14 = Context_Exit(__pyx_v_context); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 99, __pyx_L7_error)
      }
      if (PY_MAJOR_VERSION >= 3) {
        __Pyx_XGIVEREF(__pyx_t_11);
        __Pyx_XGIVEREF(__pyx_t_12);
        __Pyx_XGIVEREF(__pyx_t_13);
        __Pyx_ExceptionReset(__pyx_t_11, __pyx_t_12, __pyx_t_13);
      }
      __Pyx_XGIVEREF(__pyx_t_8);
      __Pyx_XGIVEREF(__pyx_t_9);
      __Pyx_XGIVEREF(__pyx_t_10);
      __Pyx_ErrRestore(__pyx_t_8, __pyx_t_9, __pyx_t_10);
      __pyx_t_8 = 0; __pyx_t_9 = 0; __pyx_t_10 = 0; __pyx_t_11 = 0; __pyx_t_12 = 0; __pyx_t_13 = 0;
      __pyx_lineno = __pyx_t_1; __pyx_clineno = __pyx_t_6; __pyx_filename = __pyx_t_7;
      goto __pyx_L1_error;
      __pyx_L7_error:;
      if (PY_MAJOR_VERSION >= 3) {
        __Pyx_XGIVEREF(__pyx_t_11);
        __Pyx_XGIVEREF(__pyx_t_12);
        __Pyx_XGIVEREF(__pyx_t_13);
        __Pyx_ExceptionReset(__pyx_t_11, __pyx_t_12, __pyx_t_13);
      }
      __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
      __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
      __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
      __pyx_t_11 = 0; __pyx_t_12 = 0; __pyx_t_13 = 0;
      goto __pyx_L1_error;
    }
    __pyx_L3_return: {
      __pyx_t_13 = __pyx_r;
      __pyx_r = 0;
      __pyx_t_6 = Context_Exit(__pyx_v_context); if (unlikely(__pyx_t_6 == ((int)-1))) __PYX_ERR(0, 99, __pyx_L1_error)
      __pyx_r = __pyx_t_13;
      __pyx_t_13 = 0;
      goto __pyx_L0;
    }
  }

@tarasko tarasko force-pushed the optimize_run_in_context branch 2 times, most recently from 0701321 to 1757aa8 Compare September 10, 2024 23:17
@tarasko tarasko force-pushed the optimize_run_in_context branch 2 times, most recently from 64459a4 to 1721fb9 Compare September 11, 2024 00:26
@tarasko tarasko force-pushed the optimize_run_in_context branch from 1721fb9 to b5873d5 Compare September 11, 2024 00:45
@tarasko tarasko changed the title Optimize run_in_context functions Optimize performance by using Python C API to enter/exit context Oct 15, 2024
@tarasko tarasko changed the title Optimize performance by using Python C API to enter/exit context Improve performance by using Python C API to enter/exit context Oct 15, 2024
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant