Files
mercury/library/lazy.m
Paul Bone 887a55f783 Make variable use analysis assume that the compiler cannot push signals or
waits for futures across module boundaries, which is usually true.

Add a new option to the feedback tool
--implicit-parallelism-intermodule-var-use.  This option re-enables the old
behaviour.

Fix a number of bugs and improve the pretty-printing of candidate parallel
conjunctions.

deep_profiler/var_use_analysis.m:
    Implement the new behaviour and allow it to be controlled.

    Refactor some code to slightly reduce the number of arguments passed to
    predicates.

deep_profiler/mdprof_feedback.m:
    Implement the new command line option.

    Conform to changes in feedback.automatic_parallelism.m.

deep_profiler/recursion_patterns.m:
    Fixed a bug in the handling of can-fail switches.

deep_profiler/mdprof_fb.automatic_parallelism.m:
    Fix a bug in the calculation of dependency graphs.  All goals are
    represented by vertexes and dependencies are edges.  The program failed to
    create a vertex for a goal that had no edges.

    Fix a crash when trying to compute variable use information for a goal that
    is never called.  This was triggered by providing the new variable use
    information in the feedback format.

    Using the extra feedback information improve the pretty-printing of
    candidate parallelisations.

    Conform to changes in feedback.automatic_parallelism.m

    Conform to changes in var_use_analysis.m

mdbcomp/feedback.automatic_parallelism.m:
    Add the new option to control intermodule variable use analysis.

    Provided more information in the candidate parallel conjunctions feedback.

        The costs of the goals before and after the parallel conjunction are
        now provided.

        The cost of every goal is now provided (not just calls)

        Variable production and consumption times of the shared variables are
        provided for each goal if the analysis evaluated them.

    Modified convert_candidate_par_conjunctions_proc/3 and
    convert_candidate_par_conjunction/3 to pass a reference to the current
    parallel conjunction to their higher order argument.

mdbcomp/feedback.m:
    Increment feedback file version number.

deep_profiler/program_representation_utils.m:
    Improve the pretty-printing of goal representations, in particular, their
    annotations.

deep_profiler/create_report.m:
    Conform to changes in var_use_analysis.m.

deep_profiler/display_report.m:
    Conform to changes in program_representation_utils.m.

library/lazy.m:
    Added a new predicate, read_if_val(Lazy, Value) which is true of Lazy has
    already been forced and produced Value.
    (No update to NEWS necessary).
2010-10-16 04:11:05 +00:00

178 lines
5.7 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
%-----------------------------------------------------------------------------%
% Copyright (C) 1999, 2006, 2009-2010 The University of Melbourne.
% This file may only be copied under the terms of the GNU Library General
% Public License - see the file COPYING.LIB in the Mercury distribution.
%-----------------------------------------------------------------------------%
%
% lazy.m - provides support for optional explicit lazy evaluation.
%
% Author: fjh, pbone.
% Stability: medium.
%
% This module provides the data type `lazy(T)' and the functions `val',
% `delay', and `force', which can be used to emulate lazy evaluation.
%
% A field within a data structure can be made lazy by wrapping it within a lazy
% type. Or a lazy data-structure can be implemented, for example:
%
% :- type lazy_list(T)
% ---> lazy_list(
% lazy(list_cell(T))
% ).
%
% :- type list_cell(T)
% ---> cons(T, lazy_list(T))
% ; nil.
%
% Note that this makes every list cell lazy, whereas:
%
% lazy(list(T))
%
% uses only one thunk for the entire list. And:
%
% list(lazy(T))
%
% uses one thunk for every element, but the list's structure is not lazy.
%
%-----------------------------------------------------------------------------%
:- module lazy.
:- interface.
% A lazy(T) is a value of type T which will only be evaluated on
% demand.
%
:- type lazy(T).
% Convert a value from type T to lazy(T)
%
:- func val(T) = lazy(T).
% Construct a lazily-evaluated lazy(T) from a closure
%
:- func delay((func) = T) = lazy(T).
% Force the evaluation of a lazy(T), and return the result as type T.
% Note that if the type T may itself contains subterms of type lazy(T),
% as is the case when T is a recursive type like the lazy_list(T) type
% defined in lazy_list.m, those subterms will not be evaluated --
% force/1 only forces evaluation of the lazy/1 term at the top level.
%
% A second call to force will not re-evaluate the lazy expression, it will
% simply return T.
%
:- func force(lazy(T)) = T.
% Get the value of a lazy expression if it has already been made available
% with force/1 This is useful as it can provide information without
% incurring (much) cost.
%
:- pred read_if_val(lazy(T)::in, T::out) is semidet.
% Test lazy values for equality.
%
:- pred equal_values(lazy(T)::in, lazy(T)::in) is semidet.
:- pred compare_values(comparison_result::uo, lazy(T)::in, lazy(T)::in) is det.
%-----------------------------------------------------------------------------%
%
% The declarative semantics of the above constructs are given by the
% following equations:
%
% val(X) = delay((func) = X).
%
% force(delay(F)) = apply(F).
%
% The operational semantics satisfy the following:
%
% - val/1 and delay/1 both take O(1) time and use O(1) additional space.
% In particular, delay/1 does not evaluate its argument using apply/1.
%
% - When force/1 is first called for a given term, it uses apply/1 to
% evaluate the term, and then saves the result computed by destructively
% modifying its argument; subsequent calls to force/1 on the same term
% will return the same result. So the time to evaluate force(X), where
% X = delay(F), is O(the time to evaluate apply(F)) for the first call,
% and O(1) time for subsequent calls.
%
% - Equality on values of type lazy(T) is implemented by calling force/1
% on both arguments and comparing the results. So if X and Y have type
% lazy(T), and both X and Y are ground, then the time to evaluate X = Y
% is O(the time to evaluate (X1 = force(X)) + the time to evaluate
% (Y1 = force(Y)) + the time to unify X1 and Y1).
%
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module mutvar.
:- type lazy(T)
---> lazy(mutvar(lazy_state(T)))
where equality is equal_values,
comparison is compare_values.
% Note that we use a user-defined equality predicate to ensure
% that unifying two lazy(T) values will do the right thing.
%
:- type lazy_state(T)
---> value(T)
; closure((func) = T).
%-----------------------------------------------------------------------------%
equal_values(X, Y) :-
force(X) = force(Y).
compare_values(R, X, Y) :-
compare(R, force(X), force(Y)).
%-----------------------------------------------------------------------------%
val(X) = lazy(Mutvar) :-
promise_pure (
impure new_mutvar(value(X), Mutvar)
).
delay(F) = lazy(Mutvar) :-
promise_pure (
impure new_mutvar(closure(F), Mutvar)
).
%-----------------------------------------------------------------------------%
force(Lazy) = Value :-
% The promise_equivalent_solutions scope is needed to tell the compiler
% that force will return equal answers given arguments that are equal
% but that have different representations.
promise_equivalent_solutions [Mutvar] (
Lazy = lazy(Mutvar)
),
promise_pure (
impure get_mutvar(Mutvar, State),
(
State = value(Value)
;
State = closure(Thunk),
Value = apply(Thunk),
impure set_mutvar(Mutvar, value(Value))
)
).
%-----------------------------------------------------------------------------%
read_if_val(Lazy, Value) :-
promise_equivalent_solutions [Mutvar] (
Lazy = lazy(Mutvar)
),
promise_pure (
impure get_mutvar(Mutvar, State),
State = value(Value)
).
%-----------------------------------------------------------------------------%