Quantitative Analysis
Quantitative analysis asks whether a measurable property stays within required bounds. In embedded systems, those properties include execution time, memory use, energy, power, reaction time, physical position, temperature, and network delay. Timing is the representative case because a correct control value can be unsafe if it is produced too late.
Lee and Seshia focus on execution-time analysis, especially worst-case execution time (WCET). The key theme is that WCET is a property of both the program and the platform. Loops, branches, function calls, infeasible paths, caches, pipelines, interrupts, and memory hierarchy all affect the result.
Definitions
A quantitative property is any measurable property of the system or its execution.
For a program running in environment , a quantity can be viewed abstractly as
where represents program inputs and represents environmental parameters such as cache state or network delay.
The worst-case execution time (WCET) is the largest execution time over all relevant inputs and platform states. The best-case execution time (BCET) is the smallest.
An upper bound on WCET is safe if it is greater than or equal to the true WCET. A bound is tight if it equals or closely approximates the true extreme; it is loose if it is overly pessimistic.
A threshold property asks whether a quantity always stays below or above a threshold:
A basic block is a straight-line code region with one entry and one exit. A control-flow graph (CFG) has basic blocks as nodes and possible control transfers as edges.
A loop bound is an upper bound on how many times a loop can execute. A ranking function maps program states to a well-ordered set and decreases on each loop iteration, proving termination.
Key results
Termination and loop bounds are prerequisites for WCET. Without a bound on loop iterations or recursion depth, the worst-case time may be unbounded. Determining such bounds is undecidable in general, but many embedded coding styles use simple bounded loops.
Path explosion is real. A loop body with a conditional executed times can have branch-outcome paths. WCET methods therefore avoid enumerating every path.
Some paths are infeasible. A naive maximum over all CFG paths can be too pessimistic if it includes branch combinations that cannot occur for any input.
The implicit path enumeration technique uses variables to count how often basic blocks or edges execute, then maximizes a linear cost subject to flow constraints and loop/path constraints. If block has execution-time bound and executes times, the objective is
Hardware matters. Cache misses, pipeline stalls, branch prediction, DRAM refresh, and bus contention can make instruction timing vary by orders of magnitude. Accurate WCET requires platform modeling or careful measurement.
Other quantitative analyses use similar ideas. Stack-size analysis examines call graphs and interrupt nesting. Heap analysis must handle dynamic allocation and fragmentation. Energy analysis often depends on instruction mix, data values, switching activity, and execution time.
Quantitative analysis differs from ordinary testing because it must reason about extremes. A test can show that one input completes in microseconds; it cannot by itself show that no input takes more than microseconds. Static analysis attempts to prove a bound by considering program structure and platform behavior. Measurement-based analysis attempts to guide tests toward expensive paths and use platform measurements. Many practical tools combine the two.
The environment parameter is often where hidden assumptions live. The same function may run quickly when cache lines are warm and slowly when they are cold. It may run quickly when interrupts are disabled and slowly when preempted by a high-priority ISR. It may use little energy for one data pattern and more for another because switching activity differs. A defensible bound must say which platform states and interferences are included.
There is also a useful distinction between proving a tight bound and proving a threshold. If the deadline is millisecond, an analysis that proves WCET milliseconds is sufficient even if the true WCET is milliseconds. Tightness matters when resources are scarce or schedules are dense, but safety often requires only a conservative bound below the required threshold.
Quantitative models should state whether they are compositional. If one task has a WCET of microseconds and another has a WCET of microseconds, their combined worst case is not always just microseconds. Shared caches, bus contention, locks, preemption, and pipeline state can add interference. Conversely, two worst cases may be mutually exclusive because they require incompatible inputs. Good analysis records which quantities can be safely added and which require a joint model.
Loop-bound inference is a bridge between program semantics and arithmetic constraints. A simple for loop with a constant bound is straightforward. A while loop that shifts an unsigned integer right until zero requires reasoning about bit width. A loop that depends on sensor input or network input may require environmental assumptions, input validation, or a timeout. The more the bound depends on external behavior, the more it belongs in the system requirements rather than hidden inside code.
Energy and power analysis show why execution time is not the only resource. A program may run quickly but draw high peak current, or run slowly in a low-power mode and consume less total energy. Wireless transmission, flash writes, and sensor polling can dominate CPU cost. CPS design often requires trading time, energy, accuracy, and lifetime rather than optimizing one quantity in isolation.
Quantitative assumptions should be versioned with the platform. A compiler upgrade, cache configuration change, different flash wait-state setting, or new RTOS tick rate can invalidate a previous bound. For that reason, timing and memory analyses belong in the build and release evidence, not only in an early design notebook.
Visual
| Factor | Why it affects WCET | Typical analysis response |
|---|---|---|
| Loop bounds | Repetition dominates time | Prove or annotate max iterations |
| Branch paths | Different blocks execute | CFG flow constraints |
| Infeasible paths | Naive max may be impossible | Logical constraints |
| Function calls | Stack and path expansion | Call graph analysis |
| Cache | Hits and misses differ widely | Abstract interpretation or cache constraints |
| Pipeline | Hazards and stalls | Microarchitectural model |
| Interrupts | Preemption adds latency | Include ISR interference |
Worked example 1: Loop-bound WCET estimate
Problem: A loop executes at most iterations. Each iteration executes blocks with worst-case times: condition block cycles, body block cycles, update block cycles. The loop exit condition costs cycles one extra time. Estimate a simple WCET bound.
Method:
- Condition block executes once per iteration plus one final exit check:
- Condition cost:
- Body cost:
- Update cost:
- Total bound:
Answer: A simple WCET upper bound is cycles, assuming the block bounds already include hardware effects and no interrupts occur.
Worked example 2: Cache conflict effect
Problem: A loop reads arrays x and y. On one input size, all needed values fit in one cache block after the first miss. On another size, every access alternates between two blocks mapping to the same direct-mapped cache set. Suppose a cache hit costs cycle, a miss costs cycles, and the loop performs loads. Compare memory-load costs if there is 1 miss versus 16 misses.
Method:
- Case A: one miss and fifteen hits:
- Case B: sixteen misses:
- Difference:
- Ratio:
Answer: The conflict-heavy case costs cycles for loads, about times the -cycle case. Small layout changes can have large timing effects.
Code
def loop_wcet(iterations, costs):
condition = (iterations + 1) * costs["condition"]
body = iterations * costs["body"]
update = iterations * costs["update"]
return condition + body + update
costs = {"condition": 2, "body": 10, "update": 3}
print(loop_wcet(32, costs))
def load_cost(loads, misses, hit_cost=1, miss_cost=50):
return misses * miss_cost + (loads - misses) * hit_cost
print(load_cost(16, 1), load_cost(16, 16))
Common pitfalls
- Using measured average time as a hard real-time guarantee.
- Ignoring infeasible paths in one direction and hardware variation in the other; both can dominate the bound quality.
- Writing unbounded loops or recursion in code that must have a WCET.
- Assuming cache improves all timing. Caches improve average time but can make worst-case analysis harder.
- Forgetting ISR interference when analyzing a task's execution time.
- Treating a loose WCET bound as useless. A loose safe bound may still prove a threshold property if it is below the deadline.