[PATCH] [Core] Update references in parallel

Rui Ueyama ruiu at google.com
Tue Mar 17 13:46:05 PDT 2015


On Tue, Mar 17, 2015 at 1:25 PM, Davide Italiano <davide at freebsd.org> wrote:

> REPOSITORY
>   rL LLVM
>
> ================
> Comment at: lib/Core/Resolver.cpp:355
> @@ -353,3 +354,3 @@
>            if (_symbolTable.isCoalescedAway(atom))
>              _deadAtoms.insert(ref->target());
>            continue;
> ----------------
> ruiu wrote:
> > I think this change is not thread-safe because of this line.
> _deadAtoms.insert is not thread-safe.
> Oh this is really a bummer, considering it's such an hot codepath :(
> Do you think it makes sense to surround insert with a lock and measure
> again and/or do you have a proposal for an alternative?


Yeah, this is a hot code path. I imagine protecting this line with a mutex
would be costly, but we probably should just do that and measure.

One other thing we could do is to use a concurrent queue or something as an
accumulator and then copy its contents to _deadAtoms. I wrote the following
concurrent container before. You might want to try. (Sorry, I haven't
tested so this may be slow or has a bug.)

diff --git a/include/lld/Core/Parallel.h b/include/lld/Core/Parallel.h
index 65176ac..bd80770 100644
--- a/include/lld/Core/Parallel.h
+++ b/include/lld/Core/Parallel.h
@@ -104,6 +104,39 @@ private:
   std::condition_variable _cond;
 };

+template<typename T> class ConcurrentVector {
+public:
+  ConcurrentVector() : _capacity(16), _size(0) {
+    _container.resize(_capacity);
+  }
+
+  void insert(T &&val) {
+    size_t idx = _size.fetch_add(1);
+    if (idx < _capacity) {
+      _container[idx] = std::move(val);
+      return;
+    }
+    std::unique_lock<std::mutex> lock(_mutex);
+    if (idx < _capacity) {
+      _container[idx] = std::move(val);
+      return;
+    }
+    while (capacity <= _idx)
+      _capacity *= 2;
+    _container.resize(_capacity);
+    _container[idx] = std::move(val);
+  }
+
+  size_t size() { return _size; }
+  T *data() { return _container.data(); }
+
+private:
+  std::vector<T> _container;
+  std::atomic_size_t _capacity;
+  std::atomic_size_t _size;
+  std::mutex _mutex;
+};
+
 /// \brief An abstract class that takes closures and runs them
asynchronously.
 class Executor {
 public:
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150317/0b451c8a/attachment.html>


More information about the llvm-commits mailing list