scott.smith created this revision.
Many parallel tasks just want to iterate over all the possible numbers from 0
to N-1. Rather than enqueue N work items, instead just "map" the function
across the requested integer space.
Repository:
rL LLVM
https://reviews.llvm.org/D32757
Files:
include/lldb/Utility/TaskPool.h
source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
source/Utility/TaskPool.cpp
unittests/Utility/TaskPoolTest.cpp
Index: unittests/Utility/TaskPoolTest.cpp
===================================================================
--- unittests/Utility/TaskPoolTest.cpp
+++ unittests/Utility/TaskPoolTest.cpp
@@ -52,3 +52,15 @@
ASSERT_EQ(4, count);
}
+
+TEST(TaskPoolTest, TaskMap) {
+ int data[4];
+ auto fn = [&data](int x) { data[x] = x * x; };
+
+ TaskMap(4, 1, fn);
+
+ ASSERT_EQ(data[0] == 0);
+ ASSERT_EQ(data[1] == 1);
+ ASSERT_EQ(data[2] == 4);
+ ASSERT_EQ(data[3] == 9);
+}
Index: source/Utility/TaskPool.cpp
===================================================================
--- source/Utility/TaskPool.cpp
+++ source/Utility/TaskPool.cpp
@@ -73,3 +73,29 @@
f();
}
}
+
+void TaskMap(size_t size, size_t batch, std::function<void(size_t)> const & func)
+{
+ std::atomic<size_t> idx{0};
+ size_t est_batches = std::min<size_t>((size + batch - 1) / batch,
+ std::thread::hardware_concurrency());
+
+ auto wrapper = [&idx, size, batch, &func]()
+ {
+ while (true) {
+ size_t batch_start = idx.fetch_add(batch);
+ if (batch_start >= size)
+ break;
+ size_t batch_end = std::min(batch_start + batch, size);
+ for (size_t i = batch_start; i < batch_end; i++)
+ func(i);
+ }
+ };
+
+ std::vector<std::future<void>> futures;
+ futures.reserve(est_batches);
+ for (size_t i = 0; i < est_batches; i++)
+ futures.push_back(TaskPool::AddTask(wrapper));
+ for (size_t i = 0; i < est_batches; i++)
+ futures[i].wait();
+}
Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -1946,7 +1946,8 @@
std::vector<NameToDIE> type_index(num_compile_units);
std::vector<NameToDIE> namespace_index(num_compile_units);
- std::vector<bool> clear_cu_dies(num_compile_units, false);
+ // std::vector<bool> might be implemented using bit test-and-set, so use uint8_t instead.
+ std::vector<uint8_t> clear_cu_dies(num_compile_units, false);
auto parser_fn = [debug_info, &function_basename_index,
&function_fullname_index, &function_method_index,
&function_selector_index, &objc_class_selectors_index,
@@ -1963,22 +1964,18 @@
return cu_idx;
};
- auto extract_fn = [debug_info](uint32_t cu_idx) {
+ auto extract_fn = [debug_info, &clear_cu_dies](uint32_t cu_idx) {
DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx);
if (dwarf_cu) {
// dwarf_cu->ExtractDIEsIfNeeded(false) will return zero if the
// DIEs for a compile unit have already been parsed.
- return std::make_pair(cu_idx, dwarf_cu->ExtractDIEsIfNeeded(false) > 1);
+ if (dwarf_cu->ExtractDIEsIfNeeded(false) > 1)
+ clear_cu_dies[cu_idx] = true;
}
- return std::make_pair(cu_idx, false);
};
// Create a task runner that extracts dies for each DWARF compile unit in a
// separate thread
- TaskRunner<std::pair<uint32_t, bool>> task_runner_extract;
- for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
- task_runner_extract.AddTask(extract_fn, cu_idx);
-
//----------------------------------------------------------------------
// First figure out which compile units didn't have their DIEs already
// parsed and remember this. If no DIEs were parsed prior to this index
@@ -1988,30 +1985,15 @@
// a DIE in one compile unit refers to another and the indexes accesses
// those DIEs.
//----------------------------------------------------------------------
- while (true) {
- auto f = task_runner_extract.WaitForNextCompletedTask();
- if (!f.valid())
- break;
- unsigned cu_idx;
- bool clear;
- std::tie(cu_idx, clear) = f.get();
- clear_cu_dies[cu_idx] = clear;
- }
+ TaskMap(num_compile_units, 1, extract_fn);
// Now create a task runner that can index each DWARF compile unit in a
// separate
// thread so we can index quickly.
- TaskRunner<uint32_t> task_runner;
- for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
- task_runner.AddTask(parser_fn, cu_idx);
-
- while (true) {
- std::future<uint32_t> f = task_runner.WaitForNextCompletedTask();
- if (!f.valid())
- break;
- uint32_t cu_idx = f.get();
+ TaskMap(num_compile_units, 1, parser_fn);
+ for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) {
m_function_basename_index.Append(function_basename_index[cu_idx]);
m_function_fullname_index.Append(function_fullname_index[cu_idx]);
m_function_method_index.Append(function_method_index[cu_idx]);
Index: include/lldb/Utility/TaskPool.h
===================================================================
--- include/lldb/Utility/TaskPool.h
+++ include/lldb/Utility/TaskPool.h
@@ -186,4 +186,11 @@
;
}
+// Run 'func' on every value from 0 .. size-1. Each worker will grab 'batch'
+// numbers at a time to work on, so for very fast functions, batch should be
+// large enough to avoid too much cache line contention.
+void TaskMap(size_t size, size_t batch,
+ std::function<void(size_t)> const & func);
+
+
#endif // #ifndef utility_TaskPool_h_
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits