Skip to content

feat(plan-selection): AWS Fargate us-east-1 price preset for cost model 1 - #756

Merged
zzylol merged 3 commits into
mainfrom
feat/fargate-price-preset
Oct 18, 2026
Merged

zzylol merged 3 commits into
mainfrom
feat/fargate-price-preset

Conversation

@zzylol

@zzylol zzylol commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Why

Plan selection prices candidates only with ResourceUnitCost::illustrative(), made-up numbers not tied to any provider. A deployment on AWS Fargate, billed per vCPU-second and per GB-second of memory (cost model 1), has to work out its own ResourceUnitCost by hand, and the selected plan's cost is not a dollar figure (#742).

What

  • ResourceUnitCost::aws_fargate_us_east_1(speed): AWS Fargate on-demand prices for US East (N. Virginia), Linux/x86, converted to the planner's units for cost model 1 at the deployment's resource speed; one cost unit is one US dollar.
  • stage_pipeline --cost-model aws-fargate-us-east-1: cost model 1 at those prices.
  • Rejection reasons show a nonzero cost below 0.001 in scientific notation (costlier: 2.699e-8 vs 2.361e-8 cost_per_second). Before, every dollar cost read 0.000. Costs at or above 0.001 keep three decimals, so the illustrative-price outputs are unchanged.

Only cost model 1 gets a preset. A provisioned (EC2-like) preset for cost model 2 is not part of this PR.

How

Source: https://aws.amazon.com/fargate/pricing/, checked 2026-10-18. That copy of the page left the per-hour rate tables empty. The numbers come from the page's Pricing Example 1 ("Using the Linux/X86 pricing for US East (N. Virginia) Region where CPU cost: $0.000011244 per vCPU second, memory cost: $0.000001235 per GB per second, and ephemeral storage cost: $0.0000000308 per GB per second"). Per hour, that is $0.0404784 per vCPU-hour and $0.004446 per GB-hour.

The preset takes the deployment's ResourceSpeed (PlanSelectionSettings::resource_speed), the speed Stage 3 uses for latency, so it charges exactly the core time the latency check counts. The values below are at the default ResourceSpeed::illustrative() (1e-6 ms per operation, so 1e9 operations per core-second, and 1e-7 ms per scanned byte).

Field Value Conversion / reason
cost_per_cpu_op $1.1244e-14 $0.000011244 per vCPU-second × ms_per_cpu_op / 1,000 (1e-9 s per operation)
cost_per_scanned_byte $1.1244e-15 $0.000011244 per vCPU-second × ms_per_scanned_byte / 1,000 (1e-10 s per byte). Fargate has no scan price, but a scan occupies the vCPU-seconds it bills.
cost_per_memory_byte_second ≈ $1.1502e-15 $0.000001235 per GB-second ÷ 2^30. The page says "on this page GB = 1024^3 bytes".
cost_per_disk_byte_second 0 Fargate bills only ephemeral storage configured beyond the 20 GB every task gets, and a per-byte price cannot express that. The disk bytes plan selection counts are raw data held by the data source, not by the task.
cost_per_provisioned_memory_byte_second 0 Cost model 2 field. Fargate's per-task billing is cost model 1.
cost_per_provisioned_cpu_core_second 0 Same reason. Under ProvisionedCapacity, every price the preset gives is 0, which PlanSelectionSettings::validate refuses (ZeroCalibration).

The per-second prices cannot express two parts of Fargate billing. First, the 1-minute minimum per task ("Pricing is calculated per second with a 1-minute minimum"). Second, the fixed task sizes a task is billed for (from 0.25 vCPU with 0.5 GB up), which round usage up to the next size. The doc comment states both.

Key code interfaces added / modified

crates/plan-selection/src/lib.rs

/// The price of one unit of each resource, per second of wall time. The type stays; it gains a preset.
impl ResourceUnitCost {
    /// The made-up prices plan selection uses until a deployment is calibrated (default).
    pub fn illustrative() -> Self;                 // unchanged
    /// AWS Fargate on-demand prices, us-east-1, Linux/x86, for cost model 1, in US dollars,
    /// with CPU prices converted at `speed` (the deployment's PlanSelectionSettings::resource_speed,
    /// which Stage 3 uses for latency); source URL, check date and each conversion in its doc comment.
    pub fn aws_fargate_us_east_1(speed: ResourceSpeed) -> Self; // new
}

/// A cost per second for a rejection reason: three decimals, or three significant digits
/// in scientific notation when nonzero and below 0.001. Private helper.
fn display_cost(cost_per_second: f64) -> String; // new (private)

crates/devtools/src/bin/stage_pipeline.rs

--cost-model usage-over-time        # unchanged: cost model 1, illustrative prices (default)
--cost-model aws-fargate-us-east-1  # new: cost model 1, ResourceUnitCost::aws_fargate_us_east_1(default resource_speed), dollars per second
--cost-model provisioned-capacity   # unchanged: cost model 2, illustrative prices
--cost-model cluster-capacity       # unchanged: cost model 3, with the --cluster-* flags

Usage

Example 4 (#509, planner-layering-3b: a monthly 300 s p99 over latency_ms with a rank ε = 0.01, δ = 0.01 target), priced at Fargate's prices. Verified at 64b8aae:

# The user picks the preset by name. stage_pipeline takes default_settings = PlanSelectionSettings::default()
# (resource_speed = ResourceSpeed::illustrative(): 1e-6 ms/op, 1e-7 ms/byte, also used for latency) and builds
# PlanSelectionSettings { cost_model: CostModel::UsageOverTime(
#     ResourceUnitCost::aws_fargate_us_east_1(default_settings.resource_speed)), ..default_settings }
# and Stage 3 (stage3_plan_selection) prices every valid candidate's ResourceUsage at those prices.
stage_pipeline --example planner-layering-3b --cost-model aws-fargate-us-east-1 --out ex4.json
# stage3_plan_selection in ex4.json: what the user gets back, in US dollars per second.
selected: P2                                             # whole-window KLL: 1,033,333 CPU ops/s + 10.67 MB/s scanned, no kept memory
costs.P2.cost_per_second    = 2.36124e-8                 # = 2.1 CPU-ms/s × $1.1244e-8 per CPU-ms
rejected P1:    costlier: 2.699e-8 vs 2.361e-8 cost_per_second   # exact plan, more CPU
rejected P3:    costlier: 2.455e-8 vs 2.361e-8 cost_per_second   # KLL panes at query time
rejected P3-m1: costlier: 1.226e-4 vs 2.361e-8 cost_per_second   # panes at ingestion: 106.6 GB kept × $1.1502e-15/byte-s
rejected P4, P5, P5-m1: accuracy_target_missed               # DDSketch: relative bound, rank target (unchanged)

The selection and ranking match the illustrative prices (P2 at 2.1 cost units/s). The ranking holds because Fargate's memory-to-CPU ratio (1 GiB-second ≈ 110 CPU-ms) is close to the illustrative one (1 GB-second = 125 CPU-ms).

Before this PR

The only prices were ResourceUnitCost::illustrative() (1 cost unit = 1 CPU-ms). stage_pipeline --cost-model accepted only usage-over-time, provisioned-capacity and cluster-capacity. A dollar-scale cost in a rejection reason would have printed as 0.000.

After this PR

A Fargate deployment passes CostModel::UsageOverTime(ResourceUnitCost::aws_fargate_us_east_1(settings.resource_speed)) (or --cost-model aws-fargate-us-east-1) and gets each candidate's cost in US dollars per second, with the source and check date recorded next to the numbers.

Limitations and follow-ups:

  • The prices are inputs that change. Re-check the page before relying on them.
  • The CPU conversion is only as good as the ResourceSpeed passed in. stage_pipeline has no speed flag, so it passes the default ResourceSpeed::illustrative (1e9 ops per core-second).
  • The 1-minute minimum and the fixed task sizes are not modelled (see How).
  • No cost model 2 (EC2-like) preset yet.
  • The prices are not exposed in the JSON settings, because feat(planner): plan_installable, the one call a deployment runtime makes (#749) #755 is not merged.

Verification

  • cargo nextest run -p asap-plan-selection -E 'test(aws_fargate)': the new aws_fargate_us_east_1_converts_the_page_prices checks each field against its documented conversion at the illustrative speed and at a core twice as slow (CPU and scan prices double, memory unchanged), that cost model 1 validates, and that cost model 2 is refused with ZeroCalibration. Passed.
  • cargo nextest run -p asap-devtools --test stage_pipeline: 23 passed, including the new aws_fargate_preset_prices_example_4_in_dollars (P2 selected at $2.36124e-8/s, P3-m1 ≈ $1.2262e-4/s, P1's reason in scientific notation) and the unchanged cost_model_flag_chooses_how_candidates_are_compared. The reason assertion failed before the formatting fix (costlier: 0.000 vs 0.000).
  • cargo fmt --all -- --check and cargo clippy -p asap-plan-selection -p asap-devtools --all-targets --all-features --locked -- -D warnings: clean.

Closes #742

…el 1

Add ResourceUnitCost::aws_fargate_us_east_1(): the per vCPU-second and
per GB-second prices from https://aws.amazon.com/fargate/pricing/
(checked 2026-10-18), converted to per CPU operation, per scanned byte
and per byte-second at ResourceSpeed::illustrative, the speed Stage 3
uses for latency. Disk and the provisioned prices are 0, with reasons.
stage_pipeline accepts --cost-model aws-fargate-us-east-1.

Closes #742
… rejection reasons

Under the dollar-priced Fargate preset every Example 4 cost is below
0.001, so "costlier: 0.000 vs 0.000 cost_per_second" hid the
comparison. Costs at or above 0.001 keep three decimals.
@zzylol zzylol added cost-model Cost formulas, statistics, ranking, and selection enhancement New feature or request labels Oct 18, 2026
… resource speed

aws_fargate_us_east_1 now takes the ResourceSpeed Stage 3 uses for
latency (PlanSelectionSettings::resource_speed) instead of reading
ResourceSpeed::illustrative; stage_pipeline passes its settings' speed.
The doc cites the page's "GB = 1024^3 bytes" and states what per-second
prices cannot express (1-minute minimum, fixed task sizes from
0.25 vCPU / 0.5 GB). Rename BYTES_PER_GB to BYTES_PER_GIB.
@zzylol
zzylol merged commit 4ef9f3e into main Oct 18, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cost-model Cost formulas, statistics, ranking, and selection enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plan selection: provider price presets for cost models 1 and 2 (#683 follow-up)

1 participant