pub struct Frequency { /* private fields */ }Expand description
How often a block runs, relative to one entry to the function it is in.
The entry block is Frequency::ENTRY, which is one. A block inside a loop predicted to run
ten times is ten. A block on an error path is a fraction. The unit is deliberately relative:
how often this block runs compared to the whole function is a question that can be answered
without a profile, and how often it runs compared to the rest of the program cannot.
Implementations§
Source§impl Frequency
impl Frequency
Sourcepub const ENTRY: Self
pub const ENTRY: Self
One execution per entry to the function, which is what the entry block gets.
Precise, because it is not a claim about the program. It is the definition of the unit.
Sourcepub const UNKNOWN: Self
pub const UNKNOWN: Self
Nobody has computed one for this block yet.
Zero, so that a consumer that ignores the quality is at least conservative rather than wrong in the direction that puts cold code in the hot section. The quality is what says the zero means nothing.
Sourcepub const MAX: Self
pub const MAX: Self
As high as this goes, which is what everything saturates to.
A frequency here means the arithmetic ran out of room, which nested loops will do to any fixed size number. What it must not do is wrap, because a hot block that comes out cold is a decision nobody can explain afterwards.
Sourcepub const fn times(count: u32, quality: Quality) -> Self
pub const fn times(count: u32, quality: Quality) -> Self
Runs this many times per entry to the function, believed this much.
Sourcepub const fn raw(self) -> u64
pub const fn raw(self) -> u64
The raw fixed point value, scaled by Probability::SCALE.
For a dump or a comparison. A consumer doing arithmetic on this rather than on the
Frequency is a consumer that has dropped the quality on the floor.
Sourcepub const fn is_saturated(self) -> bool
pub const fn is_saturated(self) -> bool
Whether the arithmetic ran out of room getting here.
Sourcepub fn along(self, edge: Probability) -> Self
pub fn along(self, edge: Probability) -> Self
This block’s frequency carried along an edge taken this often.
Sourcepub fn repeated(self, iterations: u32) -> Self
pub fn repeated(self, iterations: u32) -> Self
This block, once per iteration of a loop that runs iterations times.
The caller clamps the iteration count before it gets here, per section 11.2. Saturating multiplication keeps the arithmetic honest, but a nest of loops each claimed to run four billion times has already lost the argument somewhere further up.
Sourcepub fn repeated_while(self, again: Probability, cap: u32) -> Self
pub fn repeated_while(self, again: Probability, cap: u32) -> Self
This block’s frequency once the loop it heads has gone round as often as it is going to.
The header of a loop runs once for the iteration that enters it and again for every
iteration that goes back to it, so if again is the probability of going round, the header
runs 1 / (1 - again) times for each entry. That is the sum of the geometric series and it
is the whole of Wu and Larus’s method in one line, which is why section 11.3 asks for it
rather than for an iteration of the linear system until it settles.
Two things have to be true of again or this produces nonsense, and both are handled here
rather than in the caller, because a division by nearly zero is the most common way a
frequency implementation breaks. A loop with no predicted exit has again at certainty and
the series does not converge, and one with an again a hair below certainty converges on a
number no machine will run. So the count is capped at cap iterations, which is section
11.2’s max-predicted-iterations, and the cap is what a loop whose exit nothing predicted
gets.
Sourcepub fn is_hot_in_function(self, entry: Self) -> bool
pub fn is_hot_in_function(self, entry: Self) -> bool
Whether this block is hot compared with the rest of the function it is in.
Section 11.4, and GCC’s hot-bb-frequency-fraction: at least one part in
HOT_BLOCK_FRACTION of the entry block. This is the question the register allocator and
the loop passes are asking, and it is answerable with no profile at all, because it is a
comparison between two blocks that were predicted the same way.
An entry frequency of zero is not a scale to be hot against, so nothing is hot in a function that never runs.
Sourcepub const fn is_hot_in_program(self) -> Hotness
pub const fn is_hot_in_program(self) -> Hotness
Whether this block is hot compared with the whole program.
A different question from Frequency::is_hot_in_function, which is why section 11.4 asks
for two predicates named so they cannot be confused. The section placement decision wants
this one: a block that runs a thousand times per call in a function called twice is hot in
its function and cold in the program.
It is Hotness::Unknown today and will be until there is whole program profile data,
which is document 35 and is after M4. The predicate exists now so that every caller is
written against three answers from the start. A boolean that quietly means “hot, or we have
no idea” is how cold code ends up in the hot section, and retrofitting the third answer
into callers written against two is the part that does not happen.