Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GBFS: Performance/Memory Improvements + Vehicle Types #670

Merged
merged 44 commits into from
Dec 9, 2024

Conversation

pablohoch
Copy link
Member

@pablohoch pablohoch commented Nov 22, 2024

  • Adds proper vehicle type support. The API now has a single RENTAL mode with additional filters for form factors (bike, cargo bike, scooter etc.), propulsion type (human, electric etc.) and providers.
    • Note that currently all vehicle types use the bike sharing osr profile, i.e. cars are not yet properly supported.
  • Providers are now partitioned into segments based on vehicle form factors, propulsion types, return constraints, geofencing zones and vehicle type return restrictions for stations. osr routing is performed for each provider segment matching the query.
  • Vehicles with roundtrip station return constraints (vehicle must be returned to the departure station) can now be used for direct queries (only). Note that the return leg is not part of the connection, but this can be detected using the rental.returnConstraint field in the response. This is often used for cargo bikes and car sharing.
  • Faster updates:
    • The ttl field is now processed to only download files when necessary.
    • If a file is not updated (either the ttl is not expired or the contents are unchanged), the existing data is reused.
    • Only bitfields for providers in the cache (see below) where data was changed are calculated during the update.
  • Memory usage improvements (GBFS memory usage #660):
    • The bitfields for osr are only calculated once a provider is first used in a routing query or during the GBFS update if the cache is not yet full. (Queries where GBFS data is not in the cache will be slower. Providers with large geofencing zones will be especially slow.)
    • Only a limited number of bitfields (new setting: gbfs.cache_size) are kept in memory. These bitfields are also compressed.
    • Only the necessary bitfields are decompressed when processing a routing query.

Most GBFS providers don't actually use multiple vehicle form factors. Here is an example config for Switzerland, where some providers in Zurich provide bikes and scooters:

gbfs:
  feeds:
    Link_Basel:
      url: https://mds.linkyour.city/gbfs/ch_basel/gbfs.json
    bird-basel:
      url: https://mds.bird.co/gbfs/v2/public/basel/gbfs.json
    bird-biel:
      url: https://mds.bird.co/gbfs/v2/public/biel/gbfs.json
    bird-bulle:
      url: https://mds.bird.co/gbfs/v2/public/bulle/gbfs.json
    bird-kloten:
      url: https://mds.bird.co/gbfs/v2/public/kloten/gbfs.json
    bird-uster:
      url: https://mds.bird.co/gbfs/v2/public/uster/gbfs.json
    bird-winterthur:
      url: https://mds.bird.co/gbfs/v2/public/winterthur/gbfs.json
    bird-zurich:
      url: https://mds.bird.co/gbfs/v2/public/zurich/gbfs.json
    bolt_basel:
      url: https://api.mobidata-bw.de/sharing/gbfs/bolt_basel/gbfs
    bolt_zurich:
      url: https://api.mobidata-bw.de/sharing/gbfs/bolt_zurich/gbfs
    carvelo2go_ch:
      url: https://api.mobidata-bw.de/sharing/gbfs/carvelo2go_ch/gbfs
    donkey_ge:
      url: https://stables.donkey.bike/api/public/gbfs/2/donkey_ge/gbfs
    donkey_kreuzlingen:
      url: https://stables.donkey.bike/api/public/gbfs/2/donkey_kreuzlingen/gbfs.json
    donkey_le_locle:
      url: https://stables.donkey.bike/api/public/gbfs/2/donkey_le_locle/gbfs
    donkey_neuchatel:
      url: https://stables.donkey.bike/api/public/gbfs/2/donkey_neuchatel/gbfs.json
    donkey_sion:
      url: https://stables.donkey.bike/api/public/gbfs/2/donkey_sion/gbfs.json
    donkey_thun:
      url: https://stables.donkey.bike/api/public/gbfs/2/donkey_thun/gbfs.json
    donkey_yverdon-les-bains:
      url: https://stables.donkey.bike/api/public/gbfs/2/donkey_yverdon-les-bains/gbfs.json
    edrivecarsharing_ch:
      url: https://api.mobidata-bw.de/sharing/gbfs/edrivecarsharing_ch/gbfs
    lime_basel:
      url: https://api.mobidata-bw.de/sharing/gbfs/lime_basel/gbfs
    lime_opfikon:
      url: https://data.lime.bike/api/partners/v2/gbfs/opfikon/gbfs.json
    lime_uster:
      url: https://api.mobidata-bw.de/sharing/gbfs/lime_uster/gbfs
    lime_zug:
      url: https://data.lime.bike/api/partners/v2/gbfs/zug/gbfs.json
    lime_zurich:
      url: https://api.mobidata-bw.de/sharing/gbfs/lime_zurich/gbfs
    nextbike_ch:
      url: https://gbfs.nextbike.net/maps/gbfs/v2/nextbike_ch/gbfs.json
    pickebike_aubonne:
      url: https://api.mobidata-bw.de/sharing/gbfs/pickebike_aubonne/gbfs
    pickebike_basel:
      url: https://api.mobidata-bw.de/sharing/gbfs/pickebike_basel/gbfs
    pickebike_fribourg:
      url: https://api.mobidata-bw.de/sharing/gbfs/pickebike_fribourg/gbfs
    publibike:
      url: https://api.publibike.ch/v1/gbfs/v2/gbfs.json
    share_birrer_ch:
      url: https://www.share-birrer.ch/gbfs/gbfs.json
    sharedmobility.ch:
      url: https://www.sharedmobility.ch/gbfs.json
    tier_basel:
      url: https://api.mobidata-bw.de/sharing/gbfs/tier_basel/gbfs
    tier_bern:
      url: https://api.mobidata-bw.de/sharing/gbfs/tier_bern/gbfs
    tier_stgallen:
      url: https://api.mobidata-bw.de/sharing/gbfs/tier_stgallen/gbfs
    tier_winterthur:
      url: https://api.mobidata-bw.de/sharing/gbfs/tier_winterthur/gbfs
    tier_zurich:
      url: https://api.mobidata-bw.de/sharing/gbfs/tier_zurich/gbfs
    velospot_ch:
      url: https://api.mobidata-bw.de/sharing/gbfs/velospot_ch/gbfs
    voi_ch:
      url: https://api.mobidata-bw.de/sharing/gbfs/voi_ch/gbfs
    zem_ch:
      url: https://api.mobidata-bw.de/sharing/gbfs/zem_ch/gbfs
  update_interval: 60
  http_timeout: 10
  cache_size: 50

include/motis/gbfs/diff.h Outdated Show resolved Hide resolved
auto write_lock = std::unique_lock{mutex_};
if (auto it = cache_map_.find(key); it != cache_map_.end()) {
if (auto const lru_it =
std::find(lru_order_.begin(), lru_order_.end(), key);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::find(lru_order_.begin(), lru_order_.end(), key);
std::find(lru_order_.begin(), lru_order_.end(), key);

utl::find

But in general looks expensive in case the cache becomes large?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lru_order_ only stores numbers and I expected the cache size to be <= 1000. Finding a number and moving memory around (in move_to_front) in <= 8 KB should be fast enough I hope. We could probably limit gbfs_provider_idx_t (the entries in this vector) to uint16_t instead of size_t to make it more compact.

What alternative did you have in mind? For example, I don't think an additional map key -> lru index is very helpful because the indices of all the entries change every time move_to_front is called (unless only the first entry is accessed), so keeping that map updated would be expensive.

include/motis/gbfs/partition.h Outdated Show resolved Hide resolved
namespace motis::gbfs {

template <typename T>
struct partition {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how is this related to boost::interval_set or boost::interval_map?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I'm missing something, I don't think they are related. The GBFS code doesn't use intervals. The vehicle types are just mapped to numbers 0..n (index into the list of vehicle types) for the partitioning.

partition.h implements Partition refinement, which I don't think Boost.Icl does (and I don't see how it would relate to intervals). The idea is that initially, all vehicle types are equal (= a single set containing all vehicle types), then refine is called for each combination of vehicle types that share some property but are different from all other vehicle types (this includes the form factor (bike, scooter etc.), vehicle types that can be returned at a station (vs. all the other ones that can't be returned there), and geofencing zone rules that are vehicle type specific). If not all vehicle types in a set share that property, the set is split into two sets.

@felixguendling felixguendling merged commit 9505e01 into master Dec 9, 2024
11 checks passed
@felixguendling felixguendling deleted the gbfs-caching branch December 9, 2024 17:31
D3vZro added a commit to MoViDe-Project/motis that referenced this pull request Jan 30, 2025
* Use `maxTravelTime` to filter results (motis-project#668)

* Use 'maxTravelTime' to filter results

* Change unit to minutes

* Fix formatting

* Fix type for MSVC build

* Update nigiri dependency

* Set limit for maximum travel time

* GBFS: Performance/Memory Improvements + Vehicle Types (motis-project#670)

* gbfs: partition providers, faster updates, less memory usage

* fix vehicle_docks_available

* slightly faster geofencing zone mapping

* rename provider_cache -> provider_file_infos

* ts formatting

* formatting

* clang fixes

* clang fix

* clang fixes

* trying to fix apple clang

* static_cast all the things

* review changes

* fix include

* 65k gbfs providers should be enough

* remove obsolete comment

* sort vehicle status before diff

* fill cache during gbfs update

* cleanup

* partition vehicle types by form factor + propulsion type

* rental api changes (RENTAL mode + form factor + propulsion type)

* ui fix

* rename provider segment -> products

* vehicle type id -> idx

* rename more segment -> products

* one more r-tree to speed up geofencing zone mapping

* clang fix

* fix api descriptions

* api: add rental provider filter

* ui: fix direct connection display for rental connections

* return constraint support, allow roundtrip for direct connections

* ui formatting

* fix missing gbfs data after update

* http proxy support

* share decompressed bitvecs between routing requests

* fix missing initializer

---------

Co-authored-by: Felix Gündling <felix.guendling@gmail.com>

* replace wheelchair with pedestrianProfile and useRoutedTransfers params (motis-project#683)

* replace wheelchair with pedestrianProfile and useRoutedTransfers parameters

* fix test

* ui: debounce search requests

* increase trains limit to support big cities like Paris/London/..

* add timeout option

* cli changes (motis-project#685)

* cli changes

* wip

* update nigiri

* Update README.md: not beta anymore

* update nigiri: speedup ~8% by not finding 24h+ transfers

* basic benchmark and QA tooling (motis-project#686)

* bench

* wip

* wip

* wip

* wip

* fix command line flag handling

* full dataset test (motis-project#687)

* full dataset test

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* body size limit 128M

* cmake: Add option to pass flags not used for host tools (motis-project#689)

* update nigiri: rt update fixes time travel

* more rebostness against invalid delay update data

motis-project/nigiri#162

* update nigiri: trim stop time before empty check for interpolation

* motis config: fix crash with no parameters

* update nigiri: better trip names (motis-project#695)

* polish translation

* Detailed transfers flag + output exactly what nigiri routed (motis-project#698)

* wip

* output exactly what nigiri routed

* remove logging output

* remove unused variable

* fix eval

* wip

* wip

* Initial style guide docs/STYLE.md

* Fix missing closing tag (motis-project#700)

* Fix missing closing tag

* Add sections for important tools

This adds a section for `strong`, as well as `vector_map` and `vecvec`.

* Fix index out of range for stop_times last arrival of multi-section run (motis-project#704)

* fix index out of range for stop_times last arrival of multi-section run

* follow style guide

Co-authored-by: Felix Gündling <felix.guendling@gmail.com>

---------

Co-authored-by: Felix Gündling <felix.guendling@gmail.com>

* (Mobile) UI improvements (motis-project#705)

* ui: move components to lib

* ui: make components more responsive

* ui: more compact layout

* ui: i18n fixes

* ui: make toggle button state more visible

* ui: error handling, avoid repeated effect triggering

* ui: more small screen adjustments

* ui: url state handling

* ui: show backend error msgs, compact transfer display

* UI fixes (motis-project#710)

* ui: fall back to black routeTextColor (gtfs spec)

* update ui deps

* ui: workaround to avoid clickthrough

* ui: linting

* update nigiri: monotonicity enforcement on utc times (fixes interpolation for frequency expanded trips)

* ui changes

* Improve formatDuration (motis-project#713)

* Update formatDuration.ts

* fix formatting

* fix formatting

* Fix formatting

* osr_footpaths: add missing footpaths (motis-project#707)

* osr_footpaths: add missing footpaths

* update osr (ramp support)

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* formatting

---------

Co-authored-by: Michael Kutzner <174690291+MichaelKutzner@users.noreply.github.com>
Co-authored-by: Pablo Hoch <pablohoch@users.noreply.github.com>
Co-authored-by: Felix Gündling <felix.guendling@gmail.com>
Co-authored-by: Felix Gündling <felixguendling@gmail.com>
Co-authored-by: Jonah Brüchert <jbb@kaidan.im>
Co-authored-by: Traines <git@traines.eu>
Co-authored-by: Altonss <66519591+Altonss@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants