Cache the node priorities between runs
This speeds up processings on the same dataset significantly by creating a .level file that saves the level in which a node was contracted. It removes the need for expensive recomputation of priorities and such. Use with care! Running `osrm-extract` again will invalidate .level files.
This commit is contained in:
		
							parent
							
								
									8f3482561b
								
							
						
					
					
						commit
						63ba6018f3
					
				@ -158,6 +158,15 @@ class Contractor
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  public:
 | 
					  public:
 | 
				
			||||||
    template <class ContainerT> Contractor(int nodes, ContainerT &input_edge_list)
 | 
					    template <class ContainerT> Contractor(int nodes, ContainerT &input_edge_list)
 | 
				
			||||||
 | 
					      : Contractor(nodes, input_edge_list, {}, {})
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <class ContainerT>
 | 
				
			||||||
 | 
					    Contractor(int nodes,
 | 
				
			||||||
 | 
					               ContainerT &input_edge_list,
 | 
				
			||||||
 | 
					               std::vector<float> &&node_levels_)
 | 
				
			||||||
 | 
					        : node_levels(std::move(node_levels_))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::vector<ContractorEdge> edges;
 | 
					        std::vector<ContractorEdge> edges;
 | 
				
			||||||
        edges.reserve(input_edge_list.size() * 2);
 | 
					        edges.reserve(input_edge_list.size() * 2);
 | 
				
			||||||
@ -305,14 +314,14 @@ class Contractor
 | 
				
			|||||||
        ThreadDataContainer thread_data_list(number_of_nodes);
 | 
					        ThreadDataContainer thread_data_list(number_of_nodes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        NodeID number_of_contracted_nodes = 0;
 | 
					        NodeID number_of_contracted_nodes = 0;
 | 
				
			||||||
        std::vector<RemainingNodeData> remaining_nodes(number_of_nodes);
 | 
					        std::vector<NodePriorityData> node_data;
 | 
				
			||||||
        std::vector<float> node_priorities(number_of_nodes);
 | 
					        std::vector<float> node_priorities;
 | 
				
			||||||
        std::vector<NodePriorityData> node_data(number_of_nodes);
 | 
					 | 
				
			||||||
        is_core_node.resize(number_of_nodes, false);
 | 
					        is_core_node.resize(number_of_nodes, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::vector<RemainingNodeData> remaining_nodes(number_of_nodes);
 | 
				
			||||||
        // initialize priorities in parallel
 | 
					        // initialize priorities in parallel
 | 
				
			||||||
        tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, InitGrainSize),
 | 
					        tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, InitGrainSize),
 | 
				
			||||||
                          [&remaining_nodes](const tbb::blocked_range<int> &range)
 | 
					                          [this, &remaining_nodes](const tbb::blocked_range<int> &range)
 | 
				
			||||||
                          {
 | 
					                          {
 | 
				
			||||||
                              for (int x = range.begin(), end = range.end(); x != end; ++x)
 | 
					                              for (int x = range.begin(), end = range.end(); x != end; ++x)
 | 
				
			||||||
                              {
 | 
					                              {
 | 
				
			||||||
@ -320,21 +329,38 @@ class Contractor
 | 
				
			|||||||
                              }
 | 
					                              }
 | 
				
			||||||
                          });
 | 
					                          });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::cout << "initializing elimination PQ ..." << std::flush;
 | 
					        bool use_cached_node_priorities = !node_levels.empty();
 | 
				
			||||||
        tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
 | 
					        if (use_cached_node_priorities)
 | 
				
			||||||
                          [this, &node_priorities, &node_data, &thread_data_list](
 | 
					        {
 | 
				
			||||||
                              const tbb::blocked_range<int> &range)
 | 
					            std::cout << "using cached node priorities ..." << std::flush;
 | 
				
			||||||
                          {
 | 
					            node_priorities.swap(node_levels);
 | 
				
			||||||
                              ContractorThreadData *data = thread_data_list.getThreadData();
 | 
					            std::cout << "ok" << std::endl;
 | 
				
			||||||
                              for (int x = range.begin(), end = range.end(); x != end; ++x)
 | 
					        }
 | 
				
			||||||
                              {
 | 
					        else
 | 
				
			||||||
                                  node_priorities[x] =
 | 
					        {
 | 
				
			||||||
                                      this->EvaluateNodePriority(data, &node_data[x], x);
 | 
					            node_data.resize(number_of_nodes);
 | 
				
			||||||
                              }
 | 
					            node_priorities.resize(number_of_nodes);
 | 
				
			||||||
                          });
 | 
					            node_levels.resize(number_of_nodes);
 | 
				
			||||||
        std::cout << "ok" << std::endl
 | 
					 | 
				
			||||||
                  << "preprocessing " << number_of_nodes << " nodes ..." << std::flush;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            std::cout << "initializing elimination PQ ..." << std::flush;
 | 
				
			||||||
 | 
					            tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
 | 
				
			||||||
 | 
					                              [this, &node_priorities, &node_data, &thread_data_list](
 | 
				
			||||||
 | 
					                                  const tbb::blocked_range<int> &range)
 | 
				
			||||||
 | 
					                              {
 | 
				
			||||||
 | 
					                                  ContractorThreadData *data = thread_data_list.getThreadData();
 | 
				
			||||||
 | 
					                                  for (int x = range.begin(), end = range.end(); x != end; ++x)
 | 
				
			||||||
 | 
					                                  {
 | 
				
			||||||
 | 
					                                      node_priorities[x] =
 | 
				
			||||||
 | 
					                                          this->EvaluateNodePriority(data, &node_data[x], x);
 | 
				
			||||||
 | 
					                                  }
 | 
				
			||||||
 | 
					                              });
 | 
				
			||||||
 | 
					            std::cout << "ok" << std::endl;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        BOOST_ASSERT(node_priorities.size() == number_of_nodes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::cout << "preprocessing " << number_of_nodes << " nodes ..." << std::flush;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unsigned current_level = 0;
 | 
				
			||||||
        bool flushed_contractor = false;
 | 
					        bool flushed_contractor = false;
 | 
				
			||||||
        while (number_of_nodes > 2 &&
 | 
					        while (number_of_nodes > 2 &&
 | 
				
			||||||
               number_of_contracted_nodes < static_cast<NodeID>(number_of_nodes * core_factor))
 | 
					               number_of_contracted_nodes < static_cast<NodeID>(number_of_nodes * core_factor))
 | 
				
			||||||
@ -359,29 +385,32 @@ class Contractor
 | 
				
			|||||||
                // remaining graph
 | 
					                // remaining graph
 | 
				
			||||||
                std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, UINT_MAX);
 | 
					                std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, UINT_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // build forward and backward renumbering map and remap ids in remaining_nodes and
 | 
					 | 
				
			||||||
                // Priorities.
 | 
					 | 
				
			||||||
                for (const auto new_node_id : osrm::irange<std::size_t>(0, remaining_nodes.size()))
 | 
					                for (const auto new_node_id : osrm::irange<std::size_t>(0, remaining_nodes.size()))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 | 
					                    auto& node = remaining_nodes[new_node_id];
 | 
				
			||||||
 | 
					                    BOOST_ASSERT(node_priorities.size() > node.id);
 | 
				
			||||||
 | 
					                    new_node_priority[new_node_id] = node_priorities[node.id];
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // build forward and backward renumbering map and remap ids in remaining_nodes
 | 
				
			||||||
 | 
					                for (const auto new_node_id : osrm::irange<std::size_t>(0, remaining_nodes.size()))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    auto& node = remaining_nodes[new_node_id];
 | 
				
			||||||
                    // create renumbering maps in both directions
 | 
					                    // create renumbering maps in both directions
 | 
				
			||||||
                    orig_node_id_from_new_node_id_map[new_node_id] =
 | 
					                    orig_node_id_from_new_node_id_map[new_node_id] = node.id;
 | 
				
			||||||
                        remaining_nodes[new_node_id].id;
 | 
					                    new_node_id_from_orig_id_map[node.id] = new_node_id;
 | 
				
			||||||
                    new_node_id_from_orig_id_map[remaining_nodes[new_node_id].id] = new_node_id;
 | 
					                    node.id = new_node_id;
 | 
				
			||||||
                    new_node_priority[new_node_id] =
 | 
					 | 
				
			||||||
                        node_priorities[remaining_nodes[new_node_id].id];
 | 
					 | 
				
			||||||
                    remaining_nodes[new_node_id].id = new_node_id;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                // walk over all nodes
 | 
					                // walk over all nodes
 | 
				
			||||||
                for (const auto i :
 | 
					                for (const auto source :
 | 
				
			||||||
                     osrm::irange<std::size_t>(0, contractor_graph->GetNumberOfNodes()))
 | 
					                     osrm::irange<NodeID>(0, contractor_graph->GetNumberOfNodes()))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    const NodeID source = i;
 | 
					 | 
				
			||||||
                    for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(source))
 | 
					                    for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(source))
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        ContractorGraph::EdgeData &data =
 | 
					                        ContractorGraph::EdgeData &data =
 | 
				
			||||||
                            contractor_graph->GetEdgeData(current_edge);
 | 
					                            contractor_graph->GetEdgeData(current_edge);
 | 
				
			||||||
                        const NodeID target = contractor_graph->GetTarget(current_edge);
 | 
					                        const NodeID target = contractor_graph->GetTarget(current_edge);
 | 
				
			||||||
                        if (SPECIAL_NODEID == new_node_id_from_orig_id_map[i])
 | 
					                        if (SPECIAL_NODEID == new_node_id_from_orig_id_map[source])
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            external_edge_list.push_back({source, target, data});
 | 
					                            external_edge_list.push_back({source, target, data});
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
@ -428,14 +457,13 @@ class Contractor
 | 
				
			|||||||
                thread_data_list.number_of_nodes = contractor_graph->GetNumberOfNodes();
 | 
					                thread_data_list.number_of_nodes = contractor_graph->GetNumberOfNodes();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const int last = (int)remaining_nodes.size();
 | 
					            tbb::parallel_for(tbb::blocked_range<std::size_t>(0, remaining_nodes.size(), IndependentGrainSize),
 | 
				
			||||||
            tbb::parallel_for(tbb::blocked_range<int>(0, last, IndependentGrainSize),
 | 
					 | 
				
			||||||
                              [this, &node_priorities, &remaining_nodes, &thread_data_list](
 | 
					                              [this, &node_priorities, &remaining_nodes, &thread_data_list](
 | 
				
			||||||
                                  const tbb::blocked_range<int> &range)
 | 
					                                  const tbb::blocked_range<std::size_t> &range)
 | 
				
			||||||
                              {
 | 
					                              {
 | 
				
			||||||
                                  ContractorThreadData *data = thread_data_list.getThreadData();
 | 
					                                  ContractorThreadData *data = thread_data_list.getThreadData();
 | 
				
			||||||
                                  // determine independent node set
 | 
					                                  // determine independent node set
 | 
				
			||||||
                                  for (int i = range.begin(), end = range.end(); i != end; ++i)
 | 
					                                  for (auto i = range.begin(), end = range.end(); i != end; ++i)
 | 
				
			||||||
                                  {
 | 
					                                  {
 | 
				
			||||||
                                      const NodeID node = remaining_nodes[i].id;
 | 
					                                      const NodeID node = remaining_nodes[i].id;
 | 
				
			||||||
                                      remaining_nodes[i].is_independent =
 | 
					                                      remaining_nodes[i].is_independent =
 | 
				
			||||||
@ -443,17 +471,45 @@ class Contractor
 | 
				
			|||||||
                                  }
 | 
					                                  }
 | 
				
			||||||
                              });
 | 
					                              });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const auto first = stable_partition(remaining_nodes.begin(), remaining_nodes.end(),
 | 
					            // sort all remaining nodes to the beginning of the sequence
 | 
				
			||||||
 | 
					            const auto begin_independent_nodes = stable_partition(remaining_nodes.begin(), remaining_nodes.end(),
 | 
				
			||||||
                                                [](RemainingNodeData node_data)
 | 
					                                                [](RemainingNodeData node_data)
 | 
				
			||||||
                                                {
 | 
					                                                {
 | 
				
			||||||
                                                    return !node_data.is_independent;
 | 
					                                                    return !node_data.is_independent;
 | 
				
			||||||
                                                });
 | 
					                                                });
 | 
				
			||||||
            const int first_independent_node = static_cast<int>(first - remaining_nodes.begin());
 | 
					            auto begin_independent_nodes_idx = std::distance(remaining_nodes.begin(), begin_independent_nodes);
 | 
				
			||||||
 | 
					            auto end_independent_nodes_idx = remaining_nodes.size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!use_cached_node_priorities)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // write out contraction level
 | 
				
			||||||
 | 
					                tbb::parallel_for(
 | 
				
			||||||
 | 
					                    tbb::blocked_range<std::size_t>(begin_independent_nodes_idx, end_independent_nodes_idx, ContractGrainSize),
 | 
				
			||||||
 | 
					                    [this, remaining_nodes, flushed_contractor, current_level](const tbb::blocked_range<std::size_t> &range)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (flushed_contractor)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            for (int position = range.begin(), end = range.end(); position != end; ++position)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                const NodeID x = remaining_nodes[position].id;
 | 
				
			||||||
 | 
					                                node_levels[orig_node_id_from_new_node_id_map[x]] = current_level;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            for (int position = range.begin(), end = range.end(); position != end; ++position)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                const NodeID x = remaining_nodes[position].id;
 | 
				
			||||||
 | 
					                                node_levels[x] = current_level;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // contract independent nodes
 | 
					            // contract independent nodes
 | 
				
			||||||
            tbb::parallel_for(
 | 
					            tbb::parallel_for(
 | 
				
			||||||
                tbb::blocked_range<int>(first_independent_node, last, ContractGrainSize),
 | 
					                tbb::blocked_range<std::size_t>(begin_independent_nodes_idx, end_independent_nodes_idx, ContractGrainSize),
 | 
				
			||||||
                [this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int> &range)
 | 
					                [this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<std::size_t> &range)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    ContractorThreadData *data = thread_data_list.getThreadData();
 | 
					                    ContractorThreadData *data = thread_data_list.getThreadData();
 | 
				
			||||||
                    for (int position = range.begin(), end = range.end(); position != end; ++position)
 | 
					                    for (int position = range.begin(), end = range.end(); position != end; ++position)
 | 
				
			||||||
@ -462,17 +518,9 @@ class Contractor
 | 
				
			|||||||
                        this->ContractNode<false>(data, x);
 | 
					                        this->ContractNode<false>(data, x);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            // make sure we really sort each block
 | 
					
 | 
				
			||||||
            tbb::parallel_for(
 | 
					            tbb::parallel_for(
 | 
				
			||||||
                thread_data_list.data.range(),
 | 
					                tbb::blocked_range<int>(begin_independent_nodes_idx, end_independent_nodes_idx, DeleteGrainSize),
 | 
				
			||||||
                [&](const ThreadDataContainer::EnumerableThreadData::range_type &range)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    for (auto &data : range)
 | 
					 | 
				
			||||||
                        tbb::parallel_sort(data->inserted_edges.begin(),
 | 
					 | 
				
			||||||
                                           data->inserted_edges.end());
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
            tbb::parallel_for(
 | 
					 | 
				
			||||||
                tbb::blocked_range<int>(first_independent_node, last, DeleteGrainSize),
 | 
					 | 
				
			||||||
                [this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int> &range)
 | 
					                [this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int> &range)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    ContractorThreadData *data = thread_data_list.getThreadData();
 | 
					                    ContractorThreadData *data = thread_data_list.getThreadData();
 | 
				
			||||||
@ -483,6 +531,16 @@ class Contractor
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // make sure we really sort each block
 | 
				
			||||||
 | 
					            tbb::parallel_for(
 | 
				
			||||||
 | 
					                thread_data_list.data.range(),
 | 
				
			||||||
 | 
					                [&](const ThreadDataContainer::EnumerableThreadData::range_type &range)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    for (auto &data : range)
 | 
				
			||||||
 | 
					                        tbb::parallel_sort(data->inserted_edges.begin(),
 | 
				
			||||||
 | 
					                                           data->inserted_edges.end());
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // insert new edges
 | 
					            // insert new edges
 | 
				
			||||||
            for (auto &data : thread_data_list.data)
 | 
					            for (auto &data : thread_data_list.data)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -508,23 +566,25 @@ class Contractor
 | 
				
			|||||||
                data->inserted_edges.clear();
 | 
					                data->inserted_edges.clear();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            tbb::parallel_for(
 | 
					            if (!use_cached_node_priorities)
 | 
				
			||||||
                tbb::blocked_range<int>(first_independent_node, last, NeighboursGrainSize),
 | 
					            {
 | 
				
			||||||
                [this, &remaining_nodes, &node_priorities, &node_data, &thread_data_list](
 | 
					                tbb::parallel_for(
 | 
				
			||||||
                    const tbb::blocked_range<int> &range)
 | 
					                    tbb::blocked_range<int>(begin_independent_nodes_idx, end_independent_nodes_idx, NeighboursGrainSize),
 | 
				
			||||||
                {
 | 
					                    [this, &node_priorities, &remaining_nodes, &node_data, &thread_data_list](
 | 
				
			||||||
                    ContractorThreadData *data = thread_data_list.getThreadData();
 | 
					                        const tbb::blocked_range<int> &range)
 | 
				
			||||||
                    for (int position = range.begin(), end = range.end(); position != end; ++position)
 | 
					 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        NodeID x = remaining_nodes[position].id;
 | 
					                        ContractorThreadData *data = thread_data_list.getThreadData();
 | 
				
			||||||
                        this->UpdateNodeNeighbours(node_priorities, node_data, data, x);
 | 
					                        for (int position = range.begin(), end = range.end(); position != end; ++position)
 | 
				
			||||||
                    }
 | 
					                        {
 | 
				
			||||||
                });
 | 
					                            NodeID x = remaining_nodes[position].id;
 | 
				
			||||||
 | 
					                            this->UpdateNodeNeighbours(node_priorities, node_data, data, x);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // remove contracted nodes from the pool
 | 
					            // remove contracted nodes from the pool
 | 
				
			||||||
            number_of_contracted_nodes += last - first_independent_node;
 | 
					            number_of_contracted_nodes += end_independent_nodes_idx - begin_independent_nodes_idx;
 | 
				
			||||||
            remaining_nodes.resize(first_independent_node);
 | 
					            remaining_nodes.resize(begin_independent_nodes_idx);
 | 
				
			||||||
            remaining_nodes.shrink_to_fit();
 | 
					 | 
				
			||||||
            //            unsigned maxdegree = 0;
 | 
					            //            unsigned maxdegree = 0;
 | 
				
			||||||
            //            unsigned avgdegree = 0;
 | 
					            //            unsigned avgdegree = 0;
 | 
				
			||||||
            //            unsigned mindegree = UINT_MAX;
 | 
					            //            unsigned mindegree = UINT_MAX;
 | 
				
			||||||
@ -551,25 +611,37 @@ class Contractor
 | 
				
			|||||||
            //            quad: " << quaddegree;
 | 
					            //            quad: " << quaddegree;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            p.printStatus(number_of_contracted_nodes);
 | 
					            p.printStatus(number_of_contracted_nodes);
 | 
				
			||||||
 | 
					            ++current_level;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (remaining_nodes.size() > 2)
 | 
					        if (remaining_nodes.size() > 2)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (orig_node_id_from_new_node_id_map.empty())
 | 
					              if (orig_node_id_from_new_node_id_map.size() > 0)
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                for (const auto &node : remaining_nodes)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    is_core_node[node.id] = true;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              for (const auto &node : remaining_nodes)
 | 
					 | 
				
			||||||
              {
 | 
					              {
 | 
				
			||||||
                  auto orig_id = orig_node_id_from_new_node_id_map[node.id];
 | 
					                  tbb::parallel_for(
 | 
				
			||||||
                  is_core_node[orig_id] = true;
 | 
					                      tbb::blocked_range<int>(0, remaining_nodes.size(), InitGrainSize),
 | 
				
			||||||
 | 
					                      [this, &remaining_nodes](const tbb::blocked_range<int> &range)
 | 
				
			||||||
 | 
					                      {
 | 
				
			||||||
 | 
					                          for (int x = range.begin(), end = range.end(); x != end; ++x)
 | 
				
			||||||
 | 
					                          {
 | 
				
			||||||
 | 
					                              const auto orig_id = remaining_nodes[x].id;
 | 
				
			||||||
 | 
					                              is_core_node[orig_node_id_from_new_node_id_map[orig_id]] = true;
 | 
				
			||||||
 | 
					                          }
 | 
				
			||||||
 | 
					                      });
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              else
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                  tbb::parallel_for(
 | 
				
			||||||
 | 
					                      tbb::blocked_range<int>(0, remaining_nodes.size(), InitGrainSize),
 | 
				
			||||||
 | 
					                      [this, &remaining_nodes](const tbb::blocked_range<int> &range)
 | 
				
			||||||
 | 
					                      {
 | 
				
			||||||
 | 
					                          for (int x = range.begin(), end = range.end(); x != end; ++x)
 | 
				
			||||||
 | 
					                          {
 | 
				
			||||||
 | 
					                              const auto orig_id = remaining_nodes[x].id;
 | 
				
			||||||
 | 
					                              is_core_node[orig_id] = true;
 | 
				
			||||||
 | 
					                          }
 | 
				
			||||||
 | 
					                      });
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@ -589,6 +661,11 @@ class Contractor
 | 
				
			|||||||
        out_is_core_node.swap(is_core_node);
 | 
					        out_is_core_node.swap(is_core_node);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline void GetNodeLevels(std::vector<float> &out_node_levels)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        out_node_levels.swap(node_levels);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template <class Edge> inline void GetEdges(DeallocatingVector<Edge> &edges)
 | 
					    template <class Edge> inline void GetEdges(DeallocatingVector<Edge> &edges)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Percent p(contractor_graph->GetNumberOfNodes());
 | 
					        Percent p(contractor_graph->GetNumberOfNodes());
 | 
				
			||||||
@ -998,6 +1075,7 @@ class Contractor
 | 
				
			|||||||
    std::shared_ptr<ContractorGraph> contractor_graph;
 | 
					    std::shared_ptr<ContractorGraph> contractor_graph;
 | 
				
			||||||
    stxxl::vector<QueryEdge> external_edge_list;
 | 
					    stxxl::vector<QueryEdge> external_edge_list;
 | 
				
			||||||
    std::vector<NodeID> orig_node_id_from_new_node_id_map;
 | 
					    std::vector<NodeID> orig_node_id_from_new_node_id_map;
 | 
				
			||||||
 | 
					    std::vector<float> node_levels;
 | 
				
			||||||
    std::vector<bool> is_core_node;
 | 
					    std::vector<bool> is_core_node;
 | 
				
			||||||
    XORFastHash fast_hash;
 | 
					    XORFastHash fast_hash;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -48,16 +48,20 @@ ContractorOptions::ParseArguments(int argc, char *argv[], ContractorConfig &cont
 | 
				
			|||||||
    // declare a group of options that will be allowed both on command line and in config file
 | 
					    // declare a group of options that will be allowed both on command line and in config file
 | 
				
			||||||
    boost::program_options::options_description config_options("Configuration");
 | 
					    boost::program_options::options_description config_options("Configuration");
 | 
				
			||||||
    config_options.add_options()(
 | 
					    config_options.add_options()(
 | 
				
			||||||
        "profile,p", boost::program_options::value<boost::filesystem::path>(&contractor_config.profile_path)
 | 
					        "profile,p",
 | 
				
			||||||
                         ->default_value("profile.lua"),
 | 
					        boost::program_options::value<boost::filesystem::path>(&contractor_config.profile_path)
 | 
				
			||||||
 | 
					            ->default_value("profile.lua"),
 | 
				
			||||||
        "Path to LUA routing profile")(
 | 
					        "Path to LUA routing profile")(
 | 
				
			||||||
        "threads,t", boost::program_options::value<unsigned int>(&contractor_config.requested_num_threads)
 | 
					        "threads,t",
 | 
				
			||||||
                         ->default_value(tbb::task_scheduler_init::default_num_threads()),
 | 
					        boost::program_options::value<unsigned int>(&contractor_config.requested_num_threads)
 | 
				
			||||||
 | 
					            ->default_value(tbb::task_scheduler_init::default_num_threads()),
 | 
				
			||||||
        "Number of threads to use")(
 | 
					        "Number of threads to use")(
 | 
				
			||||||
		"core,k", boost::program_options::value<double>(&contractor_config.core_factor)
 | 
					        "core,k",
 | 
				
			||||||
						 ->default_value(1.0),"Percentage of the graph (in vertices) to contract [0.1]");
 | 
					        boost::program_options::value<double>(&contractor_config.core_factor)->default_value(1.0),
 | 
				
			||||||
 | 
					        "Percentage of the graph (in vertices) to contract [0.1]")(
 | 
				
			||||||
 | 
					        "level-cache,o",
 | 
				
			||||||
 | 
					        boost::program_options::value<bool>(&contractor_config.use_cached_priority)->default_value(false),
 | 
				
			||||||
 | 
					        "Use .level file to retain the contaction level for each node from the last run.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // hidden options, will be allowed both on command line and in config file, but will not be
 | 
					    // hidden options, will be allowed both on command line and in config file, but will not be
 | 
				
			||||||
    // shown to the user
 | 
					    // shown to the user
 | 
				
			||||||
@ -122,6 +126,7 @@ ContractorOptions::ParseArguments(int argc, char *argv[], ContractorConfig &cont
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void ContractorOptions::GenerateOutputFilesNames(ContractorConfig &contractor_config)
 | 
					void ContractorOptions::GenerateOutputFilesNames(ContractorConfig &contractor_config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    contractor_config.level_output_path = contractor_config.osrm_input_path.string() + ".level";
 | 
				
			||||||
    contractor_config.core_output_path = contractor_config.osrm_input_path.string() + ".core";
 | 
					    contractor_config.core_output_path = contractor_config.osrm_input_path.string() + ".core";
 | 
				
			||||||
    contractor_config.graph_output_path = contractor_config.osrm_input_path.string() + ".hsgr";
 | 
					    contractor_config.graph_output_path = contractor_config.osrm_input_path.string() + ".hsgr";
 | 
				
			||||||
    contractor_config.edge_based_graph_path = contractor_config.osrm_input_path.string() + ".ebg";
 | 
					    contractor_config.edge_based_graph_path = contractor_config.osrm_input_path.string() + ".ebg";
 | 
				
			||||||
 | 
				
			|||||||
@ -47,10 +47,13 @@ struct ContractorConfig
 | 
				
			|||||||
    boost::filesystem::path osrm_input_path;
 | 
					    boost::filesystem::path osrm_input_path;
 | 
				
			||||||
    boost::filesystem::path profile_path;
 | 
					    boost::filesystem::path profile_path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::string level_output_path;
 | 
				
			||||||
    std::string core_output_path;
 | 
					    std::string core_output_path;
 | 
				
			||||||
    std::string graph_output_path;
 | 
					    std::string graph_output_path;
 | 
				
			||||||
    std::string edge_based_graph_path;
 | 
					    std::string edge_based_graph_path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool use_cached_priority;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unsigned requested_num_threads;
 | 
					    unsigned requested_num_threads;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //A percentage of vertices that will be contracted for the hierarchy.
 | 
					    //A percentage of vertices that will be contracted for the hierarchy.
 | 
				
			||||||
 | 
				
			|||||||
@ -26,8 +26,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			|||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "processing_chain.hpp"
 | 
					#include "processing_chain.hpp"
 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "contractor.hpp"
 | 
					#include "contractor.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../data_structures/deallocating_vector.hpp"
 | 
					#include "../data_structures/deallocating_vector.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../algorithms/crc32_processor.hpp"
 | 
					#include "../algorithms/crc32_processor.hpp"
 | 
				
			||||||
@ -78,8 +78,13 @@ int Prepare::Run()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    TIMER_START(contraction);
 | 
					    TIMER_START(contraction);
 | 
				
			||||||
    std::vector<bool> is_core_node;
 | 
					    std::vector<bool> is_core_node;
 | 
				
			||||||
 | 
					    std::vector<float> node_levels;
 | 
				
			||||||
 | 
					    if (config.use_cached_priority)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ReadNodeLevels(node_levels);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    DeallocatingVector<QueryEdge> contracted_edge_list;
 | 
					    DeallocatingVector<QueryEdge> contracted_edge_list;
 | 
				
			||||||
    ContractGraph(max_edge_id, edge_based_edge_list, contracted_edge_list, is_core_node);
 | 
					    ContractGraph(max_edge_id, edge_based_edge_list, contracted_edge_list, is_core_node, node_levels);
 | 
				
			||||||
    TIMER_STOP(contraction);
 | 
					    TIMER_STOP(contraction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
 | 
					    SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
 | 
				
			||||||
@ -87,6 +92,10 @@ int Prepare::Run()
 | 
				
			|||||||
    std::size_t number_of_used_edges =
 | 
					    std::size_t number_of_used_edges =
 | 
				
			||||||
        WriteContractedGraph(max_edge_id, contracted_edge_list);
 | 
					        WriteContractedGraph(max_edge_id, contracted_edge_list);
 | 
				
			||||||
    WriteCoreNodeMarker(std::move(is_core_node));
 | 
					    WriteCoreNodeMarker(std::move(is_core_node));
 | 
				
			||||||
 | 
					    if (!config.use_cached_priority)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        WriteNodeLevels(std::move(node_levels));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TIMER_STOP(preparing);
 | 
					    TIMER_STOP(preparing);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -131,11 +140,35 @@ std::size_t Prepare::LoadEdgeExpandedGraph(
 | 
				
			|||||||
    return max_edge_id;
 | 
					    return max_edge_id;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Prepare::ReadNodeLevels(std::vector<float> &node_levels) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    boost::filesystem::ifstream order_input_stream(config.level_output_path,
 | 
				
			||||||
 | 
					                                                          std::ios::binary);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsigned level_size;
 | 
				
			||||||
 | 
					    order_input_stream.read((char *)&level_size, sizeof(unsigned));
 | 
				
			||||||
 | 
					    node_levels.resize(level_size);
 | 
				
			||||||
 | 
					    order_input_stream.read((char *)node_levels.data(),
 | 
				
			||||||
 | 
					                                    sizeof(float) * node_levels.size());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Prepare::WriteNodeLevels(std::vector<float> &&in_node_levels) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    std::vector<float> node_levels(std::move(in_node_levels));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    boost::filesystem::ofstream order_output_stream(config.level_output_path,
 | 
				
			||||||
 | 
					                                                          std::ios::binary);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsigned level_size = node_levels.size();
 | 
				
			||||||
 | 
					    order_output_stream.write((char *)&level_size, sizeof(unsigned));
 | 
				
			||||||
 | 
					    order_output_stream.write((char *)node_levels.data(),
 | 
				
			||||||
 | 
					                                    sizeof(float) * node_levels.size());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Prepare::WriteCoreNodeMarker(std::vector<bool> &&in_is_core_node) const
 | 
					void Prepare::WriteCoreNodeMarker(std::vector<bool> &&in_is_core_node) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    std::vector<bool> is_core_node(in_is_core_node);
 | 
					    std::vector<bool> is_core_node(std::move(in_is_core_node));
 | 
				
			||||||
    std::vector<char> unpacked_bool_flags(is_core_node.size());
 | 
					    std::vector<char> unpacked_bool_flags(std::move(is_core_node.size()));
 | 
				
			||||||
    for (auto i = 0u; i < is_core_node.size(); ++i)
 | 
					    for (auto i = 0u; i < is_core_node.size(); ++i)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        unpacked_bool_flags[i] = is_core_node[i] ? 1 : 0;
 | 
					        unpacked_bool_flags[i] = is_core_node[i] ? 1 : 0;
 | 
				
			||||||
@ -270,12 +303,17 @@ std::size_t Prepare::WriteContractedGraph(unsigned max_node_id,
 | 
				
			|||||||
void Prepare::ContractGraph(const unsigned max_edge_id,
 | 
					void Prepare::ContractGraph(const unsigned max_edge_id,
 | 
				
			||||||
                            DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
 | 
					                            DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
 | 
				
			||||||
                            DeallocatingVector<QueryEdge> &contracted_edge_list,
 | 
					                            DeallocatingVector<QueryEdge> &contracted_edge_list,
 | 
				
			||||||
                            std::vector<bool> &is_core_node)
 | 
					                            std::vector<bool> &is_core_node,
 | 
				
			||||||
 | 
					                            std::vector<float> &inout_node_levels) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Contractor contractor(max_edge_id + 1, edge_based_edge_list);
 | 
					    std::vector<float> node_levels;
 | 
				
			||||||
 | 
					    node_levels.swap(inout_node_levels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Contractor contractor(max_edge_id + 1, edge_based_edge_list, std::move(node_levels));
 | 
				
			||||||
    contractor.Run(config.core_factor);
 | 
					    contractor.Run(config.core_factor);
 | 
				
			||||||
    contractor.GetEdges(contracted_edge_list);
 | 
					    contractor.GetEdges(contracted_edge_list);
 | 
				
			||||||
    contractor.GetCoreMarker(is_core_node);
 | 
					    contractor.GetCoreMarker(is_core_node);
 | 
				
			||||||
 | 
					    contractor.GetNodeLevels(inout_node_levels);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -60,8 +60,11 @@ class Prepare
 | 
				
			|||||||
    void ContractGraph(const unsigned max_edge_id,
 | 
					    void ContractGraph(const unsigned max_edge_id,
 | 
				
			||||||
                       DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
 | 
					                       DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
 | 
				
			||||||
                       DeallocatingVector<QueryEdge> &contracted_edge_list,
 | 
					                       DeallocatingVector<QueryEdge> &contracted_edge_list,
 | 
				
			||||||
                       std::vector<bool> &is_core_node);
 | 
					                       std::vector<bool> &is_core_node,
 | 
				
			||||||
 | 
					                       std::vector<float> &node_levels) const;
 | 
				
			||||||
    void WriteCoreNodeMarker(std::vector<bool> &&is_core_node) const;
 | 
					    void WriteCoreNodeMarker(std::vector<bool> &&is_core_node) const;
 | 
				
			||||||
 | 
					    void WriteNodeLevels(std::vector<float> &&node_levels) const;
 | 
				
			||||||
 | 
					    void ReadNodeLevels(std::vector<float> &contraction_order) const;
 | 
				
			||||||
    std::size_t WriteContractedGraph(unsigned number_of_edge_based_nodes,
 | 
					    std::size_t WriteContractedGraph(unsigned number_of_edge_based_nodes,
 | 
				
			||||||
                                     const DeallocatingVector<QueryEdge> &contracted_edge_list);
 | 
					                                     const DeallocatingVector<QueryEdge> &contracted_edge_list);
 | 
				
			||||||
    void FindComponents(unsigned max_edge_id,
 | 
					    void FindComponents(unsigned max_edge_id,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user