diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index f99ebf0dde..24044c5113 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3312,6 +3312,109 @@ function_set_warning(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) Py_RETURN_NONE; } +static PyObject * +bench_concat(PyObject *Py_UNUSED(module), PyObject *args) +{ + Py_ssize_t loops; + if (!PyArg_ParseTuple(args, "n", &loops)) { + return NULL; + } + + PyObject *a = PyUnicode_FromString("x"); + PyObject *b = PyUnicode_FromString("="); + PyObject *ch = PyUnicode_FromString("\""); + PyObject *c = PyUnicode_FromString("string value"); + PyObject *sep = PyUnicode_FromString(", "); + assert(a != NULL && b != NULL && ch != NULL && c != NULL && sep != NULL); + + PyTime_t t1; + (void)PyTime_PerfCounterRaw(&t1); + + for (Py_ssize_t i=0; i < loops; i++) { + PyObject *str = PyUnicode_Concat(a, b); + assert(str != NULL); + + for (int j=0; j<10; j++) { + if (j != 0) { + PyUnicode_Append(&str, sep); + assert(str != NULL); + } + PyUnicode_Append(&str, ch); + assert(str != NULL); + PyUnicode_Append(&str, c); + assert(str != NULL); + PyUnicode_Append(&str, ch); + assert(str != NULL); + } + + Py_DECREF(str); + } + + PyTime_t t2; + (void)PyTime_PerfCounterRaw(&t2); + + Py_DECREF(a); + Py_DECREF(b); + Py_DECREF(ch); + Py_DECREF(c); + Py_DECREF(sep); + + return PyFloat_FromDouble(PyTime_AsSecondsDouble(t2 - t1)); +} + +static PyObject * +bench_writer(PyObject *Py_UNUSED(module), PyObject *args) +{ + Py_ssize_t loops; + if (!PyArg_ParseTuple(args, "n", &loops)) { + return NULL; + } + + PyObject *a = PyUnicode_FromString("x"); + PyObject *b = PyUnicode_FromString("="); + PyObject *sep = PyUnicode_FromString(", "); + PyObject *c = PyUnicode_FromString("string value"); + assert(a != NULL && b != NULL && sep != NULL && c != NULL); + + PyTime_t t1; + (void)PyTime_PerfCounterRaw(&t1); + + for (Py_ssize_t i=0; i < loops; i++) { + PyUnicodeWriter *writer = PyUnicodeWriter_Create(); + // Overallocation is enabled by default + + assert(PyUnicodeWriter_WriteStr(writer, a) == 0); + assert(PyUnicodeWriter_WriteChar(writer, '=') == 0); + + for (int j=0; j<10; j++) { + if (j != 0) { + assert(PyUnicodeWriter_WriteStr(writer, sep) == 0); + } + assert(PyUnicodeWriter_WriteChar(writer, '"') == 0); + assert(PyUnicodeWriter_WriteStr(writer, c) == 0); + if (j == 9) { + // Disable overallocation before the last write + PyUnicodeWriter_SetOverallocate(writer, 0); + } + assert(PyUnicodeWriter_WriteChar(writer, '"') == 0); + } + + PyObject *str = PyUnicodeWriter_Finish(writer); + assert(str != NULL); + Py_DECREF(str); + } + + PyTime_t t2; + (void)PyTime_PerfCounterRaw(&t2); + + Py_DECREF(a); + Py_DECREF(b); + Py_DECREF(sep); + Py_DECREF(c); + + return PyFloat_FromDouble(PyTime_AsSecondsDouble(t2 - t1)); +} + static PyMethodDef TestMethods[] = { {"set_errno", set_errno, METH_VARARGS}, {"test_config", test_config, METH_NOARGS}, @@ -3454,6 +3557,8 @@ static PyMethodDef TestMethods[] = { {"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS}, {"test_weakref_capi", test_weakref_capi, METH_NOARGS}, {"function_set_warning", function_set_warning, METH_NOARGS}, + {"bench_concat", bench_concat, METH_VARARGS}, + {"bench_writer", bench_writer, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 8646664532..6a590aa734 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13115,6 +13115,7 @@ PyUnicodeWriter_Create(void) return NULL; } _PyUnicodeWriter_Init((_PyUnicodeWriter*)writer); + PyUnicodeWriter_SetOverallocate(writer, 1); return writer; }