Skip to content

Coord_Query_Statement::check_area_block - expensive ilat/ilon conversions #5

Description

@mmd-osm
[timeout:3600][maxsize:3000000000];
area[boundary=administrative][admin_level]["de:amtlicher_gemeindeschluessel"~"^09"]->.a;
.a out count;
( way(area.a)["addr:housenumber"];
  node(area.a)["addr:housenumber"];
);
out count;
@ubuntu:~/osm-3s-patch-version/build/bin$ /usr/bin/time -v ./o3 --db-dir=db/ < ph
encoding remark: Please enter your query and terminate it with CTRL+D.
<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="Overpass API">
<note>The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.</note>
<meta osm_base=""/>

  <count>
    <tag k="nodes" v="0"/>
    <tag k="ways" v="0"/>
    <tag k="relations" v="0"/>
    <tag k="areas" v="2317"/>
    <tag k="total" v="2317"/>
  </count>
  <count>
    <tag k="nodes" v="467196"/>
    <tag k="ways" v="1017886"/>
    <tag k="relations" v="0"/>
    <tag k="areas" v="0"/>
    <tag k="total" v="1485082"/>
  </count>

</osm>
	Command being timed: "./o3 --db-dir=db/"
	User time (seconds): 204.09
	System time (seconds): 0.37
	Percent of CPU this job got: 100%
	Elapsed (wall clock) time (h:mm:ss or m:ss): 3:24.46
	Average shared text size (kbytes): 0
	Average unshared data size (kbytes): 0
	Average stack size (kbytes): 0
	Average total size (kbytes): 0
	Maximum resident set size (kbytes): 784856
	Average resident set size (kbytes): 0
	Major (requiring I/O) page faults: 0
	Minor (reclaiming a frame) page faults: 168840
	Voluntary context switches: 1
	Involuntary context switches: 259
	Swaps: 0
	File system inputs: 0
	File system outputs: 0
	Socket messages sent: 0
	Socket messages received: 0
	Signals delivered: 0
	Page size (bytes): 4096
	Exit status: 0

@ubuntu:~/osm-3s-patch-version/build/bin$ /usr/bin/time -v ./osm3s_query --db-dir=db/ < ph
encoding remark: Please enter your query and terminate it with CTRL+D.
<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="Overpass API">
<note>The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.</note>
<meta osm_base=""/>

  <count>
    <tag k="nodes" v="0"/>
    <tag k="ways" v="0"/>
    <tag k="relations" v="0"/>
    <tag k="areas" v="2317"/>
    <tag k="total" v="2317"/>
  </count>
  <count>
    <tag k="nodes" v="467196"/>
    <tag k="ways" v="1017886"/>
    <tag k="relations" v="0"/>
    <tag k="areas" v="0"/>
    <tag k="total" v="1485082"/>
  </count>

</osm>
	Command being timed: "./osm3s_query --db-dir=db/"
	User time (seconds): 55.80
	System time (seconds): 0.42
	Percent of CPU this job got: 100%
	Elapsed (wall clock) time (h:mm:ss or m:ss): 0:56.22
	Average shared text size (kbytes): 0
	Average unshared data size (kbytes): 0
	Average stack size (kbytes): 0
	Average total size (kbytes): 0
	Maximum resident set size (kbytes): 883220
	Average resident set size (kbytes): 0
	Major (requiring I/O) page faults: 0
	Minor (reclaiming a frame) page faults: 194466
	Voluntary context switches: 1
	Involuntary context switches: 75
	Swaps: 0
	File system inputs: 0
	File system outputs: 0
	Socket messages sent: 0
	Socket messages received: 0
	Signals delivered: 0
	Page size (bytes): 4096
	Exit status: 0
diff --git a/src/overpass_api/core/type_area.h b/src/overpass_api/core/type_area.h
index a57f29a..453e0a9 100644
--- a/src/overpass_api/core/type_area.h
+++ b/src/overpass_api/core/type_area.h
@@ -313,6 +313,8 @@ struct Area_Block
   Id_Type id;
   std::vector< uint64 > coors;
 
+  std::vector< std::pair< uint32, int32 > > ilat_ilon_pairs;
+
   Area_Block() : id(0u) {}
 
   Area_Block(void* data) : id(*(Id_Type*)data)
diff --git a/src/overpass_api/statements/area_query.cc b/src/overpass_api/statements/area_query.cc
index cd10022..90ca17f 100644
--- a/src/overpass_api/statements/area_query.cc
+++ b/src/overpass_api/statements/area_query.cc
@@ -35,6 +35,109 @@
 #include "recurse.h"
 
 
+
+namespace area_query {
+
+namespace detail {
+
+const static int HIT = 1;
+const static int TOGGLE_EAST = 2;
+const static int TOGGLE_WEST = 4;
+
+int check_area_block2
+(uint32 ll_index_ilat, int32 ll_index_ilon, const Area_Block& area_block,
+    uint32 coord_lat, int32 coord_lon)
+{
+  int state = 0;
+
+  auto it(area_block.ilat_ilon_pairs.begin());
+  uint32 lat = ll_index_ilat | it->first;                             // avoid ::ilat / ::ilon 
+  int32 lon = ll_index_ilon | it->second;                        // avoid ::ilat / ::ilon
+
+  while (++it != area_block.ilat_ilon_pairs.end())
+  {
+    uint32 last_lat = lat;
+    int32 last_lon = lon;
+
+    lat = ll_index_ilat | it->first;
+    lon = ll_index_ilon | it->second;
+
+    if (last_lon < lon)
+    {
+      if (lon < coord_lon)
+        continue; // case (1)
+      else if (last_lon > coord_lon)
+        continue; // case (1)
+      else if (lon == coord_lon)
+      {
+        if (lat < coord_lat)
+          state ^= TOGGLE_WEST; // case (4)
+        else if (lat == coord_lat)
+          return HIT; // case (2)
+        // else: case (1)
+        continue;
+      }
+      else if (last_lon == coord_lon)
+      {
+        if (last_lat < coord_lat)
+          state ^= TOGGLE_EAST; // case (4)
+        else if (last_lat == coord_lat)
+          return HIT; // case (2)
+        // else: case (1)
+        continue;
+      }
+    }
+    else if (last_lon > lon)
+    {
+      if (lon > coord_lon)
+        continue; // case (1)
+      else if (last_lon < coord_lon)
+        continue; // case (1)
+      else if (lon == coord_lon)
+      {
+        if (lat < coord_lat)
+          state ^= TOGGLE_EAST; // case (4)
+        else if (lat == coord_lat)
+          return HIT; // case (2)
+        // else: case (1)
+        continue;
+      }
+      else if (last_lon == coord_lon)
+      {
+        if (last_lat < coord_lat)
+          state ^= TOGGLE_WEST; // case (4)
+        else if (last_lat == coord_lat)
+          return HIT; // case (2)
+        // else: case (1)
+        continue;
+      }
+    }
+    else // last_lon == lon
+    {
+      if (lon == coord_lon &&
+          ((last_lat <= coord_lat && coord_lat <= lat) || (lat <= coord_lat && coord_lat <= last_lat)))
+        return HIT; // case (2)
+      continue; // else: case (1)
+    }
+
+    uint32 intersect_lat = lat +
+        ((int64)coord_lon - lon)*((int64)last_lat - lat)/((int64)last_lon - lon);
+    if (coord_lat > intersect_lat)
+      state ^= (TOGGLE_EAST | TOGGLE_WEST); // case (3)
+    else if (coord_lat == intersect_lat)
+      return HIT; // case (2)
+    // else: case (1)
+  }
+  return state;
+}
+
+
+}
+
+}
+
+
+
 class Area_Constraint : public Query_Constraint
 {
   public:
@@ -441,6 +544,10 @@ void Area_Query_Statement::collect_nodes
 
   uint32 loop_count = 0;
   uint32 current_idx(0);
+
+  uint32 current_idx_ilat(0);
+  int32 current_idx_ilon(0);
+
   while (!(area_it == area_blocks_db.discrete_end()))
   {
     current_idx = area_it.index().val();
@@ -459,6 +566,23 @@ void Area_Query_Statement::collect_nodes
       ++area_it;
     }
 
+    /* Test: Precalculate ilat/ilon pairs */
+    {
+      for (auto &it : areas)
+        for (auto& it2 : it.second)
+          for (auto coor : it2.coors)
+          {
+            uint32 _lat = ::ilat((coor>>32)&0xff, coor & 0xffffffff);
+            int32 _lon = ::ilon(((coor>>32)&0xff) ^ 0x40000000, coor & 0xffffffff); 
+            it2.ilat_ilon_pairs.push_back(std::make_pair(_lat, _lon));
+          }
+      current_idx_ilat = ::ilat(current_idx, 0);
+      current_idx_ilon = ::ilon(current_idx, 0);   // ^ 0x40000000 is only being applies once here
+    }
+
+    /* ------------------------------ */
+
+
     while (nodes_it != nodes.end() && nodes_it->first.val() < current_idx)
     {
       nodes_it->second.clear();
@@ -475,6 +599,7 @@ void Area_Query_Statement::collect_nodes
             + 91.0)*10000000+0.5);
         int32 ilon(::lon(nodes_it->first.val(), iit->ll_lower)*10000000
             + (::lon(nodes_it->first.val(), iit->ll_lower) > 0 ? 0.5 : -0.5));
+
         for (std::map< Area_Skeleton::Id_Type, std::vector< Area_Block > >::const_iterator it = areas.begin();
 	     it != areas.end(); ++it)
         {
@@ -484,7 +609,8 @@ void Area_Query_Statement::collect_nodes
           {
             ++loop_count;
 
-	    int check(Coord_Query_Statement::check_area_block(current_idx, *it2, ilat, ilon));
+	    int check(area_query::detail::check_area_block2(current_idx_ilat, current_idx_ilon, *it2, ilat, ilon));
+	    //int check(Coord_Query_Statement::check_area_block(current_idx, *it2, ilat, ilon));
 	    if (check == Coord_Query_Statement::HIT && add_border)
 	    {
 	      inside = 1;
@@ -494,10 +620,10 @@ void Area_Query_Statement::collect_nodes
 	      inside ^= check;
           }
           if (inside)
-	  {
-	    into.push_back(*iit);
-	    break;
-	  }
+          {
+            into.push_back(*iit);
+            break;
+          }
         }
       }
       nodes_it->second.swap(into);
@@ -679,6 +805,7 @@ void has_inner_points(const Area_Block& string_a, const Area_Block& string_b, in
     uint32 ilat = (coords_a[i].first + coords_a[i+1].first)/2;
     uint32 ilon = (coords_a[i].second + coords_a[i+1].second)/2 + 0x80000000u;
     int check = Coord_Query_Statement::check_area_block(0, string_b, ilat, ilon);
+
     if (check & Coord_Query_Statement::HIT)
       inside = check;
     else if (check)
@@ -708,6 +835,18 @@ void Area_Query_Statement::collect_ways
       add_way_to_area_blocks(way_geometries.get_geometry(*it2), it2->id.val(), way_segments);
   }
 
+  /* Test: Populate ilat/ilon pairs */
+  {
+    for (auto &it : way_segments)
+      for (auto& it2 : it.second)
+        for (auto coor : it2.coors)
+        {
+          uint32 _lat = ::ilat((coor>>32)&0xff, coor & 0xffffffff);
+          int32 _lon = ::ilon(((coor>>32)&0xff) ^ 0x40000000, coor & 0xffffffff);
+          it2.ilat_ilon_pairs.push_back(std::make_pair(_lat, _lon));
+        }
+  }
+
   std::map< uint32, std::vector< std::pair< uint32, Way::Id_Type > > > way_coords_to_id;
   for (typename std::map< Uint31_Index, std::vector< Way_Skeleton > >::iterator it = ways.begin(); it != ways.end(); ++it)
   {
@@ -724,6 +863,9 @@ void Area_Query_Statement::collect_ways
   // Fill node_status with the area related status of each node and segment
   uint32 loop_count = 0;
   uint32 current_idx(0);
+  uint32 current_idx_ilat(0);
+  int32 current_idx_ilon(0);
+
   while (!(area_it == area_blocks_db.discrete_end()))
   {
     current_idx = area_it.index().val();
@@ -742,6 +884,20 @@ void Area_Query_Statement::collect_ways
       ++area_it;
     }
 
+    /* Test: Populate ilat/ilon pairs */
+    {
+      for (auto &it : areas)
+        for (auto& it2 : it.second)
+          for (auto coor : it2.coors)
+          {
+            uint32 _lat = ::ilat((coor>>32)&0xff, coor & 0xffffffff);
+            int32 _lon = ::ilon(((coor>>32)&0xff) ^ 0x40000000, coor & 0xffffffff);
+            it2.ilat_ilon_pairs.push_back(std::make_pair(_lat, _lon));
+          }
+      current_idx_ilat = ::ilat(current_idx, 0);
+      current_idx_ilon = ::ilon(current_idx, 0);
+    }
+
     // check nodes
     while (nodes_it != way_coords_to_id.end() && nodes_it->first < current_idx)
       ++nodes_it;
@@ -763,7 +919,8 @@ void Area_Query_Statement::collect_ways
           {
             ++loop_count;
 
-	    int check(Coord_Query_Statement::check_area_block(current_idx, *it2, ilat, ilon));
+	    // int check(Coord_Query_Statement::check_area_block(current_idx, *it2, ilat, ilon));
+	    int check(area_query::detail::check_area_block2(current_idx_ilat, current_idx_ilon, *it2, ilat, ilon));
 	    if (check == Coord_Query_Statement::HIT)
             {
               inside = Coord_Query_Statement::HIT;

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions