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

0.6.0 #27

Merged
merged 21 commits into from
Feb 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 23 additions & 23 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ jobs:
rust: [stable, nightly]

steps:
- uses: rui314/setup-mold@v1
- uses: hecrj/setup-rust-action@v1
with:
rust-version: ${{ matrix.rust }}
- uses: actions/checkout@master
- name: Run tests
run: cargo check --verbose
- uses: rui314/setup-mold@v1
- uses: hecrj/setup-rust-action@v1
with:
rust-version: ${{ matrix.rust }}
- uses: actions/checkout@master
- name: Run tests
run: cargo check --verbose

test:
if: "!contains(github.event.head_commit.message, '[SKIP CI]')"
Expand All @@ -27,13 +27,13 @@ jobs:
rust: [stable, nightly]

steps:
- uses: rui314/setup-mold@v1
- uses: hecrj/setup-rust-action@v1
with:
rust-version: ${{ matrix.rust }}
- uses: actions/checkout@master
- name: Run tests
run: cargo test --verbose
- uses: rui314/setup-mold@v1
- uses: hecrj/setup-rust-action@v1
with:
rust-version: ${{ matrix.rust }}
- uses: actions/checkout@master
- name: Run tests
run: cargo test --verbose

test-fastfloat:
if: "!contains(github.event.head_commit.message, '[SKIP CI]')"
Expand All @@ -44,19 +44,18 @@ jobs:
rust: [stable, nightly]

steps:
- uses: rui314/setup-mold@v1
- uses: hecrj/setup-rust-action@v1
with:
rust-version: ${{ matrix.rust }}
- uses: actions/checkout@master
- name: Run tests
run: cargo test --verbose --features fastfloat
- uses: rui314/setup-mold@v1
- uses: hecrj/setup-rust-action@v1
with:
rust-version: ${{ matrix.rust }}
- uses: actions/checkout@master
- name: Run tests
run: cargo test --verbose --features fastfloat

rustdoc:
runs-on: ubuntu-latest

needs: [check, test, test-fastfloat]
steps:
- uses: rui314/setup-mold@v1
- name: Checkout repository
uses: actions/checkout@v2

Expand All @@ -65,6 +64,7 @@ jobs:

- name: Deploy Docs
uses: peaceiris/actions-gh-pages@364c31d33bb99327c77b3a5438a83a357a6729ad # v3.4.0
if: success() && github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message, '[SKIP CI]')
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_branch: gh-pages
Expand Down
16 changes: 9 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "lta_models"
version = "0.5.0"
authors = ["budinverse <[email protected]>"]
version = "0.6.0"
authors = ["zeon256 <[email protected]>"]
edition = "2021"
license = "MIT"
description = "🚍Models for lta-rs"
Expand All @@ -13,22 +13,24 @@ exclude = [
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { version = "1.0.159", features = ["derive"] }
serde = { version = "1.0.195", features = ["derive"] }
serde_repr = "0.1.12"
serde_json = "1.0.95"
regex = "1.7.3"
time = { version = "0.3.20", features = ["serde-human-readable"]}
time = { version = "0.3.20", features = ["serde-human-readable", "macros"]}
lazy_static = "1.4.0"
fast-float = { version = "0.2", optional = true }
serde_json = "1.0.40"

[dev-dependencies]
serde_json = "1.0.40"
bincode = "1.3.3"
criterion = "0.3"
mimalloc = "0.1.25"
rmp-serde = "1.1.2"
flexbuffers = "2.0.0"

[features]
fastfloat = ["fast-float"]

[[bench]]
name = "benchmark"
harness = false
harness = false
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
<a href="https://crates.io/crates/lta_models">
<img src="https://img.shields.io/crates/v/lta-models"/>
</a>
<a href="https://crates.io/crates/lta_models">
<img src="https://img.shields.io/badge/forbid_unsafe-yes-blue"/>
</a>
</p>

This repository contains the data structures required to interact with LTA's datamall APIs. All data structures implements `Serialize` and `Deserialize`.
Expand All @@ -23,9 +26,19 @@ This repository contains the data structures required to interact with LTA's dat
## `Cargo.toml` setup
```toml
# extra features available: fastfloat
lta-models = { version = "0.5.0" }
lta-models = { version = "0.6.0" }
```

## Supported formats

| Format | Supported? | Tested? |
| ----------- | ---------- | ------- |
| JSON | ✅ | ✅ |
| Bincode | ✅ | ✅ |
| Flexbuffer | ✅ | ✅ |
| MessagePack | ✅ | ✅ |


## Performance & `fast-float` implementation
Some of the deserialization code _may_ benefit from using the `fastfloat` feature, but during testing the biggest performance improvement can be seen when you swap out the system allocator to something faster like [`mimalloc`](https://github.com/microsoft/mimalloc) or [`jemalloc`](https://github.com/jemalloc/jemalloc)

Expand Down
146 changes: 86 additions & 60 deletions benches/benchmark.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use lta_models::{bus::bus_arrival::NextBusRaw, prelude::*};

use mimalloc::MiMalloc;
use time::macros::datetime;

#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;

#[rustfmt::skip]
mod de {
use lta_models::{prelude::*, crowd::crowd_density::{CrowdDensityForecast, CrowdDensityForecastRawResp}};
use std::fmt::Debug;

use lta_models::prelude::*;
use lta_models::bus::bus_arrival::NextBusRaw;
use serde::{Deserialize, Serialize};

pub fn generate_bench<'de, I, S, F>(input_fn: F) -> S
where
F: FnOnce() -> &'de str,
I: Deserialize<'de> + Into<S>,
S: Serialize,
S: Serialize + Debug
{
let str_data = input_fn();
serde_json::from_str(str_data).map(|v: I| v.into()).unwrap()
Expand All @@ -31,7 +36,7 @@ mod de {
}

pub fn bus_arrival() -> BusArrivalResp {
gen!(RawBusArrivalResp, _, "../dumped_data/bus_arrival.json")
gen!(BusArrivalRespRaw, _, "../dumped_data/bus_arrival.json")
}

pub fn bus_routes() -> Vec<BusRoute> {
Expand Down Expand Up @@ -94,69 +99,90 @@ mod de {
gen!(StationCrowdLevelRawResp, _, "../dumped_data/crowd_density_rt.json")
}

pub fn crowd_density_forecast() -> CrowdDensityForecast {
pub fn crowd_density_forecast() -> CrowdDensityForecast {
gen!(CrowdDensityForecastRawResp, _, "../dumped_data/crowd_density_forecast.json")
}

pub fn transmute_nextbus(data: NextBusRaw) -> NextBus {
let nx = unsafe {
std::mem::transmute::<_, NextBus>(data)
};
nx
}
}

#[rustfmt::skip]
pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("de::bike_parking.json", |b| b.iter(|| de::bike_parking()));
c.bench_function("de::bus_arrival.json", |b| b.iter(|| de::bus_arrival()));
c.bench_function("de::bus_route.json", |b| b.iter(|| de::bus_routes()));
c.bench_function("de::bus_services.json", |b| b.iter(|| de::bus_service()));
c.bench_function("de::bus_stops.json", |b| b.iter(|| de::bus_stops()));
c.bench_function("de::carpark_avail.json", |b| b.iter(|| de::carpark_avail()));
c.bench_function("de::erp_rates.json", |b| b.iter(|| de::erp_rates()));
c.bench_function("de::est_travel_time.json", |b| b.iter(|| de::est_travel_time()));
c.bench_function("de::faulty_traffic_lights.json", |b| b.iter(|| de::faulty_traffic_lights()));
c.bench_function("de::passenger_vol_bus_stops.json", |b| b.iter(|| de::passenger_vol_bus_stops()));
c.bench_function("de::passenger_od_bus_stops.json", |b| b.iter(|| de::passenger_vol_od_bus_stops()));
c.bench_function("de::passenger_vol_od_train.json", |b| b.iter(|| de::passenger_vol_od_train()));
c.bench_function("de::passenger_vol_train.json", |b| b.iter(|| de::passenger_vol_train()));
c.bench_function("de::taxi_avail.json", |b| b.iter(|| de::taxi_avail()));
c.bench_function("de::taxi_stands.json", |b| b.iter(|| de::taxi_stands()));
c.bench_function("de::train_service_alert.json", |b| b.iter(|| de::train_service_alert()));
c.bench_function("de::crowd_density_rt.json", |b| b.iter(|| de::crowd_density_rt()));
c.bench_function("de::crowd_density_forecast.json", |b| b.iter(|| de::crowd_density_forecast()));

let bike_parking = de::bike_parking();
let bus_arrival = de::bus_arrival();
let bus_routes = de::bus_routes();
let bus_service = de::bus_service();
let bus_stops = de::bus_stops();
let carpark_avail = de::carpark_avail();
let erp_rates = de::erp_rates();
let est_travel_time = de::est_travel_time();
let faulty_traffic_lights = de::faulty_traffic_lights();
let passenger_vol_bus_stops = de::passenger_vol_bus_stops();
let passenger_vol_od_bus_stops = de::passenger_vol_od_bus_stops();
let passenger_vol_train = de::passenger_vol_train();
let passenger_vol_od_train = de::passenger_vol_od_train();
let taxi_avail = de::taxi_avail();
let taxi_stands = de::taxi_stands();
let train_service_alert = de::train_service_alert();
let crowd_density_rt = de::crowd_density_rt();
let crowd_density_forecast = de::crowd_density_forecast();

c.bench_function("ser::bike_parking.json", |b| b.iter(|| serde_json::to_string(black_box(&bike_parking))));
c.bench_function("ser::bus_arrival.json", |b| b.iter(|| serde_json::to_string(black_box(&bus_arrival))));
c.bench_function("ser::bus_route.json", |b| b.iter(|| serde_json::to_string(black_box(&bus_routes))));
c.bench_function("ser::bus_services.json", |b| b.iter(|| serde_json::to_string(black_box(&bus_service))));
c.bench_function("ser::bus_stops.json", |b| b.iter(|| serde_json::to_string(black_box(&bus_stops))));
c.bench_function("ser::carpark_avail.json", |b| b.iter(|| serde_json::to_string(black_box(&carpark_avail))));
c.bench_function("ser::erp_rates.json", |b| b.iter(|| serde_json::to_string(black_box(&erp_rates))));
c.bench_function("ser::est_travel_time.json", |b| b.iter(|| serde_json::to_string(black_box(&est_travel_time))));
c.bench_function("ser::faulty_traffic_lights.json", |b| b.iter(|| serde_json::to_string(black_box(&faulty_traffic_lights))));
c.bench_function("ser::passenger_vol_bus_stops.json", |b| b.iter(|| serde_json::to_string(black_box(&passenger_vol_bus_stops))));
c.bench_function("ser::passenger_od_bus_stops.json", |b| b.iter(|| serde_json::to_string(black_box(&passenger_vol_od_bus_stops))));
c.bench_function("ser::passenger_vol_od_train.json", |b| b.iter(|| serde_json::to_string(black_box(&passenger_vol_od_train))));
c.bench_function("ser::passenger_vol_train.json", |b| b.iter(|| serde_json::to_string(black_box(&passenger_vol_train))));
c.bench_function("ser::taxi_avail.json", |b| b.iter(|| serde_json::to_string(black_box(&taxi_avail))));
c.bench_function("ser::taxi_stands.json", |b| b.iter(|| serde_json::to_string(black_box(&taxi_stands))));
c.bench_function("ser::train_service_alert.json", |b| b.iter(|| serde_json::to_string(black_box(&train_service_alert))));
c.bench_function("ser::crowd_density_rt.json", |b| b.iter(|| serde_json::to_string(black_box(&crowd_density_rt))));
c.bench_function("ser::crowd_density_forecast.json", |b| b.iter(|| serde_json::to_string(black_box(&crowd_density_forecast))));
let sample_data = NextBusRaw {
origin_code: 77009,
dest_code: 77009,
est_arrival: datetime!(2023-04-06 14:47:57 +8),
lat: 1.314452,
long: 103.910009,
visit_no: 1,
load: BusLoad::SeatsAvailable,
feature: BusFeature::WheelChairAccessible,
bus_type: BusType::SingleDecker,
};

c.bench_function("transmute_nextbus", |b| b.iter(|| de::transmute_nextbus(black_box(sample_data.clone()))));
c.bench_function("into_nextbus", |b| b.iter(|| NextBus::from(black_box(sample_data.clone()))));
c.bench_function("de::bike_parking.json", |b| b.iter(|| de::bike_parking()));
c.bench_function("de::bus_arrival.json", |b| b.iter(|| de::bus_arrival()));
c.bench_function("de::bus_route.json", |b| b.iter(|| de::bus_routes()));
c.bench_function("de::bus_services.json", |b| b.iter(|| de::bus_service()));
c.bench_function("de::bus_stops.json", |b| b.iter(|| de::bus_stops()));
c.bench_function("de::carpark_avail.json", |b| b.iter(|| de::carpark_avail()));
c.bench_function("de::erp_rates.json", |b| b.iter(|| de::erp_rates()));
c.bench_function("de::est_travel_time.json", |b| b.iter(|| de::est_travel_time()));
c.bench_function("de::faulty_traffic_lights.json", |b| b.iter(|| de::faulty_traffic_lights()));
c.bench_function("de::passenger_vol_bus_stops.json", |b| b.iter(|| de::passenger_vol_bus_stops()));
c.bench_function("de::passenger_od_bus_stops.json", |b| b.iter(|| de::passenger_vol_od_bus_stops()));
c.bench_function("de::passenger_vol_od_train.json", |b| b.iter(|| de::passenger_vol_od_train()));
c.bench_function("de::passenger_vol_train.json", |b| b.iter(|| de::passenger_vol_train()));
c.bench_function("de::taxi_avail.json", |b| b.iter(|| de::taxi_avail()));
c.bench_function("de::taxi_stands.json", |b| b.iter(|| de::taxi_stands()));
c.bench_function("de::train_service_alert.json", |b| b.iter(|| de::train_service_alert()));
c.bench_function("de::crowd_density_rt.json", |b| b.iter(|| de::crowd_density_rt()));
c.bench_function("de::crowd_density_forecast.json", |b| b.iter(|| de::crowd_density_forecast()));

let bike_parking = de::bike_parking();
let bus_arrival = de::bus_arrival();
let bus_routes = de::bus_routes();
let bus_service = de::bus_service();
let bus_stops = de::bus_stops();
let carpark_avail = de::carpark_avail();
let erp_rates = de::erp_rates();
let est_travel_time = de::est_travel_time();
let faulty_traffic_lights = de::faulty_traffic_lights();
let passenger_vol_bus_stops = de::passenger_vol_bus_stops();
let passenger_vol_od_bus_stops = de::passenger_vol_od_bus_stops();
let passenger_vol_train = de::passenger_vol_train();
let passenger_vol_od_train = de::passenger_vol_od_train();
let taxi_avail = de::taxi_avail();
let taxi_stands = de::taxi_stands();
let train_service_alert = de::train_service_alert();
let crowd_density_rt = de::crowd_density_rt();
let crowd_density_forecast = de::crowd_density_forecast();

c.bench_function("ser::bike_parking.json", |b| b.iter(|| serde_json::to_string(black_box(&bike_parking))));
c.bench_function("ser::bus_arrival.json", |b| b.iter(|| serde_json::to_string(black_box(&bus_arrival))));
c.bench_function("ser::bus_route.json", |b| b.iter(|| serde_json::to_string(black_box(&bus_routes))));
c.bench_function("ser::bus_services.json", |b| b.iter(|| serde_json::to_string(black_box(&bus_service))));
c.bench_function("ser::bus_stops.json", |b| b.iter(|| serde_json::to_string(black_box(&bus_stops))));
c.bench_function("ser::carpark_avail.json", |b| b.iter(|| serde_json::to_string(black_box(&carpark_avail))));
c.bench_function("ser::erp_rates.json", |b| b.iter(|| serde_json::to_string(black_box(&erp_rates))));
c.bench_function("ser::est_travel_time.json", |b| b.iter(|| serde_json::to_string(black_box(&est_travel_time))));
c.bench_function("ser::faulty_traffic_lights.json", |b| b.iter(|| serde_json::to_string(black_box(&faulty_traffic_lights))));
c.bench_function("ser::passenger_vol_bus_stops.json", |b| b.iter(|| serde_json::to_string(black_box(&passenger_vol_bus_stops))));
c.bench_function("ser::passenger_od_bus_stops.json", |b| b.iter(|| serde_json::to_string(black_box(&passenger_vol_od_bus_stops))));
c.bench_function("ser::passenger_vol_od_train.json", |b| b.iter(|| serde_json::to_string(black_box(&passenger_vol_od_train))));
c.bench_function("ser::passenger_vol_train.json", |b| b.iter(|| serde_json::to_string(black_box(&passenger_vol_train))));
c.bench_function("ser::taxi_avail.json", |b| b.iter(|| serde_json::to_string(black_box(&taxi_avail))));
c.bench_function("ser::taxi_stands.json", |b| b.iter(|| serde_json::to_string(black_box(&taxi_stands))));
c.bench_function("ser::train_service_alert.json", |b| b.iter(|| serde_json::to_string(black_box(&train_service_alert))));
c.bench_function("ser::crowd_density_rt.json", |b| b.iter(|| serde_json::to_string(black_box(&crowd_density_rt))));
c.bench_function("ser::crowd_density_forecast.json", |b| b.iter(|| serde_json::to_string(black_box(&crowd_density_forecast))));
}

criterion_group!(benches, criterion_benchmark);
Expand Down
Loading
Loading