apple / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies. This fork is used to manage Apple’s stable releases of Clang as well as support the Swift project.
https://llvm.org
Other
1.09k stars 320 forks source link

[llvm/Support/VirtualOutputBackends] Don't create unbuffered streams when the `MirroringOutputBackend` is used #8925

Closed akyrtzi closed 6 days ago

akyrtzi commented 1 week ago

MirroringOutputBackend was forcing the raw_ostreams to be unbuffered, causing significant slowdown due to I/O. When enabling Clang caching for building Clang or WebKit, the "from scratch" (all cache misses) build was slower than the regular non-caching build. For building debug Clang the overhead was ~22%, and for debug build of WebKit, it was ~15%.

The overhead went away after removing the SetUnbuffered() calls.

rdar://130514092

akyrtzi commented 1 week ago

@swift-ci Please test LLVM

akyrtzi commented 1 week ago

I put back the flush(); call in pwrite_impl(), otherwise SupportTests/VirtualOutputBackendAdaptors/makeMirroringOutputBackend unit test is failing.

akyrtzi commented 1 week ago

@swift-ci Please test LLVM

cachemeifyoucan commented 1 week ago

I put back the flush(); call in pwrite_impl(), otherwise SupportTests/VirtualOutputBackendAdaptors/makeMirroringOutputBackend unit test is failing.

If it is only that test, it is fine to flush in the unit test before checking content.

akyrtzi commented 1 week ago

If it is only that test, it is fine to flush in the unit test before checking content.

My worry is that the test failure is indication that the flush call is necessary to support the behavioral expectations of pwrite callers.

MirroringOutput::pwrite_impl() is not called during compilation so I'm not so worried about it, we can revisit after input from @dexonsmith

dexonsmith commented 6 days ago

The unbuffered behaviour was intentional, and it seemed important, but I can't remember why... it's possible it only mattered for some clients (and it's possible those clients were hypothetical).

Maybe this was for live display of command-line output? (Or stderr?)

Or maybe it was something more subtle, like ensuring there's only one buffer, rather than a chain of buffers... at some point I had to do funny things with buffers to fix a weird crash after compilation failed.

akyrtzi commented 6 days ago

@dexonsmith could you comment on this override of MirroringOutput:

    void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override {
      this->flush();
      F1->getOS().pwrite(Ptr, Size, Offset);
      F2->getOS().pwrite(Ptr, Size, Offset);
    }

pwrite_impl() is not called during compilation but I was worried the flush() call may cause some performance issue if it does get used. I did notice that the SupportTests/VirtualOutputBackendAdaptors/makeMirroringOutputBackend unit test depends on the presence of the flush() call.

Should we not be worried about performance issues related to calling flush() for each pwrite call?