@unitpad/modules 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bowen Deng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,35 @@
1
- # Temporary Holding Version
1
+ # @unitpad/modules
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The numbers that [UnitPad](https://unitpad.app) sheets import with `use`: latencies, throughputs, sizes, prices and limits for
4
+ system design, each with its source. They are plain [Numbat](https://numbat.dev) modules, so they work in UnitPad and in the Numbat
5
+ command line.
6
+
7
+ ```numbat
8
+ use latency::hardware
9
+ use throughput::s3
10
+
11
+ latency_main_memory / latency_l1_cache
12
+ throughput_s3_get_requests_per_prefix * 4
13
+ ```
14
+
15
+ ## In UnitPad
16
+
17
+ Open the Modules menu, or type `use` in a sheet. The module's card shows its source and the month its numbers were last checked.
18
+
19
+ ## In the Numbat command line
20
+
21
+ ```bash
22
+ npm install @unitpad/modules
23
+ export NUMBAT_MODULES_PATH="$PWD/node_modules/@unitpad/modules/modules"
24
+ ```
25
+
26
+ Not run yet. To have the shared count units (`request`, `message`, `IOPS`) in every session, put `use units::systems` in your `init.nbt`.
27
+
28
+ ## Licence
29
+
30
+ MIT. See [`LICENSE`](LICENSE).
31
+
32
+ ## Contribute
33
+
34
+ Fix an outdated number, add a module, or replace a dead source. [`CONTRIBUTING.md`](CONTRIBUTING.md) says how, and
35
+ [`docs/style.md`](docs/style.md) says how a module is written.
@@ -0,0 +1,66 @@
1
+ # Availability and durability
2
+ # Nines, downtime budgets, composing components, and real failure rates.
3
+ # availability_serial / availability_parallel assume independent failures;
4
+ # correlated failures (same rack, AZ, deploy, config push) make reality worse.
5
+ # Import with: use availability then use the availability_* values and functions
6
+ # title: Availability
7
+ # checked: unverified
8
+ # description: Nines and downtime budgets, serial/parallel composition, disk AFR, S3/EC2 durability and SLAs
9
+ # vendor: aws, backblaze
10
+
11
+ @url("https://en.wikipedia.org/wiki/High_availability")
12
+ @description("Availability with n nines (n ≥ 0): availability_nines(4) is 0.9999")
13
+ @example("availability_nines(4)")
14
+ fn availability_nines(n: Scalar) -> Scalar = 1 - 10^(-n)
15
+
16
+ @url("https://en.wikipedia.org/wiki/High_availability")
17
+ @description("Downtime per year at availability fraction a (0 ≤ a ≤ 1; pass 0.999 or 99.9%, not 99.9). 99.9% is ~8.8 h, 99.99% is ~53 min, 99.999% is ~5.3 min")
18
+ @example("availability_downtime_year(0.999)")
19
+ fn availability_downtime_year(a: Scalar) -> Time = (1 - a) * 1 year
20
+
21
+ @url("https://en.wikipedia.org/wiki/High_availability")
22
+ @description("Average downtime per month at availability fraction a (0 ≤ a ≤ 1; pass 0.999 or 99.9%, not 99.9), using Numbat's average month unit. 99.9% is ~44 min, 99.99% is ~4.4 min")
23
+ @example("availability_downtime_month(0.999)")
24
+ fn availability_downtime_month(a: Scalar) -> Time = (1 - a) * 1 month
25
+
26
+ @url("https://en.wikipedia.org/wiki/Reliability_engineering")
27
+ @description("Availability of two components in series (both must work): multiply their availability fractions a and b, each from 0 to 1")
28
+ @example("availability_serial(0.99, 0.999)")
29
+ fn availability_serial(a: Scalar, b: Scalar) -> Scalar = a * b
30
+
31
+ @url("https://en.wikipedia.org/wiki/Reliability_engineering")
32
+ @description("Availability of n independent replicas where any one suffices: 1 - (1 - a)^n. Pass availability a from 0 to 1 and a nonnegative replica count n")
33
+ @example("availability_parallel(0.99, 3)")
34
+ fn availability_parallel(a: Scalar, n: Scalar) -> Scalar = 1 - (1 - a)^n
35
+
36
+ # --- Measured failure rates ---
37
+ # highlight: HDD AFR
38
+ @url("https://www.backblaze.com/blog/backblaze-drive-stats-for-2025/")
39
+ @description("Hard drive annualized failure rate (Backblaze 2025: 1.36% across ~344k drives; lifetime 1.30%)")
40
+ let availability_hdd_afr = 0.0136
41
+
42
+ @url("https://docs.aws.amazon.com/ebs/latest/userguide/general-purpose.html")
43
+ @description("EBS gp3/gp2 volume annual failure rate (AWS: no higher than 0.2%)")
44
+ let availability_ebs_afr = 0.002
45
+
46
+ # --- Provider design targets and SLAs ---
47
+ # highlight: S3 durability
48
+ @url("https://aws.amazon.com/s3/storage-classes/")
49
+ @description("S3 Standard designed durability (11 nines)")
50
+ let availability_s3_durability = 0.99999999999
51
+
52
+ @url("https://aws.amazon.com/s3/storage-classes/")
53
+ @description("S3 Standard designed availability (99.99%)")
54
+ let availability_s3_designed = 0.9999
55
+
56
+ @url("https://aws.amazon.com/s3/sla/")
57
+ @description("S3 Standard availability SLA, what AWS credits against (99.9%)")
58
+ let availability_s3_sla = 0.999
59
+
60
+ @url("https://aws.amazon.com/compute/sla/")
61
+ @description("EC2 region-level SLA for instances spread over multiple AZs (99.99%)")
62
+ let availability_ec2_region_sla = 0.9999
63
+
64
+ @url("https://aws.amazon.com/compute/sla/")
65
+ @description("EC2 single-instance SLA (99.5%, ~3.6 h/month)")
66
+ let availability_ec2_instance_sla = 0.995
@@ -0,0 +1,67 @@
1
+ # Capacity-planning rules of thumb
2
+ # Peak traffic, utilization headroom, Little's Law, queueing, fan-out tails and USL.
3
+ # Import with: use capacity then use the capacity_* values and functions
4
+ # title: Capacity
5
+ # checked: unverified
6
+ # description: Peak factor, utilization target, node sizing, queueing (Little's Law, M/M/1, USL) and fan-out tail math
7
+
8
+ # highlight: peak factor
9
+ @description("Peak-to-average traffic factor (2-5; rule of thumb with no primary source, replace with your measured peak/avg)")
10
+ let capacity_peak_factor = 3
11
+
12
+ # highlight: target util
13
+ @url("https://en.wikipedia.org/wiki/M/M/1_queue")
14
+ @description("Keep steady-state utilization below this; single-server queueing delay grows as rho/(1-rho)")
15
+ let capacity_target_utilization = 0.7
16
+
17
+ # highlight: seconds/day
18
+ @url("https://en.wikipedia.org/wiki/Day")
19
+ @description("Seconds per day (~10^5 s, so QPS is roughly daily actions / 86_400 s)")
20
+ let capacity_seconds_per_day = 86_400 s
21
+
22
+ @url("https://en.wikipedia.org/wiki/Little%27s_law")
23
+ @description("Concurrency in flight (Little's Law, L = lambda * W): rate times time")
24
+ @example("capacity_concurrency(200 request/s, 0.5 s)")
25
+ fn capacity_concurrency<R: Dim>(rate: R / Time, w: Time) -> R = rate * w
26
+
27
+ @url("https://en.wikipedia.org/wiki/M/M/1_queue")
28
+ @description("M/M/1 mean queueing delay in units of service time, rho/(1-rho); requires 0 ≤ rho < 1. Values: 1.0 at 50%, 2.3 at 70%, 9.0 at 90%. A pool of many workers (M/M/c) queues far less at the same rho")
29
+ @example("capacity_wait_multiplier(0.7)")
30
+ fn capacity_wait_multiplier(rho: Scalar) -> Scalar = rho / (1 - rho)
31
+
32
+ @url("https://en.wikipedia.org/wiki/M/M/1_queue")
33
+ @description("M/M/1 mean response time in units of service time, 1/(1-rho); requires 0 ≤ rho < 1. Values: 2x at 50%, 3.3x at 70%, 10x at 90%")
34
+ @example("capacity_response_multiplier(0.7)")
35
+ fn capacity_response_multiplier(rho: Scalar) -> Scalar = 1 / (1 - rho)
36
+
37
+ @url("https://en.wikipedia.org/wiki/M/M/c_queue")
38
+ @description("Nodes so each runs at or below a given utilization (0 < utilization ≤ 1): ceil(load / (per_node * utilization))")
39
+ @example("capacity_nodes_with_utilization(5000 request/s, 1000 request/s, 0.7)")
40
+ fn capacity_nodes_with_utilization<D: Dim>(load: D, per_node: D, utilization: Scalar) -> Scalar =
41
+ ceil(load / (per_node * utilization))
42
+
43
+ @url("https://en.wikipedia.org/wiki/M/M/c_queue")
44
+ @description("Nodes so each runs at or below capacity_target_utilization (the module default). Pass your own utilization with capacity_nodes_with_utilization")
45
+ @example("capacity_nodes(5000 request/s, 1000 request/s)")
46
+ fn capacity_nodes<D: Dim>(load: D, per_node: D) -> Scalar =
47
+ capacity_nodes_with_utilization(load, per_node, capacity_target_utilization)
48
+
49
+ @url("https://cacm.acm.org/research/the-tail-at-scale/")
50
+ @description("Fraction of fan-out requests that hit at least one slow backend: 1 - (1 - p_slow)^n. 1% slow over 100 backends is 63%")
51
+ @example("capacity_fanout_slow(0.01, 100)")
52
+ fn capacity_fanout_slow(p_slow: Scalar, n: Scalar) -> Scalar = 1 - (1 - p_slow)^n
53
+
54
+ @url("https://sre.google/sre-book/addressing-cascading-failures/")
55
+ @description("Load amplification when every layer retries: attempts^depth (Google SRE: 3 retries = 4 attempts at 3 layers is 64x)")
56
+ @example("capacity_retry_amplification(4, 3)")
57
+ fn capacity_retry_amplification(attempts: Scalar, depth: Scalar) -> Scalar = attempts^depth
58
+
59
+ @url("http://www.perfdynamics.com/Manifesto/USLscalability.html")
60
+ @description("Universal Scalability Law relative throughput C(N) for node count N > 0, contention alpha ≥ 0, and coherency beta ≥ 0")
61
+ @example("capacity_usl(8, 0.1, 0.01)")
62
+ fn capacity_usl(n: Scalar, alpha: Scalar, beta: Scalar) -> Scalar = n / (1 + alpha * (n - 1) + beta * n * (n - 1))
63
+
64
+ @url("http://www.perfdynamics.com/Manifesto/USLscalability.html")
65
+ @description("Node count where USL throughput peaks, N* = sqrt((1 - alpha) / beta). Requires 0 ≤ alpha < 1 and beta > 0")
66
+ @example("capacity_usl_peak_nodes(0.1, 0.01)")
67
+ fn capacity_usl_peak_nodes(alpha: Scalar, beta: Scalar) -> Scalar = sqrt((1 - alpha) / beta)
@@ -0,0 +1,74 @@
1
+ # AWS list prices, us-east-1
2
+ # On-demand list prices; tiers, savings plans and other regions differ.
3
+ # Prices use the built-in `USD` unit (dimension Money).
4
+ # Import with: use cost then use the cost_* values
5
+ # usage: cost_s3_storage * 10 TB * 1 year -> USD
6
+ # usage: cost_ec2_vcpu * 8 vcpu * 1 hour -> USD
7
+ # usage: cost_s3_put * 100_000 request -> USD
8
+ # usage: cost_ebs_gp3_iops * 1_000 IOPS * 1 month -> USD
9
+ # usage: cost_dynamodb_write * 1_000_000 dynamodb_write_request_unit -> USD
10
+ # title: Cost (AWS)
11
+ # checked: 2026-10
12
+ # description: AWS us-east-1 list prices: compute, S3, EBS, DynamoDB and data transfer
13
+ # vendor: aws
14
+ # source: https://aws.amazon.com/pricing/
15
+
16
+ # --- Compute ---
17
+ # `vcpu` is a shared unit (`units::systems::compute`), so per-vCPU prices scale by a typed vCPU count.
18
+
19
+ # highlight: m7i.large
20
+ @url("https://instances.vantage.sh/aws/ec2/m7i.large")
21
+ @description("EC2 m7i.large on-demand, Linux (2 vCPU, 8 GiB)")
22
+ let cost_ec2_m7i_large = 0.1008 USD / hour
23
+
24
+ @url("https://instances.vantage.sh/aws/ec2/m7i.large")
25
+ @description("EC2 general-purpose price per vCPU-hour, 4 GiB RAM per vCPU (cost_ec2_m7i_large / (2 vcpu))")
26
+ let cost_ec2_vcpu = cost_ec2_m7i_large / (2 vcpu)
27
+
28
+ # --- S3 Standard ---
29
+ # highlight: S3 storage
30
+ @url("https://aws.amazon.com/s3/pricing/")
31
+ @description("S3 Standard storage, first 50 TB")
32
+ let cost_s3_storage = 0.023 USD / GB / month
33
+
34
+ # S3 request prices are billed per request, so multiplying by a typed request
35
+ # count produces USD.
36
+ @url("https://aws.amazon.com/s3/pricing/")
37
+ @description("S3 PUT/COPY/POST/LIST, per request ($0.005 per 1,000)")
38
+ let cost_s3_put = 0.005 USD / (1000 request)
39
+
40
+ @url("https://aws.amazon.com/s3/pricing/")
41
+ @description("S3 GET, per request ($0.0004 per 1,000)")
42
+ let cost_s3_get = 0.0004 USD / (1000 request)
43
+
44
+ # --- EBS ---
45
+ @url("https://aws.amazon.com/ebs/pricing/")
46
+ @description("EBS gp3 storage (includes 3,000 IOPS and 125 MB/s)")
47
+ let cost_ebs_gp3 = 0.08 USD / GB / month
48
+
49
+ @url("https://aws.amazon.com/ebs/pricing/")
50
+ @description("EBS gp3 IOPS above the 3,000 baseline, per provisioned IOPS-month")
51
+ let cost_ebs_gp3_iops = 0.005 USD / IOPS / month
52
+
53
+ # --- DynamoDB on-demand ---
54
+ # Priced per read and write request unit (`dynamodb_rru`, `dynamodb_wru`), which
55
+ # the shared `units` module defines so `throughput::db` caps use them too.
56
+
57
+ @url("https://aws.amazon.com/dynamodb/pricing/on-demand/")
58
+ @description("DynamoDB on-demand write, per write request unit ($0.625 per million)")
59
+ let cost_dynamodb_write = 0.625 USD / (1_000_000 dynamodb_write_request_unit)
60
+
61
+ @url("https://aws.amazon.com/dynamodb/pricing/on-demand/")
62
+ @description("DynamoDB on-demand read, per read request unit ($0.125 per million)")
63
+ let cost_dynamodb_read = 0.125 USD / (1_000_000 dynamodb_read_request_unit)
64
+
65
+ # --- Data transfer ---
66
+ # highlight: egress
67
+ @url("https://aws.amazon.com/s3/pricing/")
68
+ @description("Data transfer out to the internet, first 10 TB/month")
69
+ let cost_egress_internet = 0.09 USD / GB
70
+
71
+ # highlight: cross-AZ
72
+ @url("https://aws.amazon.com/ec2/pricing/on-demand/")
73
+ @description("Data transfer between AZs in a region, charged in each direction (so $0.02/GB per round trip; often dominates replication cost)")
74
+ let cost_cross_az = 0.01 USD / GB
@@ -0,0 +1,18 @@
1
+ # Dimensionless platform caps
2
+ # Counts that are neither time, rate nor bytes: concurrency and item counts.
3
+ # A count of something the shared units cover carries that unit; others are plain.
4
+ # Import with: use count then use the count_* values
5
+ # title: Count
6
+ # checked: unverified
7
+ # description: Dimensionless caps: concurrent executions and items per object
8
+ # vendor: aws
9
+
10
+ # highlight: Lambda concurrency
11
+ @url("https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html")
12
+ @description("Lambda default concurrent executions per region (adjustable to tens of thousands); in requests, so it compares with capacity_concurrency")
13
+ let count_lambda_concurrency = 1_000 request
14
+
15
+ # highlight: parts per object
16
+ @url("https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts.html")
17
+ @description("S3 maximum parts per multipart upload")
18
+ let count_s3_parts_max = 10_000
@@ -0,0 +1,70 @@
1
+ # Modern hardware latencies (2026)
2
+ # Bulk reads are derived from the throughput modules (size / bandwidth) so the
3
+ # two stay consistent; modules can't import each other, so the bandwidth is
4
+ # repeated inline and named in each description.
5
+ # Import with: use latency::hardware then use the latency_hardware_* values
6
+ # title: Latency (hardware)
7
+ # checked: unverified
8
+ # description: Current memory, NVMe, SSD, HDD, fsync, EBS and context-switch latencies (2026)
9
+
10
+ # --- Memory ---
11
+ # highlight: 1 MB memory
12
+ @url("https://www.cs.virginia.edu/stream/")
13
+ @description("Read 1 MB sequentially from memory on one core (1 MB / throughput_dram_core 20 GB/s)")
14
+ let latency_hardware_read_1mb_memory = 1 MB / (20 GB/s)
15
+
16
+ @url("https://eli.thegreenplace.net/2018/measuring-context-switching-and-memory-overheads-for-linux-threads/")
17
+ @description("Linux thread context switch, direct cost (measured 1.2-1.5 us pinned, ~2.2 us unpinned)")
18
+ let latency_hardware_context_switch = 1.5 us
19
+
20
+ # --- NVMe / SSD ---
21
+ # highlight: NVMe 4K QD1
22
+ @url("https://simplyblock.io/glossary/nvme-latency/")
23
+ @description("NVMe random 4 KB read at queue depth 1 (20-100 us; set by NAND read time, not PCIe generation)")
24
+ let latency_hardware_nvme_read_4kb = 60 us
25
+
26
+ @url("https://semiconductor.samsung.com/ssd/enterprise-ssd/pm1743/")
27
+ @description("Read 1 MB sequentially from a PCIe 5.0 NVMe SSD (1 MB / 14 GB/s)")
28
+ let latency_hardware_read_1mb_nvme = 1 MB / (14 GB/s)
29
+
30
+ @url("https://en.wikipedia.org/wiki/Solid-state_drive")
31
+ @description("Read 1 MB sequentially from a SATA SSD (1 MB / 550 MB/s)")
32
+ let latency_hardware_read_1mb_sata_ssd = 1 MB / (550 MB/s)
33
+
34
+ # highlight: fsync SSD
35
+ @url("https://etcd.io/docs/v3.5/op-guide/performance/")
36
+ @description("fsync/fdatasync on SSD (etcd docs: often under 1 ms; enterprise drives with power-loss protection are ~tens of us)")
37
+ let latency_hardware_fsync_ssd = 1 ms
38
+
39
+ # --- HDD (7,200 RPM) ---
40
+ # highlight: HDD random
41
+ @url("https://en.wikipedia.org/wiki/IOPS")
42
+ @description("HDD random 4 KB access, seek + rotation (1 / 75-80 IOPS; half a rotation alone is 4.17 ms)")
43
+ let latency_hardware_hdd_random_access = 13 ms
44
+
45
+ @url("https://en.wikipedia.org/wiki/Hard_disk_drive")
46
+ @description("Read 1 MB sequentially from HDD (1 MB / 200 MB/s)")
47
+ let latency_hardware_read_1mb_hdd = 1 MB / (200 MB/s)
48
+
49
+ @url("https://etcd.io/docs/v3.5/op-guide/performance/")
50
+ @description("fsync/fdatasync on a spinning disk (etcd docs: about 10 ms)")
51
+ let latency_hardware_fsync_hdd = 10 ms
52
+
53
+ # --- Cloud block storage ---
54
+ # highlight: EBS io2
55
+ @url("https://docs.aws.amazon.com/ebs/latest/userguide/general-purpose.html")
56
+ @description("EBS io2 Block Express I/O, average for 16 KiB (AWS: under 500 us)")
57
+ let latency_hardware_ebs_io2 = 500 us
58
+
59
+ @url("https://docs.aws.amazon.com/ebs/latest/userguide/general-purpose.html")
60
+ @description("EBS gp3 I/O (AWS: single-digit millisecond; ~1 ms typical)")
61
+ let latency_hardware_ebs_gp3 = 1 ms
62
+
63
+ # --- CPU work ---
64
+ @url("https://github.com/facebook/zstd")
65
+ @description("Compress 1 MB with zstd -1 on one core (1 MB / 510 MB/s; ratio ~2.9 on Silesia)")
66
+ let latency_hardware_compress_1mb_zstd = 1 MB / (510 MB/s)
67
+
68
+ @url("https://github.com/facebook/zstd")
69
+ @description("Decompress 1 MB with zstd on one core (1 MB / 1,550 MB/s)")
70
+ let latency_hardware_decompress_1mb_zstd = 1 MB / (1550 MB/s)
@@ -0,0 +1,98 @@
1
+ # LLM latency numbers (2026)
2
+ # Hosted-model speeds move every few months: re-check per model on Artificial
3
+ # Analysis, which measures output tokens/s and time to first token per API.
4
+ # Decode is memory-bandwidth bound, so latency_llm_decode_token gives a floor
5
+ # from first principles.
6
+ # Import with: use latency::llm then use the latency_llm_* values and functions
7
+ # title: Latency (LLM)
8
+ # checked: unverified
9
+ # description: Token generation and first-token latencies, GPU memory bandwidth and compute, and decode/prefill/KV-cache math (2026)
10
+ # vendor: nvidia
11
+ # source: https://artificialanalysis.ai/
12
+
13
+ # --- Measured magnitudes (order of magnitude; varies ~3x by model and provider) ---
14
+ # highlight: token
15
+ @url("https://artificialanalysis.ai/")
16
+ @description("Generate one token on a small local model on a GPU (~50-150 tokens/s)")
17
+ let latency_llm_local_token = 15 ms
18
+
19
+ @url("https://artificialanalysis.ai/")
20
+ @description("Generate one token on a hosted frontier model (~30-150 tokens/s)")
21
+ let latency_llm_frontier_token = 20 ms
22
+
23
+ @url("https://artificialanalysis.ai/")
24
+ @description("Time to first token, small local model, short prompt")
25
+ let latency_llm_local_first_token = 75 ms
26
+
27
+ @url("https://artificialanalysis.ai/")
28
+ @description("Generate one token on a small local model (CPU only, ~10 tokens/s)")
29
+ let latency_llm_local_cpu_token = 100 ms
30
+
31
+ @url("https://artificialanalysis.ai/")
32
+ @description("Time to first token on specialized inference hardware")
33
+ let latency_llm_fast_first_token = 250 ms
34
+
35
+ # highlight: first token
36
+ @url("https://artificialanalysis.ai/")
37
+ @description("Time to first token, frontier model, short prompt, no cache (~0.5-2 s)")
38
+ let latency_llm_frontier_first_token = 1 s
39
+
40
+ # highlight: reply
41
+ @url("https://artificialanalysis.ai/")
42
+ @description("Short response (~100 output tokens): first token + 100 x token time")
43
+ let latency_llm_frontier_response = 3 s
44
+
45
+ @url("https://artificialanalysis.ai/")
46
+ @description("Long context prefill (~100K input tokens, no cache; prefill runs ~5k-20k tokens/s)")
47
+ let latency_llm_frontier_prefill = 10 s
48
+
49
+ # highlight: reasoning
50
+ @url("https://artificialanalysis.ai/")
51
+ @description("Reasoning response (single call with thinking; 5 s to minutes)")
52
+ let latency_llm_frontier_reasoning = 30 s
53
+
54
+ # --- Tokens ---
55
+ @url("https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them")
56
+ @description("Tokens per English word (~1.3; 1 token is ~0.75 words or ~4 characters; tokenizer-specific)")
57
+ let latency_llm_tokens_per_word = 1.33
58
+
59
+ # --- GPU memory bandwidth (decode reads every weight once per token) ---
60
+ @url("https://www.nvidia.com/en-us/data-center/h100/")
61
+ @description("NVIDIA H100 SXM HBM bandwidth (3.35 TB/s, 80 GB)")
62
+ let latency_llm_hbm_h100 = 3.35 TB/s
63
+
64
+ # highlight: H200 HBM
65
+ @url("https://www.nvidia.com/en-us/data-center/h200/")
66
+ @description("NVIDIA H200 HBM bandwidth (4.8 TB/s, 141 GB)")
67
+ let latency_llm_hbm_h200 = 4.8 TB/s
68
+
69
+ @url("https://www.nvidia.com/en-us/data-center/dgx-b200/")
70
+ @description("NVIDIA B200 HBM bandwidth per GPU (DGX B200: 64 TB/s across 8 GPUs, 1,440 GB total)")
71
+ let latency_llm_hbm_b200 = 8 TB/s
72
+
73
+ @url("https://www.nvidia.com/en-us/data-center/h100/")
74
+ @description("Decode floor per token at batch size 1: weight bytes / memory bandwidth (70B params x 2 B on one H100: ~42 ms)")
75
+ @example("latency_llm_decode_token(140 GB, 3.35 TB/s)")
76
+ fn latency_llm_decode_token(weights: DigitalInformation, bandwidth: DigitalInformation / Time) -> Time = weights / bandwidth
77
+
78
+ # --- GPU compute (prefill is compute bound: every prompt token runs every weight) ---
79
+ # highlight: H100 BF16
80
+ @url("https://www.nvidia.com/en-us/data-center/h100/")
81
+ @description("NVIDIA H100 SXM dense BF16 tensor compute (~989 TFLOP/s; the spec sheet's 1,979 is with sparsity). Real kernels reach ~40-60% of it")
82
+ let latency_llm_flop_h100 = 989 TFLOP/s
83
+
84
+ @url("https://arxiv.org/abs/2001.08361")
85
+ @description("Forward-pass compute for a dense transformer: 2 x params x tokens (Kaplan et al. 2020, C_forward ≈ 2N per token; attention adds a little at long context)")
86
+ @example("latency_llm_forward_flop(70e9, 1_000) -> TFLOP")
87
+ fn latency_llm_forward_flop(params: Scalar, tokens: Scalar) -> FloatingPointOperation = 2 * params * tokens * FLOP
88
+
89
+ @url("https://arxiv.org/abs/2001.08361")
90
+ @description("Prefill floor: latency_llm_forward_flop(params, tokens) / (compute x utilization), with 0 < utilization ≤ 1 (70B params, 10K tokens, one H100 at 50%: ~2.8 s)")
91
+ @example("latency_llm_prefill(70e9, 10_000, latency_llm_flop_h100, 0.5)")
92
+ fn latency_llm_prefill(params: Scalar, tokens: Scalar, compute: FloatingPointOperation / Time, utilization: Scalar) -> Time =
93
+ latency_llm_forward_flop(params, tokens) / (compute * utilization)
94
+
95
+ @url("https://arxiv.org/abs/2309.06180")
96
+ @description("KV cache bytes per token: 2 (K and V) x layers x kv_heads x head_dim x bytes per value")
97
+ @example("latency_llm_kv_bytes_per_token(32, 8, 128, 2 B)")
98
+ fn latency_llm_kv_bytes_per_token(layers: Scalar, kv_heads: Scalar, head_dim: Scalar, bytes: DigitalInformation) -> DigitalInformation = 2 * layers * kv_heads * head_dim * bytes
@@ -0,0 +1,74 @@
1
+ # Network latency by geography, plus protocol round trips and clock error
2
+ # Physics sets the floor: light in fiber covers ~200 km per ms.
3
+ # Import with: use latency::network then use the latency_network_* values and functions
4
+ # title: Latency (network)
5
+ # checked: unverified
6
+ # description: Fiber speed, same-AZ / cross-AZ / cross-region RTTs, handshakes and clock uncertainty
7
+ # vendor: aws
8
+ # source: https://etcd.io/docs/v3.5/op-guide/performance/
9
+
10
+ # --- Physics ---
11
+ @url("https://en.wikipedia.org/wiki/Optical_fiber")
12
+ @description("Speed of light in fiber (c / refractive index ~1.47, about 204,000 km/s or ~5 us per km)")
13
+ let latency_network_fiber_speed = 299_792_458 m/s / 1.47
14
+
15
+ @url("https://en.wikipedia.org/wiki/Optical_fiber")
16
+ @description("Round-trip floor over fiber for a straight-line distance: 2 × distance / latency_network_fiber_speed; real routes are ~1.5-2x longer")
17
+ @example("latency_network_fiber_rtt(100 km)")
18
+ fn latency_network_fiber_rtt(distance: Length) -> Time = 2 * distance / latency_network_fiber_speed
19
+
20
+ # --- Cloud geography (AWS) ---
21
+ # highlight: same AZ
22
+ @url("https://www.bitsand.cloud/posts/cross-az-latencies")
23
+ @description("RTT within one availability zone (~50-200 us; estimate, AWS publishes no figure, measure with ping)")
24
+ let latency_network_same_az_rtt = 100 us
25
+
26
+ # highlight: cross AZ
27
+ @url("https://www.bitsand.cloud/posts/cross-az-latencies")
28
+ @description("RTT between AZs in one region (measured 0.39-2.42 ms across 28 regions, most under 1 ms; AWS: single-digit ms)")
29
+ let latency_network_cross_az_rtt = 1 ms
30
+
31
+ @url("https://www.cloudping.co/")
32
+ @description("RTT US East <-> US West (us-east-1 <-> us-west-2, ~60-70 ms; etcd docs: ~50 ms within the US)")
33
+ let latency_network_us_coast_rtt = 65 ms
34
+
35
+ # highlight: transatlantic
36
+ @url("https://www.cloudping.co/")
37
+ @description("RTT US East <-> Western Europe (us-east-1 <-> eu-west-1, ~70-80 ms)")
38
+ let latency_network_transatlantic_rtt = 75 ms
39
+
40
+ @url("https://www.cloudping.co/")
41
+ @description("RTT US West <-> Japan (us-west-2 <-> ap-northeast-1, ~100 ms)")
42
+ let latency_network_transpacific_rtt = 100 ms
43
+
44
+ @url("https://www.cloudping.co/")
45
+ @description("RTT US East <-> Australia (us-east-1 <-> ap-southeast-2, ~200 ms; etcd docs: up to 400 ms between continents)")
46
+ let latency_network_antipodal_rtt = 200 ms
47
+
48
+ # --- Last mile ---
49
+ @url("https://hpbn.co/mobile-networks/")
50
+ @description("Mobile (4G LTE) RTT to the first internet hop (~50 ms; 3G is several hundred ms)")
51
+ let latency_network_mobile_rtt = 50 ms
52
+
53
+ # --- Protocol round trips (multiply by the RTT) ---
54
+ @url("https://www.rfc-editor.org/rfc/rfc9293")
55
+ @description("Round trips for a TCP handshake before the first request byte")
56
+ let latency_network_tcp_handshake_rtts = 1
57
+
58
+ @url("https://www.rfc-editor.org/rfc/rfc8446")
59
+ @description("Extra round trips for a TLS 1.3 handshake (TLS 1.2 needs 2; 0-RTT resumption needs 0)")
60
+ let latency_network_tls13_handshake_rtts = 1
61
+
62
+ @url("https://www.rfc-editor.org/rfc/rfc8446")
63
+ @description("Time to the first response on a new TCP + TLS 1.3 connection: (latency_network_tcp_handshake_rtts + latency_network_tls13_handshake_rtts + 1) × rtt")
64
+ @example("latency_network_new_connection(20 ms)")
65
+ fn latency_network_new_connection(rtt: Time) -> Time = (latency_network_tcp_handshake_rtts + latency_network_tls13_handshake_rtts + 1) * rtt
66
+
67
+ # --- Clocks ---
68
+ @url("https://static.googleusercontent.com/media/research.google.com/en//archive/spanner-osdi2012.pdf")
69
+ @description("Spanner TrueTime uncertainty epsilon (sawtooth 1-7 ms, ~4 ms most of the time); NTP over the internet is similar or worse")
70
+ let latency_network_clock_uncertainty_truetime = 4 ms
71
+
72
+ @url("https://aws.amazon.com/about-aws/whats-new/2023/11/amazon-time-sync-service-microsecond-accurate-time/")
73
+ @description("Amazon Time Sync with PTP hardware clocks: microsecond-range accuracy on supported EC2 instances")
74
+ let latency_network_clock_uncertainty_ptp = 1 us
@@ -0,0 +1,67 @@
1
+ # Per-operation latencies of common infrastructure, as seen by a client in-region
2
+ # These are the numbers you add up in a request's latency budget. Medians unless noted.
3
+ # Import with: use latency::service then use the latency_service_* values
4
+ # title: Latency (service)
5
+ # checked: unverified
6
+ # description: Typical request latencies: Redis, SQL, DynamoDB, S3, Kafka, etcd/Raft, Lambda cold start
7
+ # vendor: aws, redis, kafka, etcd
8
+
9
+ # highlight: Redis GET
10
+ @url("https://redis.io/docs/latest/operate/oss_and_stack/management/optimization/benchmarks/")
11
+ @description("Redis GET/SET p50 in-AZ (~0.1-0.2 ms server-side on loopback plus one same-AZ RTT)")
12
+ let latency_service_redis_get = 0.3 ms
13
+
14
+ @url("https://www.cybertec-postgresql.com/en/postgres-scaling-advice-for-2021/")
15
+ @description("Relational point query by primary key, cached, in-AZ (~1 ms; estimate: tens of us of work plus RTT and driver overhead)")
16
+ let latency_service_sql_point_query = 1 ms
17
+
18
+ # highlight: DynamoDB
19
+ @url("https://aws.amazon.com/dynamodb/")
20
+ @description("DynamoDB GetItem/PutItem (AWS: single-digit millisecond at any scale)")
21
+ let latency_service_dynamodb = 5 ms
22
+
23
+ # highlight: S3 first byte
24
+ @url("https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimizing-performance.html")
25
+ @description("S3 Standard small-object / first-byte latency (AWS: roughly 100-200 ms)")
26
+ let latency_service_s3_first_byte = 150 ms
27
+
28
+ @url("https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-express-performance.html")
29
+ @description("S3 Express One Zone first-byte latency (AWS: consistent single-digit ms, up to 10x faster than Standard)")
30
+ let latency_service_s3_express_first_byte = 5 ms
31
+
32
+ # highlight: Kafka e2e
33
+ @url("https://engineering.linkedin.com/kafka/benchmarking-apache-kafka-2-million-writes-second-three-cheap-machines")
34
+ @description("Kafka produce-to-consume end to end, p50 (LinkedIn: 2 ms p50, 3 ms p99, 14 ms p99.9)")
35
+ let latency_service_kafka_e2e = 2 ms
36
+
37
+ @url("https://engineering.linkedin.com/kafka/benchmarking-apache-kafka-2-million-writes-second-three-cheap-machines")
38
+ @description("Kafka produce-to-consume end to end, p99.9 (LinkedIn benchmark)")
39
+ let latency_service_kafka_e2e_p999 = 14 ms
40
+
41
+ @url("https://developer.confluent.io/learn/kafka-performance/")
42
+ @description("Kafka produce-to-consume end to end, p99 (Confluent benchmark: 5 ms at 200 MB/s, 3 brokers, 1 KB messages, acks=all, min.insync.replicas=2, fsync off)")
43
+ let latency_service_kafka_e2e_p99 = 5 ms
44
+
45
+ # The produce / publish / commit / fetch split is config- and load-dependent (acks,
46
+ # ISR spread); only the config defaults below are documented bounds. See Confluent's
47
+ # breakdown: https://www.confluent.io/blog/configure-kafka-to-minimize-latency
48
+ @url("https://kafka.apache.org/documentation/#consumerconfigs")
49
+ @description("Kafka consumer fetch long-poll bound: fetch.max.wait.ms default (the broker waits up to this for fetch.min.bytes)")
50
+ let latency_service_kafka_fetch_max_wait = 500 ms
51
+
52
+ @url("https://kafka.apache.org/documentation/#brokerconfigs")
53
+ @description("Kafka ISR eviction threshold: replica.lag.time.max.ms default (a follower lagging longer is dropped from the in-sync replicas)")
54
+ let latency_service_kafka_replica_lag_max = 30 s
55
+
56
+ # highlight: consensus write
57
+ @url("https://etcd.io/docs/v3.5/op-guide/performance/")
58
+ @description("Consensus (Raft/etcd) write, light load: one member RTT plus fsync (etcd benchmark: 1.6 ms avg)")
59
+ let latency_service_consensus_write = 1.6 ms
60
+
61
+ @url("https://etcd.io/docs/v3.5/op-guide/performance/")
62
+ @description("etcd linearizable read, single connection (etcd benchmark: 0.7 ms; serializable 0.3 ms)")
63
+ let latency_service_consensus_read = 0.7 ms
64
+
65
+ @url("https://aws.amazon.com/blogs/compute/operating-lambda-performance-optimization-part-1/")
66
+ @description("AWS Lambda cold start (AWS: under 100 ms to over 1 s; under 1% of invocations)")
67
+ let latency_service_lambda_cold_start = 500 ms