Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
157841 stories
·
33 followers

Cognitive Databases, Intelligent Data

1 Share
No longer passive storage and query engines, databases are becoming active, intelligent participants in how modern systems interpret, connect, and act on data. As AI moves deeper into production and enterprises adopt generative and agentic architectures, the database layer is being reshaped to support semantic search, contextual retrieval, and real-time decision-making. Vector databases, semantic indexing, and AI-driven optimization are changing how developers work with both structured and unstructured data, while the line between transactional and analytical systems continues to fade under hybrid workload demands. This report examines these industry shifts in practical terms, exploring how relational, NoSQL, vector, and multi-model systems are coming together to support AI-native applications. Our research, guest thought leadership, and practitioner insights look at how teams are bringing vector search into production, updating architectures for AI workloads, and redesigning data pipelines around semantic and contextual intelligence.
Read the whole story
alvinashcraft
1 minute ago
reply
Pennsylvania, USA
Share this story
Delete

Microsoft expands Azure AI and HPC infrastructure with AMD

1 Share

AI workloads are scaling faster than any single infrastructure approach can support — with more models, new agent-driven workloads and surging compute demand driving the need for greater specialization across the stack. To meet this need, Microsoft continues to evolve Azure’s infrastructure, including expanding its AI fleet with AMD’s most advanced AI and high-performance computing (HPC) solutions.

Our approach to AI infrastructure is designed to support the breadth of how AI systems are built and run. We closely work with industry innovators like AMD as well as our own purpose-built silicon and systems to provide customers with a comprehensive, open and heterogenous platform to achieve the best performance, cost and energy efficiency outcomes.

Building on our close collaboration with AMD, Microsoft is bringing AMD’s latest Helios AI platform and next-generation EPYC datacenter processors to Azure. These technologies will power three upcoming Azure offerings: HDv2 VMs for data processing, HXv2 VMs for electronic design automation (EDA) and ND MI455X v7 VMs for AI inference workloads.

Expanded infrastructure for inference, AI data systems and chip design

YouTube Video

Built for AI data systems — Azure HDv2

CPU infrastructure is essential to the performance and efficiency of modern AI systems. AI accelerators depend on high-density, power-efficient CPU compute to process data, coordinate workloads and keep pipelines running at scale. Without this, training jobs don’t have enough data to learn from, and agents don’t have enough capacity to perform tasks on behalf of customers. Azure HDv2 virtual machines are one of our latest offerings designed from the ground up to eliminate these bottlenecks and empower massive agentic workload adoption.

Co-designed with AMD, HDv2 VMs expand Azure’s portfolio of purpose-built solutions for the most demanding CPU workloads from AI customers, including data preparation, search, reinforcement learning and agent coordination at scale. Featuring nearly 500 physical 6th Gen AMD EPYC CPU cores, 4 terabytes of RAM, 32 terabytes of local NVMe storage and 400 Gbs Azure Boost networking, HDv2 VMs are built for the workload needs of our most demanding AI customers.

Optimized for silicon design and technical computing — Azure HXv2

The AI era has created tremendous need and opportunity for firms developing the silicon products that power this infrastructure. For this reason, Azure HX virtual machines, launched in partnership with AMD in 2023 and featuring AMD’s unique 3D V-cache technology, have seen significant adoption among silicon design firms working to bring more capable and efficient AI silicon to market. Today, we are announcing the next step in our workload optimized journey for these customers, HXv2.

HXv2 virtual machines build on and extend the strengths of HX. They both continue the differentiation Azure offers for RTL simulation workloads by again employing 3D V-cache technology, while offering significant improvements to single threaded performance and memory. HXv2 VMs will feature 176 AMD 6th Gen EPYC CPU cores with a clock frequency of more than 5 GHz, 50% more addressable cache per core and VM sizes with nearly 2 or 4 terabytes of RAM, helping customers optimize their workloads to memory needs.

Azure HXv2 is also designed to support a broader range of technical computing workloads including scientific simulation, engineering analysis and other distributed memory applications. The significantly increased per VM and per core performance, and the inclusion of 800 Gb InfiniBand, enable large-scale MPI-based simulations and make HXv2 an ideal fit for a wide variety of HPC customers.

AMD, a leading HX-series customer, highlights this impact directly:

Engineering teams are pushing the limits of simulation, chip design and scientific computing. At AMD, we experience those demands firsthand as we design future AMD EPYC CPUs and AMD Instinct GPUs. Azure HX is an important platform for scaling complex EDA workloads, and we’re excited about Azure HXv2, which is designed to deliver even greater performance and scalability. We look forward to continuing our collaboration with Microsoft as we help advance infrastructure for the world’s most demanding engineering and scientific workloads.”

— Mark Papermaster, Executive Vice President and CTO, AMD

The HXv2 also leverages Microsoft’s long-standing collaboration to optimize Synopsys AI-powered EDA solutions on Azure:

“As AI compute continues to push the limits of semiconductor design, our collaboration with Microsoft on the Azure HX-series demonstrates a shared vision for enabling customers to deliver next-generation AI systems with precision and scale in accelerated design cycles. These systems have enabled Synopsys customers to reliably and efficiently leverage cloud-based compute, extending EDA workloads beyond traditional infrastructure constraints so they can meet ambitious development schedules while maximizing design quality and delivering dramatic performance gains.”

— Shankar Krishnamoorthy, Chief Product Development Officer, Synopsys

Production-scale AI inference — ND MI455X v7

ND MI455X v7 is designed for the reasoning, search and agentic workloads behind modern AI services. Powered by the AMD Helios rackscale solution, it expands Azure’s infrastructure options for large-scale inference and is designed to deliver strong performance and efficiency for demanding AI workloads.

Together, these new capabilities expand Azure capabilities while giving customers more flexibility to choose the right compute for each unique AI workflow: from inference, to data systems, to chip design. Customer choice is a core design principle built directly into Microsoft Azure, and we’re excited to bring AMD’s most advanced innovations at production scale.

To learn more about Azure’s high-performance computing and AI infrastructure capabilities, visit Azure.com.

Scott Guthrie is responsible for a set of hyperscale cloud computing solutions and services including Azure, Microsoft’s cloud computing platform, generative AI solutions, data platforms and information and cybersecurity. These platforms and services help organizations across the globe solve urgent challenges — and transform for the future.

The post Microsoft expands Azure AI and HPC infrastructure with AMD appeared first on The Official Microsoft Blog.

Read the whole story
alvinashcraft
4 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Escape Analysis in Go – Stack vs. Heap Allocations Explained

1 Share

One of the design choices Google made when developing Go was to abstract memory management away from developers so they could focus on what really matters – writing code. Things like escape analysis and garbage collection are thus automatic, and the Go compiler works in almost mystical ways.

That’s one of the best features of Go, so long as your program works. But when memory issues arise, and you need to demystify the process to optimize it, that’s when the perspective shifts and the mystery is no longer so appealing.

In this article, we’ll explain one of the most confusing performance optimization problems – escape analysis, i.e. how the compiler decides what stays on the stack, and what moves to the heap. We’ll cover what escape analysis is and how it works, what the most common escape cases are and how to inspect them, why inspections might be hard to use, and even how GoLand can perhaps help with that.

What is escape analysis in Go?

Escape analysis is a compiler optimization that determines whether a value can be allocated on the stack or must be moved to the heap. In other words, in Golang, the escape analysis process inspects every value your program creates to answer the question: Can this safely live on the stack, or does something outside the current function still need it after the function returns (and therefore it needs to live on the heap)?

The stack is a per-goroutine region where allocations are significantly cheaper and reclaimed automatically when a function returns, so storage happens fast but is short-lived. The heap is a shared, longer-lived memory space that the garbage collector must track and clean up, so it’s more resource-intensive. Escape analysis is the bridge between the two.

A value is said to “escape” when the compiler can’t prove that it’s done being used by the time the function exits, as explained in the Go documentation. For each value, it asks whether any reference to that value can outlive the function that created it. If the answer is no, the value stays on the stack. If the answer is yes – or if the compiler simply can’t prove the answer is no – the value is allocated on the heap to be safe. The classic example is returning a pointer to a local variable – the function ends, but a reference to that variable lives on, so the value can’t sit on the stack frame that’s about to be discarded. It escapes to the heap instead.

It’s worth pointing out here that escape decisions are not set in stone. They can change depending on how you structure your code, the Go version you’re compiling with, as well as on the environment (OS/architecture), compiler settings, and other optimization decisions like inlining. That’s why you can’t assume a value will or will not always escape in a given context – you need to check every time.

And why should I care?

Unlike in some other languages, in Go you don’t manually choose between stack and heap allocation the way you might with malloc and free in C. Instead, the compiler makes the call. Go also manages memory safety for you, so as to prevent escaped values from being unsafe.

Many developers stop there and never bother with escape analysis. After all, the documentation says that “you don’t need to know”, and if it works, it works, right?

Having said that, you do still have agency and can write code in ways that influence these compiler decisions – in a good way or indeed in a bad way. That’s why an understanding of escape analysis is actually a must-have skill for any Go developer.

Common reasons values escape to the heap

Most of the time, when a value escapes to the heap, it’s for one of a handful of recurring reasons. Recognizing these patterns helps you read compiler output faster and tells you whether a given allocation needs investigation or is simply the best way to run your code. 

It’s important to note that not every escape is a problem – programs with any degree of complexity will inevitably have things living on the heap. The goal here is to recognize the patterns, not to eliminate them all.

Returning pointers

Returning a pointer to a local value is probably the most common cause of an escape. The value is created inside the function, but the caller holds onto a reference after the function returns, so it can’t live on the stack frame that’s being torn down.

func NewUser(name string) *User {
    u := User{Name: name} // u escapes to the heap
    return &u
}

This is safe in Go – the compiler notices that &u outlives NewUser and moves the value to the heap automatically. Whether you should care depends on context. Returning pointers is idiomatic and often the right call for API clarity and readability. The right choice depends on your API design and measured performance impact, not on a blanket rule about avoiding pointers.

Closures and goroutines

Captured variables will escape when a closure or goroutine may outlive the function that created them. The compiler has to assume the captured value is still reachable, so it allocates it on the heap.

func process(data []byte) {
    go func() {
        handle(data) // data may escape: the goroutine can outlive the process
    }()
}

Goroutines are a frequent source of confusion here, precisely because they can keep running after the parent function has returned. From the compiler’s point of view, anything the goroutine touches might be needed indefinitely, so it plays it safe.

Interfaces and dynamic values

Passing a concrete value through an interface can sometimes lead to a heap allocation. This most often occurs in formatting, logging, and interface-based APIs, where values are boxed into an interface{} (any) before they are handled.

func logValue(v int) {
    fmt.Println(v) // v is passed as an interface and may escape
}

However, interface use does not automatically cause heap allocation. Plenty of interface calls don’t allocate at all, and the compiler keeps getting better at this. Treat interfaces as something to check rather than avoid entirely.

Slices, maps, and structs

Values can escape when they’re stored inside a data structure that outlives the current function. If you put a pointer into a map, a slice, or a struct field, and that container lives longer than the function, the stored value has to live just as long.

type Cache struct {
    items map[string]*Item
}

func (c *Cache) Add(key string, it *Item) {
    c.items[key] = it // it escapes: stored in a structure that outlives the call
}

The relationship between the container and the value it holds is crucial here. A slice that never leaves the function may keep its contents on the stack; the same slice returned to a caller or stored in a long-lived struct will push its contents to the heap.

How to check escape analysis in Go

The good news is you don’t really need to remember any common reasons for escapes or guess whether a value escaped or not in a particular instant. The Go compiler flags can tell you that, and in fact, inspecting the compiler’s output is the only reliable way to know what’s happening for sure.

The log covers more than just escapes, though. Alongside allocation decisions, the compiler reports inlining details and other diagnostics, so you get a fairly complete picture of the optimization choices it made for a given build. The downside is that the output isn’t precisely user-friendly or easy to navigate, but we will come back to that later.

How to use compiler flags

The Go compiler surfaces escape analysis information through the -gcflags debug flag with the -m option:

go build -gcflags="-m" ./...

The -m flag asks the compiler to print its optimization decisions, including whether a value escaped. The output looks roughly like this:

./user.go:6:2: moved to heap: u
./user.go:7:9: &u escapes to heap

You can pass -m twice (-gcflags="-m -m") for more detailed reasoning, though that quickly becomes verbose. There are more flag variations, but -gcflags="-m" is the one you’ll probably reach for most.

As you can see, the output is keyed by file, line, and column, and escape analysis can be buried among other comments. This means the real work is mapping each message back to the relevant source code so you can understand it in context.

Why it’s hard to work with escape analysis logs

While compiler flags are the only way to reliably see what decisions the compiler made, they are arguably not the most ergonomic one. The report may be perfectly readable when you work with a small file, but in larger projects and with daily use, it can quickly become frustrating. No wonder then that it’s a heavily underutilized feature of the Go SDK.

A few common pain points have come up in our discussions with Go developers:

  • The output is noisy – a real build prints escape decisions, inlining notes, and other diagnostics all in one place, and most of it isn’t what they’re looking for at the moment.
  • Messages are hard to connect to the source – each line is tagged with a file, line, and column, but they still have to open that file and find the right spot.
  • They have to constantly switch context – reading a message in the terminal, then jumping to the editor to see the code, then back again. This disrupts their concentration and slows the investigation.
  • Not every escaping value is worth optimizing, but the output treats every allocation equally. Meanwhile, most of them don’t matter for performance, and it’s hard to separate signal from noise.

None of this makes command-line escape analysis bad. It’s a genuinely powerful diagnostic that’s just not always convenient, especially when you’re trying to answer a focused question inside a large codebase. Because escape analysis has been locked behind obscure compiler flags and hard-to-parse logs, it’s become a niche practice even among experienced Go developers. That’s why our GoLand team has designed a tool that lowers the barrier to entry and bridges the gap between “powerful” and “convenient”.

How GoLand helps with escape analysis

The GoLand escape analysis support that arrived in the 2026.2 release was built to address the pain points we’d heard from developers. Under the hood, the tool largely does what you would do manually, running the go build command with the -gcflags="-m -m" flag. (To be precise, GoLand runs -gcflags="-m=2 -json=0,<path>", since we found that storing logs in JSON format provides a more structured and stable output).

But the tool now also adds a layer that parses that raw gcflags output and brings it directly into the editor, so you can stay close to your code while investigating allocation decisions instead of bouncing between the terminal and your files.

Running the escape analysis tool

The workflow is pretty straightforward. You open the Go Optimization window, choose Escape analysis, pick a scope, and run it.

You can analyze a single file or a whole package – the file-scoped option is handy for tightly focused units of code, such as an individual AWS Lambda handler, where you only care about one function’s allocations.

You can also choose which message types to show (see: How to read escape messages) and set environment variables for the Go process before running. The most frequently used are compiler flags (goflags) – on top of the standard -m, you might also be interested in -N (disables compiler optimizations) and -l (disables function inlining). The values of the GOARCH and GOOS environment variables can also affect your output, as some compiler decisions are target-dependent and can affect inlining, allocation decisions, and the diagnostics reported by gcflags.

Working with the output

Once the analysis finishes, you’ll find the results where they’re most useful:

  • In the editor: Gutter markers with escape messages appear right next to the lines they describe. If several messages belong to one line, the marker will show you the count. Also, hovering over the gutter marker will show you the compiler message and the escape flow. Hovering over a function name will show the escape results for that function, so you no longer have to match line numbers by hand.
  • In Go Optimization tools: This tool window lists the results by file, function and/or category, and then message type. You can also filter the logs by message type to cut through the noise. Click on any result to jump straight to the corresponding line in the editor.
  • Views: By default, the Escape analysis tool shows the output as a parsed tree. If you prefer the unprocessed output from the compiler’s command, the console output view shows it raw. Even there, the lines are clickable and take you to the right place in your code.

Comparing files

After you make changes to your code, you can rerun the analysis and compare results in separate tabs to see whether the allocation actually moved off the heap. This is important for iterative work and making sure the changes you make actually move the needle. If you’re already used to profiling your programs, this is a natural extension of that process. And if not, you can read more on how to profile Go code with GoLand to get a more detailed picture.

How to read escape messages

The console messages are generic. The two you’ll see most often are escapes to heap and moved to heap. Both indicate that a value couldn’t stay on the stack. Others describe inlining and parameter behavior.

Treat these as the diagnostic signals that they are, not as refactoring instructions. A moved to heap message is just information about what the compiler did. Whether it’s worth acting on depends entirely on how that affects performance.

Here are the message types that the GoLand tool surfaces and what they mean – they map directly to the compiler reports:

MessageWhat it means
Escape to HeapA value must be allocated on the heap because it’s still needed after the function returns.
Moved to HeapThe compiler couldn’t guarantee the value is no longer needed after the function returned, so it allocated it on the heap.
Leak ParamA function parameter escapes the current function and may need to stay valid after it returns.
Can InlineA function is small and simple enough that the compiler can (but doesn’t have to) replace calls to it with its body.
Inlining CallThe compiler actually inlined a specific call.
OtherAdditional compiler diagnostics related to escape and optimization decisions.

To read more about this and see examples, go to the GoLand documentation.

Escape analysis and performance

Escape analysis matters for performance because heap allocations aren’t free. Every value on the heap generates more work for the garbage collector to track and reclaim, and the allocation itself carries overhead that stack allocation doesn’t. If you reduce unnecessary heap allocations on a hot path, you can potentially meaningfully cut both GC pressure and latency.

That said, heap allocation is normal and frequently necessary in Go. Plenty of values should live on the heap, and trying to force everything onto the stack is a losing game that hurts your code’s readability for little to no gain. Escape analysis is most valuable in specific places: hot paths, tight loops, high-throughput services, serialization and deserialization code, and latency-sensitive workflows. Outside those areas, an escaping value is usually just an escaping value. In other words, the old adage about premature optimization applies to escape analysis like nowhere else, and you should only focus on the proverbial 3%.

The single most important habit is to measure. Escape analysis tells you what the compiler decided, but it doesn’t tell you whether that decision is hurting you – only benchmarks and profiling can do that. Use escape analysis alongside benchmarks and profiling in Go, and always measure before and after a change to see whether it actually helped. Escape analysis is one performance input, not a complete strategy on its own, and not every escaping value is worth a developer’s time.

Best practices for working with escape analysis

Finally, here’s a short, practical checklist for using escape analysis well in real projects:

  1. Start with measurement. Use profiling and benchmarks to find allocations that actually matter before you open the escape analysis logs. Don’t optimize unquestioningly.
  2. Focus on hot paths. Concentrate your attention on tight loops, high-throughput code, and latency-sensitive sections. Apart from these instances, escapes rarely justify the effort of avoiding them.
  3. Understand why the value escaped. Read the compiler message and the escape flow so you’re fixing the cause, not the symptom.
  4. Avoid unnecessary micro-optimizations. Treat heap allocation as a signal worth examining, not as an automatic bug to be eliminated.
  5. Protect readability and design. Don’t contort an API or sacrifice clarity to shave an allocation that doesn’t show up in your benchmarks. Maintainable code always wins over clever code.
  6. Verify your changes. Rerun the analysis and re-measure to confirm that a change did what you intended.

You may also be interested in Go’s official Guide to the Go Garbage Collector, which has an optimization guide for the entire GC, including how to eliminate heap allocations with escape analysis.

FAQ

Does escape analysis improve Go app performance?

Yes and no. When speaking of escape analysis as a part of the compilation process, it was designed to ensure optimal performance by prioritizing fast allocation and reducing garbage collection pressure, both of which improve your app’s performance.

However, as a developer tool, escape analysis is just a diagnostic, not an optimization that you turn on. What can improve performance is using its output to spot avoidable heap allocations on hot paths and adjusting your code accordingly. With code that isn’t performance-critical, acting on escape results usually changes nothing measurable.

Is escape analysis the same as profiling?

No. Profiling tells you where your program spends time or memory at runtime. Escape analysis is a compile-time snapshot of where values are allocated and why. They’re complementary: Profiling tells you where to look, and escape analysis helps you understand why the allocations are occurring in those locations.

Can the results of an escape analysis change between Go versions?

Yes. Escape decisions depend on the compiler, and the Go team improves its analysis and inlining over time, as they did in the 1.25 and 1.26 releases. A value that escapes in one Go version may stay on the stack when using another.

Should developers avoid pointers to reduce heap allocations?

Not as a rule. Returning or passing pointers can cause values to escape, but pointers are idiomatic and often the clearest choice. Avoiding them everywhere harms readability and can even hurt performance if large values have to be copied. Decide based on API design and measured impact, and use escape analysis to check rather than to enforce a blanket policy.

Do interfaces always cause values to escape?

No. Passing values through interfaces can contribute to heap allocation in some cases – often around formatting and logging – but it doesn’t always, and the compiler keeps getting better at avoiding it. Interface boundaries are worth keeping an eye on in the compiler output, but they’re not a guaranteed source of escapes.

When should I care about Go escape analysis?

When you have a performance-sensitive path and evidence that allocations are part of the problem. If profiling points to allocation pressure in a hot loop, a high-throughput service, or serialization code, escape analysis helps you understand and address it. For everyday code that meets its performance goals, you can let the compiler do its job and move on as Go intended.

Read the whole story
alvinashcraft
9 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

The Tokens You Can’t Wait For

1 Share

Somewhere in a Singapore data center, a bank is paying for eight H100s that spend most of the night waiting. The cluster was bought for good reasons (discomfort with customer documents leaving the building, a strategy team’s aversion to lock-in), so the bank secured its own sovereign compute. Now the finance team is asking why a machine that costs more per hour than a senior engineer runs at a fraction of its capacity. This is the GPU hangover. Over the last two years, enterprises rushed to lock in private clusters and reserved cloud nodes to build AI they could control. The hardware arrived; the utilization did not. The reason isn’t bad planning. It’s a mismatch between how standard models generate text and how enterprises actually use them, and text diffusion is the most interesting candidate for closing the gap. It’s also the most oversold, and the oversell hides in which workloads it actually helps.

Start with the physics. A standard autoregressive model, from the Llama, Mistral, or GPT families, for instance, generates one token at a time. The weights never change and never leave the card; they sit in the GPU’s high-bandwidth memory the whole time. The bottleneck is one level down. Arithmetic happens only in the chip’s tiny pool of on-chip memory, which is nowhere near big enough to hold a multibillion-parameter model. So for every single token, the full set of weights has to be streamed out of that main memory and through the compute units again—rereading the model from the card’s own memory into the card’s calculators, once per token, because the calculators cannot keep it resident. The math finishes almost instantly and the units then idle, waiting for the next slice of weights. Measured as arithmetic intensity, operations per byte moved, this sits near 1 at batch size one, while modern GPUs are built for intensities in the hundreds. The chip is starved, bottlenecked not by a shortage of compute but by the speed of the feed. The escape hatch is batching: Read the weights once and use them to compute the next token for hundreds of requests at the same time, amortizing that one expensive read across hundreds of tokens of useful work. On the same hardware, small versus large batches can swing cost per token 10- to 30-fold, which is why public APIs, running enormous batches across thousands of users, are cheap.

Everything hinges on whether you can accumulate concurrent work. An overnight queue of a million documents is trivially batchable, because nobody’s waiting. But when a single request must return in under a second, say a developer’s code completion or an onboarding check while the customer stands at the counter, you’ve spent your latency budget and can’t wait to fill a batch. The first kind of workload is not really memory-bound; you batch your way out of it. The second kind is, and no amount of total volume rescues it. And there’s a further subtlety: Generating tokens is memory-bound, but reading the prompt is already compute-bound, since the input is processed in parallel. Document extraction is mostly reading, long input and short output, so even a standard model spends much of that job in the regime where it was never starved in the first place.

Diffusion attacks exactly the part that is starved. Borrowing its mechanism from image generation, it starts with a block of masked or noisy tokens and refines the whole block in parallel over a few denoising passes, less like a typewriter and more like an editor revising a full draft at once. Because each pass does real arithmetic across the whole block, it’s compute-bound even at batch size one. Where autoregressive intensity sits near 1, a comparable diffusion model’s lands in the hundreds. It saturates the compute you already pay for without the concurrency you don’t have. The numbers are real. Inception Labs’ Mercury reported over 1,100 tokens per second on H100s for code generation, and the 2026 Mercury 2 release reported roughly 1,000 tokens per second on Blackwell at low latency. Google showed the paradigm at frontier scale with Gemini Diffusion, and open source LLaDA showed diffusion models follow autoregressive-like scaling laws. These are early but real: Mercury 2 is commercially available, Gemini Diffusion is in enterprise preview with general availability expected later in 2026, and the open models are maturing fast, even as autoregressive systems still dominate on tooling and ecosystem rather than any theoretical ceiling. So the headline is true in one specific place: for a latency-bound, single-stream request, diffusion can run an order of magnitude faster, because the autoregressive model is stuck memory-bound and cannot be batched out of it. But saturating the GPU is an engineering metric, and you can saturate a chip doing useless work. The real question is what it costs to produce a useful token, and on which workloads.

Before declaring a winner, a fair comparison has to account for what autoregressive serving can already do. Speculative decoding and its descendants, Medusa and EAGLE, use a small draft model to propose several tokens that the main model verifies in a single pass, giving roughly two- to four-fold single-stream speedups with no change in quality. Mixture-of-experts models attack the same wall from another direction, activating only a fraction of their weights per token and so moving less memory per token generated. The question is therefore not autoregressive versus diffusion in the abstract; it’s whether diffusion’s structural parallelism beats a speculatively decoded model’s incremental gain on the workload you actually have. For a tight single-stream latency target, diffusion’s edge is large and durable. For offline batch, neither trick matters much, because batching already pushes both architectures into compute-bound territory. Any framing that ignores speculative decoding is selling a false binary.

Whichever trick you reach for, the economics reduce to a single identity:

Effective cost per token = node cost per hour ÷ (throughput × utilization)

A public API is priced per token, concurrency independent, with no idle penalty. Owned compute is priced per hour, and its per-token cost is derived from how much you push through, so throughput and utilization are the only levers, and diffusion moves the first one decisively but only where batching is unavailable. The prices make the stakes concrete. A reserved AWS p5.48xlarge, eight H100s, lists near $55 an hour on demand, and one-year savings plans cut that by roughly 40 percent, to about $33 an hour. Against a cheap commodity API, a small model under a dollar per million tokens, owned compute loses on pure cost regardless of architecture; a $33-an-hour box, however well used, can’t beat a token you can rent for 40 cents. Diffusion’s economic win appears in only two situations: when the token you would otherwise buy is expensive, frontier or reasoning output at $5 to $15 per million, where a saturated owned node comfortably undercuts the API, or when the data can’t go to an external API at all, so the comparison becomes owned diffusion versus owned autoregressive. Most regulated enterprises live in that second case.

Nowhere is the distinction clearer than in the bank’s own document operation, which has two faces that look alike and behave like opposites. The overnight batch, millions of KYC packets, letters of credit, and loan files parsed into JSON while no one waits, is the easiest possible workload to batch. With continuous batching, a standard model runs at several thousand tokens per second and clears the queue on a single node; diffusion is somewhat faster and finishes the window sooner, but both fit on one box at a similar cost. If this were the whole workload, switching architectures would be hard to justify, because autoregressive batching has already solved most of the problem, and this job is mostly prefill anyway, its input tokens dwarfing the JSON output an API would bill for. The real-time path inverts the conclusion entirely. A relationship manager onboarding a customer needs the documents parsed in under a second while the customer waits; an officer clearing a letter of credit needs the answer now; an agentic flow is blocked on a single document before it can proceed. These requests arrive one at a time, each with a hard latency budget, so you can’t batch them, because batching trades latency for throughput and there is none to trade. A large autoregressive model in single-stream decode emits only tens of tokens per second, so a few hundred tokens of output take several seconds, and speculative decoding helps but does not reach interactive speed, while diffusion returns the same record in well under a second. The cost shows up as node count, and now it’s correctly attributed: to hold a subsecond target with the autoregressive model you must keep batches tiny, so each node serves only a handful of concurrent real-time requests and meeting peak demand means overprovisioning across many nodes, whereas diffusion clears each request fast enough that one node absorbs far more low-latency traffic and fits the same service level on a fraction of the fleet. The savings are real, and they come from the latency constraint defeating batching, not from low concurrency in the abstract.

The lesson of those two jobs generalizes into a routing rule sharper than the usual advice of customer-facing on APIs and internal on owned compute. The real test has two axes: whether the work can be batched, meaning it’s offline-tolerant rather than latency-bound and serial, and what each token is worth. Latency-bound, decode-heavy, low-value generation such as code completion, real-time extraction, and the chatter of agentic workflows is the diffusion sweet spot, where batching is unavailable, the quality gap is tolerable, and a fast owned node beats both an overprovisioned autoregressive fleet and an expensive API. High-value reasoning, where a wrong answer is costly, stays on frontier autoregressive models. And offline batch of any value density goes to whatever you already run well, because batching has already made it efficient.

That discipline matters because diffusion carries real constraints. Quality isn’t free: Diffusion trades some accuracy for speed, landing around 85% to 95% of strong autoregressive baselines, competitive on structured output but trailing by 5% to 15% percent on hard reasoning, on vendor and secondary figures that deserve independent verification against your own data. That’s fine for field extraction and not fine for credit decisions, so any serious deployment budgets a fallback for outputs that miss a confidence threshold and folds its cost back into the effective rate. Being compute-bound is itself a cost, since diffusion earns its high intensity partly by doing more total work per useful token, which is why the metric that matters is always tokens per dollar at an acceptable quality bar and never utilization on its own. The baseline is also moving: speculative decoding, better schedulers, and mixture-of-experts models keep narrowing the gap without a model swap, so diffusion has to beat a moving target rather than the naive one. And the tooling is early, with open-source diffusion serving in 2026 sitting roughly where open-source autoregressive serving did in early 2024, functional and improving fast but short on the mature inference stacks teams take for granted with vLLM or TensorRT-LLM. Every conclusion here also moves with two prices you don’t fully control, the API rate you compare against and the hardware rate you negotiated, so it is worth dating your assumptions and revisiting them.

The hangover, in the end, is not that enterprises bought the wrong hardware. Many bought it for reasons like sovereignty, data control, the avoidance of lock-in that have nothing to do with token economics and won’t go away. They bought it expecting it to behave like a public cloud, then ran it at a concurrency that cloud economics depend on and that their most valuable internal workloads, the latency-bound ones, can never reach. Text diffusion is not a way to beat the API, nor a blanket upgrade for everything an enterprise runs. It’s a precise tool for a precise gap, the latency-bound, decode-heavy, sovereignty-constrained work where batching is impossible and an autoregressive model leaves a node both starved and overprovisioned. For the copilots, the real-time checks, and the agentic steps that have to answer now, it turns that node from a guilty line item into a saturated asset, on a fraction of the boxes the alternative would need. That’s a narrower claim than rescuing your hardware ROI, and a far more durable one. The future of enterprise AI is the right architecture, on the right hardware, carrying the right tokens, and knowing which tokens those are is the part no vendor will sell you.

Sources for further reading

Inception Labs, “Mercury: Ultra-Fast Language Models Based on Diffusion” (arXiv:2506.17298) and Mercury 2 launch coverage, February 2026

Consistency Diffusion Language Models” (arXiv:2511.19269) on the arithmetic intensity of autoregressive versus diffusion decoding across batch sizes

Baseten’s “A guide to LLM inference and performance” on the memory wall, batching, and the prefill versus decode distinction

Leviathan et al., “Fast Inference from Transformers via Speculative Decoding” (2023), with Medusa and EAGLE; AWS EC2 P5 pricing pages and 2025 P5 savings-plan announcements

LLaDA2.0 (Bie et al., 2025) on the scaling behavior of diffusion language models.

Note: Throughput figures are engineering approximations for a 70B-class model; substitute your own measured numbers, at your own batch sizes and sequence lengths, before any procurement decision.



Read the whole story
alvinashcraft
10 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

The “Pixel Police” are Retired: Why AI Agents are the New Mediators of Web Design

1 Share
The designer-developer handoff is officially dead—and AI just pulled the trigger. Instead of wasting weeks translating pixels into code, teams are now building live, together, in real time with AI agents doing the grunt work.
Read the whole story
alvinashcraft
10 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Setup the GitHub Copilot App to manage an Azure Subscription

1 Share
From: ITOpsTalk
Duration: 3:31
Views: 28

This video walks you through installing and configuring the GitHub Copilot App to manage an Azure subscription

▶️ https://github.com/github/app

Content is for educational purposes and is not monetized.

▶️ Orin's social links: https://aka.ms/orin
▶️ Script and vocal performance by Orin
▶️ Clockwork Orin Avatar by D-ID
▶️ Voice enhancement by 11labs

Read the whole story
alvinashcraft
13 minutes ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories