[llvm] r319839 - [Orc] Add a SymbolStringPool data structure for efficient storage and fast

David Blaikie via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 14 13:21:02 PST 2017


On Tue, Dec 5, 2017 at 1:45 PM Lang Hames via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> Author: lhames
> Date: Tue Dec  5 13:44:56 2017
> New Revision: 319839
>
> URL: http://llvm.org/viewvc/llvm-project?rev=319839&view=rev
> Log:
> [Orc] Add a SymbolStringPool data structure for efficient storage and fast
> comparison of symbol names.
>
> SymbolStringPool is a thread-safe string pool that will be used in
> upcoming Orc
> APIs to facilitate efficient storage and fast comparison of symbol name
> strings.
>
> Added:
>     llvm/trunk/include/llvm/ExecutionEngine/Orc/SymbolStringPool.h
>     llvm/trunk/unittests/ExecutionEngine/Orc/SymbolStringPoolTest.cpp
> Modified:
>     llvm/trunk/unittests/ExecutionEngine/Orc/CMakeLists.txt
>
> Added: llvm/trunk/include/llvm/ExecutionEngine/Orc/SymbolStringPool.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/SymbolStringPool.h?rev=319839&view=auto
>
> ==============================================================================
> --- llvm/trunk/include/llvm/ExecutionEngine/Orc/SymbolStringPool.h (added)
> +++ llvm/trunk/include/llvm/ExecutionEngine/Orc/SymbolStringPool.h Tue
> Dec  5 13:44:56 2017
> @@ -0,0 +1,133 @@
> +//===- SymbolStringPool.h - Multi-threaded pool for JIT symbols -*- C++
> -*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// Contains a multi-threaded string pool suitable for use with ORC.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H
> +#define LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H
> +
> +#include "llvm/ADT/StringMap.h"
> +#include <atomic>
> +#include <mutex>
> +
> +namespace llvm {
> +namespace orc {
> +
> +class SymbolStringPtr;
> +
> +/// @brief String pool for symbol names used by the JIT.
> +class SymbolStringPool {
> +  friend class SymbolStringPtr;
> +public:
> +  /// @brief Create a symbol string pointer from the given string.
> +  SymbolStringPtr intern(StringRef S);
> +
> +  /// @brief Remove from the pool any entries that are no longer
> referenced.
> +  void clearDeadEntries();
> +
> +  /// @brief Returns true if the pool is empty.
> +  bool empty() const;
> +private:
> +  using RefCountType = std::atomic_uint64_t;
> +  using PoolMap = StringMap<RefCountType>;
> +  using PoolMapEntry = StringMapEntry<RefCountType>;
> +  mutable std::mutex PoolMutex;
> +  PoolMap Pool;
> +};
> +
> +/// @brief Pointer to a pooled string representing a symbol name.
> +class SymbolStringPtr {
> +  friend class SymbolStringPool;
> +public:
> +  SymbolStringPtr() = default;
> +  SymbolStringPtr(const SymbolStringPtr &Other)
> +    : S(Other.S) {
> +    if (S)
> +      ++S->getValue();
> +  }
> +
> +  SymbolStringPtr& operator=(const SymbolStringPtr &Other) {
> +    if (S)
> +      --S->getValue();
> +    S = Other.S;
> +    if (S)
> +      ++S->getValue();
> +    return *this;
> +  }
> +
> +  SymbolStringPtr(SymbolStringPtr &&Other) : S(nullptr) {
> +    std::swap(S, Other.S);
> +  }
> +
> +  SymbolStringPtr& operator=(SymbolStringPtr &&Other) {
> +    if (S)
> +      --S->getValue();
> +    S = nullptr;
> +    std::swap(S, Other.S);
> +    return *this;
> +  }
> +
> +  ~SymbolStringPtr() {
> +    if (S)
> +      --S->getValue();
> +  }
> +
> +  bool operator==(const SymbolStringPtr &Other) const {
>

In general, any op overload that can be a non-member should be (though it
can still be a friend and defined inline, so it doesn't change the code
much) so that any conversions that apply to the RHS apply equally to the
LHS.


> +    return S == Other.S;
> +  }
> +
> +  bool operator!=(const SymbolStringPtr &Other) const {
> +    return !(*this == Other);
> +  }
> +
> +private:
> +
> +  SymbolStringPtr(SymbolStringPool::PoolMapEntry *S)
> +      : S(S) {
> +    if (S)
> +      ++S->getValue();
> +  }
> +
> +  SymbolStringPool::PoolMapEntry *S = nullptr;
> +};
> +
> +SymbolStringPtr SymbolStringPool::intern(StringRef S) {
> +  std::lock_guard<std::mutex> Lock(PoolMutex);
> +  auto I = Pool.find(S);
> +  if (I != Pool.end())
> +    return SymbolStringPtr(&*I);
> +
> +  bool Added;
> +  std::tie(I, Added) = Pool.try_emplace(S, 0);
>

This implementation involves two map lookups (one to find, another to
emplace if the find fails) - if you call try_emplace first, and inspect its
"Added" result to decide what to do (you might not have to do anything,
actually), then you can use one lookup.


> +  assert(Added && "Insert should always succeed here");
> +  return SymbolStringPtr(&*I);
> +}
> +
> +void SymbolStringPool::clearDeadEntries() {
> +  std::lock_guard<std::mutex> Lock(PoolMutex);
> +  for (auto I = Pool.begin(), E = Pool.end(); I != E;) {
> +    auto Tmp = std::next(I);
> +    if (I->second == 0)
> +      Pool.erase(I);
> +    I = Tmp;
>

This ^ might be better written as:

auto Tmp = I++;
if (Tmp->second == 0)
  Pool.erase(Tmp);

So there's no need to "remember" the assignment to I at the end? (action at
a distance, etc) - though I can appreciate having the "increment" action at
the end of the loop as it's written here.


> +  }
> +}
> +
> +bool SymbolStringPool::empty() const {
> +  std::lock_guard<std::mutex> Lock(PoolMutex);
> +  return Pool.empty();
> +}
> +
> +} // end namespace orc
> +
> +} // end namespace llvm
> +
> +#endif // LLVM_EXECUTIONENGINE_ORC_SYMBOLSTRINGPOOL_H
>
> Modified: llvm/trunk/unittests/ExecutionEngine/Orc/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/Orc/CMakeLists.txt?rev=319839&r1=319838&r2=319839&view=diff
>
> ==============================================================================
> --- llvm/trunk/unittests/ExecutionEngine/Orc/CMakeLists.txt (original)
> +++ llvm/trunk/unittests/ExecutionEngine/Orc/CMakeLists.txt Tue Dec  5
> 13:44:56 2017
> @@ -21,6 +21,7 @@ add_llvm_unittest(OrcJITTests
>    RemoteObjectLayerTest.cpp
>    RPCUtilsTest.cpp
>    RTDyldObjectLinkingLayerTest.cpp
> +  SymbolStringPoolTest.cpp
>    )
>
>  target_link_libraries(OrcJITTests ${LLVM_PTHREAD_LIB})
>
> Added: llvm/trunk/unittests/ExecutionEngine/Orc/SymbolStringPoolTest.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/Orc/SymbolStringPoolTest.cpp?rev=319839&view=auto
>
> ==============================================================================
> --- llvm/trunk/unittests/ExecutionEngine/Orc/SymbolStringPoolTest.cpp
> (added)
> +++ llvm/trunk/unittests/ExecutionEngine/Orc/SymbolStringPoolTest.cpp Tue
> Dec  5 13:44:56 2017
> @@ -0,0 +1,43 @@
> +//===----- SymbolStringPoolTest.cpp - Unit tests for SymbolStringPool
> -----===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
> +#include "gtest/gtest.h"
> +
> +using namespace llvm;
> +using namespace llvm::orc;
> +
> +namespace {
> +
> +TEST(SymbolStringPool, UniquingAndEquality) {
> +  SymbolStringPool SP;
> +  auto P1 = SP.intern("hello");
> +
> +  std::string S("hel");
> +  S += "lo";
> +  auto P2 = SP.intern(S);
> +
> +  auto P3 = SP.intern("goodbye");
> +
> +  EXPECT_EQ(P1, P2) << "Failed to unique entries";
> +  EXPECT_NE(P1, P3) << "Inequal pooled symbol strings comparing equal";
> +}
> +
> +TEST(SymbolStringPool, ClearDeadEntries) {
> +  SymbolStringPool SP;
> +  {
> +    auto P1 = SP.intern("s1");
> +    SP.clearDeadEntries();
> +    EXPECT_FALSE(SP.empty()) << "\"s1\" entry in pool should still be
> retained";
> +  }
> +  SP.clearDeadEntries();
> +  EXPECT_TRUE(SP.empty()) << "pool should be empty";
> +}
> +
> +}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20171214/ca670f0c/attachment.html>


More information about the llvm-commits mailing list