Files
mercury/deep_profiler/measurement_units.m
Zoltan Somogyi 943220205d Avoid using unknown formats.
deep_profiler/measurement_units.m:
    When writing out floats with given numbers of decimal places
    after the dot, use fixed format strings that the compiler can check.

deep_profiler/Mercury.options:
    Stop specifying --no-warn-unknown-format-calls for measurement_units.m.

deep_profiler/display.m:
deep_profiler/display_report.m:
    Conform to the change in measurement_units.m.

deep_profiler/html_format.m:
    Style fix.
2021-07-31 16:53:52 +10:00

390 lines
10 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2008-2011 The University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%---------------------------------------------------------------------------%
%
% File: measurement_units.m.
% Author: pbone.
%
% This module contains abstract data types for representing memory, time
% and percentages, and predicates and functions for operating on them.
%
%---------------------------------------------------------------------------%
:- module measurement_units.
:- interface.
%---------------------------------------------------------------------------%
%
% Memory
%
% Units for measuring memory.
%
:- type memory_units
---> units_words
; units_bytes.
% Memory abstract data type.
%
% This type represents an amount of computer memory while abstracting away
% how the memory is measured.
%
:- type memory.
% memory_words(Words, BytesPerWord) = Memory
%
% Convert number of words to memory type.
%
:- func memory_words(int, int) = memory.
% Division for memory units. Use of this function may return fractions of
% units.
%
:- func (memory) / (int) = (memory) is det.
:- type num_decimal_places
---> ndp_0
; ndp_2.
% Format a memory value using the given units.
%
% The third argument is the number of decimal places to show.
%
:- func format_memory(memory, memory_units, num_decimal_places) = string.
:- pred compare_memory(memory::in, memory::in, comparison_result::out) is det.
%---------------------------------------------------------------------------%
%
% Percent
%
% Percent abstract data type.
%
:- type percent.
% Convert from float between 0.0 and 1.0 (inclusive) and percent type.
% Input of values outside the range above will throw exceptions.
%
:- func percent(float) = percent.
% Format a percentage. Prints the percentage with one decimal place and a
% '%' symbol.
%
:- func format_percent(percent) = string.
:- pred percent_at_or_above_threshold(int::in, percent::in) is semidet.
%---------------------------------------------------------------------------%
%
% Time
%
% Time abstract data type.
%
:- type time.
% ticks_to_time(Ticks, TicksPerSec) = Time
%
% Converts profiler ticks to time,
%
:- func ticks_to_time(int, int) = time.
% time_percall(Time, Calls) = TimePercall
%
% Time / Calls = TimePerCall.
%
:- func time_percall(time, int) = time.
% Format a time, this prints the time in the most readable units for its
% magnitude. One or two letters follow the time to describe the units.
%
% Currently supported units are seconds; milli, micro, nano and pico
% seconds. For micro seconds a letter u is used rather than the greek
% letter mu.
%
:- func format_time(time) = string.
%---------------------------------------------------------------------------%
%
% Probability
%
:- type probability.
% A certain thing, A probability of 1.0.
%
:- func certain = probability.
% An impossible thing. A probability of 0.0.
%
:- func impossible = probability.
% Any probability. Note that the float augment must be between 0.0 and 1.0
% inclusive.
%
:- func probable(float) = probability.
% Convert a probability value into a floating point value.
%
:- func probability_to_float(probability) = float.
% Combine probabilities.
%
:- func or(probability, probability) = probability.
:- func and(probability, probability) = probability.
% The probability of the given probability not occurring.
%
:- func not_probability(probability) = probability.
%---------------------------------------------------------------------------%
%
% Code for formatting numbers.
%
% Format an integer and place commas between groups of three digits.
%
:- func commas(int) = string.
:- func one_decimal_fraction(float) = string.
:- func two_decimal_fraction(float) = string.
:- func four_decimal_fraction(float) = string.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module char.
:- import_module float.
:- import_module list.
:- import_module require.
:- import_module string.
%---------------------------------------------------------------------------%
%
% Memory.
%
:- type memory
---> memory(
words :: float,
word_size :: int
).
memory_words(WordsI, BytesPerWord) = memory(WordsF, BytesPerWord) :-
WordsF = float(WordsI).
memory(Nom, BPW) / Denom =
( if Denom = 0 then
memory(0.0, BPW)
else
memory(Nom / float(Denom), BPW)
).
format_memory(memory(Words, BPW), units_bytes, Decimals) =
format_number(Decimals, Words * float(BPW)).
format_memory(memory(Words, _), units_words, Decimals) =
format_number(Decimals, Words).
:- func format_number(num_decimal_places, float) = string.
format_number(Decimals, Num) = Str :-
(
Decimals = ndp_0,
string.format("%.0f", [f(Num)], Str0)
;
Decimals = ndp_2,
string.format("%.2f", [f(Num)], Str0)
),
Str = decimal_fraction(Str0).
compare_memory(MemoryA, MemoryB, Result) :-
MemoryA = memory(WordsA, WordSizeA),
MemoryB = memory(WordsB, WordSizeB),
require(unify(WordSizeA, WordSizeB),
"compare_memory: word size mismatch"),
compare(Result, WordsA, WordsB).
%---------------------------------------------------------------------------%
%
% Percentages.
%
:- type percent
---> percent_float(float).
percent(P) = percent_float(P).
format_percent(percent_float(P)) = String :-
string.format("%.2f", [f(P * 100.0)], String).
percent_at_or_above_threshold(Threshold, percent_float(P)) :-
(P * float(100)) >= float(Threshold).
%---------------------------------------------------------------------------%
%
% Time.
%
% Time is stored in seconds using a float.
%
:- type time
---> time_sec(float).
ticks_to_time(Ticks, TicksPerSec) = Time :-
% TicksPerSec will not be zero.
SecPerTick = 1.0 / float(TicksPerSec),
Time = time_sec(float(Ticks) * SecPerTick).
time_percall(time_sec(Time), Calls) = time_sec(TimePerCall) :-
( if Calls = 0 then
TimePerCall = 0.0
else
TimePerCall = Time / float(Calls)
).
:- func milli = float.
milli = 0.001.
:- func micro = float.
micro = 0.000001.
:- func nano = float.
nano = 0.000000001.
:- func pico = float.
pico = 0.000000000001.
% TODO: When there is no resolution beyond 10ms since there is a clock tick
% every 10ms, the decimal points on some of these numbers should not be shown.
% However it's probably useful to show at least 2 decimal points when the value
% is within the range 1-10 seconds.
%
% TODO: If the display system supports printing the greek letter mu, then it
% should be used rather than the latin letter u.
format_time(time_sec(F)) = String :-
( if F < nano then
% Print in ps.
string.format("%.1fps", [f(F / pico)], String)
else if F < micro then
% Print in ns.
string.format("%.1fns", [f(F / nano)], String)
else if F < milli then
% Print in us.
string.format("%.1fus", [f(F / micro)], String)
else if F < 1.0 then
% Print in ms.
string.format("%.1fms", [f(F / milli)], String)
else
% Print in seconds.
string.format("%.1fs", [f(F)], String)
).
%---------------------------------------------------------------------------%
%
% Probabilities.
%
:- type probability == float.
certain = 1.0.
impossible = 0.0.
probable(Prob) = Prob :-
( if
Prob =< 1.0,
Prob >= 0.0
then
true
else
error(format("Probability %f out of range 0.0 to 1.0 inclusive",
[f(Prob)]))
).
probability_to_float(Prob) = Prob.
% Combine disjunct probabilities by the negation of the conjunction of
% their negations.
%
% A V B = ~(~A ^ ~B)
%
or(A, B) = not_probability(and(not_probability(A), not_probability(B))).
% Combine conjoint probabilities with multiplication.
and(A, B) = A * B.
not_probability(X) = 1.0 - X.
%---------------------------------------------------------------------------%
%
% Code for formatting numbers.
%
commas(Num) = Str :-
string.int_to_string(Num, Str0),
add_commas_intstr(Str0, Str).
one_decimal_fraction(Measure) = Str :-
string.format("%.1f", [f(Measure)], Str0),
Str = decimal_fraction(Str0).
two_decimal_fraction(Measure) = Str :-
string.format("%.2f", [f(Measure)], Str0),
Str = decimal_fraction(Str0).
four_decimal_fraction(Measure) = Str :-
string.format("%.4f", [f(Measure)], Str0),
Str = decimal_fraction(Str0).
% Format a string representing a floating point number,
% placing commas between groups of three digits in the integer part.
%
:- func decimal_fraction(string) = string.
decimal_fraction(Str0) = Representation :-
string.split_at_char('.', Str0) = SubStrings,
( if
SubStrings = [WholeString0, FractionString]
then
add_commas_intstr(WholeString0, WholeString),
Representation = WholeString ++ "." ++ FractionString
else if
% If there are no decimal symbols in the number, try to work with it
% as an integer.
SubStrings = [WholeString]
then
add_commas_intstr(WholeString, Representation)
else
unexpected($pred, "didn't split on decimal point properly")
).
%---------------------------------------------------------------------------%
:- pred add_commas_intstr(string::in, string::out) is det.
add_commas_intstr(Str0, Str) :-
string.to_char_list(Str0, Chars0),
list.reverse(Chars0, RevChars0),
string.from_char_list(reverse(add_commas(RevChars0)), Str).
:- func add_commas(list(char)) = list(char).
add_commas([]) = [].
add_commas([C]) = [C].
add_commas([C, D]) = [C, D].
add_commas([C, D, E]) = [C, D, E].
add_commas([C, D, E, F | R]) = [C, D, E, (',') | add_commas([F | R])].
%---------------------------------------------------------------------------%
:- end_module measurement_units.
%---------------------------------------------------------------------------%