Catch the Segfault, Skip the Syscall · Morning Gist
Friday, October 25 stories · 11 min
Catch the Segfault, Skip the Syscall
Today: profiler tricks that cut overhead, a CDN ranking that moved when the measurement changed, and Shopify going back to native after five years of React Native.
Picked from 27 new articles across 34 sources · arrow keys for other days
Today in 30 seconds
30s left
Datadog cut its async Python profiler's overhead by more than 60% by replacing process_vm_readv syscalls with a memcpy that catches SIGSEGV. story 1 ↓
Cloudflare went from fastest in 60% to 74% of the top 1,000 networks, but it also started measuring from Turnstile Challenge Pages. story 2 ↓
Fowler defines a "sensible default" as a known-good practice you follow unless you can justify overriding it, which leaves more room for argument than "best practice". story 3 ↓
Shopify is moving six apps from React Native back to native, saying cheaper porting between platforms makes the extra layer not worth it. story 4 ↓
Cloudflare Traces (open beta) turns WAF, routing, cache and origin steps into OpenTelemetry spans, propagating W3C traceparent and exporting over OTLP. story 5 ↓
1/5Datadog Engineering· Sep 30
Datadog's async Python profiler swaps process_vm_readv for fault-tolerant memcpy
Datadog rebuilt how its profiler links asyncio tasks in flame graphs, then cut overhead by more than 60% by catching SIGSEGV instead of making syscalls.
Why it matters · Sampling profilers break down when there are far more units of concurrency than threads. Datadog shows how it attributed time correctly across those units and why per-object syscall costs forced a different way of reading memory safely.
Image: Datadog Engineering
Standard flame graphs flatten asyncio programs. Each task has its own stack, so a Cassandra query run in a task spawned by validate_user shows up as a separate stack. Nothing ties the time back to the request path that caused it, so time attributed to callers is also wrong. Datadog's fix is what it calls stacked stacks.
Reconstructing task relationships
At each sample, the profiler collects every asyncio task and walks each task's coroutine chain from the root to the innermost frame. It records which task is currently awaiting which. That can differ from which task created it, and it can change over a task's lifetime. Stack building starts from leaf tasks, meaning tasks that are running or awaiting something other than a task. It pushes the leaf's frames, then the frames of the task awaiting it, and so on up to the outermost task. The result is that async code split across tasks, async code in a single task, and the equivalent synchronous code all produce comparable flame graphs. CPython's new Tachyon profiler in 3.15 later took a similar approach.
Tasks can outlive the code that created them, which breaks a flame-graph assumption. Datadog's rule: a task's time counts toward its creator while the creator is running, then toward whichever task is awaiting it.
The overhead problem and the fix
Sync profiling costs O(threads). Async profiling adds O(tasks), and a server may run one task per request. The 2024 Stack v2 sampler read memory without taking the GIL by using process_vm_readv. That call fails safely on freed memory but costs one syscall per read. A thread's frames can often be copied in a single call, but tasks and coroutines are many small structures, so each task needed several calls. Under adaptive sampling, overhead pushed the sample rate down to its floor of 1 Hz.
2/5Cloudflare· Lai Yi Ohlsen· Oct 2
Cloudflare's 'fastest in 74% of networks' jump comes with a methodology change
Cloudflare's share of top-1,000 networks where it is fastest rose from 60% to 74% after it began measuring from Turnstile Challenge Pages.
Why it matters · This is a useful example of how a vendor benchmark works and where it can mislead. A ranking can move because the data source changed, not because the network got faster. That matters whenever you compare CDNs on numbers published by one of the vendors.
Map of countries where Cloudflare ranks fastest across top networks as of August 2026.1 / 3
Cloudflare says it is now the fastest provider in 74% of the world's 1,000 largest networks, up from 60% in April 2026. It became fastest on 150 more networks and in 38 more countries. The post never separates the two possible causes, though. The gain came at the same time as a new way of collecting data, and the article gives no network or routing change to explain it.
How the benchmark works
The networks are the top 1,000 by estimated user population, using APNIC data. The metric is TCP connection time: how long the user's device takes to finish the handshake. Cloudflare argues this tracks perceived speed because it reflects distance, routing and congestion. Providers are ranked by the trimean of connection times, a weighted average of the 25th, 50th and 75th percentiles that dampens outliers.
Since 2021 the data has come from Cloudflare-branded error pages. When a user lands on one, the browser fetches small files in the background from Cloudflare, CloudFront, Google, Fastly and Akamai, and records how long each connection takes. These are real users on real networks at a real moment, but only from a narrow set of situations.
3/5Martin Fowler· Martin Fowler· Sep 29
Fowler on "Sensible Defaults": Best Practices You Have to Justify Overriding
A short bliki entry defines the Thoughtworks term: a known-good starting point that teams should reassess in each new context and override when there's reason to.
Why it matters · Calling something a "best practice" tends to shut down discussion. A sensible default keeps the practice and the expectation that you'll follow it, but invites a reasoned exception. That's useful framing for anyone writing team standards or reviewing architecture choices.
Image: Martin Fowler
Martin Fowler's latest bliki entry defines a term that's already common inside Thoughtworks. A sensible default is a practice you should use for a given kind of task unless some overriding context says otherwise. His software examples are "use version control", "separate UI logic from domain logic" and "automate deployment pipelines".
Why not just say "best practice"
The term is chosen to contrast with "best practice". Fowler says people dislike "best practice" because it suggests you should always do the thing. A sensible default comes with a different expectation. You reassess it whenever the context changes, and you can, and should, override it when the circumstances call for it.
The most useful line in the piece is Evan Bottcher's definition. Bottcher popularized the term within Thoughtworks:
A sensible default is what we'd expect you to do, the practices to apply, if there are no hard constraints in the environment. Do these practices, or do better, and be prepared to explain why you've chosen some other way.
This puts the burden of proof on whoever departs from the default. Following the default needs no argument. Departing from it needs one, and "do better" is allowed. Bottcher got the name from a conversation with James Ross. He liked it because it carried the nuance he wanted: "a known-good starting point."
How Thoughtworks uses it
Thoughtworks has published a playbook of its sensible defaults. It expects its people to know them and use them when starting any new piece of work. Fowler says the practices became defaults because the company has used them in many situations and found them effective. He also expects teams to know each default's limitations and to judge when a particular situation calls for changing it.
4/5The Pragmatic Engineer· Gergely Orosz· Sep 29
Shopify reverses its 2020 React Native bet and goes back to native
Six apps moved to React Native over five years. Shopify now says cheaper cross-platform porting makes the extra abstraction layer not worth keeping.
Why it matters · This is a rare public reversal of a big architecture decision, with the reasoning laid out. The trade-off shifted because the cost of writing everything twice dropped, while the cost of an extra framework layer stayed the same.
Native vs React Native trade-offs before AI coding tools, the basis for Shopify's 2020 choice1 / 4
Six years ago, Shopify committed to React Native (RN). It has now announced that its mobile apps will be rebuilt in Swift and Kotlin. Gergely Orosz walks through why the original decision made sense and what changed.
Why RN won in 2020, and held up
The main problem in 2020 was Android. Building native Android apps took a long time, and Shopify had iOS-only apps such as Arrive (now Shop) and Ping. Mobile mattered a lot: 71% of buyers purchased on mobile in Q3 2019. The RN rewrite of Arrive shared 95% of its code across platforms, crashed less than the native iOS app had, and finally gave Shopify an Android version. Over five years all six apps moved to RN.
5/5Cloudflare· Mar Witek· Oct 2
Cloudflare Traces emits OpenTelemetry spans for every step of the edge request path
Now in open beta: WAF, transforms, routing, cache, and origin time become spans, with W3C traceparent propagation, rule-based sampling, and OTLP export.
Why it matters · If Cloudflare sits in front of your origin, the CDN has been a gap in your traces. This adds per-step spans for the edge and joins them to your existing W3C traces, so you can tell whether latency or a block came from Cloudflare or your stack.
Security rule spans show evaluation time, the resulting action, and which rule blocked or challenged the request.1 / 4
This is a product launch, and the post has little on internals. What it does describe clearly is the trace model and the sampling controls. Cloudflare Traces, now in open beta, takes the automatic instrumentation Workers Tracing introduced last year and applies it to the rest of the HTTP request path. You don't need to add any code. Once you enable tracing on a domain, Cloudflare records each supported processing step as an OpenTelemetry span with its timing, outcome, and attributes.
What the spans show
The trace answers questions you would otherwise piece together from separate logs and config:
Removing C++ exceptions from the sampling path cut overhead 15%, and interning strings cut another 25%. Neither was enough. Reservoir sampling of tasks was ruled out because building the dependency tree requires metadata for every task anyway.
The bigger change was a protected memcpy. The sampler installs SIGSEGV/SIGBUS handlers with sigaction. When not armed, they forward signals to the previously installed handler. try_memcpy arms the handler, and on a fault jumps to a recovery instruction pointer and returns an error. Faults are expensive but rare: code objects are effectively immortal and tasks outlive a single copy. The non-fault path costs about the same as a plain memcpy. The hard parts were coexisting with other handlers such as faulthandler and staying async-signal-safe. This alone cut sync overhead by about 50%. Across services where the changes rolled out, overhead fell more than 60%, and sampling frequency was no longer stuck at the 1 Hz floor.
In production, the new profiles found an infinite loop in pylzstr on malformed input, which was causing uvicorn worker kills. They also found a library building large log.debug strings for an INFO-level logger, which explained CPU spikes the team had seen but never traced.
Remember
Stacked stacks follow which task is awaiting which, not which created it, and attribute time to the current awaiter.
process_vm_readv's per-call syscall cost scales badly when copying many small task and coroutine objects.
A memcpy guarded by an armed SIGSEGV handler cut sync overhead ~50%; total overhead fell more than 60%.
Cloudflare now runs the same background test on a small fraction of free Challenge Pages. These are Turnstile-delivered gate pages, usually triggered by WAF rules, that check the browser for signs of automation before letting a visitor through. The test fetches from a fixed set of endpoints and records whether each request completed and how long it took. Cloudflare says it is designed to add no noticeable latency, and that it will raise the sampling rate only if data quality improves and users see no slowdown.
The gain is reach: many more samples, from more networks, including networks outside the top 1,000. That allows analyses a count of networks can't support, such as weighting by number of users, grouping by country, and estimating what share of traffic the measured networks represent.
Read the headline number with care
The author is open about the mechanism. In many networks the top providers are only 1–2 ms apart, for example Cloudflare at 50 ms vs Fastly at 51 ms, close enough that day-to-day noise can flip the ranking. The post says Cloudflare "may have previously ranked second" in such networks. More samples narrow the confidence intervals, and the post credits that for the improvement. No confidence intervals are published, though. Some of the 14-point gain is likely ties being decided by less noise rather than speed gained. There is also a small mismatch in the numbers: 14 points of 1,000 is 140 networks, but the post says 150. The gap is probably net of networks lost, but the post doesn't explain it.
Remember
Ranking metric: trimean (weighted P25/P50/P75) of TCP connection time across APNIC's 1,000 largest networks.
New data source: background fetches on sampled free Turnstile Challenge Pages, alongside the error-page data used since 2021.
Leaders are often 1–2 ms apart, so some of the 60%→74% gain likely reflects resolved ties.
Fowler ties this to the twelfth agile principle: "At regular intervals, the team reflects on how to become more effective, then tunes and adjusts its behavior accordingly." The defaults themselves are also reviewed regularly. Fowler calls that review the heart of the Thoughtworks Technology Radar.
The entry ends with a note on where the term came from. Fowler found a post on sensible defaults by Steve Bennett, written around the time Bottcher talked to Ross. He doesn't know whether Ross got the name from Bennett or whether the phrase appeared independently.
The piece is short and argues for no particular practice. What it offers is vocabulary: a way to set team standards that keeps the case for consistency and still makes exceptions something you argue for openly.
Remember
A sensible default is what you do when nothing in the environment forces otherwise. It's not an always-rule.
Bottcher's rule: follow the default or do better, but be ready to explain why you didn't follow it.
Defaults need regular review. Thoughtworks reviews its own through the Technology Radar, guided by agile's twelfth principle.
In a 2025 retrospective, Head of Mobile Mustafa Ali reported:
P75 screen loads under 500ms
More than 99.9% crash-free sessions
No more work spent keeping iOS and Android at feature parity
Hot reloading, which replaced native compile cycles that took several minutes even for trivial changes
The costs were real too. Debugging was flaky, the app depended on more third-party libraries, and native code was still needed for heavy animations, background jobs and widgets.
What changed
Ali argues that coding agents now handle enough of the implementation, translation between platforms, testing and review that building every feature twice "is no longer the deciding factor." Meanwhile, RN's structural cost hasn't gone away. RN keeps a React Host Tree that maps onto a native Host View Tree, which adds a layer between app code and UIKit or Jetpack Compose. The 2024 New Architecture didn't close that gap much. When Shopify migrated its Shopify and Point of Sale apps, startup got about 10% faster on Android and 3% on iOS, and some complex screens got slower until the team tuned them.
To stop the two codebases from drifting apart, Shopify is building a shared verification test suite. The same business-logic tests run against both the Swift and Kotlin implementations, headless on desktop, and a feature can't ship until it passes on both. Shopify keeps its single team model: one engineer builds a feature on both platforms. Engineering head Farhan Thawar puts it this way: "React, as the shared language, is now replaced by the English language."
Progress so far: the Shop app shipped fully native after 12 weeks, and the main Shopify app is in progress. Ali says each rebuild must meet or beat current performance, stability and accessibility. Thawar expects startup time and responsiveness to improve once the migration is done. There are no measurements yet to back that up.
Orosz notes that Airbnb made the same round trip between 2016 and 2018, also for performance reasons. He suggests Kotlin Multiplatform, which shares business logic while keeping each platform's UI native, may gain ground as a middle path.
Remember
RN delivered for Shopify: P75 screen loads under 500ms and over 99.9% crash-free sessions, yet the extra layer still capped performance.
Moving to RN's New Architecture improved startup only 10% on Android and 3% on iOS, and slowed some screens at first.
A shared Swift/Kotlin test suite running headless on desktop stops the duplicated codebases from drifting apart.
Security rules: when custom or managed rules ran, how long evaluation took, and the action taken. Span events name the rule behind a block or challenge.
Transforms: the http_request_transform span lists each rewrite, the request component it touched, the rule responsible, and where it happened relative to routing.
Routing:workers_routing shows whether a route matched, the routing type, and the matching pattern.
Cache and origin: nested cache, upstream, and origin spans split out where the time went. In the post's example, a cache miss spent 527 ms of a 539 ms request waiting on origin.
Cloudflare says its internal traces often run to thousands of spans from dozens of services. The public version is a curated subset of those.
Sampling, propagation, export
You set a baseline sampling rate for the domain, such as 1%. Trace Rules override it for matching traffic and use the same Rules language as the rest of Cloudflare's config. That lets you trace 100% of requests for one customer's hostname, source IP, or a temporary debug header while everything else stays at the baseline. It's a practical way to reproduce a reported issue without raising tracing volume across the whole domain.
For distributed tracing, Cloudflare can accept an incoming W3C traceparent header, controlled by an incoming propagation policy, so its spans join a trace that started upstream. It can also forward a new traceparent to your origin, so downstream services continue the same trace. You configure OTLP export once per account as a destination, then choose which domains send to it. To see one connected trace, send both Cloudflare and application spans to the same backend.
One gap matters today: accepting context is all-or-nothing under the policy. "Authenticated context propagation", which would let only trusted callers continue an existing trace, is still on the roadmap. Also planned are more spans (DDoS, Access, Queues, Workflows), on-demand tracing of a single request, and 365-day retention.
Pricing starts December 1, 2026 and is based on bytes, not span counts. The free plan includes 0.5 GB of ingestion per day with 7-day retention. Paid plans include 50 GB of ingestion and 10 GB-month of storage, then charge $0.25/GB ingested and $0.10/GB-month stored.
Remember
Edge processing steps (WAF, transforms, routing, cache, origin) become OpenTelemetry spans automatically once a domain enables tracing.
Trace Rules can raise sampling to 100% for one hostname, IP, or debug header while other traffic stays at 1%.
Accepts and forwards W3C traceparent and exports over OTLP. Restricting incoming context to trusted callers isn't available yet.