[pygobject] invoke state: add a free memory cache for PyGIInvokeArgState
- From: Christoph Reiter <creiter src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pygobject] invoke state: add a free memory cache for PyGIInvokeArgState
- Date: Sun, 27 Sep 2015 14:47:26 +0000 (UTC)
commit e1921b7224ca1e909d9fe5483a09414742d0baf4
Author: Christoph Reiter <creiter src gnome org>
Date: Sat Sep 26 21:29:54 2015 +0200
invoke state: add a free memory cache for PyGIInvokeArgState
Keep one free allocation per argument count around
to reduce g_slice_alloc/free usage.
Reduces CPU time for simple functions by 10% and 5% for closures.
https://bugzilla.gnome.org/show_bug.cgi?id=750658
gi/pygi-closure.c | 6 +---
gi/pygi-invoke.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++-----
gi/pygi-invoke.h | 4 +++
3 files changed, 61 insertions(+), 10 deletions(-)
---
diff --git a/gi/pygi-closure.c b/gi/pygi-closure.c
index f54d886..6a68e2b 100644
--- a/gi/pygi-closure.c
+++ b/gi/pygi-closure.c
@@ -317,9 +317,7 @@ _invoke_state_init_from_cache (PyGIInvokeState *state,
state->args = NULL;
state->error = NULL;
- state->args = g_slice_alloc0 (state->n_args * sizeof (PyGIInvokeArgState));
- if (state->args == NULL && state->n_args != 0) {
- PyErr_NoMemory();
+ if (!_pygi_invoke_arg_state_init (state)) {
return FALSE;
}
@@ -332,7 +330,7 @@ _invoke_state_init_from_cache (PyGIInvokeState *state,
static void
_invoke_state_clear (PyGIInvokeState *state)
{
- g_slice_free1 (state->n_args * sizeof (PyGIInvokeArgState), state->args);
+ _pygi_invoke_arg_state_free (state);
Py_XDECREF (state->py_in_args);
}
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c
index af4d7c0..0290fc9 100644
--- a/gi/pygi-invoke.c
+++ b/gi/pygi-invoke.c
@@ -216,6 +216,59 @@ _py_args_combine_and_check_length (PyGICallableCache *cache,
return combined_py_args;
}
+/* To reduce calls to g_slice_*() we (1) allocate all the memory depended on
+ * the argument count in one go and (2) keep one version per argument count
+ * around for faster reuse.
+ */
+
+#define PyGI_INVOKE_ARG_STATE_SIZE(n) (n * (sizeof (PyGIInvokeArgState) + sizeof (GIArgument *)))
+#define PyGI_INVOKE_ARG_STATE_N_MAX 10
+static gpointer free_arg_state[PyGI_INVOKE_ARG_STATE_N_MAX];
+
+/**
+ * _pygi_invoke_arg_state_init:
+ * Sets PyGIInvokeState.args and PyGIInvokeState.ffi_args.
+ * On error returns FALSE and sets an exception.
+ */
+gboolean
+_pygi_invoke_arg_state_init (PyGIInvokeState *state) {
+
+ gpointer mem;
+
+ if (state->n_args < PyGI_INVOKE_ARG_STATE_N_MAX && (mem = free_arg_state[state->n_args]) != NULL) {
+ free_arg_state[state->n_args] = NULL;
+ memset (mem, 0, PyGI_INVOKE_ARG_STATE_SIZE (state->n_args));
+ } else {
+ mem = g_slice_alloc0 (PyGI_INVOKE_ARG_STATE_SIZE (state->n_args));
+ }
+
+ if (mem == NULL && state->n_args != 0) {
+ PyErr_NoMemory();
+ return FALSE;
+ }
+
+ if (mem != NULL) {
+ state->args = mem;
+ state->ffi_args = (gpointer)((gchar *)mem + state->n_args * sizeof (PyGIInvokeArgState));
+ }
+
+ return TRUE;
+}
+
+/**
+ * _pygi_invoke_arg_state_free:
+ * Frees PyGIInvokeState.args and PyGIInvokeState.ffi_args
+ */
+void
+_pygi_invoke_arg_state_free(PyGIInvokeState *state) {
+ if (state->n_args < PyGI_INVOKE_ARG_STATE_N_MAX && free_arg_state[state->n_args] == NULL) {
+ free_arg_state[state->n_args] = state->args;
+ return;
+ }
+
+ g_slice_free1 (PyGI_INVOKE_ARG_STATE_SIZE (state->n_args), state->args);
+}
+
static gboolean
_invoke_state_init_from_cache (PyGIInvokeState *state,
PyGIFunctionCache *function_cache,
@@ -245,14 +298,10 @@ _invoke_state_init_from_cache (PyGIInvokeState *state,
}
state->n_py_in_args = PyTuple_Size (state->py_in_args);
- state->args = g_slice_alloc0 (state->n_args * (sizeof (PyGIInvokeArgState) + sizeof (GIArgument *)));
- if (state->args == NULL && state->n_args != 0) {
- PyErr_NoMemory();
+ if (!_pygi_invoke_arg_state_init (state)) {
return FALSE;
}
- state->ffi_args = (gpointer)((char*)state->args + state->n_args * sizeof (PyGIInvokeArgState));
-
state->error = NULL;
if (cache->throws) {
@@ -268,7 +317,7 @@ _invoke_state_init_from_cache (PyGIInvokeState *state,
static void
_invoke_state_clear (PyGIInvokeState *state, PyGIFunctionCache *function_cache)
{
- g_slice_free1 (state->n_args * (sizeof (PyGIInvokeArgState) + sizeof (GIArgument *)), state->args);
+ _pygi_invoke_arg_state_free (state);
Py_XDECREF (state->py_in_args);
}
diff --git a/gi/pygi-invoke.h b/gi/pygi-invoke.h
index b49ffa7..dfed2e0 100644
--- a/gi/pygi-invoke.h
+++ b/gi/pygi-invoke.h
@@ -38,6 +38,10 @@ PyObject *pygi_callable_info_invoke (GIBaseInfo *info, PyObject *py_args,
PyObject *_wrap_g_callable_info_invoke (PyGIBaseInfo *self, PyObject *py_args,
PyObject *kwargs);
+gboolean _pygi_invoke_arg_state_init (PyGIInvokeState *state);
+
+void _pygi_invoke_arg_state_free (PyGIInvokeState *state);
+
G_END_DECLS
#endif /* __PYGI_INVOKE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]