[llvm] r214135 - IR: Optimize size of use-list order shuffle vectors
Duncan P. N. Exon Smith
dexonsmith at apple.com
Tue Jul 29 10:15:45 PDT 2014
> On 2014-Jul-29, at 09:23, David Blaikie <dblaikie at gmail.com> wrote:
>
> On Mon, Jul 28, 2014 at 3:41 PM, Duncan P. N. Exon Smith
> <dexonsmith at apple.com> wrote:
>> Author: dexonsmith
>> Date: Mon Jul 28 17:41:50 2014
>> New Revision: 214135
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=214135&view=rev
>> Log:
>> IR: Optimize size of use-list order shuffle vectors
>>
>> Since we're storing lots of these, save two-pointers per vector
>
> It saves two pointers but costs one integer, right? At the cost of
> never having a capacity that differs from the size, which means more
> reallocation overhead? And I see there is no reallocation.. so that
> explains it then.
Yup. These are calculated once and then processed later.
Also, it saves 3 pointers but costs one integer (2 pointers overall).
- sizeof(ShuffleVector) == 32
- sizeof(SmallVector<unsigned, 6>) == 48
> +Chandler: This is where I want std::dynamic_array.
>
>> with a
>> custom type rather than using the relatively heavy `SmallVector`.
>>
>> Part of PR5680.
>>
>> Modified:
>> llvm/trunk/include/llvm/IR/UseListOrder.h
>> llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp
>>
>> Modified: llvm/trunk/include/llvm/IR/UseListOrder.h
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/UseListOrder.h?rev=214135&r1=214134&r2=214135&view=diff
>> ==============================================================================
>> --- llvm/trunk/include/llvm/IR/UseListOrder.h (original)
>> +++ llvm/trunk/include/llvm/IR/UseListOrder.h Mon Jul 28 17:41:50 2014
>> @@ -25,11 +25,58 @@ class Module;
>> class Function;
>> class Value;
>>
>> +/// \brief Structure to hold a use-list shuffle vector.
>> +///
>> +/// Stores most use-lists locally, but large use-lists use an extra heap entry.
>> +/// Costs two fewer pointers than the equivalent \a SmallVector.
>> +class UseListShuffleVector {
>> + unsigned Size;
>> + union {
>> + unsigned *Ptr;
>> + unsigned Array[6];
>> + } Storage;
>> +
>> + bool isSmall() const { return Size <= 6; }
>> + unsigned *data() { return isSmall() ? Storage.Array : Storage.Ptr; }
>> + const unsigned *data() const {
>> + return isSmall() ? Storage.Array : Storage.Ptr;
>> + }
>> +
>> +public:
>> + UseListShuffleVector() : Size(0) {}
>> + UseListShuffleVector(UseListShuffleVector &&X) {
>> + std::memcpy(this, &X, sizeof(UseListShuffleVector));
>> + X.Size = 0;
>> + }
>> + explicit UseListShuffleVector(size_t Size) : Size(Size) {
>> + if (!isSmall())
>> + Storage.Ptr = new unsigned[Size];
>> + }
>> + ~UseListShuffleVector() {
>> + if (!isSmall())
>> + delete Storage.Ptr;
>> + }
>> +
>> + typedef unsigned *iterator;
>> + typedef const unsigned *const_iterator;
>> +
>> + size_t size() const { return Size; }
>> + iterator begin() { return data(); }
>> + iterator end() { return begin() + size(); }
>> + const_iterator begin() const { return data(); }
>> + const_iterator end() const { return begin() + size(); }
>> + unsigned &operator[](size_t I) { return data()[I]; }
>> + unsigned operator[](size_t I) const { return data()[I]; }
>> +};
>> +
>> /// \brief Structure to hold a use-list order.
>> struct UseListOrder {
>> - const Function *F;
>> const Value *V;
>> - SmallVector<unsigned, 8> Shuffle;
>> + const Function *F;
>> + UseListShuffleVector Shuffle;
>> +
>> + UseListOrder(const Value *V, const Function *F, size_t ShuffleSize)
>> + : V(V), F(F), Shuffle(ShuffleSize) {}
>> };
>>
>> typedef std::vector<UseListOrder> UseListOrderStack;
>>
>> Modified: llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp?rev=214135&r1=214134&r2=214135&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp (original)
>> +++ llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp Mon Jul 28 17:41:50 2014
>> @@ -133,12 +133,11 @@ static void predictValueUseListOrderImpl
>> return;
>>
>> // Store the shuffle.
>> - UseListOrder O;
>> - O.V = V;
>> - O.F = F;
>> - for (auto &I : List)
>> - O.Shuffle.push_back(I.second);
>> - Stack.push_back(O);
>> + UseListOrder O(V, F, List.size());
>> + assert(List.size() == O.Shuffle.size() && "Wrong size");
>> + for (size_t I = 0, E = List.size(); I != E; ++I)
>> + O.Shuffle[I] = List[I].second;
>> + Stack.emplace_back(std::move(O));
>
> Generally I'd suggest skipping emplace_back where push_back will have
> the same performance characteristics (since you don't need to call
> anything other than the move ctor, which push_back can do just fine)
>
> But given the use of the small-size optimization, pushing back the
> result isn't ideal either, it's probably better to allocate the
> element in the Stack then initialize it there so you don't have to
> copy the small portion over:
>
> // Is there an easy way to make a sequence one larger and return a
> reference to that new element? It seems such a common operation...
> Stack.resize(Stack.size() + 1);
> UseListOrder &O = Stack.back();
> ...
>
Fixed in r214184.
> In addition/alternatively, I'm not sure how valuable the small-size
> optimization is if all of them are going in another container anyway.
> Usually the small optimization is most valuable when it avoids malloc
> allocation entirely (by using stack space) but here each element in
> Stack will have the small footprint in use - so wasted small buffers
> will be costing heap space...
Every use list shuffle will be at least size 2 (otherwise, there's
nothing to shuffle). If mallocs had 0B memory overhead,
`std::vector<unsigned>` of size 2 would cost 32B. Since mallocs
actually do have overhead (usually at least 16B), the common case (2-6
items) will take less memory.
> (Chandler, again - thoughts on this tradeoff? I'm perhaps too readily
> open to avoiding premature optimization and thus avoid small-size
> optimizations until there's a really good reason to add them, but I
> haven't done as much profiling/performance work to have an intuition
> about when they're not premature and just good practice)
>
>
>> }
>>
>> static void predictValueUseListOrder(const Value *V, const Function *F,
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list