Skip to main content

Recorded on 2026-09-01 with the JWT sessions of that day. The session paths and the token wording below describe that day, not the current design. For today's design read the Rails authentication pages and the JodApp Web authentication pages.

Web latency baseline — prod, measured on the web instance

This page holds one benchmark run. It measures how long the Jod web server and the Jod Rails API take to answer.

It exists to answer one question. Should a page fetch its data in a React Router loader() or in a clientLoader()?

  • A loader() runs on the web server. The web server calls the Rails API over a private name inside the VPC. Then it sends finished HTML to the browser. The user waits once.
  • A clientLoader() runs in the browser. The page shell arrives first. Then the browser calls the Rails API itself over the public internet, through Cloudflare. The user waits twice, and the second wait leaves the page half empty.

The two shapes pay different network costs. This run measures both costs so the choice rests on numbers, not on a guess.

This run is a baseline, not the final answer​

A new session middleware is coming to the web server. On every navigation that carries a session cookie, it will call GET /identities/sessions/current on the Rails API. That middleware does not exist yet. It did not run during this benchmark.

So treat these numbers as the "before" picture. Run the same script again after the middleware ships, with the same flags. Then put the two reports side by side.

What was measured, and from where​

ItemValue
Environmentprod
Modeserver (from the prod web instance)
Started (UTC)2026-09-01T14:56:34Z
Finished (UTC)2026-09-01T14:58:03Z
Run time89 seconds
Machine host nameip-10-0-143-187
Machine kernelLinux 6.8.0-1029-aws aarch64
curlcurl 8.5.0 (aarch64-unknown-linux-gnu) libcurl/8.5.0 OpenSSL/3.0.13 zlib/1.3 brotli/1.1.0 zstd/1.5.5 libidn2/2.3.7 libpsl/0.21.2 (+libidn2/2.3.7) libssh/0.10.6/openssl/zlib nghttp2/1.59.0 librtmp/2.3 OpenLDAP/2.6.7
Web instancejodapp.prod.web, private IP 10.0.143.187
Rails API instancejodapp.prod.api, private IP 10.0.155.4
Public web hostjodapp.com
Public API hostapi.jodapp.com
Private API hostapi.internal.jodapp.com
Measured requests per measurement20
Warm-up requests per measurement3
Total requests sent276
User-Agent, API requestsjod-latency-benchmark/1.0
User-Agent, page requestsMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 jod-latency-benchmark/1.0
Session cookiesupplied. Its value is not in this report.

Two notes on how the server-side run reaches its targets.

  • The Rails API is called by its private name, api.internal.jodapp.com. That name only resolves inside the VPC. This is the exact path a loader() uses.
  • Pages are called at http://localhost with the header Host: jodapp.com. The web app runs under Kamal 2. kamal-proxy listens on port 80 and forwards to the container on port 5173. It routes by host name, so the header is required.

These page numbers are the web server on its own. They leave out three things a real visitor pays for:

  • Cloudflare, which sits in front of the public host name
  • the HAProxy load balancer, which ends the TLS connection
  • the trip from the visitor to Singapore and back

The client-side mode measures those three. This mode measures what the web server itself costs.

The two API endpoints, and why there are two​

This report measures the Rails API twice, with two different endpoints. They answer different questions.

EndpointWhat it doesWhat its number means
/upThe Rails health route. It touches no database.The network floor. The smallest cost the path can have. No page ever calls it, so it is not the cost of a data fetch.
GET /identities/sessions/currentVerifies the JWT from the session cookie, then asks two services whether the user may enter the talent area and the employer area.One real signed-in fetch. This is what a page actually pays, and it is the endpoint the coming middleware calls.

The gap between the two is the Rails work. That split matters. Only one half of it changes when you move a fetch from the server to the browser.

  • The network half changes a lot. The private path stays inside the VPC. The public path crosses the internet and Cloudflare.
  • The Rails half does not change at all. The same query runs either way.

So read the two numbers together. Reading /up on its own leads to the wrong conclusion, in a way that is easy to miss.

  • The gap in milliseconds between the two paths is the same either way. The Rails work is added to both sides, so it cancels out.
  • What changes is how large that gap looks next to the whole wait.
  • On /up alone, the gap is almost the entire number. Next to a real fetch it is one part of a larger total.

That share is what the decision turns on. A gap of 30 ms matters a lot when the whole fetch takes 35 ms. It matters much less when the whole fetch takes 300 ms.

Does this environment serve the session endpoint?​

Environments do not always run the same build. So the script checks before it starts, instead of assuming. It sends one request with no cookie and reads the status code.

AnswerWhat it meansWhat the script does
401The route is there. The cookie is simply missing on a check request.Measures the real fetch.
404This Rails API does not serve the path.Skips the measurement, rather than recording 404 timings as a result.

On this run, /identities/sessions/current answered on prod. So the numbers below include one real signed-in fetch.

Why the GET, and not the session refresh​

The path /identities/sessions/current answers four verbs. Only one of them belongs in a benchmark.

VerbCan this benchmark use it?
GETYes. It changes nothing. It verifies the JWT, then asks two services whether the user may enter the talent area and the employer area.
PATCHNo. It rotates the JWT and sets new cookies. That is a write. It would also end the session being used to run the benchmark, because each call replaces the cookie the last one used.
POSTNo. It signs a user in. It is a write, and it needs a password.
DELETENo. It signs the user out. It is a write.

This script only ever sends GET requests. It never touches the other three.

The GET is the right one for a second reason. The coming middleware calls this exact endpoint on every request that carries a session cookie. So its cost is the cost the middleware will add.

A heavier endpoint to compare against​

The session endpoint is deliberately small. It answers who is signed in and where they may go, and it carries no page data.

For a heavier read, run the script again with --session-endpoint /identities/users/current. That one loads the user with about ten associated tables and serialises the lot. It shows what a fatter fetch costs on the same two paths.

How to read the numbers​

Every number in this report is milliseconds.

TermWhat it means
TTFB (time_starttransfer)The wait until the first byte of the response arrives. This is the wait the user feels.
Whole response (time_total)The wait until the last byte arrives. For a big HTML page this is larger than TTFB.
DNS (time_namelookup)Time spent turning the host name into an IP address.
TCP connect (time_connect)Time spent opening the TCP connection.
TLS handshake (time_appconnect)Time spent on the TLS handshake. It is 0 on plain HTTP.
Ready to send (time_pretransfer)Everything above, finished. The request has not left yet.

Two connection shapes appear below.

ShapeHow it was producedWhat it stands for
New connection each timeOne curl process per request. A new process cannot reuse a connection.The first call after a cold start. It pays DNS, TCP and TLS.
Connection reusedOne curl process, many URLs. curl keeps the connection open.Real life. Node's built-in fetch keeps connections alive by default, and so does a browser. Use this number when you reason about loader() and clientLoader().

In a reused-connection measurement the DNS, TCP and TLS rows read close to 0. That is correct. The connection was already open, so no time was spent opening it.

The p95 uses the nearest-rank method. Sort the samples, then take the sample at position ceil(0.95 times n). With 20 samples that is the 19th.

Warm-up requests are listed under each table. They are never mixed into min, median, mean, p95 or max.

Every page request carries a cb query parameter. Its value is different every time. So no cache can answer the request.

Every measured request sends Accept-Encoding for gzip, the way a browser and Node's fetch both do.

Warnings from this run​

Read these before you trust any number below.

  • Web server page /privacy, a light public page: the page did not stream. Time to first byte (976.13 ms) is almost the whole response (976.62 ms). The usual cause is that the page defers no data: with no Suspense boundary and no deferred loader value, React Router must resolve every loader before it sends any HTML, so nothing can arrive early. A User-Agent the server treats as a bot has the same effect. Neither is a fault in this script.
  • Web server page /jobs, a public list page: the page did not stream. Time to first byte (828.32 ms) is almost the whole response (829.29 ms). The usual cause is that the page defers no data: with no Suspense boundary and no deferred loader value, React Router must resolve every loader before it sends any HTML, so nothing can arrive early. A User-Agent the server treats as a bot has the same effect. Neither is a fault in this script.
  • Web server page /employers/dashboard, signed in: the page did not stream. Time to first byte (342.56 ms) is almost the whole response (343.16 ms). The usual cause is that the page defers no data: with no Suspense boundary and no deferred loader value, React Router must resolve every loader before it sends any HTML, so nothing can arrive early. A User-Agent the server treats as a bot has the same effect. Neither is a fault in this script.

Results​

Network floor, web server to Rails API, private name, new connection each time​

The smallest cost the private path can have. /up touches no database, so this is network time and nothing else.

  • URL: http://api.internal.jodapp.com/up
  • Connection shape: new connection each time
  • Requests: 3 warm-up, 20 measured
  • Connections opened: 23
  • Status codes: 200 x23
  • HTTP version: HTTP/1.1 x23
  • cf-cache-status: header not present
Measureminmedianmeanp95max
TTFB (time_starttransfer)5.936.436.527.108.19
Whole response (time_total)6.066.556.657.228.33
DNS (time_namelookup)1.021.191.281.812.62
TCP connect (time_connect)1.902.072.192.683.57
TLS handshake (time_appconnect)not usednot usednot usednot usednot used
Ready to send (time_pretransfer)1.952.122.232.723.62

All values are milliseconds.

The TLS row says "not used" because no TLS handshake happened. Either the request went over plain HTTP, or the connection was already open.

Warm-up requests. They are shown here and left out of the table above.

RequestTTFBWhole responseStatus
18.638.77200
26.626.75200
36.146.28200

Network floor, web server to Rails API, private name, connection reused​

The same network floor with the connection already open. No page ever calls /up, so this is not the cost of a data fetch.

  • URL: http://api.internal.jodapp.com/up
  • Connection shape: connection reused
  • Requests: 3 warm-up, 20 measured
  • Connections opened: 1
  • Status codes: 200 x23
  • HTTP version: HTTP/1.1 x23
  • cf-cache-status: header not present
Measureminmedianmeanp95max
TTFB (time_starttransfer)3.623.954.034.484.56
Whole response (time_total)3.694.024.124.584.67
DNS (time_namelookup)0.010.010.010.010.02
TCP connect (time_connect)0.000.000.000.000.00
TLS handshake (time_appconnect)not usednot usednot usednot usednot used
Ready to send (time_pretransfer)0.040.050.050.050.07

All values are milliseconds.

The TLS row says "not used" because no TLS handshake happened. Either the request went over plain HTTP, or the connection was already open.

Warm-up requests. They are shown here and left out of the table above.

RequestTTFBWhole responseStatus
16.726.86200
23.733.80200
34.074.17200

In this measurement request 1 also opened the connection. That is why it is slower than the rest.

Network floor, web server to Rails API over the PUBLIC host, new connection each time​

What the web server pays today to reach the Rails API, before the repointing. /up touches no database, so this is network only.

  • URL: https://api.jodapp.com/up
  • Connection shape: new connection each time
  • Requests: 3 warm-up, 20 measured
  • Connections opened: 23
  • Status codes: 200 x23
  • HTTP version: HTTP/2 x23
  • cf-cache-status: DYNAMIC x23
Measureminmedianmeanp95max
TTFB (time_starttransfer)60.30621.63667.251384.051516.95
Whole response (time_total)60.48621.85667.461384.241517.16
DNS (time_namelookup)0.800.871.141.056.10
TCP connect (time_connect)3.21140.86120.40219.67220.51
TLS handshake (time_appconnect)40.48290.17287.95450.38943.76
Ready to send (time_pretransfer)40.61290.32288.08450.52943.88

All values are milliseconds.

Warm-up requests. They are shown here and left out of the table above.

RequestTTFBWhole responseStatus
1554.29554.49200
2790.86791.04200
3856.60856.82200

Network floor, web server to Rails API over the PUBLIC host, connection reused​

The same, with the connection already open. Compare this against the private-name floor to see what the repointing saves.

  • URL: https://api.jodapp.com/up
  • Connection shape: connection reused
  • Requests: 3 warm-up, 20 measured
  • Connections opened: 1
  • Status codes: 200 x23
  • HTTP version: HTTP/2 x23
  • cf-cache-status: DYNAMIC x23
Measureminmedianmeanp95max
TTFB (time_starttransfer)12.2613.9213.7114.9115.18
Whole response (time_total)12.3814.0413.8415.0315.31
DNS (time_namelookup)0.010.010.010.020.02
TCP connect (time_connect)0.000.000.000.000.00
TLS handshake (time_appconnect)not usednot usednot usednot usednot used
Ready to send (time_pretransfer)0.060.070.070.080.11

All values are milliseconds.

The TLS row says "not used" because no TLS handshake happened. Either the request went over plain HTTP, or the connection was already open.

Warm-up requests. They are shown here and left out of the table above.

RequestTTFBWhole responseStatus
159.8860.07200
214.7214.87200
315.0715.18200

In this measurement request 1 also opened the connection. That is why it is slower than the rest.

One real signed-in fetch, web server over the PUBLIC host, new connection each time​

What one real API call inside a loader() costs today, before the repointing.

  • URL: https://api.jodapp.com/identities/sessions/current
  • Connection shape: new connection each time
  • Requests: 3 warm-up, 20 measured
  • Connections opened: 23
  • Status codes: 200 x23
  • HTTP version: HTTP/2 x23
  • cf-cache-status: DYNAMIC x23
  • Sent a session cookie. Its value is not in this report.
Measureminmedianmeanp95max
TTFB (time_starttransfer)65.96514.93443.41942.26965.22
Whole response (time_total)66.19515.13443.63942.47965.43
DNS (time_namelookup)0.790.861.161.006.81
TCP connect (time_connect)3.1789.8290.60177.64230.73
TLS handshake (time_appconnect)39.49186.69198.61364.56463.64
Ready to send (time_pretransfer)39.62186.83198.75364.72463.78

All values are milliseconds.

Warm-up requests. They are shown here and left out of the table above.

RequestTTFBWhole responseStatus
1746.50746.69200
269.4669.65200
3766.91767.29200

One real signed-in fetch, web server over the PUBLIC host, connection reused​

The number the repointing will change. Compare it against the same fetch over the private name.

  • URL: https://api.jodapp.com/identities/sessions/current
  • Connection shape: connection reused
  • Requests: 3 warm-up, 20 measured
  • Connections opened: 1
  • Status codes: 200 x23
  • HTTP version: HTTP/2 x23
  • cf-cache-status: DYNAMIC x23
  • Sent a session cookie. Its value is not in this report.
Measureminmedianmeanp95max
TTFB (time_starttransfer)21.1724.0224.2928.1829.14
Whole response (time_total)21.3024.1624.4228.3029.29
DNS (time_namelookup)0.010.020.020.020.03
TCP connect (time_connect)0.000.000.000.000.00
TLS handshake (time_appconnect)not usednot usednot usednot usednot used
Ready to send (time_pretransfer)0.080.090.090.130.13

All values are milliseconds.

The TLS row says "not used" because no TLS handshake happened. Either the request went over plain HTTP, or the connection was already open.

Warm-up requests. They are shown here and left out of the table above.

RequestTTFBWhole responseStatus
166.2366.42200
223.0523.20200
321.3021.44200

In this measurement request 1 also opened the connection. That is why it is slower than the rest.

One real signed-in fetch, private name, new connection each time​

What one real API call inside a loader() costs when the connection is new.

  • URL: http://api.internal.jodapp.com/identities/sessions/current
  • Connection shape: new connection each time
  • Requests: 3 warm-up, 20 measured
  • Connections opened: 23
  • Status codes: 200 x23
  • HTTP version: HTTP/1.1 x23
  • cf-cache-status: header not present
  • Sent a session cookie. Its value is not in this report.
Measureminmedianmeanp95max
TTFB (time_starttransfer)12.8314.4114.6516.8919.20
Whole response (time_total)13.0014.5414.8017.0219.34
DNS (time_namelookup)1.001.111.412.445.34
TCP connect (time_connect)1.892.022.333.336.27
TLS handshake (time_appconnect)not usednot usednot usednot usednot used
Ready to send (time_pretransfer)1.952.092.393.396.32

All values are milliseconds.

The TLS row says "not used" because no TLS handshake happened. Either the request went over plain HTTP, or the connection was already open.

Warm-up requests. They are shown here and left out of the table above.

RequestTTFBWhole responseStatus
113.4013.55200
215.4215.56200
314.9615.09200

One real signed-in fetch, private name, connection reused​

What one real API call inside a loader() costs in real life. Node keeps connections open, so this is the number the decision rests on.

  • URL: http://api.internal.jodapp.com/identities/sessions/current
  • Connection shape: connection reused
  • Requests: 3 warm-up, 20 measured
  • Connections opened: 1
  • Status codes: 200 x23
  • HTTP version: HTTP/1.1 x23
  • cf-cache-status: header not present
  • Sent a session cookie. Its value is not in this report.
Measureminmedianmeanp95max
TTFB (time_starttransfer)10.4811.3511.4012.1012.46
Whole response (time_total)10.5811.4711.5012.2012.55
DNS (time_namelookup)0.010.010.020.020.02
TCP connect (time_connect)0.000.000.000.000.00
TLS handshake (time_appconnect)not usednot usednot usednot usednot used
Ready to send (time_pretransfer)0.050.060.060.080.09

All values are milliseconds.

The TLS row says "not used" because no TLS handshake happened. Either the request went over plain HTTP, or the connection was already open.

Warm-up requests. They are shown here and left out of the table above.

RequestTTFBWhole responseStatus
114.4714.60200
211.2911.37200
312.3712.45200

In this measurement request 1 also opened the connection. That is why it is slower than the rest.

Web server page /up, the control​

The web server cost with no loader and no session code. Every other page number includes this cost.

  • URL: http://localhost/up
  • Host header: jodapp.com
  • Connection shape: new connection each time
  • Requests: 3 warm-up, 20 measured
  • Connections opened: 23
  • Status codes: 200 x23
  • HTTP version: HTTP/1.1 x23
  • cf-cache-status: header not present
Measureminmedianmeanp95max
TTFB (time_starttransfer)9.029.7711.7214.3938.40
Whole response (time_total)9.3010.1112.2214.6839.63
DNS (time_namelookup)0.020.020.020.020.02
TCP connect (time_connect)0.130.140.140.160.16
TLS handshake (time_appconnect)not usednot usednot usednot usednot used
Ready to send (time_pretransfer)0.170.180.180.200.20

All values are milliseconds.

The TLS row says "not used" because no TLS handshake happened. Either the request went over plain HTTP, or the connection was already open.

Warm-up requests. They are shown here and left out of the table above.

RequestTTFBWhole responseStatus
110.9211.67200
249.4649.86200
310.7511.01200

Web server page /privacy, a light public page​

A near-static page under the public root. It shows the render cost with almost no data fetching.

  • URL: http://localhost/privacy
  • Host header: jodapp.com
  • Connection shape: new connection each time
  • Requests: 3 warm-up, 20 measured
  • Connections opened: 23
  • Status codes: 200 x23
  • HTTP version: HTTP/1.1 x23
  • cf-cache-status: header not present
Measureminmedianmeanp95max
TTFB (time_starttransfer)927.99976.131065.111378.001684.85
Whole response (time_total)928.51976.621065.771378.691685.40
DNS (time_namelookup)0.020.020.020.030.04
TCP connect (time_connect)0.130.140.150.180.24
TLS handshake (time_appconnect)not usednot usednot usednot usednot used
Ready to send (time_pretransfer)0.170.180.190.270.28

All values are milliseconds.

The TLS row says "not used" because no TLS handshake happened. Either the request went over plain HTTP, or the connection was already open.

Warm-up requests. They are shown here and left out of the table above.

RequestTTFBWhole responseStatus
11424.111424.73200
2941.62942.15200
3971.24971.76200

Web server page /jobs, a public list page​

A public page whose loader() does real API work. No sign-in needed.

  • URL: http://localhost/jobs
  • Host header: jodapp.com
  • Connection shape: new connection each time
  • Requests: 3 warm-up, 20 measured
  • Connections opened: 23
  • Status codes: 200 x23
  • HTTP version: HTTP/1.1 x23
  • cf-cache-status: header not present
Measureminmedianmeanp95max
TTFB (time_starttransfer)808.86828.32902.891332.781332.99
Whole response (time_total)809.77829.29903.601333.451333.77
DNS (time_namelookup)0.020.020.020.020.04
TCP connect (time_connect)0.130.140.150.150.43
TLS handshake (time_appconnect)not usednot usednot usednot usednot used
Ready to send (time_pretransfer)0.170.180.190.190.48

All values are milliseconds.

The TLS row says "not used" because no TLS handshake happened. Either the request went over plain HTTP, or the connection was already open.

Warm-up requests. They are shown here and left out of the table above.

RequestTTFBWhole responseStatus
11172.111172.71200
21314.381315.11200
3824.92825.94200

Web server page /employers/dashboard, signed in​

The real employer journey. Its loader() fetches signed-in data from the Rails API.

  • URL: http://localhost/employers/dashboard
  • Host header: jodapp.com
  • Connection shape: new connection each time
  • Requests: 3 warm-up, 20 measured
  • Connections opened: 23
  • Status codes: 200 x23
  • HTTP version: HTTP/1.1 x23
  • cf-cache-status: header not present
  • Sent a session cookie. Its value is not in this report.
Measureminmedianmeanp95max
TTFB (time_starttransfer)325.68342.56486.361203.811224.30
Whole response (time_total)326.14343.16486.841204.181224.74
DNS (time_namelookup)0.020.020.020.020.06
TCP connect (time_connect)0.130.140.150.200.29
TLS handshake (time_appconnect)not usednot usednot usednot usednot used
Ready to send (time_pretransfer)0.180.190.230.350.71

All values are milliseconds.

The TLS row says "not used" because no TLS handshake happened. Either the request went over plain HTTP, or the connection was already open.

Warm-up requests. They are shown here and left out of the table above.

RequestTTFBWhole responseStatus
1334.67335.16200
2367.22367.71200
3334.21334.75200

What these numbers mean for loader() and clientLoader()​

What repointing the app at the private host will change​

This is the before-and-after. Both numbers below were measured on this machine, in this run, minutes apart. So they can be compared directly.

One API call from the web serverMedian
Today, over the public host api.jodapp.com24.02 ms
After repointing, over api.internal.jodapp.com11.35 ms
What the change saves, per API call12.67 ms
The same, for the /up network floorMedian
Today, over the public host13.92 ms
After repointing3.95 ms
What the change saves9.97 ms

Multiply the saving by the number of API calls one page render makes. That product is what the repointing takes off the page.

Every measurement in this run​

QuestionAnswer from this run
What will one real API call inside a loader() cost after repointing?11.35 ms, median, on a connection that is already open
How much of that is network?3.95 ms, median, the /up floor
How much of that is Rails work?7.40 ms
What does that real call cost when the connection is new?14.41 ms, median
What does opening the connection add?3.06 ms
What does the web server cost with no loader at all?10.11 ms, median, for /up
What does a light public page cost?976.62 ms, median, for /privacy
What does a public list page cost?829.29 ms, median, for /jobs
What does the signed-in employer dashboard cost?343.16 ms, median

Read it like this.

  • One real API call inside a loader() adds about 11.35 ms to the page. The connection is already open, so this is the honest number. Node keeps connections alive by default.
  • About 7.40 ms of that is Rails work: verifying the JWT, loading the user and its associated tables, and building the JSON. The rest is network.
  • The network on its own costs about 3.95 ms. That is /up, which touches no database. No page ever calls it. It is the smallest cost this path can have, not a result.
  • Opening a fresh connection costs about 3.06 ms more. The web server pays this once, not on every request.
  • The web server needs about 10.11 ms to answer /up. That page runs no loader and no session code. Every other page number includes this cost.
  • On /jobs, about 819.18 ms of the wait is loader work and rendering. That sits on top of the /up cost.
  • On /employers/dashboard, about 333.05 ms of the wait is loader work and rendering. That sits on top of the /up cost.

What the coming session middleware will cost​

The middleware will call the Rails API once per navigation that carries a session cookie. That call travels the same private path measured above.

On these numbers it will add about 11.35 ms to every such navigation, if it reuses the connection.

Two things could move that number.

  • The middleware may call a lighter endpoint than the one measured here. Then it costs less.
  • If the middleware opens a new connection each time, add the connection cost from the table above.

Run this script again after the middleware ships. Compare /privacy and /employers/dashboard between the two reports. The difference is what the middleware costs.

What is still missing​

This run only measured the server side. It cannot tell you what a clientLoader() costs. That call comes from the browser, over the public internet.

Run the client-side mode next, then read the two reports together: --mode client --env prod

The exact commands this run used​

Each line below sends one request. The script sent the same request many times.

For a reused-connection measurement, the script passed every URL to one curl call. curl then kept the connection open between them.

Network floor, web server to Rails API, private name, new connection each time​

curl -sS -o /dev/null -D - --compressed --max-time 20 -A 'jod-latency-benchmark/1.0' -w 'TIMING %{time_namelookup} %{time_connect} %{time_appconnect} %{time_pretransfer} %{time_starttransfer} %{time_total} %{http_code} %{size_download} %{num_connects} %{http_version}' 'http://api.internal.jodapp.com/up'

Network floor, web server to Rails API, private name, connection reused​

curl -sS -o /dev/null -D - --compressed --max-time 20 -A 'jod-latency-benchmark/1.0' -w 'TIMING %{time_namelookup} %{time_connect} %{time_appconnect} %{time_pretransfer} %{time_starttransfer} %{time_total} %{http_code} %{size_download} %{num_connects} %{http_version}' 'http://api.internal.jodapp.com/up'

Network floor, web server to Rails API over the PUBLIC host, new connection each time​

curl -sS -o /dev/null -D - --compressed --max-time 20 -A 'jod-latency-benchmark/1.0' -w 'TIMING %{time_namelookup} %{time_connect} %{time_appconnect} %{time_pretransfer} %{time_starttransfer} %{time_total} %{http_code} %{size_download} %{num_connects} %{http_version}' 'https://api.jodapp.com/up'

Network floor, web server to Rails API over the PUBLIC host, connection reused​

curl -sS -o /dev/null -D - --compressed --max-time 20 -A 'jod-latency-benchmark/1.0' -w 'TIMING %{time_namelookup} %{time_connect} %{time_appconnect} %{time_pretransfer} %{time_starttransfer} %{time_total} %{http_code} %{size_download} %{num_connects} %{http_version}' 'https://api.jodapp.com/up'

One real signed-in fetch, web server over the PUBLIC host, new connection each time​

curl -sS -o /dev/null -D - --compressed --max-time 20 -A 'jod-latency-benchmark/1.0' -K cookie.conf -w 'TIMING %{time_namelookup} %{time_connect} %{time_appconnect} %{time_pretransfer} %{time_starttransfer} %{time_total} %{http_code} %{size_download} %{num_connects} %{http_version}' 'https://api.jodapp.com/identities/sessions/current'

About cookie.conf:

  • It holds one line: header = "Cookie: ...".
  • The quotes are required. In a curl config file an unquoted value stops at the first space, and a cookie header always has spaces in it.
  • The script writes it into a private temporary folder, with file mode 600.
  • The script deletes it when it exits.
  • curl reads the cookie from that file, never from the command line. So the cookie never shows up in ps output.

One real signed-in fetch, web server over the PUBLIC host, connection reused​

curl -sS -o /dev/null -D - --compressed --max-time 20 -A 'jod-latency-benchmark/1.0' -K cookie.conf -w 'TIMING %{time_namelookup} %{time_connect} %{time_appconnect} %{time_pretransfer} %{time_starttransfer} %{time_total} %{http_code} %{size_download} %{num_connects} %{http_version}' 'https://api.jodapp.com/identities/sessions/current'

About cookie.conf:

  • It holds one line: header = "Cookie: ...".
  • The quotes are required. In a curl config file an unquoted value stops at the first space, and a cookie header always has spaces in it.
  • The script writes it into a private temporary folder, with file mode 600.
  • The script deletes it when it exits.
  • curl reads the cookie from that file, never from the command line. So the cookie never shows up in ps output.

One real signed-in fetch, private name, new connection each time​

curl -sS -o /dev/null -D - --compressed --max-time 20 -A 'jod-latency-benchmark/1.0' -K cookie.conf -w 'TIMING %{time_namelookup} %{time_connect} %{time_appconnect} %{time_pretransfer} %{time_starttransfer} %{time_total} %{http_code} %{size_download} %{num_connects} %{http_version}' 'http://api.internal.jodapp.com/identities/sessions/current'

About cookie.conf:

  • It holds one line: header = "Cookie: ...".
  • The quotes are required. In a curl config file an unquoted value stops at the first space, and a cookie header always has spaces in it.
  • The script writes it into a private temporary folder, with file mode 600.
  • The script deletes it when it exits.
  • curl reads the cookie from that file, never from the command line. So the cookie never shows up in ps output.

One real signed-in fetch, private name, connection reused​

curl -sS -o /dev/null -D - --compressed --max-time 20 -A 'jod-latency-benchmark/1.0' -K cookie.conf -w 'TIMING %{time_namelookup} %{time_connect} %{time_appconnect} %{time_pretransfer} %{time_starttransfer} %{time_total} %{http_code} %{size_download} %{num_connects} %{http_version}' 'http://api.internal.jodapp.com/identities/sessions/current'

About cookie.conf:

  • It holds one line: header = "Cookie: ...".
  • The quotes are required. In a curl config file an unquoted value stops at the first space, and a cookie header always has spaces in it.
  • The script writes it into a private temporary folder, with file mode 600.
  • The script deletes it when it exits.
  • curl reads the cookie from that file, never from the command line. So the cookie never shows up in ps output.

Web server page /up, the control​

curl -sS -o /dev/null -D - --compressed --max-time 20 -A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 jod-latency-benchmark/1.0' -H 'Host: jodapp.com' -H 'Accept: text/html,application/xhtml+xml' -w 'TIMING %{time_namelookup} %{time_connect} %{time_appconnect} %{time_pretransfer} %{time_starttransfer} %{time_total} %{http_code} %{size_download} %{num_connects} %{http_version}' 'http://localhost/up'

Web server page /privacy, a light public page​

curl -sS -o /dev/null -D - --compressed --max-time 20 -A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 jod-latency-benchmark/1.0' -H 'Host: jodapp.com' -H 'Accept: text/html,application/xhtml+xml' -w 'TIMING %{time_namelookup} %{time_connect} %{time_appconnect} %{time_pretransfer} %{time_starttransfer} %{time_total} %{http_code} %{size_download} %{num_connects} %{http_version}' 'http://localhost/privacy'

Web server page /jobs, a public list page​

curl -sS -o /dev/null -D - --compressed --max-time 20 -A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 jod-latency-benchmark/1.0' -H 'Host: jodapp.com' -H 'Accept: text/html,application/xhtml+xml' -w 'TIMING %{time_namelookup} %{time_connect} %{time_appconnect} %{time_pretransfer} %{time_starttransfer} %{time_total} %{http_code} %{size_download} %{num_connects} %{http_version}' 'http://localhost/jobs'

Web server page /employers/dashboard, signed in​

curl -sS -o /dev/null -D - --compressed --max-time 20 -A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 jod-latency-benchmark/1.0' -H 'Host: jodapp.com' -H 'Accept: text/html,application/xhtml+xml' -K cookie.conf -w 'TIMING %{time_namelookup} %{time_connect} %{time_appconnect} %{time_pretransfer} %{time_starttransfer} %{time_total} %{http_code} %{size_download} %{num_connects} %{http_version}' 'http://localhost/employers/dashboard'

About cookie.conf:

  • It holds one line: header = "Cookie: ...".
  • The quotes are required. In a curl config file an unquoted value stops at the first space, and a cookie header always has spaces in it.
  • The script writes it into a private temporary folder, with file mode 600.
  • The script deletes it when it exits.
  • curl reads the cookie from that file, never from the command line. So the cookie never shows up in ps output.

How to reproduce this run​

./jod-latency-benchmark.sh --mode server --env prod --samples 20 --warmup 3

Raw samples​

Every request this run made, in the order it made them. Times are milliseconds.

Open the raw samples

Network floor, web server to Rails API, private name, new connection each time​

RequestKindDNSTCPTLSReady to sendTTFBWhole responseStatusBytesConnectionsHTTP
1warmup3.394.300.004.358.638.772007311.1
2warmup1.582.510.002.566.626.752007311.1
3warmup1.202.120.002.186.146.282007311.1
4sample1.102.000.002.046.326.452007311.1
5sample1.021.900.001.957.047.162007311.1
6sample1.051.970.002.016.276.402007311.1
7sample1.562.460.002.506.236.362007311.1
8sample1.062.010.002.076.676.802007311.1
9sample1.202.140.002.185.946.082007311.1
10sample1.282.200.002.257.107.222007311.1
11sample1.192.060.002.136.416.542007311.1
12sample1.282.200.002.266.016.152007311.1
13sample2.623.570.003.628.198.332007311.1
14sample1.182.080.002.126.646.792007311.1
15sample1.232.160.002.216.877.002007311.1
16sample1.101.990.002.026.046.172007311.1
17sample1.112.020.002.065.936.062007311.1
18sample1.232.150.002.216.176.302007311.1
19sample1.202.150.002.196.636.772007311.1
20sample1.082.000.002.046.006.122007311.1
21sample1.162.030.002.076.456.572007311.1
22sample1.091.960.002.006.856.982007311.1
23sample1.812.680.002.726.656.772007311.1

Network floor, web server to Rails API, private name, connection reused​

RequestKindDNSTCPTLSReady to sendTTFBWhole responseStatusBytesConnectionsHTTP
1warmup1.122.030.002.076.726.862007311.1
2warmup0.020.000.000.043.733.802007301.1
3warmup0.010.000.000.044.074.172007301.1
4sample0.010.000.000.053.964.052007301.1
5sample0.010.000.000.044.154.242007301.1
6sample0.010.000.000.043.623.692007301.1
7sample0.010.000.000.033.903.992007301.1
8sample0.020.000.000.053.813.902007301.1
9sample0.010.000.000.044.364.472007301.1
10sample0.010.000.000.053.783.912007301.1
11sample0.010.000.000.054.004.082007301.1
12sample0.010.000.000.044.354.442007301.1
13sample0.010.000.000.053.853.942007301.1
14sample0.010.000.000.074.564.672007301.1
15sample0.010.000.000.053.934.002007301.1
16sample0.010.000.000.034.314.402007301.1
17sample0.020.000.000.054.334.432007301.1
18sample0.020.000.000.053.763.852007301.1
19sample0.020.000.000.053.703.792007301.1
20sample0.010.000.000.054.484.582007301.1
21sample0.010.000.000.044.184.262007301.1
22sample0.010.000.000.053.753.832007301.1
23sample0.010.000.000.043.733.812007301.1

Network floor, web server to Rails API over the PUBLIC host, new connection each time​

RequestKindDNSTCPTLSReady to sendTTFBWhole responseStatusBytesConnectionsHTTP
1warmup0.8490.52212.29212.41554.29554.492008212
2warmup0.89175.66388.97389.08790.86791.042008212
3warmup0.86139.54286.25286.37856.60856.822008212
4sample0.92141.22290.89291.05585.60585.842008212
5sample0.87174.53357.86357.98722.62722.832008212
6sample0.934.1846.4646.6168.0968.272008212
7sample0.83178.11943.76943.881354.341354.562008212
8sample0.8390.57190.94191.07533.07533.252008212
9sample1.03140.50289.44289.60580.27580.502008212
10sample0.86174.27378.92379.071516.951517.162008212
11sample0.873.8240.4740.6177.5277.802008212
12sample0.94139.58288.71288.86870.72870.902008212
13sample0.84150.21309.10309.23657.66657.862008212
14sample0.803.6340.8741.0060.3060.482008212
15sample0.8376.57169.67169.80497.71497.922008212
16sample6.10187.03400.81400.93794.65794.842008212
17sample0.853.2141.8842.0084.7284.922008212
18sample0.88220.51450.38450.521379.901380.082008212
19sample1.05178.18374.41374.56755.12755.302008212
20sample0.88219.67446.65446.771384.051384.242008212
21sample0.86174.42381.47381.58784.97785.152008212
22sample0.8276.60164.73164.87336.41336.622008212
23sample0.8971.10151.53151.70300.32300.712008212

Network floor, web server to Rails API over the PUBLIC host, connection reused​

RequestKindDNSTCPTLSReady to sendTTFBWhole responseStatusBytesConnectionsHTTP
1warmup1.053.2741.0441.1759.8860.072008212
2warmup0.020.000.000.0714.7214.872008202
3warmup0.020.000.000.0715.0715.182008202
4sample0.020.000.000.0715.1815.322008202
5sample0.010.000.000.0614.9115.032008202
6sample0.010.000.000.0614.2914.432008202
7sample0.020.000.000.0614.5514.662008202
8sample0.010.000.000.0614.2614.422008202
9sample0.010.000.000.0612.2912.412008202
10sample0.010.000.000.0713.9414.062008202
11sample0.020.000.000.0713.9014.022008202
12sample0.010.000.000.1114.4714.602008202
13sample0.020.000.000.0713.2713.422008202
14sample0.010.000.000.0713.3713.492008202
15sample0.020.000.000.0714.8714.992008202
16sample0.020.000.000.0712.3012.442008202
17sample0.010.000.000.0612.2612.382008202
18sample0.010.000.000.0613.9914.112008202
19sample0.020.000.000.0714.5314.662008202
20sample0.020.000.000.0713.0713.232008202
21sample0.020.000.000.0712.6212.732008202
22sample0.020.000.000.0713.0313.142008202
23sample0.020.000.000.0813.0613.202008202

One real signed-in fetch, web server over the PUBLIC host, new connection each time​

RequestKindDNSTCPTLSReady to sendTTFBWhole responseStatusBytesConnectionsHTTP
1warmup0.82177.45363.62363.77746.50746.6920017512
2warmup0.873.3540.3540.4969.4669.6520017512
3warmup0.85177.52365.91366.06766.91767.2920017512
4sample0.79140.06289.12289.27585.83586.1120017512
5sample0.843.3540.2640.3968.1868.3620017512
6sample0.8076.52162.89163.01334.83335.0220017512
7sample0.853.3840.8340.9674.7974.9820017512
8sample0.9890.84189.62189.75374.01374.1920017512
9sample0.82140.60289.28289.41828.26828.4620017512
10sample0.85148.54306.13306.26615.46615.6720017512
11sample0.84140.20293.35293.50595.77595.9620017512
12sample1.00140.50290.04290.17592.55592.7420017512
13sample0.863.1739.4939.6274.6374.8320017512
14sample0.8088.81183.76183.90526.02526.2220017512
15sample0.86154.44318.47318.60965.22965.4320017512
16sample0.883.6040.2940.4265.9666.1920017512
17sample0.933.5640.0640.1972.5872.8020017512
18sample0.89175.59363.11363.25751.93752.4520017512
19sample6.81230.73463.64463.78942.26942.4720017512
20sample0.9183.72177.13177.30503.84504.0420017512
21sample0.873.2939.9140.0673.3873.5720017512
22sample0.86177.64364.56364.72739.76739.9520017512
23sample0.833.3640.2240.3682.9983.1820017512

One real signed-in fetch, web server over the PUBLIC host, connection reused​

RequestKindDNSTCPTLSReady to sendTTFBWhole responseStatusBytesConnectionsHTTP
1warmup0.843.7440.0940.2166.2366.4220017512
2warmup0.020.000.000.0923.0523.2020017502
3warmup0.020.000.000.0821.3021.4420017502
4sample0.020.000.000.1322.3422.5120017502
5sample0.020.000.000.0922.7422.8720017502
6sample0.020.000.000.0924.5524.6820017502
7sample0.030.000.000.1023.9624.1020017502
8sample0.020.000.000.0822.4222.5820017502
9sample0.020.000.000.0827.0027.1220017502
10sample0.020.000.000.0825.4225.5720017502
11sample0.020.000.000.1222.6322.7620017502
12sample0.020.000.000.0926.1026.2420017502
13sample0.020.000.000.0924.7424.8620017502
14sample0.020.000.000.0829.1429.2920017502
15sample0.020.000.000.0924.4924.6520017502
16sample0.020.000.000.0923.6323.7620017502
17sample0.020.000.000.0824.0924.2220017502
18sample0.020.000.000.0825.3925.5320017502
19sample0.020.000.000.0822.3222.4720017502
20sample0.020.000.000.1328.1828.3020017502
21sample0.020.000.000.0822.5422.6620017502
22sample0.020.000.000.0922.8623.0220017502
23sample0.020.000.000.1121.1721.3020017502

One real signed-in fetch, private name, new connection each time​

RequestKindDNSTCPTLSReady to sendTTFBWhole responseStatusBytesConnectionsHTTP
1warmup1.332.250.002.3013.4013.5520027511.1
2warmup1.972.910.002.9815.4215.5620027511.1
3warmup1.232.170.002.2314.9615.0920027511.1
4sample1.112.020.002.0813.9314.0620027511.1
5sample1.072.020.002.0914.6214.7620027511.1
6sample1.082.000.002.0414.3214.4520027511.1
7sample1.922.880.002.9514.3814.5120027511.1
8sample1.112.020.002.0713.0513.2020027511.1
9sample1.102.020.002.0712.8313.0020027511.1
10sample1.162.060.002.1213.3013.4520027511.1
11sample1.091.990.002.0515.1115.2520027511.1
12sample2.443.330.003.3916.8917.0220027511.1
13sample1.051.970.002.2114.3814.5120027511.1
14sample1.172.060.002.1114.4414.5720027511.1
15sample1.071.960.002.0113.7913.9220027511.1
16sample1.132.060.002.1215.0215.3420027511.1
17sample1.011.930.001.9814.8715.0020027511.1
18sample1.011.890.001.9515.0015.1320027511.1
19sample5.346.270.006.3219.2019.3420027511.1
20sample1.121.970.002.0314.1814.3120027511.1
21sample1.041.980.002.0414.2914.4320027511.1
22sample1.182.070.002.1314.7114.8520027511.1
23sample1.062.040.002.1014.6814.8620027511.1

One real signed-in fetch, private name, connection reused​

RequestKindDNSTCPTLSReady to sendTTFBWhole responseStatusBytesConnectionsHTTP
1warmup1.162.050.002.1014.4714.6020027511.1
2warmup0.020.000.000.0511.2911.3720027501.1
3warmup0.010.000.000.0512.3712.4520027501.1
4sample0.020.000.000.0611.1211.2120027501.1
5sample0.010.000.000.0512.1012.2020027501.1
6sample0.020.000.000.0612.4612.5520027501.1
7sample0.020.000.000.0611.8311.9520027501.1
8sample0.020.000.000.0611.4311.5420027501.1
9sample0.020.000.000.0611.2511.3420027501.1
10sample0.020.000.000.0611.7011.8020027501.1
11sample0.020.000.000.0811.8111.9120027501.1
12sample0.020.000.000.0710.6910.7920027501.1
13sample0.020.000.000.0711.0411.1220027501.1
14sample0.020.000.000.0611.3511.4520027501.1
15sample0.020.000.000.0611.5711.6620027501.1
16sample0.020.000.000.0611.7311.8220027501.1
17sample0.020.000.000.0911.5711.6520027501.1
18sample0.020.000.000.0611.1811.2520027501.1
19sample0.010.000.000.0511.1711.2620027501.1
20sample0.020.000.000.0610.9911.1020027501.1
21sample0.020.000.000.0611.3611.4920027501.1
22sample0.020.000.000.0711.2111.3020027501.1
23sample0.020.000.000.0610.4810.5820027501.1

Web server page /up, the control​

RequestKindDNSTCPTLSReady to sendTTFBWhole responseStatusBytesConnectionsHTTP
1warmup0.020.150.000.1910.9211.67200464511.1
2warmup0.020.160.000.2049.4649.86200464211.1
3warmup0.020.130.000.1710.7511.01200464211.1
4sample0.020.140.000.2010.3310.59200464211.1
5sample0.020.130.000.179.8510.12200464211.1
6sample0.020.130.000.179.7310.05200464511.1
7sample0.020.140.000.179.7010.07200464211.1
8sample0.020.160.000.209.199.52200464211.1
9sample0.020.140.000.179.629.90200464011.1
10sample0.020.130.000.1738.4039.63200464511.1
11sample0.020.160.000.209.7110.46200464011.1
12sample0.020.130.000.1713.7714.09200464211.1
13sample0.020.130.000.2011.1411.64200464211.1
14sample0.020.130.000.179.4610.11200464211.1
15sample0.020.130.000.189.8210.11200464211.1
16sample0.020.150.000.189.269.55200464211.1
17sample0.020.150.000.1910.0312.22200464211.1
18sample0.020.140.000.1814.3914.68200464211.1
19sample0.020.140.000.1810.1610.44200464211.1
20sample0.020.150.000.199.029.30200464211.1
21sample0.020.140.000.179.6310.02200464211.1
22sample0.020.140.000.189.049.40200464111.1
23sample0.020.130.000.1712.0912.48200464311.1

Web server page /privacy, a light public page​

RequestKindDNSTCPTLSReady to sendTTFBWhole responseStatusBytesConnectionsHTTP
1warmup0.020.130.000.171424.111424.732001433211.1
2warmup0.020.160.000.20941.62942.152001433211.1
3warmup0.020.140.000.17971.24971.762001433211.1
4sample0.020.140.000.18993.11993.652001433211.1
5sample0.020.130.000.17963.14963.742001433211.1
6sample0.040.160.000.20956.98957.642001433211.1
7sample0.030.160.000.21966.25966.832001433211.1
8sample0.020.130.000.17981.12981.622001433211.1
9sample0.020.130.000.20963.48964.022001433211.1
10sample0.020.140.000.18974.45974.962001433211.1
11sample0.020.140.000.181018.481019.422001433211.1
12sample0.020.130.000.17949.33949.962001433211.1
13sample0.020.140.000.18927.99928.512001433211.1
14sample0.020.140.000.171004.451005.062001433211.1
15sample0.020.140.000.17977.81978.282001433211.1
16sample0.020.150.000.191378.001378.692001433211.1
17sample0.020.180.000.271354.751355.442001433211.1
18sample0.020.140.000.17964.88965.472001433211.1
19sample0.020.240.000.281684.851685.402001433211.1
20sample0.020.150.000.20967.08967.742001433211.1
21sample0.020.130.000.171322.031322.632001433211.1
22sample0.020.140.000.21988.95989.602001433211.1
23sample0.020.140.000.18965.06966.692001433211.1

Web server page /jobs, a public list page​

RequestKindDNSTCPTLSReady to sendTTFBWhole responseStatusBytesConnectionsHTTP
1warmup0.020.140.000.181172.111172.712001433311.1
2warmup0.020.140.000.171314.381315.112001433311.1
3warmup0.020.150.000.20824.92825.942001433311.1
4sample0.020.140.000.17811.68812.272001433311.1
5sample0.020.130.000.17815.81816.502001433311.1
6sample0.020.130.000.17811.92812.522001433311.1
7sample0.020.140.000.19867.33867.902001433311.1
8sample0.020.430.000.481332.991333.772001433311.1
9sample0.020.150.000.19830.51831.112001433311.1
10sample0.020.140.000.19833.74834.432001433311.1
11sample0.020.150.000.19808.86809.772001433311.1
12sample0.020.140.000.17823.72824.322001433311.1
13sample0.020.140.000.18816.76817.462001433311.1
14sample0.020.140.000.191323.401323.972001433311.1
15sample0.020.130.000.17826.14827.462001433311.1
16sample0.020.140.000.18837.39838.002001433311.1
17sample0.020.130.000.17817.81818.402001433311.1
18sample0.020.130.000.17830.75831.352001433311.1
19sample0.020.140.000.18833.97834.662001433311.1
20sample0.020.130.000.171332.781333.452001433311.1
21sample0.020.130.000.17825.32825.902001433311.1
22sample0.040.150.000.19815.87816.572001433311.1
23sample0.020.140.000.18861.03862.192001433311.1

Web server page /employers/dashboard, signed in​

RequestKindDNSTCPTLSReady to sendTTFBWhole responseStatusBytesConnectionsHTTP
1warmup0.020.140.000.19334.67335.16200739111.1
2warmup0.020.140.000.23367.22367.71200739111.1
3warmup0.020.150.000.20334.21334.75200739111.1
4sample0.020.140.000.19326.76327.12200739111.1
5sample0.060.180.000.23326.08326.52200739111.1
6sample0.020.140.000.19327.58328.03200739111.1
7sample0.020.140.000.23331.80332.17200739111.1
8sample0.020.140.000.19331.85332.20200739111.1
9sample0.020.170.000.22783.25783.62200739111.1
10sample0.020.300.000.35541.49541.93200739111.1
11sample0.020.140.000.18343.28343.76200739111.1
12sample0.020.170.000.23325.68326.14200739111.1
13sample0.020.140.000.19340.69341.08200739111.1
14sample0.020.140.000.20915.85917.29200739111.1
15sample0.020.200.000.71349.15349.53200739111.1
16sample0.020.150.000.20327.52327.92200739111.1
17sample0.020.130.000.18332.06332.42200739111.1
18sample0.020.130.000.231224.301224.74200739111.1
19sample0.020.150.000.19355.03355.48200739111.1
20sample0.020.140.000.191203.811204.19200739111.1
21sample0.020.140.000.19353.83354.17200739111.1
22sample0.020.140.000.19345.44345.84200739111.1
23sample0.020.140.000.19341.84342.56200739111.1