1 September 2026 · measurement
Concurrency at the contract level changes what a machine can do. In uModel the unit of parallel work is the individual contract, so a projection spreads across every available thread without being reorganised to allow it.
This architecture is expected to significantly reduce cloud cost after it is deployed.
Most projection systems parallelise at a coarser grain. Work is distributed across scenarios, or across groups of contracts assembled for the purpose — a partition the modeller has to define, maintain, and reason about. That works, but it ties the available concurrency to how the run was carved up rather than to how much hardware is present: a single-scenario run has nothing to spread, and an awkward grouping leaves threads idle. Getting finer-grained concurrency out of such a system usually means restructuring the model.
Here the contract is already an independent unit of work, so there is no partition to design. Seven scenarios or one, ten thousand contracts or a hundred thousand — the same run fills the machine.
That is an architectural property, not a tuning setting. The measurement below is what it looks like on one desktop.
One fund. Three contract types projected together — liabilities and assets advancing in the same run, not reconciled afterwards.
| Contracts | Work per contract | |
|---|---|---|
| Term life | 9,995 | Monthly cash flows, an iterative Newton solve for net level premium at issue, a reserve at every year |
| Universal life | 5,000 | Account value mechanics — cost of insurance, loads, credited interest, cash value — plus solves for guaranteed maturity premium and guaranteed maturity fund |
| Fixed-rate bonds | 1,000 | Cash flows, and credit rating migration through an eight-state model — AAA to CCC plus Default, driven by a transition matrix |
Roughly 16,000 contracts, seriatim — no compression, no grouping, no model points. The solving is per contract, not per model point.
7 scenarios. 600 months — 50 years. Every contract, every month, every scenario.
One desktop: eight cores, sixteen logical processors.
2 minutes 13 seconds. 132,677 ms from enqueue to completion, all seven scenarios finished.
The engine measures its own thread engagement: wall time against CPU time consumed gives the number of threads actually kept busy.
| Contracts | Wall | CPU | Threads busy (of 16) | |
|---|---|---|---|---|
| Term life | 9,995 | 258 ms | 3,656 ms | 14.2 |
| Universal life | 5,000 | 152 ms | 2,046 ms | 13.5 |
| Fixed-rate bonds | 1,000 | 115 ms | 859 ms | 7.5 |

All sixteen logical processors during this run. Each dip is a scenario boundary: one scenario finishes and the next is set up before contract work resumes.
With seven scenarios completing inside a couple of minutes, those boundaries fall often enough to show. Run the same model over a hundred thousand contracts and each scenario takes long enough that a sixty-second window may contain no boundary at all — the same view becomes a flat wall:

The same machine during a 100,000-contract stress test on 2026-08-30. No dips in the window — at that volume a single scenario occupies the processor for longer than the chart shows.
Two caveats worth stating plainly. Sixteen logical processors is eight physical cores with hyperthreading, so fourteen threads busy is not a fourteen-fold speed-up. And this run recomputes term cash flows for all seven scenarios even though they do not vary by scenario — reuse is an optimisation not applied here, so the time is an upper bound.
None of that changes the shape of the result. One desktop carried sixteen thousand seriatim contracts with per-contract solving, an asset portfolio under credit migration, and a full scenario set, in a little over two minutes — because the work was already in a form the hardware could take.