Skip to content

bpo-31993: Do not create frames for large bytes and str objects#5114

Merged
serhiy-storchaka merged 8 commits into
python:masterfrom
serhiy-storchaka:pypickle-dump-mem-optim
Jan 11, 2018
Merged

bpo-31993: Do not create frames for large bytes and str objects#5114
serhiy-storchaka merged 8 commits into
python:masterfrom
serhiy-storchaka:pypickle-dump-mem-optim

Conversation

@serhiy-storchaka

@serhiy-storchaka serhiy-storchaka commented Jan 6, 2018

Copy link
Copy Markdown
Member

when serialize into memory buffer with C pickle implementations.

This optimization already is performed when serialize into memory with Python pickle implementations or into a file with both implementations.

https://bugs.python.org/issue31993

when serialize into memory buffer with C pickle implementations.

This optimization already is performed when serialize into memory
with Python pickle implementations or into a file with both
implementations.
Comment thread Modules/_pickle.c Outdated
/* Bypass the in-memory buffer to directly stream large data
into the underlying file object. */
if (_Pickler_write_large_bytes(self, header, len, obj) < 0) {
if (_Pickler_write_large_bytes(self, header, len,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this change? If self->write == NULL, It calls _Pickler_Write(self, header, len) < 0) followed by _Pickler_Write(self, PyBytes_AS_STRING(obj), size) exactly as above.

@serhiy-storchaka serhiy-storchaka Jan 6, 2018

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it first commits the current frame and temporary disables framing.

Comment thread Modules/_pickle.c Outdated

/* No-copy code-path to write large contiguous data directly into the
underlying file object, bypassing the output_buffer of the Pickler. */
/* Write large contiguous data directly into the underlying file object,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you rephrase the comments now that this is called also when there is no underlying file object?
See comments in pickle.py for inspiration.

@serhiy-storchaka

Copy link
Copy Markdown
Member Author

Using PyMemoryView_FromMemory() isn't safe since it refers to the temporary data that will be deallocate after destroying a string.

@ogrisel ogrisel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The refactoring looks good to me. Maybe we should add a test to check that the number of frames is not too large in a pickled list of large bytes instances. For instance using count_opcode(pickle.FRAME, pickled) in pickletester.py.

Please also find a comment below in the memory copy induced by PyBytes_FromStringAndSize when dumping large unicode objects.

Comment thread Modules/_pickle.c Outdated
if (_Pickler_CommitFrame(self)) {
return -1;
}
/* Disable frameing temporarily */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: framing

Comment thread Modules/_pickle.c Outdated
/* Stream write the payload into the file without going through the
output buffer. */
if (payload == NULL) {
payload = mem = PyBytes_FromStringAndSize(data, data_size);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This causes an extra memory copy for large str (unicode) objects (compared to the unsafe previous code that relied on PyMemoryView_FromMemory).

This can be measured with:
https://gist.github.com/ogrisel/0e7b3282c84ae4a581f3b9ec1d84b45a

But I am not sure how to write a safe version of the pickling code that would not cause this extra copy. If it's not possible, the entry for bpo-31993 in the changelog should probably be updated.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least I would like this to go to a separate PR. Please let's not mix concerns.

@serhiy-storchaka

Copy link
Copy Markdown
Member Author

Thank you for your review. _pickle.dumps() was not called by corresponding tests. Now test_framing_large_objects covers it.

@ogrisel ogrisel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Comment thread Lib/test/pickletester.py
with self.subTest(proto=proto, fast=fast):
if hasattr(self, 'pickler'):
if fast is None:
pickled = self.dumps(obj, proto)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the point of the None test? Can you please add a comment?

@serhiy-storchaka
serhiy-storchaka merged commit 0a2da50 into python:master Jan 11, 2018
@serhiy-storchaka
serhiy-storchaka deleted the pypickle-dump-mem-optim branch January 11, 2018 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance Performance or resource usage skip news

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants