ITADN

pass2coefficient = 1.0 measures ~1.5x faster than the c=0 default across nine profiles

#967Openmott-dev 创建于 1 天前
M
mott-devcommented
Hi, I run BRouter 1.7.9 in server mode as the routing engine for a cycle route planner. While investigating long-distance performance I ended up setting `assign pass2coefficient = 1.0` in all nine profiles I ship, which turned out to be a large and consistent speedup at essentially unchanged routes. Since [algorithm.html](https://brouter.de/brouter/algorithm.html) gives an explicit rationale for the `c=0` default that points the other way, I would rather bring the numbers here than sit on a local patch. There may well be something I measured wrong. ## Setup BRouter 1.7.9, server mode, identical rd5 tiles, single container, nothing changed but the one profile line. Endpoints are German main stations, e.g. Koblenz Hbf `7.5976,50.3299` -> Würzburg Hbf `9.9346,49.8019`. The comparison metric is `properties.cost`, not length or ascent — those two are proxies for the objective function and can move against each other. Cost is deterministic and reproducible; the timings below are single default/variant pairs measured back to back per corridor, so treat them as indicative. The effect is far outside the run-to-run scatter (~3 % between adjacent runs), but it is not a repeated-trials study. ## 1. Timing Nine shipped profiles, three corridors each, 150–360 km, one of them hilly: | profile | speedup | Δ cost | |---|---|---| | trekking | 1.63x | +0.0494 % | | trekking-steep | 1.60x | 0 | | trekking-ignore-cr | 1.44x | 0 | | trekking-noferries | 1.62x | +0.0494 % | | fastbike | 1.59x | +0.0043 % | | fastbike-lowtraffic | 1.54x | 0 | | fastbike-verylowtraffic | 1.55x | 0 | | gravel | 1.68x | 0 | | mtb | 1.09x | 0 | Mean 1.52x. Six of nine return a bit-identical route. On longer corridors with `trekking` (500 km / 750 km / 1250 km) the factor is 1.57x / 1.84x / 2.18x - it grows with distance. Re-checked against a freshly built image on Koblenz -> Würzburg with identical tiles, baked-in 1.0 against the stock default: trekking 1.43x, fastbike 1.45x, gravel 1.77x, mtb 1.12x, `Δ cost = 0` in all four. `mtb` is the outlier at 1.09x, and it explains itself: it sets `pass1coefficient 1.8`, so pass 0 is already greedy and little is left for pass 1 to save. ## 2. The part I would like to understand [algorithm.html](https://brouter.de/brouter/algorithm.html) says: > The reason that c=0 (=Dijkstra) is used in the second pass and not c=1 > (=A-Star) is simply that for c=0 the open-set is smaller, because many paths > run into the cutoff at an early time and do not have to be managed in the > open-set anymore. and that open-set size drives performance and memory consumption. My numbers point the other way. **but I measured wall-clock time, and the argument above is about open-set size.** Those are different quantities and both statements can hold at once: a smaller open set that still costs more overall, for instance because far more nodes reach the cutoff at `RoutingEngine.java:2139` before being discarded. So the actual question is: was the open-set argument measured, and on which metric? If it is open-set peak or memory, my result is not a contradiction at all, it would just mean the trade-off the docs describe is no longer the one that dominates on current hardware and tile sizes. I can run `nodesVisited` per pass over these corridors if that is the useful number, and post it here. ## 3. Secondary observation: `c=1.0` is not exactly optimal Happy to split this into its own issue if you prefer, it only matters if someone actually runs the second pass with a non-zero coefficient. The commonly stated guarantee is coefficient <= 1 implies the optimal route. I see a small but strictly one-sided deviation at exactly 1.0: three of nine profiles return a slightly more expensive route, worst case +0.0494 %. It is never cheaper. Concrete case, `fastbike`, Koblenz -> Würzburg, 227 km: | pass2coefficient | cost | Δ | |---|---|---| | 0.0 | 303028 | - | | 1.0 … 0.75 | 303041 | +13 | | 0.5 | 303028 | 0 | A step, not a gradient. 13 cost units are 13 m of perfect road on 227 km, so this is not a practical problem for us, but it does suggest the admissibility condition is not quite holding. What I ruled out: * **Cost factors below 1 in the profile.** Of 1688 way segments on that route, none is below `CostPerKm 1000`. `mtb`'s sub-1 uphill/downhill factors are wrapped in a `max 1.0`, and the profile says so itself. * **Path-dependent elevation cost.** That would affect the default equally and would make the variant cheaper about as often as more expensive. It is consistently more expensive. That leaves `airdistance` itself. `CheapRuler.distance` is an approximation with a signed error, and where it overestimates it stops being a lower bound on the remaining cost regardless of what the profile contains. **This is a hypothesis, not a measurement** — I have not yet compared `CheapRuler.distance` against a geodesic reference over these corridors. If the sign and magnitude of that error are already known to someone, it would save the experiment. For context on why I suspect it there and not in the rounding: #499 fixed a systematic overestimate in `calcDistance` caused by `(int) d + 1`, but that one accumulated over many short links, whereas `airdistance` is a single node-to-target call, rounding can contribute at most ~0.5 m here and cannot account for 13. #128 adopted CheapRuler explicitly for speed and does not discuss its error. Thanks for BRouter, and for the algorithm page, it is the reason this was findable at all.
0 条评论