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 const & func); + + #endif // #ifndef utility_TaskPool_h_ 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 type_index(num_compile_units); std::vector namespace_index(num_compile_units); - std::vector clear_cu_dies(num_compile_units, false); + // std::vector might be implemented using bit test-and-set, so use uint8_t instead. + std::vector 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> 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 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 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: 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 const & func) +{ + std::atomic idx{0}; + size_t est_batches = std::min((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> 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: 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); +}