Skip to content
New issue

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

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

Already on GitHub? Sign in 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
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.

1 participant