Kaydet (Commit) c1efe5f0 authored tarafından Serhiy Storchaka's avatar Serhiy Storchaka

Issue #23344: marshal.dumps() is now 20-25% faster on average.

üst ce921c62
...@@ -381,8 +381,9 @@ The following performance enhancements have been added: ...@@ -381,8 +381,9 @@ The following performance enhancements have been added:
* Many operations on :class:`io.BytesIO` are now 50% to 100% faster. * Many operations on :class:`io.BytesIO` are now 50% to 100% faster.
(Contributed by Serhiy Storchaka in :issue:`15381`.) (Contributed by Serhiy Storchaka in :issue:`15381`.)
* :func:`marshal.dumps` with versions 3 and 4 is now 40-50% faster on average. * :func:`marshal.dumps` is now faster (65%-85% with versions 3--4, 20-25% with
(Contributed by Serhiy Storchaka in :issue:`20416`.) versions 0--2 on typical data, and up to 5x in best cases).
(Contributed by Serhiy Storchaka in :issue:`20416` and :issue:`23344`.)
Build and C API Changes Build and C API Changes
......
...@@ -13,6 +13,8 @@ Core and Builtins ...@@ -13,6 +13,8 @@ Core and Builtins
Library Library
------- -------
- Issue #23344: marshal.dumps() is now 20-25% faster on average.
- Issue #20416: marshal.dumps() with protocols 3 and 4 is now 40-50% faster on - Issue #20416: marshal.dumps() with protocols 3 and 4 is now 40-50% faster on
average. average.
......
...@@ -78,42 +78,75 @@ typedef struct { ...@@ -78,42 +78,75 @@ typedef struct {
int version; int version;
} WFILE; } WFILE;
#define w_byte(c, p) if (((p)->fp)) putc((c), (p)->fp); \ #define w_byte(c, p) do { \
else if ((p)->ptr != (p)->end) *(p)->ptr++ = (c); \ if ((p)->ptr != (p)->end || w_reserve((p), 1)) \
else w_more((c), p) *(p)->ptr++ = (c); \
} while(0)
static void static void
w_more(char c, WFILE *p) w_flush(WFILE *p)
{
assert(p->fp != NULL);
fwrite(p->buf, 1, p->ptr - p->buf, p->fp);
p->ptr = p->buf;
}
static int
w_reserve(WFILE *p, Py_ssize_t needed)
{ {
Py_ssize_t size, newsize; Py_ssize_t pos, size, delta;
if (p->str == NULL) if (p->ptr == NULL)
return; /* An error already occurred */ return 0; /* An error already occurred */
if (p->fp != NULL) {
w_flush(p);
return needed <= p->end - p->ptr;
}
assert(p->str != NULL);
pos = p->ptr - p->buf;
size = PyBytes_Size(p->str); size = PyBytes_Size(p->str);
newsize = size + size + 1024; if (size > 16*1024*1024)
if (newsize > 32*1024*1024) { delta = (size >> 3); /* 12.5% overallocation */
newsize = size + (size >> 3); /* 12.5% overallocation */ else
delta = size + 1024;
delta = Py_MAX(delta, needed);
if (delta > PY_SSIZE_T_MAX - size) {
p->error = WFERR_NOMEMORY;
return 0;
} }
if (_PyBytes_Resize(&p->str, newsize) != 0) { size += delta;
p->ptr = p->end = NULL; if (_PyBytes_Resize(&p->str, size) != 0) {
p->ptr = p->buf = p->end = NULL;
return 0;
} }
else { else {
p->ptr = PyBytes_AS_STRING((PyBytesObject *)p->str) + size; p->buf = PyBytes_AS_STRING(p->str);
p->end = p->ptr = p->buf + pos;
PyBytes_AS_STRING((PyBytesObject *)p->str) + newsize; p->end = p->buf + size;
*p->ptr++ = c; return 1;
} }
} }
static void static void
w_string(const char *s, Py_ssize_t n, WFILE *p) w_string(const char *s, Py_ssize_t n, WFILE *p)
{ {
Py_ssize_t m;
if (!n || p->ptr == NULL)
return;
m = p->end - p->ptr;
if (p->fp != NULL) { if (p->fp != NULL) {
fwrite(s, 1, n, p->fp); if (n <= m) {
Py_MEMCPY(p->ptr, s, n);
p->ptr += n;
}
else {
w_flush(p);
fwrite(s, 1, n, p->fp);
}
} }
else { else {
while (--n >= 0) { if (n <= m || w_reserve(p, n - m)) {
w_byte(*s, p); Py_MEMCPY(p->ptr, s, n);
s++; p->ptr += n;
} }
} }
} }
...@@ -573,26 +606,34 @@ w_clear_refs(WFILE *wf) ...@@ -573,26 +606,34 @@ w_clear_refs(WFILE *wf)
void void
PyMarshal_WriteLongToFile(long x, FILE *fp, int version) PyMarshal_WriteLongToFile(long x, FILE *fp, int version)
{ {
char buf[4];
WFILE wf; WFILE wf;
memset(&wf, 0, sizeof(wf)); memset(&wf, 0, sizeof(wf));
wf.fp = fp; wf.fp = fp;
wf.ptr = wf.buf = buf;
wf.end = wf.ptr + sizeof(buf);
wf.error = WFERR_OK; wf.error = WFERR_OK;
wf.version = version; wf.version = version;
w_long(x, &wf); w_long(x, &wf);
w_flush(&wf);
} }
void void
PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version) PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version)
{ {
char buf[BUFSIZ];
WFILE wf; WFILE wf;
memset(&wf, 0, sizeof(wf)); memset(&wf, 0, sizeof(wf));
wf.fp = fp; wf.fp = fp;
wf.ptr = wf.buf = buf;
wf.end = wf.ptr + sizeof(buf);
wf.error = WFERR_OK; wf.error = WFERR_OK;
wf.version = version; wf.version = version;
if (w_init_refs(&wf, version)) if (w_init_refs(&wf, version))
return; /* caller mush check PyErr_Occurred() */ return; /* caller mush check PyErr_Occurred() */
w_object(x, &wf); w_object(x, &wf);
w_clear_refs(&wf); w_clear_refs(&wf);
w_flush(&wf);
} }
typedef WFILE RFILE; /* Same struct with different invariants */ typedef WFILE RFILE; /* Same struct with different invariants */
...@@ -1533,7 +1574,7 @@ PyMarshal_WriteObjectToString(PyObject *x, int version) ...@@ -1533,7 +1574,7 @@ PyMarshal_WriteObjectToString(PyObject *x, int version)
wf.str = PyBytes_FromStringAndSize((char *)NULL, 50); wf.str = PyBytes_FromStringAndSize((char *)NULL, 50);
if (wf.str == NULL) if (wf.str == NULL)
return NULL; return NULL;
wf.ptr = PyBytes_AS_STRING((PyBytesObject *)wf.str); wf.ptr = wf.buf = PyBytes_AS_STRING((PyBytesObject *)wf.str);
wf.end = wf.ptr + PyBytes_Size(wf.str); wf.end = wf.ptr + PyBytes_Size(wf.str);
wf.error = WFERR_OK; wf.error = WFERR_OK;
wf.version = version; wf.version = version;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment