This is an archive of the discontinued LLVM Phabricator instance.

[libcxx] [test] Disable allocation checks in class.path tests on windows
ClosedPublic

Authored by mstorsjo on Mar 11 2021, 1:12 AM.

Details

Summary

On windows, the path internal representation is wchar_t, and
input/output often goes through utf8 inbetween, which causes extra
allocations.

MS STL does the same, so this shouldn't be a standards compliance
issue.

This is a more targeted and precise solution, as an alternative to
D97497.

Diff Detail

Event Timeline

mstorsjo requested review of this revision.Mar 11 2021, 1:12 AM
mstorsjo created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptMar 11 2021, 1:12 AM
Herald added a reviewer: Restricted Project. · View Herald Transcript
mstorsjo updated this revision to Diff 329884.Mar 11 2021, 1:58 AM

Use the right form of string_view (matching the path char type) in the
concat test, to avoid allocations in one case there.

Also if preferred, I can split out some of the changes that aren't straightforward disablings (two changes in the concat test, that allow keeping the current checks).

curdeius added inline comments.
libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
190

Aren't there cases where it won't allocate? Even if CharT is path::value_type? Looking at the code the answer is negative, but I'd like your confirmation.

On a different note.
I've been looking at operator/= to which append delegates, and we seem to miss an optimization when calling substr.

At https://github.com/llvm/llvm-project/blob/main/libcxx/include/filesystem#L1029 and https://github.com/llvm/llvm-project/blob/main/libcxx/include/filesystem#L1034, __p.__pn_ is a string (string_type), so .substr() returns a string.
This string gets appended to __pn_ and immediately discarded.
I think we should do string_view_type{__p.__pn_}.substr() and so avoid this temporary string. WDYT?

libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp
347

Here (see below).

373

That's a drive-by fix, right? If this is correct, shouldn't line 347 be similar?
BTW, preferably I'd remove this change from this revision.

mstorsjo added inline comments.Mar 11 2021, 2:59 AM
libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
190

Thanks for the suggestions about optimizations - yeah that could help (and would avoid one temporary allocation I presume?).

Regarding this particular case, both parameters to operator/= and append() are of type InputIter, which are pass through an intermediate path object, see https://github.com/llvm/llvm-project/blob/main/libcxx/include/filesystem#L1039-L1051.

However, the append that we do on line 367 (with RHS being a path), doesn't do allocations, so we could add such a guard there. That seems to run successfully even with the current form of the header.

libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp
373

It's a separate fix to make it not require allocations, yeah, otherwise we'd need to disable the allocation guard below. Sure, I can split it out for clarity. I guess we could change line 347 too - there's no allocation guard there so it works either way, but having it use the path native type probably is closer to the original intent.

mstorsjo added inline comments.Mar 11 2021, 3:21 AM
libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
190

Actually, scratch that, the appends on line 367 don't use long enough things to hit the allocator.

We could add another case here above (say around line 182) that appends using a plain path as RHS. With your suggestion for operator/=, that one succeeds with a DisableAllocationGuard, so we could add such a thing here too. Should that go before or after the rest here, though? It feels a bit silly to be adding a new testcase to show off that the header file fix has the intended effect, when the rest of the file (with its existing DisableAllocationGuards) actually is failing.

mstorsjo updated this revision to Diff 329917.Mar 11 2021, 4:07 AM

Updated after splitting out D98406. Updated path.native.obs/string_alloc.pass.cpp to disable the checks much more precisely, keeping the checks for the native type.

Quuxplusone added inline comments.
libcxx/test/support/test_macros.h
378

I think this macro's name needs to start with TEST_.
Orthogonally, I think WIN should be WIN32, for greppability.
So perhaps #define TEST_NOT_WIN32(...)? I wanted to say TEST_EXCEPT_ON_WIN32, except that I think someone might misread "EXCEPT" as having something to do with C++ exceptions.

Alternatively, introduce a specific type DisableAllocationGuardExceptOnWin32 and use that instead of DisableAllocationGuard in certain places.

(Really DisableAllocation was a bad name in the first place — it doesn't disable the allocation guard, it is the allocation guard! — and what's meant is more like ExpectNoAllocations, ExpectNoAllocationsExceptOnWin32. Blech.)

mstorsjo added inline comments.Mar 11 2021, 6:33 AM
libcxx/test/support/test_macros.h
378

I kinda intentionally left out the "test" prefix of the macro, designing it similar to the LIBCPP_ONLY() macro, but inverted. And it's not so much a "test this"-macro but more generically just a more convenient ifdef. (In some cases, a macro like IF_WIN32_ELSE(win, else) macro also would be convenient, but probably not worth it, and it'd be less clear.)

WIN32 for greppability sounds good.

Agree about DisableAllocation being a non-ideal name, ExpectNoAllocations sounds good. I'm not entirely sold on making an ExceptOnWin32 variant though, as the exact condition for where/when to disable things (ie require that no allocations are done) varies, see e.g. the current modifications in string_alloc.pass.cpp.

libcxx/test/support/test_macros.h
378

I kinda intentionally left out the "test" prefix of the macro, designing it similar to the LIBCPP_ONLY() macro

I do like analogies to existing code... but... look at literally every other macro in "test_macros.h"! They either begin with TEST_ (TEST_HAS_NO_EXCEPTIONS, TEST_STD_VER, TEST_CONSTEXPR_CXX14, TEST_SAFE_STATIC, TEST_IGNORE_NODISCARD) or their names are arguably specific to testing (ASSERT_NOEXCEPT, LIBCPP_ASSERT) or it's the LIBCPP_ONLY macro, which feels like it just snuck in next to the various flavors of LIBCPP_ASSERT and nobody noticed. 😛
So I think starting with TEST_ needs to be part of any macro-based solution.

mstorsjo added inline comments.Mar 11 2021, 7:47 AM
libcxx/test/support/test_macros.h
378

Ok, fair enough, TEST_NOT_WIN32() it is then.

mstorsjo updated this revision to Diff 329967.Mar 11 2021, 7:51 AM

Renamed the macro from NOT_WIN() to TEST_NOT_WIN32() as requested.

@Quuxplusone Does this look ok to you now? It's much more targeted and precise than before, and allows retaining some checks against allocations in the files.

Regarding renaming the classes to make their use more obvious, that's probably doable, but I'd like to do such changes after the changes I have here (and maybe a few more in my queue) have landed.

Sure, LGTM. (The naming/logic is still a bit uglier than I wish, but I have no concrete suggestions and don't wish to block this.) @curdeius, LGTY?

curdeius accepted this revision.Mar 15 2021, 9:12 AM

Yes, LGTM.

This revision is now accepted and ready to land.Mar 15 2021, 9:12 AM