This is an archive of the discontinued LLVM Phabricator instance.

[libc] Move printf writer to new design
ClosedPublic

Authored by michaelrj on Jun 28 2023, 1:30 PM.

Details

Summary

The new printf writer design focuses on optimizing the fast path. It
inlines any write to a buffer or string, and by handling buffering
itself can more effectively work with both internal and external file
implementations. The overflow hook should allow for expansion to
asprintf with minimal extra code.

Diff Detail

Event Timeline

michaelrj created this revision.Jun 28 2023, 1:30 PM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptJun 28 2023, 1:30 PM
michaelrj requested review of this revision.Jun 28 2023, 1:30 PM
sivachandra added inline comments.Jul 9 2023, 11:27 PM
libc/src/stdio/printf_core/char_converter.h
32 ↗(On Diff #535503)

char_converter.h and string_converter.h changes seem to be unrelated to the topic of the patch?

libc/src/stdio/printf_core/vfprintf_internal.h
26

This is potentially leaking entrypoints. Is simplicity of flush_and_write and vfprintf_internal the only reason? Can you instead do this:

namespace internal {

#ifdef LIBC_COPT_PRINTF_USE_SYSTEM_FILE
LIBC_INLINE int ferror_unlocked(FILE *f) {
  return ::ferror_unlocked(f);
}
...
#else
LIBC_INLINE int ferror_unlocked(FILE *f) {
  return reinterpret_cast<__llvm_libc::File *>(f)->ferror_unlocked(f);
}
...
#endif

} // namespace internal
libc/src/stdio/printf_core/writer.h
24

Looking at the implementation of the hooks above, it seems to me that the expectation is for the hook to adjust the buffer state. I would rather have a single internal place to manage all internal state. So, I suggest the following changes:

  1. Call this hook StreamWriter instead of OverflowHook. This hook should just do the job of writing to the underlying stream and return the errors it might run in to.
  2. Let the Writer class alone manage the internal state.
  3. The StreamWriter hook should only be called when the writer object's buffer fills up (or at the end of course).
  4. If StreamWriter is nullptr, then the writer should drop write data on the floor once the buffer fills up.

Does it cover all use cases?

27

Why isn't the buffer state kept with the writer? In other words, what is the benefit of this separate buffer type WriteBuffer?

michaelrj marked 2 inline comments as done.

clean up entrypoint leaking and unrelated changes

libc/src/stdio/printf_core/char_converter.h
32 ↗(On Diff #535503)

yes. I'll move them to a separate patch.

libc/src/stdio/printf_core/writer.h
24

That covers almost all the use cases. We still need the OverflowHook to be able to modify the buffer to handle the case of asprintf, which dynamically allocates a string for its output. In that case when the buffer fills, the pointer may need to be changed and we don't want to reset the current write position.

27

It allows us to pass just the WriteBuffer to the OverflowHook, since the OverflowHook needs to be able to modify the buffer based not only on the buffer's state but also the length of the new string being written.

sivachandra added inline comments.Jul 14 2023, 10:53 AM
libc/src/stdio/printf_core/writer.h
24

asprintf should be implemented with the separation of abstractions intact. So:

  1. The printf writer works with a statically allocated (stack) buffer similar to fprintf.
  2. The StreamWriter is responsible for maintaining the expanding output buffer. The void * argument to of StreamWriter points to the expandable buffer (likely encapsulated with additional state).

move to WriteBuffer->stream_writer = nullptr for snprintf

The write buffer is still separate to simplify buffer flushing after the printf_main call

sivachandra accepted this revision.Jul 19 2023, 9:23 AM
This revision is now accepted and ready to land.Jul 19 2023, 9:23 AM

rebase and clean up

update comment and rebase before land

This revision was landed with ongoing or failed builds.Jul 20 2023, 11:08 AM
This revision was automatically updated to reflect the committed changes.
libc/test/src/stdio/printf_core/converter_test.cpp