Skip to content

About

Benchmarks and a logistics system simulation with the Java SDK

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Lemma Java performance harness

This repository is a Maven harness that generates Lemma Specs at representative catalog scales and times cold load, evaluation, scoped updates, and snapshot restore through the Java engine. The logistics ladder fixtures here are byte-identical to those used by the engine’s published snapshot benchmarks. On release builds, an enterprise workspace (126000 rate cells, about 10 MiB of Spec text) cold-loads in about 32 s and restores from a snapshot in about 0.5 s; full tables and methodology are in the engine benchmarks reference. Recreate via the Java SDK with the commands in Run. Catalog sizing notes are in research/; a short hand-written Spec is in examples/.

The same logistics ladder can also be timed against Drools (--engine drools|both): same use case, native encoding in each product (Lemma catalog-as-Spec vs Drools catalog-as-facts). Results: RESULTS.md.

The work is licensed under Apache-2.0 (LICENSE).

Requirements

exec:java forks a dedicated JVM (fork=true). Default heap -Xmx2g. For the larger presets, pass -Dexec.jvmArgs="-Xmx8g".

Run

Micro shapes (typically finishes in seconds; may share one JVM):

./mvnw -q exec:java -Dexec.args="--shape deep,wide,unless --rules 100,1000 --loads 3 --warmup 10 --evals 50"

Logistics ingest / restore / eval (about half a minute per cold compile at the largest preset; multiply by --loads). Multi-size runs dispatch one fresh JVM per rate_cells:

./mvnw -q exec:java -Dexec.jvmArgs="-Xmx8g" \
  -Dexec.args="--shape logistics --rules 1050,6300,18900,126000 --loads 3 --warmup 10 --evals 50"

Scoped tip replan on the logistics workspace (Lemma-only). --rules is rate_cells:

./mvnw -q exec:java -Dexec.jvmArgs="-Xmx8g" \
  -Dexec.args="--shape replan --rules 1050,6300,18900,126000 --loads 3"

snapshot aliases logistics stages (compile builds a ready snapshot; restore loads it).

Lemma and Drools side by side (--engine both and/or multiple sizes → sequential child JVMs, one engine × one size each):

./mvnw -q exec:java -Dexec.jvmArgs="-Xmx8g" \
  -Dexec.args="--engine both --shape logistics --rules 1050,6300,18900,126000 --loads 3 --warmup 10 --evals 50"

Write generated Spec text without running the engine:

./mvnw -q exec:java -Dexec.args="--shape logistics --rules 1050 --generate-only --write target/generated-lemma"

In the result tables, timings are milliseconds.

Shapes

Shape --rules N Measures
deep chain length load / eval
wide data + pair rules + fold load / eval
unless arms on one rule load / eval
logistics rate-cell preset (below) ingest / restore / eval
replan rate-cell preset (same as logistics) tip Spec update vs full plan (lemma-only)
snapshot same presets as logistics same as logistics

Logistics and snapshot presets

--rules (rate_cells) Profile Contents
1050 ground 1 carrier, Ground service (7x150 cells), ZIP3 zones, quote, and rate-shop
6300 carrier 1 carrier, 6 services
18900 d2c 3 carriers, 6 services
126000 enterprise 20 contracts, 6 services

Workspace Specs include zones_*, rates_*, accessorials, fuel_*, quote_*, and the terminal rule rate_shop.cheapest. See research/logistics-system-lookup-scale.md and research/logistics-in-lemma-syntax.md. Prices in generated Specs are synthetic. Both engines assert eval against a shared CatalogFixture oracle (Lemma exact cents; Drools ±0.01).

Logistics columns (use-case ops)

Column Lemma Drools
compile_ms Emit Spec → Engine.load → snapshot() Emit catalog facts → serialize fact artefact (pipeline DRL compiled once per JVM, untimed)
restore_ms Engine.fromSnapshot Deserialize facts → newKieSession → insert catalog into WM
eval_* Engine.run Insert shipment, fireAllRules, read seed Cheapest
ready_bytes Snapshot size Serialized catalog facts

Drools keeps a fixed pipeline DRL (ground/air rate + cheapest; ~4 rules) at every ladder size. Catalog scale is RateCell / ZoneCell / lane facts in working memory, not rules.

Clean JVMs

Published logistics / replan / snapshot cells must not share a process with another engine, another rate_cells size, or Maven. The harness forks exec:java and, for --engine both or multiple --rules, dispatches sequential child JVMs (one engine × one size). Micro shapes may share a JVM.

Scoped-update fixture (--shape replan)

Lemma-only. Same logistics workspace as --shape logistics, plus a light tip Spec. Measures min tip replan vs full plan:

  1. Full plan (catalog + rate_shop + rate_tip V1) → compile_ms
  2. Restore → restore_ms
  3. update(rate_tip V2) — thin Spec that uses one already-planned quote (cheapest: q.total + 100); catalog + rate_shop kept → upd_tip_ms
  4. Identical tip update → upd_tip_same_ms
  5. Eval rate_tip.cheapest after tip update

Ideal tip would uses rate_shop, but engine panics on tip → rate_shop → quote data-target chains; tip→quote (same depth as rate_shop→quote) works.

Column Operation
compile_ms Full logistics ingest + light tip
restore_ms Engine.fromSnapshot
upd_tip_ms update(rate_tip) with surcharge tip
upd_tip_same_ms Identical tip update
eval_after_tip_ms rate_tip.cheapest after tip update
ok Matches expected (first quote total + 100)

Micro shapes still report engine_load_ms = Engine.load of Spec text (no snapshot round-trip).

Java API

import com.lemmabase.lemma.Engine;
import com.lemmabase.lemma.Response;
import com.lemmabase.lemma.RuleResult;
import com.lemmabase.lemma.RunRequest;
import java.math.BigDecimal;
import java.util.Map;

try (Engine engine = Engine.create()) {
  engine.load("""
      spec order
      data quantity: number
      data unit_price: number
      rule total: quantity * unit_price
      """);

  Response response =
      engine.run(
          RunRequest.of("order")
              .data(
                  Map.of(
                      "quantity", 3,
                      "unit_price", new BigDecimal("19.99"))));

  RuleResult.Number total = (RuleResult.Number) response.results().get("total");
  BigDecimal amount = total.number();
}

Use BigDecimal or integers for decimals; float and double are rejected. Override limits with Engine.create(ResourceLimits.builder()...). Engine serializes calls on an internal lock.

Measured (logistics ladder)

Java SDK timings for this harness are in RESULTS.md, including Drools side-by-side numbers.

Figures below are from the Lemma engine’s release snapshot bench (cargo benchmarks engine), same machine as the engine benchmarks doc, on fixtures byte-identical to SpecGenerator.logistics. Source of truth: engine benchmarks.

Profile Rate cells Source Load Snapshot Restore
ground 1050 0.1 MiB 147 ms 0.9 MiB 5.7 ms
carrier 6300 0.5 MiB 1.2 s 5.0 MiB 29 ms
d2c 18900 1.5 MiB 3.7 s 14.9 MiB 83 ms
enterprise 126000 10.1 MiB 32.3 s 101.4 MiB 537 ms

Run the same ladder through this harness with --shape logistics or --shape snapshot and the --rules presets in Run.

About

Benchmarks and a logistics system simulation with the Java SDK

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages