[m-rev.] For review: Coverage Profiling

Paul Bone pbone at csse.unimelb.edu.au
Sat Mar 1 17:58:48 AEDT 2008


For review by Zoltan.

Estimated hours taken: 100
Branches: main

Introduced coverage profiling.  Like regular profiling it shows 'hot
spots' within a program, coverage profiling goes further to show the most
common execution paths through a procedure.  It's intended that the coverage
profiling data will be used by the upcoming automatic parallelism feature,
but may be used to analyze the profile of a program for other purposes.

This patch provides a complete implementation, that instruments a program to
record flows of execution not available through regular deep profiling.  It
associates coverage profiling information with ProcStatic structures, A later
version will use ProcDynamic structures if it is not too expensive.

For now coverage statistics can be viewed with the mdprof_dump tool.

compiler/deep_profiling.m:
    + Introduced coverage profiling transformation after deep profiling
	  transformation, it will be run if at least one coverage point type is
	  enabled

compiler/goal_util.m:
    + Created create_conj_from_list/3, to create a conjunction from a list
      of goals.
    + Edited create_conj/4 to be implemented in terms of
      create_conj_from_list/3

compiler/hlds_goal.m:
    + Added egi_maybe_dp field to extra_goal_info to contain extra information
      used in the coverage profiling transformation of the deep profiler.
    + Added dp_goal_info structure to store this extra information.

compiler/hlds_pred.m:
    + Added a list of coverage_point_info structures to the hlds_proc_static
      structure.

compiler/hlds_out.m:
	+ Added the ability to dump the dp_goal_info structure when the correct
	  option is given.

compiler/layout.m:
    + Added extra layout structures to store coverage point static and
      dynamic data for each procedure.

compiler/layout_out.m:
    + Added code to write out new layout structures in the Low Level C
      Backend.
    + Added code to write out references to coverage point data from the proc
      static structures.
    + Conform to changes in layout.m

compiler/opt_debug.m:
    + Conform to changes in layout.m

compiler/options.m:
    + Added command line parameters to enable coverage profiling and
      different coverage points, as well as options that can cause coverage
	  points not to be inserted in some circumstances.

compiler/handle_options.m:
	+ Added hlds dump options to the 'all' aliases for dumping the new
	  dp_goal_info structure in the hlds_info.

deep_profiler/dump.m:
    + Modified to dump coverage profiling data read in from Deep.data file.

deep_profiler/profile.m:
    + Added coverage points to proc static structure.

deep_profiler/read_profile.m:
    + Incremented Deep.data format version number.
    + Read coverage points from Deep.data file.
    + Confirm to changes in profile.m

library/profiling_builtin.m:
    + Added real definition and dummy implementation of
      increment_coverage_point_count/2.  This represents the instrumentation
      introduced by the coverage profiling transformation.

mdbcomp/program_representation.m:
    + Added types to support coverage profiling
    + Added coverage_point_type_num/2 to translate between coverage point
      types and integers to represent them in the runtime and Deep.data files.

runtime/mercury_deep_profiling.c:
    + Incremented Deep.data format version.
    + Implemented writing out of coverage points to the Deep.data file.

runtime/mercury_deep_profiling.h:
    + Modified runtime structures to support storing coverage point
      information in proc static structures.


Index: compiler/deep_profiling.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/deep_profiling.m,v
retrieving revision 1.74
diff -u -u -r1.74 deep_profiling.m
--- compiler/deep_profiling.m	27 Feb 2008 07:23:04 -0000	1.74
+++ compiler/deep_profiling.m	1 Mar 2008 06:52:02 -0000
@@ -34,6 +34,7 @@
 :- import_module check_hlds.mode_util.
 :- import_module check_hlds.type_util.
 :- import_module hlds.code_model.
+:- import_module hlds.goal_util.
 :- import_module hlds.hlds_goal.
 :- import_module hlds.hlds_pred.
 :- import_module hlds.hlds_rtti.
@@ -541,12 +542,15 @@
             counter.init(0), [], !.VarInfo, FileName, MaybeRecInfo),
 
         % This call transforms the goals of the procedure.
-        deep_prof_transform_goal(empty, Goal0, TransformedGoal, _,
+        deep_prof_transform_goal(empty, Goal0, Goal1, _,
             DeepInfo0, DeepInfo),
-
         !:VarInfo = DeepInfo ^ deep_varinfos,
         CallSites = DeepInfo ^ deep_call_sites,
 
+        % Do coverage profiling if requested.
+        maybe_coverage_prof_transform_goal(ModuleInfo, PredProcId,
+            MaybeRecInfo, Goal1, TransformedGoal, !VarInfo, CoveragePoints),
+
         (
             MaybeRecInfo = yes(RecInfo),
             RecInfo ^ role = inner_proc(OuterPredProcId)
@@ -562,7 +566,7 @@
         
         IsInInterface = is_proc_in_interface(ModuleInfo, PredId, ProcId),
         ProcStatic = hlds_proc_static(FileName, LineNumber, IsInInterface,
-            CallSites),
+            CallSites, CoveragePoints),
         ShroudedPredProcId = shroud_pred_proc_id(proc(PredId, ProcId)),
         ProcStaticConsId = deep_profiling_proc_layout(ShroudedPredProcId),
         generate_unify(ProcStaticConsId, ProcStaticVar,
@@ -1834,6 +1838,1265 @@
     MaybeDeepInfo = yes(DeepInfo),
     proc_info_set_maybe_deep_profile_info(MaybeDeepInfo, !ProcInfo).
 
+
+%-----------------------------------------------------------------------------%
+% Coverage Profiling.
+%-----------------------------------------------------------------------------%
+
+
+    % This structure is passed between predicates in this section.
+    %
+:- type coverage_info
+    --->    coverage_info(
+                ci_coverage_points          :: map(int, coverage_point_info),
+                ci_cp_index_counter         :: counter,
+                ci_var_info                 :: var_info,
+                ci_pred_proc_id             :: pred_proc_id,
+                ci_maybe_rec_info           :: maybe(deep_recursion_info),
+                ci_coverage_profiling_opts  :: coverage_profiling_options
+            ).
+
+
+    % Store what coverage profiling options have been selected.
+    %
+:- type coverage_profiling_options
+    --->    coverage_profiling_options(
+                cpo_may_fail            :: bool,
+                cpo_multi               :: bool,
+                cpo_any                 :: bool,
+                cpo_branch_ite          :: bool,
+                cpo_branch_switch       :: bool,
+                cpo_branch_disj         :: bool,
+                cpo_use_portcounts      :: bool,
+                cpo_use_trivial         :: bool,
+                cpo_use_2pass           :: bool
+            ).
+
+
+    % Return wheather each coverage point type should be enabled and iff
+    % coverage any coverage points are enabled then preform the coverage
+    % proflining pass.
+    %
+:- pred coverage_profiling_options(globals::in, bool::out,
+    coverage_profiling_options::out) is det.
+
+coverage_profiling_options(Globals, DoCoverageProfiling,
+        CoveragePointOptions) :-
+    globals.lookup_bool_option(Globals, coverage_profiling,
+        DoCoverageProfiling),
+
+    %
+    % Coverage point types.
+    %
+    globals.lookup_bool_option(Globals, profile_deep_coverage_may_fail,
+        MayFail),
+    globals.lookup_bool_option(Globals, profile_deep_coverage_multi,
+        Multi),
+    globals.lookup_bool_option(Globals, profile_deep_coverage_any,
+        Any),
+    globals.lookup_bool_option(Globals, profile_deep_coverage_branch_ite,
+        BranchIf),
+    globals.lookup_bool_option(Globals, profile_deep_coverage_branch_switch,
+        BranchSwitch),
+    globals.lookup_bool_option(Globals, profile_deep_coverage_branch_disj,
+        BranchDisj),
+
+    %
+    % Interpret options for tuning the coverage profiling pass.
+    %
+    globals.lookup_bool_option(Globals, profile_deep_coverage_use_portcounts,
+        UsePortCounts),
+    globals.lookup_bool_option(Globals, profile_deep_coverage_use_trivial,
+        UseTrivial),
+    bool.or(UsePortCounts, UseTrivial, Use2Pass),
+
+    CoveragePointOptions = coverage_profiling_options(MayFail, Multi, Any,
+        BranchIf, BranchSwitch, BranchDisj, UsePortCounts, UseTrivial,
+        Use2Pass).
+
+
+
+    % Transform the goal if coverage profiling should be performed, otherwise
+    % return it un-altered.
+    %
+:- pred maybe_coverage_prof_transform_goal(module_info::in, pred_proc_id::in,
+    maybe(deep_recursion_info)::in, hlds_goal::in, hlds_goal::out,
+    var_info::in, var_info::out, list(coverage_point_info)::out) is det.
+
+maybe_coverage_prof_transform_goal(ModuleInfo, PredProcId, MaybeRecInfo, !Goal,
+        !VarInfo, CoveragePoints) :-
+    module_info_get_globals(ModuleInfo, Globals),
+    coverage_profiling_options(Globals, DoCoverageProfiling, 
+        CoverageProfilingOptions),
+    ( 
+        DoCoverageProfiling = yes,
+        CoverageInfo0 = init_coverage_info(!.VarInfo, PredProcId,
+            MaybeRecInfo, CoverageProfilingOptions),
+        (
+            CoverageProfilingOptions ^ cpo_use_2pass = yes,
+            coverage_prof_first_pass(CoverageProfilingOptions, !Goal,
+                goal_has_port_counts, _)
+        ;
+            CoverageProfilingOptions ^ cpo_use_2pass = no
+        ),
+        coverage_prof_transform_goal(cord.empty, ModuleInfo, !Goal,
+            coverage_after_known, _, CoverageInfo0, CoverageInfo, _),
+        CoverageInfo ^ ci_coverage_points = CoveragePointsMap,
+        CoverageInfo ^ ci_var_info = !:VarInfo,
+        coverage_points_map_list(CoveragePointsMap, CoveragePoints)
+    ;
+        DoCoverageProfiling = no,
+        CoveragePoints = []
+    ).
+   
+
+    % Transform a goal for coverage profiling.  This is done in several
+    % steps.
+    %
+    % Step 1: Some information is gathered about the goal from the
+    % hlds_goal_info structure including any annotations made by the first
+    % pass.
+    %
+    % Step 2: A decision is made to insert a coverage point after this goal
+    % or not.  This applies to may_fail multi and any coverage point types
+    % only.
+    % 
+    % Step 3: Different conditions and information collected above are used
+    % to determine if coverage information is known for goals that may
+    % execute before this goal completes, either within an enclosing
+    % conjunction or from within the current goal.
+    %
+    % Step 4: If this goal is non-atomic the algorithm recurses to transform
+    % inner goals.
+    %
+    % Step 5: Depending on step 2, a coverage point may be inserted after
+    % this goal.
+    %
+:- pred coverage_prof_transform_goal(goal_path::in, module_info::in,
+    hlds_goal::in, hlds_goal::out,
+    coverage_after_known::in, coverage_after_known::out,
+    coverage_info::in, coverage_info::out, bool::out) is det.
+
+coverage_prof_transform_goal(Path, ModuleInfo, Goal0, Goal,
+        CoverageAfterKnown0, NextCoverageAfterKnown, !Info, AddedImpurity) :- 
+    Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
+    Detism = GoalInfo0 ^ goal_info_get_determinism,
+   
+    %
+    % Depending on command line arguments first pass information may or may-not
+    % be available, in which case sensible defaults should be assumed.
+    %
+    Use2Pass = !.Info ^ ci_coverage_profiling_opts ^ cpo_use_2pass,
+    (
+        Use2Pass = yes,
+        dp_goal_info(GoalTrivial, GoalHasPortCounts) = 
+            goal_info_get_dp_info(GoalInfo0)
+    ;
+        Use2Pass = no,
+        GoalTrivial = goal_is_nontrivial,
+        GoalHasPortCounts = goal_doesnot_have_port_counts
+    ),
+  
+    %
+    % Consider inserting a coverage point after this goal to measure how
+    % many solutions it may have.  The goal's determinism, whether the goal
+    % is trivial, if coverage information is already available and the
+    % coverage profiling options are all considered in making this decision.
+    %
+    (
+        GoalTrivial = goal_is_nontrivial,
+        (
+            GoalHasPortCounts = goal_doesnot_have_port_counts,
+            (
+                CoverageAfterKnown0 = coverage_after_unknown,
+                
+                (
+                    GoalExpr0 = conj(_, _)
+                ->
+                    %
+                    % Never insert coverage points after conjunctions, wait
+                    % until the algorithm recurses to inside the conjunction
+                    % and make a better decision about the last conjunct, this
+                    % can reduce the number of coverage points inserted in some
+                    % cases.
+                    %
+                    MaybeCPType = no
+                ;
+                    (
+                        ( Detism = detism_semi
+                        ; Detism = detism_cc_non
+                        ),
+                        
+                        CoverMayFail = !.Info ^ ci_coverage_profiling_opts ^
+                            cpo_may_fail,
+                        (
+                            CoverMayFail = yes,
+                            MaybeCPType = yes(cp_type_solns_may_fail)
+                        ;
+                            CoverMayFail = no,
+                            MaybeCPType = no
+                        )
+                    ;
+                        Detism = detism_multi,
+                        
+                        CoverMulti = !.Info ^ ci_coverage_profiling_opts ^
+                            cpo_multi,
+                        (
+                            CoverMulti = yes,
+                            MaybeCPType = yes(cp_type_solns_multi)
+                        ;
+                            CoverMulti = no,
+                            MaybeCPType = no
+                        )
+                    ;
+                        Detism = detism_non,
+                        
+                        CoverAny = !.Info ^ ci_coverage_profiling_opts ^
+                            cpo_any,
+                        (
+                            CoverAny = yes,
+                            MaybeCPType = yes(cp_type_solns_any)
+                        ;
+                            CoverAny = no,
+                            
+                            MaybeCPType = no
+                        )
+                    ;
+                        %
+                        % In this case we know that execution will always stop
+                        % at this goal, no coverage point is needed (or would
+                        % work).
+                        %
+                        ( Detism = detism_erroneous
+                        ; Detism = detism_failure
+                        ),
+                        MaybeCPType = no
+                    ;
+                        %
+                        % This should never occur, as other coverage points
+                        % would have been inserted to ensure coverage is known
+                        % here, unless they are disabled.  We don't insert a
+                        % coverage point here since we shouldn't have to.
+                        %
+                        ( Detism = detism_det
+                        ; Detism = detism_cc_multi
+                        ),
+                        MaybeCPType = no
+                    )
+                )
+            ;
+                CoverageAfterKnown0 = coverage_after_known,
+                
+                MaybeCPType = no
+            )
+        ;
+            GoalHasPortCounts = goal_has_port_counts,
+        
+            MaybeCPType = no
+        )
+    ;
+        GoalTrivial = goal_is_trivial,
+
+        MaybeCPType = no
+    ),
+
+    
+    % Update coverage known information.
+    (
+        MaybeCPType = yes(_),
+        CoverageAfterKnown = coverage_after_known
+    ;
+        MaybeCPType = no,
+        (
+            % If the goal has a port count then coverage is known at this
+            % point.
+            GoalHasPortCounts = goal_has_port_counts,
+            CoverageAfterKnown = coverage_after_known
+        ;
+            GoalHasPortCounts = goal_doesnot_have_port_counts,
+            (
+                % If there is not exactly one solution then the coverage is
+                % not known.
+                ( Detism = detism_semi
+                ; Detism = detism_multi
+                ; Detism = detism_non
+                ; Detism = detism_cc_non
+                ; Detism = detism_erroneous
+                ; Detism = detism_failure
+                ),
+                
+                CoverageAfterKnown = coverage_after_unknown
+            ; 
+                % Otherwise the coverage remains the same.
+                ( Detism = detism_det
+                ; Detism = detism_cc_multi
+                ),
+                
+                CoverageAfterKnown = CoverageAfterKnown0
+            )
+        )
+    ),
+
+    % Apply transformation recursively.
+    (   
+        ( GoalExpr0 = unify(_, _, _, _, _)
+        ; GoalExpr0 = plain_call(_, _, _, _, _, _)
+        ; GoalExpr0 = generic_call(_, _, _, _)
+        ; GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _)
+        ),
+        AddedImpurityInner = no,
+        GoalExpr1 = GoalExpr0,
+        NextCoverageAfterKnown = CoverageAfterKnown
+    ;
+        (
+            GoalExpr0 = conj(ConjType, Goals0),
+            coverage_prof_transform_conj(Path, ModuleInfo, 1, ConjType,
+                Goals0, Goals, CoverageAfterKnown, NextCoverageAfterKnown,
+                !Info, AddedImpurityInner),
+            GoalExpr1 = conj(ConjType, Goals)
+        ;
+            %
+            % There may be optimizations that can prevent us from
+            % inserting superfluous coverage points, however they are
+            % most likely to be non-trivial.
+            %
+            GoalExpr0 = disj(Goals0),
+            coverage_prof_transform_disj(Path, ModuleInfo, 1, 
+                Goals0, Goals, !Info, AddedImpurityInner),
+            (
+                ( Detism = detism_det
+                ; Detism = detism_cc_multi
+                ),
+                NextCoverageAfterKnown = CoverageAfterKnown
+            ;
+                %
+                % If the disjunction is semi, non or multi deterministic
+                % then we don't know the coverage before it. The same is
+                % true for erroneous and failure determinisms.
+                %
+                ( Detism = detism_semi
+                ; Detism = detism_multi
+                ; Detism = detism_non
+                ; Detism = detism_cc_non
+                ; Detism = detism_erroneous
+                ; Detism = detism_failure
+                ),
+                NextCoverageAfterKnown = coverage_after_unknown
+            ),
+            GoalExpr1 = disj(Goals)
+        ;
+            GoalExpr0 = switch(Var, SwitchCanFail, Cases0),
+            coverage_prof_transform_switchcase(Path, ModuleInfo, 1,
+                SwitchCanFail, Cases0, Cases,
+                CoverageAfterKnown, NextCoverageAfterKnown0, !Info,
+                AddedImpurityInner),
+            (
+                SwitchCanFail = cannot_fail,
+                NextCoverageAfterKnown = NextCoverageAfterKnown0
+            ;
+                SwitchCanFail = can_fail,
+                NextCoverageAfterKnown = coverage_after_unknown
+            ),
+            GoalExpr1 = switch(Var, SwitchCanFail, Cases)
+        ;
+            (
+                GoalExpr0 = negation(NegGoal0),
+                coverage_prof_transform_goal(snoc(Path, step_neg), ModuleInfo,
+                    NegGoal0, NegGoal,
+                    CoverageAfterKnown, NextCoverageAfterKnown,
+                    !Info, AddedImpurityInner), 
+                GoalExpr1 = negation(NegGoal)
+            ;
+                GoalExpr0 = scope(Reason, ScopeGoal0),
+                ( 
+                    Detism = ScopeGoal0 ^ hlds_goal_info ^
+                        goal_info_get_determinism
+                ->
+                    ScopeCut = scope_is_no_cut
+                ;
+                    ScopeCut = scope_is_cut
+                ),
+                coverage_prof_transform_goal(snoc(Path, step_scope(ScopeCut)),
+                    ModuleInfo, ScopeGoal0, ScopeGoal,
+                    CoverageAfterKnown, NextCoverageAfterKnown,
+                    !Info, AddedImpurityInner), 
+                GoalExpr1 = scope(Reason, ScopeGoal)
+            )
+        ;
+            GoalExpr0 = if_then_else(ITEExistVars, Cond, Then, Else),
+            coverage_prof_transform_ite(Path, ModuleInfo, ITEExistVars,
+                Cond, Then, Else, GoalExpr1,
+                CoverageAfterKnown, NextCoverageAfterKnown,
+                !Info, AddedImpurityInner)
+        )
+    ;
+        GoalExpr0 = shorthand(_),
+        unexpected(this_file, 
+            "deep_profiling.coverage_prof_transform_goal: " ++ 
+            "shorthand should have gone by now")
+    ),
+    add_impurity_if_needed(AddedImpurityInner, GoalInfo0, GoalInfo1),
+    Goal1 = hlds_goal(GoalExpr1, GoalInfo1),
+     
+    % If determined above create the coverage profiling instrumentation.
+    (
+        MaybeCPType = yes(CPType),
+        CPInfo = coverage_point_info(Path, CPType),
+        
+        make_coverage_point(!Info, ModuleInfo, CPInfo, CPGoals),
+        create_conj_from_list([Goal1 | CPGoals], plain_conj, Goal),
+
+        AddedImpurity = yes
+    ;
+        MaybeCPType = no,
+
+        Goal = Goal1,
+        AddedImpurity = AddedImpurityInner
+    ).
+
+
+    % Perform the coverage profiling transformation for conjuncts starting
+    % at the tail of the goal list and moving back towards the head.  The
+    % goal list represents the list of goals within a conjunction minus
+    % 'Pos' goals removed from the head.
+    %
+    % This is done tail first as to take advantage of knoledge of goals after
+    % the current goal within the conjunction.
+    %
+:- pred coverage_prof_transform_conj(goal_path::in, module_info::in,
+    int::in, conj_type::in, list(hlds_goal)::in, list(hlds_goal)::out,
+    coverage_after_known::in, coverage_after_known::out,
+    coverage_info::in, coverage_info::out, bool::out) is det.
+
+coverage_prof_transform_conj(_, _, _, _, [], [], !CoverageAfterKnown, !Info, no).
+coverage_prof_transform_conj(Path, ModuleInfo, Pos, ConjType, 
+        [Goal0 | Goals0], Goals, CoverageAfterKnown0, NextCoverageAfterKnown,
+        !Info, AddedImpurity) :-
+    coverage_prof_transform_conj(Path, ModuleInfo, Pos+1, ConjType,
+        Goals0, Goals1, CoverageAfterKnown0, CoverageAfterKnown, !Info,
+        AddedImpurityTail),
+    coverage_prof_transform_goal(snoc(Path, step_conj(Pos)), ModuleInfo,
+        Goal0, Goal1, CoverageAfterKnown, NextCoverageAfterKnown, !Info,
+        AddedImpurityHead),
+    (
+        Goal1 = hlds_goal(conj(plain_conj, ConjGoals), _),
+        ConjType = plain_conj
+    ->
+        Goals = ConjGoals ++ Goals1
+    ;
+        Goals = [ Goal1 | Goals1 ]
+    ),
+    bool.or(AddedImpurityHead, AddedImpurityTail, AddedImpurity).
+
+
+    % Perform the coverage profiling transformation over goals within a
+    % disjunction.  The list of goals represents the tail of the disjunction
+    % currently being transformed.
+    %
+    % Disjuncts are also transformed in reverse order, as knoledge from
+    % later disjuncts can be used to reduce the number of coverage points
+    % placed in earlier disjuncts.
+    %
+:- pred coverage_prof_transform_disj(goal_path::in, module_info::in, int::in,
+    list(hlds_goal)::in, list(hlds_goal)::out, 
+    coverage_info::in, coverage_info::out, bool::out) is det.
+
+coverage_prof_transform_disj(_, _, _, [], [], !Info, no).
+
+coverage_prof_transform_disj(Path, ModuleInfo, Pos, 
+        [Goal0 | Goals0], [Goal | Goals], !Info, AddedImpurity) :-
+    % Transform the tail of the disjunction.
+    coverage_prof_transform_disj(Path, ModuleInfo, Pos+1, Goals0, Goals,
+        !Info, AddedImpurityTail),
+
+    % Transform this goal and optionally add a coverage point before it.
+    DisjPath = snoc(Path, step_disj(Pos)),
+    coverage_prof_transform_goal(DisjPath, ModuleInfo,
+        Goal0, Goal1, coverage_after_unknown, NextCoverageAfterKnown, !Info,
+        AddedImpurityHead0),
+    CPOBranchDisj = !.Info ^ ci_coverage_profiling_opts ^ cpo_branch_disj,
+    (
+        CPOBranchDisj = yes,
+        (
+            NextCoverageAfterKnown = coverage_after_unknown,
+            insert_coverage_point_before(coverage_point_info(DisjPath,
+                cp_type_branch_arm), ModuleInfo, Goal1, Goal, !Info),
+            AddedImpurityHead = yes
+        ;
+            NextCoverageAfterKnown = coverage_after_known,
+            Goal = Goal1,
+            AddedImpurityHead = AddedImpurityHead0
+        )
+    ;
+        CPOBranchDisj = no,
+        Goal = Goal1,
+        AddedImpurityHead = AddedImpurityHead0
+    ),
+
+    bool.or(AddedImpurityHead, AddedImpurityTail, AddedImpurity).
+
+
+:- pred coverage_prof_transform_switchcase(goal_path::in, module_info::in,
+    int::in, can_fail::in, list(case)::in, list(case)::out, 
+    coverage_after_known::in, coverage_after_known::out, 
+    coverage_info::in, coverage_info::out, bool::out) is det.
+
+coverage_prof_transform_switchcase(_, _, _, _, [], [], 
+    _, coverage_after_known, !Info, no).
+
+coverage_prof_transform_switchcase(Path, ModuleInfo, Pos, SwitchCanFail,
+        [Case0 | Cases0], [Case | Cases], CoverageAfterSwitchKnown,
+        NextCoverageAfterKnown, !Info, AddedImpurity) :-
+    Goal0 = Case0 ^ case_goal,
+
+    %
+    % If the switch cannot fail and this is the last case then the coverage
+    % at the end of this case can be computed from the coverage after the
+    % entire switch and coverage information for the tail of the switch
+    % such as branch coverage points.
+    %
+    (
+        Cases0 = [],
+        (
+            SwitchCanFail = cannot_fail,
+            CoverageAfterHeadKnown = CoverageAfterSwitchKnown
+        ;
+            SwitchCanFail = can_fail,
+            CoverageAfterHeadKnown = coverage_after_unknown
+        )
+    ;
+        Cases0 = [_ | _],
+        CoverageAfterHeadKnown = coverage_after_unknown
+    ),
+
+    SwitchPath = snoc(Path, step_disj(Pos)),
+    coverage_prof_transform_goal(SwitchPath, ModuleInfo, Goal0, Goal1, 
+        CoverageAfterHeadKnown, NextCoverageAfterKnown0, !Info,
+        AddedImpurityHead0),
+    
+    % Possibly insert coverage point.
+    CPOBranchSwitch = !.Info ^ ci_coverage_profiling_opts ^
+        cpo_branch_switch,
+    (
+        CPOBranchSwitch = yes,
+        (
+            NextCoverageAfterKnown0 = coverage_after_unknown,
+            insert_coverage_point_before(coverage_point_info(SwitchPath,
+                cp_type_branch_arm), ModuleInfo, Goal1, Goal, !Info),
+            AddedImpurityHead = yes,
+            NextCoverageAfterKnownHead = coverage_after_known
+        ;
+            NextCoverageAfterKnown0 = coverage_after_known,
+            Goal = Goal1,
+            AddedImpurityHead = AddedImpurityHead0,
+            NextCoverageAfterKnownHead = NextCoverageAfterKnown0
+        )
+    ;
+        CPOBranchSwitch = no,
+        Goal = Goal1,
+        AddedImpurityHead = AddedImpurityHead0,
+        NextCoverageAfterKnownHead = NextCoverageAfterKnown0
+    ),
+
+    % Handle recursive case and prepare output variables.
+    coverage_prof_transform_switchcase(Path, ModuleInfo, Pos+1,
+        SwitchCanFail, Cases0, Cases,
+        CoverageAfterSwitchKnown, NextCoverageAfterKnownTail, !Info,
+        AddedImpurityTail),
+    Case = Case0 ^ case_goal := Goal,
+    coverage_after_known_branch(NextCoverageAfterKnownHead,
+        NextCoverageAfterKnownTail, NextCoverageAfterKnown), 
+    bool.or(AddedImpurityHead, AddedImpurityTail, AddedImpurity).
+
+
+    % Determine if branch coverage points should be inserted in either or
+    % both of the then and else branches, insert them and transform the
+    % sub-goals.
+    %
+    % This is performed by first transforming the Else and Then branches,
+    % then making decisions about cooverage points and inserting them, then
+    % transforming the condition and constructing the new ITE goal_expr.
+    %
+:- pred coverage_prof_transform_ite(goal_path::in, module_info::in,
+    list(prog_var)::in, hlds_goal::in, hlds_goal::in, hlds_goal::in,
+    hlds_goal_expr::out,
+    coverage_after_known::in, coverage_after_known::out, 
+    coverage_info::in, coverage_info::out, bool::out) is det.
+
+coverage_prof_transform_ite(Path, ModuleInfo, ITEExistVars, Cond0, Then0,
+        Else0, GoalExpr, CoverageAfterITEKnown, NextCoverageAfterKnown,
+        !Info, AddedImpurity) :-
+    %
+    % If the then and else goals have exactly one solution and coverage is
+    % known after the ite, then the coverage at the end of one branch can
+    % be computed from the other branch and the coverage known after the
+    % ITE.  This helps later to insert fewer coverage points in the
+    % beginning of the branches, and may also help reduce coverage points
+    % within the branches. 
+    %
+    (
+        CoverageAfterITEKnown = coverage_after_known,
+        ThenDetism = Then0 ^ hlds_goal_info ^ goal_info_get_determinism,
+        (
+            ( ThenDetism = detism_det
+            ; ThenDetism = detism_cc_multi
+            ),
+            ElseDetism = Else0 ^ hlds_goal_info ^ goal_info_get_determinism,
+            (
+                ( ElseDetism = detism_det
+                ; ElseDetism = detism_cc_multi
+                ),
+                
+                %
+                % Now which should have coverage known,
+                %
+                Use2Pass = !.Info ^ ci_coverage_profiling_opts ^
+                    cpo_use_2pass,
+                (
+                    Use2Pass = yes,
+                    dp_goal_info(_, ThenHasPortCounts) =
+                        goal_info_get_dp_info(Then0 ^ hlds_goal_info)
+                ;
+                    Use2Pass = no,
+                    ThenHasPortCounts = goal_doesnot_have_port_counts
+                ),
+                
+                (
+                    ThenHasPortCounts = goal_doesnot_have_port_counts,
+
+                    CoverageAfterElseKnown = coverage_after_known,
+                    CoverageAfterThenKnown = coverage_after_unknown
+                ;
+                    ThenHasPortCounts = goal_has_port_counts,
+                   
+                    % 
+                    % Although we don't know if Else has port counts, at
+                    % this point we're either making the deliberate
+                    % decision below or an arbitrary decision, so
+                    % it doesn't matter if Else has port counts or not.
+                    %
+                    CoverageAfterElseKnown = coverage_after_unknown,
+                    CoverageAfterThenKnown = coverage_after_known
+                )
+            ;
+                ( ElseDetism = detism_semi
+                ; ElseDetism = detism_multi
+                ; ElseDetism = detism_non
+                ; ElseDetism = detism_cc_non
+                ; ElseDetism = detism_erroneous
+                ; ElseDetism = detism_failure
+                ),
+                CoverageAfterElseKnown = coverage_after_unknown,
+                CoverageAfterThenKnown = coverage_after_unknown
+            )
+        ;
+            ( ThenDetism = detism_semi
+            ; ThenDetism = detism_multi
+            ; ThenDetism = detism_non
+            ; ThenDetism = detism_cc_non
+            ; ThenDetism = detism_erroneous
+            ; ThenDetism = detism_failure
+            ),
+            CoverageAfterElseKnown = coverage_after_unknown,
+            CoverageAfterThenKnown = coverage_after_unknown
+        )
+    ;
+        CoverageAfterITEKnown = coverage_after_unknown,
+        CoverageAfterElseKnown = coverage_after_unknown,
+        CoverageAfterThenKnown = coverage_after_unknown
+    ),
+    
+    
+    % Transform Else branch,
+    coverage_prof_transform_goal(snoc(Path, step_ite_else), ModuleInfo, 
+        Else0, Else1, CoverageAfterElseKnown, CoverageBeforeElseKnown1, !Info, 
+        AddedImpurityElseGoal),
+   
+    % Transform Then branch.
+    coverage_prof_transform_goal(snoc(Path, step_ite_then), ModuleInfo,
+        Then0, Then1, CoverageAfterThenKnown, CoverageBeforeThenKnown1, !Info, 
+        AddedImpurityThenGoal),
+    
+    %
+    % Gather information and decide what coverage points to insert.
+    %
+    % Notice that it doesn't matter if any of the goals are trivial or not,
+    % we want to know what branch is taken regardless of how inexpensive it
+    % may be as different variables may be used in different branches.
+    %
+    % Whatever we do we will ensure that the coverage will be known at the
+    % beginning of each branch,
+    %
+    CPOBranchIf = !.Info ^ ci_coverage_profiling_opts ^ cpo_branch_ite,
+    dp_goal_info(_, CondHasPortCounts) =
+        Cond0 ^ hlds_goal_info ^ goal_info_get_dp_info, 
+    (
+        CPOBranchIf = yes,
+        CondHasPortCounts = goal_doesnot_have_port_counts,
+        
+        (
+            CoverageBeforeThenKnown1 = coverage_after_unknown,
+            
+            InsertCPThen = yes(coverage_point_info(snoc(Path, step_ite_then),
+                cp_type_branch_arm))
+        ;
+            CoverageBeforeThenKnown1 = coverage_after_known,
+            
+            InsertCPThen = no
+        ),
+        (
+            CoverageBeforeElseKnown1 = coverage_after_unknown,
+       
+            InsertCPElse = yes(coverage_point_info(snoc(Path, step_ite_else),
+                cp_type_branch_arm))
+        ;
+            CoverageBeforeElseKnown1 = coverage_after_known,
+            
+            InsertCPElse = no
+        )
+    ;
+        CPOBranchIf = yes,
+        CondHasPortCounts = goal_has_port_counts,
+        
+        % Don't insert any coverage points.
+        InsertCPThen = no,
+        InsertCPElse = no
+    ;
+        CPOBranchIf = no,
+        
+        % Don't insert any coverage points,
+        InsertCPThen = no,
+        InsertCPElse = no
+    ),
+
+    %
+    % Insert any coverage points.
+    %
+    maybe_insert_coverage_point_before(InsertCPElse, ModuleInfo, Else1, Else,
+        CoverageBeforeElseKnown1, CoverageBeforeElseKnown, !Info, 
+        AddedImpurityElseCP),
+    bool.or(AddedImpurityElseGoal, AddedImpurityElseCP, AddedImpurityElse),
+
+    maybe_insert_coverage_point_before(InsertCPThen, ModuleInfo, Then1, Then,
+        CoverageBeforeThenKnown1, CoverageBeforeThenKnown, !Info,
+        AddedImpurityThenCP),
+    bool.or(AddedImpurityThenGoal, AddedImpurityThenCP, AddedImpurityThen),
+
+    %
+    % Transform Cond branch.
+    %
+    coverage_after_known_branch(CoverageBeforeThenKnown, CoverageBeforeElseKnown,
+        CoverageKnownAfterCond),
+    coverage_prof_transform_goal(snoc(Path, step_ite_cond), ModuleInfo, 
+        Cond0, Cond, CoverageKnownAfterCond, NextCoverageAfterKnown, !Info,
+        AddedImpurityCond),
+    
+    %
+    % Build goal experession and tidy up.
+    %
+    AddedImpurity = bool.or(AddedImpurityCond,
+        bool.or(AddedImpurityThen, AddedImpurityElse)), 
+    GoalExpr = if_then_else(ITEExistVars, Cond, Then, Else).
+
+
+    % Insert a coverage point in a conjunction before the current goal if
+    % the coverage point info has been provided.
+    %
+:- pred maybe_insert_coverage_point_before(maybe(coverage_point_info)::in,
+    module_info::in, hlds_goal::in, hlds_goal::out,
+    coverage_after_known::in, coverage_after_known::out, 
+    coverage_info::in, coverage_info::out, bool::out) is det.
+
+maybe_insert_coverage_point_before(no, _, !Goal, !CoverageAfterKnown,
+    !Info, no).
+
+maybe_insert_coverage_point_before(yes(CPInfo), ModuleInfo, !Goal,
+        _, coverage_after_known, !Info, yes) :-
+    insert_coverage_point_before(CPInfo, ModuleInfo, !Goal, !Info).
+
+
+    % Insert a coverage point before the given goal,  This returns a flat
+    % conjunction consisting of a coverage point followed by the input
+    % goal.
+    %
+:- pred insert_coverage_point_before(coverage_point_info::in,
+    module_info::in, hlds_goal::in, hlds_goal::out, 
+    coverage_info::in, coverage_info::out) is det.
+
+insert_coverage_point_before(CPInfo, ModuleInfo, !Goal, !Info) :-
+    make_coverage_point(!Info, ModuleInfo, CPInfo, CPGoals),
+    (
+        !.Goal = hlds_goal(conj(plain_conj, InnerGoals), _)
+    ->
+        Goals = CPGoals ++ InnerGoals
+    ;
+        Goals = CPGoals ++ [!.Goal]
+    ),
+    create_conj_from_list(Goals, plain_conj, !:Goal).
+
+
+    % Used to describe if coverage information is known at a partiular point
+    % within a procedure.
+    %
+:- type coverage_after_known
+    --->    coverage_after_known
+    ;       coverage_after_unknown.
+
+    % At a branch of execution two coverage known values must be merged,
+    % this is at the beginning of the branch since it's used for the main
+    % pass which is done in reverse.
+    %
+:- pred coverage_after_known_branch(coverage_after_known::in,
+    coverage_after_known::in, coverage_after_known::out) is det.
+
+coverage_after_known_branch(coverage_after_known, coverage_after_known,
+    coverage_after_known).
+coverage_after_known_branch(coverage_after_known, coverage_after_unknown,
+    coverage_after_unknown).
+coverage_after_known_branch(coverage_after_unknown, _,
+    coverage_after_unknown).
+    
+    % Create a coverage info struture, initializing some values to sensible
+    % defaults..
+    %
+:- func init_coverage_info(var_info, pred_proc_id,
+    maybe(deep_recursion_info), coverage_profiling_options) = coverage_info.
+
+init_coverage_info(VarInfo, PredProcId, MaybeRecInfo, CoverageProfilingOptions) =
+        CoverageInfo :-
+    CoverageInfo = coverage_info(map.init, counter.init(0), VarInfo,
+        PredProcId, MaybeRecInfo, CoverageProfilingOptions).
+
+    % Boolean or for goal_trivial data type.
+    %
+:- pred goal_trivial_and(goal_trivial::in, goal_trivial::in,
+    goal_trivial::out) is det.
+
+goal_trivial_and(A, B, Trivial) :-
+    (
+        A = goal_is_trivial,
+        B = goal_is_trivial
+    ->
+        Trivial = goal_is_trivial
+    ;
+        Trivial = goal_is_nontrivial
+    ).
+
+
+:- pred goal_has_port_counts_and(goal_has_port_counts::in,
+    goal_has_port_counts::in, goal_has_port_counts::out) is det.
+
+goal_has_port_counts_and(A, B, HasPortCounts) :-
+    (
+        A = goal_has_port_counts,
+        B = goal_has_port_counts
+    ->
+        HasPortCounts = goal_has_port_counts
+    ;
+        HasPortCounts = goal_doesnot_have_port_counts
+    ).
+
+
+    % Given the a goal and whether port counts are availible before it
+    % determine if port counts can be used to determine how often execution
+    % reaches the poind imediatly after this goal.
+    %
+:- pred has_port_counts_after(hlds_goal::in, goal_has_port_counts::in,
+    goal_has_port_counts::in, goal_has_port_counts::out) is det.
+
+has_port_counts_after(Goal, PCDirect, PCBefore, PC) :-
+    (
+        % 
+        % The trivial case.  If port counts are directly availible then
+        % the can be used to determine coverage immediately after it.
+        %
+        PCDirect = goal_has_port_counts,
+        PC = goal_has_port_counts
+    ;
+        PCDirect = goal_doesnot_have_port_counts,
+        
+        %
+        % If port counts arn't directly avalible but are before this goal
+        % and this goal behaves deterministically (it cannot fail or redo),
+        % then they can be used to determine how often execution reaches the
+        % point after this goal).
+        %
+        Detism = Goal ^ hlds_goal_info ^ goal_info_get_determinism,
+        has_port_counts_if_det(Detism, PCBefore, PC)
+    ).
+    
+    
+    % Given the current goal's determinism and wheather the next earliest goal
+    % has port counts does this goal have port counts
+    %
+:- pred has_port_counts_if_det(determinism::in, goal_has_port_counts::in,
+    goal_has_port_counts::out) is det.
+
+has_port_counts_if_det(Detism, HasPortCounts0, HasPortCounts) :-
+    (
+        ( Detism = detism_det
+        ; Detism = detism_cc_multi )
+    ->
+        HasPortCounts = HasPortCounts0
+    ;
+        HasPortCounts = goal_doesnot_have_port_counts
+    ).
+
+
+
+    % Used to gather some information about goals before the coverage
+    % transformation.
+    %
+:- pred coverage_prof_first_pass(coverage_profiling_options::in, hlds_goal::in,
+    hlds_goal::out, goal_has_port_counts::in, dp_goal_info::out) is det.
+
+coverage_prof_first_pass(CPOptions, Goal0, hlds_goal(GoalExpr, GoalInfo),
+        HasPortCountsBefore, Info) :-
+    Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
+
+    (
+        %
+        % Call Goals
+        %
+        ( GoalExpr0 = plain_call(_, _, _, _, _, _)
+        ; GoalExpr0 = generic_call(_, _, _, _)
+        ; GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _) ),
+        
+        Trivial0 = goal_is_nontrivial,
+        HasPortCountsDirect = goal_has_port_counts,
+        GoalExpr = GoalExpr0
+    ;
+        GoalExpr0 = unify(_, _, _, _, _),
+
+        Trivial0 = goal_is_trivial,
+        HasPortCountsDirect = goal_doesnot_have_port_counts,
+        GoalExpr = GoalExpr0
+    ;
+        GoalExpr0 = conj(ConjType, Goals0),
+        map_foldl2(coverage_prof_first_pass_conj(CPOptions), Goals0, Goals,
+            goal_is_trivial, Trivial0, HasPortCountsBefore,
+            HasPortCountsDirect),
+        GoalExpr = conj(ConjType, Goals) 
+    ;
+        GoalExpr0 = disj(Goals0),
+        coverage_prof_first_pass_disj(CPOptions, Goals0, Goals,
+            Trivial0, HasPortCountsBefore, HasPortCountsDirect0),
+        GoalExpr = disj(Goals),
+        
+        %
+        % Only if the disjunction cannot fail can we know the coverage after
+        % the disjunction if port counts are available from every disjunct.
+        %
+        Detism = goal_info_get_determinism(GoalInfo0),
+        determinism_components(Detism, CanFail, _),
+        (
+            CanFail = can_fail,
+            HasPortCountsDirect = goal_doesnot_have_port_counts
+        ;
+            CanFail = cannot_fail,
+            HasPortCountsDirect0 = HasPortCountsDirect
+        )
+    ;
+        GoalExpr0 = switch(Var, CanFail, Cases0),
+        coverage_prof_first_pass_switchcase(CPOptions, Cases0, Cases, Trivial0,
+            HasPortCountsCases),
+        GoalExpr = switch(Var, CanFail, Cases),
+        (
+            CanFail = can_fail,
+            HasPortCountsDirect = goal_doesnot_have_port_counts
+        ;
+            CanFail = cannot_fail,
+            HasPortCountsDirect = HasPortCountsCases
+        )
+    ;
+        GoalExpr0 = negation(InnerGoal0),
+        coverage_prof_first_pass(CPOptions, InnerGoal0, InnerGoal,
+            HasPortCountsBefore, dp_goal_info(Trivial0, HasPortCountsDirect)),
+        GoalExpr = negation(InnerGoal)
+    ;
+        GoalExpr0 = scope(Reason, InnerGoal0),
+        coverage_prof_first_pass(CPOptions, InnerGoal0, InnerGoal,
+            HasPortCountsBefore, dp_goal_info(Trivial0, HasPortCountsDirect)),
+        GoalExpr = scope(Reason, InnerGoal)
+    ;
+        GoalExpr0 = if_then_else(Vars, CondGoal0, ThenGoal0, ElseGoal0),
+       
+        %
+        % The then and else parts of a ITE goal will be able to use the
+        % port counts provided by the cond goal if it has them.
+        %
+        coverage_prof_first_pass(CPOptions, CondGoal0, CondGoal,
+            HasPortCountsBefore, dp_goal_info(TrivialCond, HasPortCountsCond)),
+        
+        coverage_prof_first_pass(CPOptions, ThenGoal0, ThenGoal,
+            HasPortCountsCond, dp_goal_info(TrivialThen, HasPortCountsThen)),
+        coverage_prof_first_pass(CPOptions, ElseGoal0, ElseGoal,
+            HasPortCountsCond, dp_goal_info(TrivialElse, HasPortCountsElse)),
+
+        GoalExpr = if_then_else(Vars, CondGoal, ThenGoal, ElseGoal),
+
+
+        %
+        % An ITE is trivial iff all of it's inner goals are trivial, 
+        %
+        goal_trivial_and(TrivialCond, TrivialThen, Trivial1),
+        goal_trivial_and(Trivial1, TrivialElse, Trivial0),
+
+        %
+        % And it has port counts iff it will end in a goal with a port count
+        % regardless of how the condition evaluates.
+        %
+        goal_has_port_counts_and(HasPortCountsThen, HasPortCountsElse,
+            HasPortCountsDirect)
+    ;
+        GoalExpr0 = shorthand(_),
+        unexpected(this_file, 
+            "deep_profiling.goal_is_nontrivial: " ++ 
+            "shorthand should have gone by now")
+    ),
+    
+    (
+        CPOptions ^ cpo_use_portcounts = yes,
+        has_port_counts_after(Goal0, HasPortCountsDirect, HasPortCountsBefore,
+            HasPortCounts)
+    ;
+        CPOptions ^ cpo_use_portcounts = no,
+        HasPortCounts = goal_doesnot_have_port_counts
+    ),
+   
+    (
+        CPOptions ^ cpo_use_trivial = yes,
+        Trivial = Trivial0
+    ;
+        CPOptions ^ cpo_use_trivial = no,
+        Trivial = goal_is_nontrivial
+    ),
+
+    %
+    % Annotate the goal with this new information.
+    %
+    Info = dp_goal_info(Trivial, HasPortCounts),
+    goal_info_set_maybe_dp_info(yes(Info), GoalInfo0, GoalInfo).
+
+
+    % Combine information about goals within a conjunction
+    %
+:- pred coverage_prof_first_pass_conj(coverage_profiling_options::in,
+    hlds_goal::in, hlds_goal::out, goal_trivial::in, goal_trivial::out,
+    goal_has_port_counts::in, goal_has_port_counts::out) is det.
+
+coverage_prof_first_pass_conj(CPOptions, Goal0, Goal, TrivialAcc, Trivial,
+        HasPortCountsAcc, HasPortCounts) :-
+    coverage_prof_first_pass(CPOptions, Goal0, Goal, HasPortCountsAcc,
+        dp_goal_info(TrivialGoal, HasPortCounts)),
+    goal_trivial_and(TrivialAcc, TrivialGoal, Trivial).
+
+
+    % Combine information about goals within a disjunction
+    %
+    % A portcount may be avalible to the goal executed when first entering a
+    % disjunction.  However it's impractical to deterimine if any disjuncts
+    % other than the first are ever tried.  So port counts at the beginning of
+    % them are unknown.
+    %
+:- pred coverage_prof_first_pass_disj(coverage_profiling_options::in,
+    list(hlds_goal)::in, list(hlds_goal)::out, goal_trivial::out, 
+    goal_has_port_counts::in, goal_has_port_counts::out) is det.
+
+coverage_prof_first_pass_disj(_, [], [], goal_is_trivial, !HasPortCounts).
+
+coverage_prof_first_pass_disj(CPOptions, [ Goal0 | Goals0 ], [ Goal | Goals ],
+        Trivial, HasPortCountsBefore, HasPortCounts) :-
+    coverage_prof_first_pass(CPOptions, Goal0, Goal, HasPortCountsBefore,
+        dp_goal_info(TrivialGoal, HasPortCountsGoal)),
+    coverage_prof_first_pass_disj(CPOptions, Goals0, Goals, TrivialDisj,
+        goal_doesnot_have_port_counts, HasPortCountsDisj), 
+    goal_trivial_and(TrivialGoal, TrivialDisj, Trivial),
+    goal_has_port_counts_and(HasPortCountsGoal, HasPortCountsDisj,
+        HasPortCounts).
+
+
+    % A switch is handled like a disjunction except that it can't be known how
+    % often execution will enter the first case, so this also cannot use the
+    % portcount of a goal before it.
+    %
+:- pred coverage_prof_first_pass_switchcase(coverage_profiling_options::in,
+    list(case)::in, list(case)::out, goal_trivial::out, 
+    goal_has_port_counts::out) is det.
+
+coverage_prof_first_pass_switchcase(_, [], [], goal_is_trivial, goal_has_port_counts).
+
+coverage_prof_first_pass_switchcase(CPOptions, [ Case0 | Cases0 ], [ Case | Cases ],
+        Trivial, HasPortCounts) :-
+    Case0 = case(FirstFunctor, LaterFunctors, Goal0),
+
+    coverage_prof_first_pass(CPOptions, Goal0, Goal,
+        goal_doesnot_have_port_counts, 
+        dp_goal_info(TrivialGoal, HasPortCountsGoal)),
+    coverage_prof_first_pass_switchcase(CPOptions, Cases0, Cases,
+        TrivialSwitchcase, HasPortCountsSwitchcase), 
+    goal_trivial_and(TrivialGoal, TrivialSwitchcase, Trivial),
+    goal_has_port_counts_and(HasPortCountsGoal, HasPortCountsSwitchcase,
+        HasPortCounts),
+
+    Case = case(FirstFunctor, LaterFunctors, Goal).
+
+
+    % Builds a list of goals that will form a conjunction) for a coverage
+    % point.
+    %
+:- pred make_coverage_point(coverage_info::in, coverage_info::out, 
+    module_info::in, coverage_point_info::in, list(hlds_goal)::out) is det.
+
+make_coverage_point(!CoverageInfo, ModuleInfo, CoveragePointInfo, Goals) :-
+    CoveragePointInfos0 = !.CoverageInfo ^ ci_coverage_points,
+    CPIndexCounter0 = !.CoverageInfo ^ ci_cp_index_counter,
+
+    counter.allocate(CPIndex, CPIndexCounter0, CPIndexCounter),
+    map.det_insert(CoveragePointInfos0, CPIndex, CoveragePointInfo, 
+        CoveragePointInfos),
+    !:CoverageInfo = !.CoverageInfo ^ ci_coverage_points := CoveragePointInfos,
+    !:CoverageInfo = !.CoverageInfo ^ ci_cp_index_counter := CPIndexCounter,
+
+    %
+    % Build unifications for the coverage point index and the proc static.
+    %
+    some [!VarInfo] (
+        !:VarInfo = !.CoverageInfo ^ ci_var_info,
+        
+        generate_var("CPIndex", int_type, CPIndexVar, !VarInfo),
+        generate_unify(int_const(CPIndex), CPIndexVar, GoalUnifyIndex),
+        generate_var("ProcLayout", c_pointer_type, ProcLayoutVar, !VarInfo),
+        proc_static_cons_id(!.CoverageInfo, ProcStaticConsId),
+        generate_unify(ProcStaticConsId, ProcLayoutVar, GoalUnifyProcLayout), 
+        
+        !:CoverageInfo = !.CoverageInfo ^ ci_var_info := !.VarInfo
+    ),
+
+    %
+    % Build a call to the instrumentation code.
+    %
+    get_deep_profile_builtin_ppid(ModuleInfo, "increment_coverage_point_count", 
+        2, PredId, ProcId),
+    Ground = ground(shared, none),
+    make_foreign_args([ ProcLayoutVar, CPIndexVar ],
+        [ (yes("ProcLayout" - (Ground -> Ground)) - native_if_possible),
+          (yes("CPIndex" - (Ground -> Ground)) - native_if_possible) ],
+        [ c_pointer_type, int_type ], ForeignArgVars),
+    coverage_point_ll_code(ForeignCallAttrs, ForeignCode),
+    CallGoalExpr = call_foreign_proc(ForeignCallAttrs, PredId, ProcId, 
+        ForeignArgVars, [], no, ForeignCode),
+    
+    Vars = [ ProcLayoutVar, CPIndexVar ],
+    NonLocals = list_to_set(Vars),
+    instmap_delta_from_assoc_list(assoc_list.from_corresponding_lists(Vars, 
+        [Ground, Ground]), InstMapDelta),
+    CallGoalInfo = impure_init_goal_info(NonLocals, InstMapDelta, detism_det),
+    CallGoal = hlds_goal(CallGoalExpr, CallGoalInfo), 
+
+    % construct complete goal list.
+    Goals = [ GoalUnifyIndex, GoalUnifyProcLayout, CallGoal ].
+      
+
+
+    % Turn a map of coverage points and their indexs into a list in sorted
+    % order.
+    %
+:- pred coverage_points_map_list(map(int, coverage_point_info)::in, 
+    list(coverage_point_info)::out) is det.
+
+coverage_points_map_list(Map, List) :-
+    to_sorted_assoc_list(Map, AssocList),
+    values(AssocList, List).
+
+
+    % Retrive the pred and proc ids from either the deep_mabye_rec_info or
+    % deep_pred_proc_id fields of a deep_info structure.
+    %
+:- pred pred_proc_id(coverage_info::in, pred_id::out, proc_id::out) is det.
+
+pred_proc_id(CoverageInfo, PredId, ProcId) :-
+    MaybeRecInfo = CoverageInfo ^ ci_maybe_rec_info,
+    PredProcId = CoverageInfo ^ ci_pred_proc_id,
+    (
+        MaybeRecInfo = yes(RecInfo),
+        RecInfo ^ role = inner_proc(OuterPredProcId)
+    ->
+        OuterPredProcId = proc(PredId, ProcId)
+    ;
+        PredProcId = proc(PredId, ProcId)
+    ).
+    
+    
+    % Create a proc static cons id from the deep recursion info.  This is used
+    % in several places.
+    %
+:- pred proc_static_cons_id(coverage_info::in, cons_id::out) is det.
+
+proc_static_cons_id(CoverageInfo, ProcStaticConsId) :-
+    pred_proc_id(CoverageInfo, PredId, ProcId),
+    ShroudedPredProcId = shroud_pred_proc_id(proc(PredId, ProcId)),
+    ProcStaticConsId = deep_profiling_proc_layout(ShroudedPredProcId).
+
+
+    % Returns a string containing the Low Level C code for a coverage point.
+    %
+:- pred coverage_point_ll_code(pragma_foreign_proc_attributes::out, 
+    pragma_foreign_code_impl::out) is det.
+
+coverage_point_ll_code(ForeignProcAttrs, ForeignCodeImpl) :-
+    some [ !ForeignProcAttrs ] (
+        % I don't think this would be thread safe but the cost of the mutexes
+        % may be too high.
+        !:ForeignProcAttrs = default_attributes(lang_c),
+        set_may_call_mercury(proc_will_not_call_mercury, !ForeignProcAttrs),
+        set_purity(purity_impure, !ForeignProcAttrs),
+        set_terminates(proc_terminates, !ForeignProcAttrs),
+        set_may_throw_exception(proc_will_not_throw_exception, 
+            !ForeignProcAttrs),
+        ForeignProcAttrs = !.ForeignProcAttrs
+    ),
+    ForeignCodeImpl = fc_impl_ordinary(Code, no),
+    Code = 
+"{
+#ifdef MR_DEEP_PROFILING
+
+    const MR_ProcLayout *pl;
+    MR_ProcStatic       *ps;
+
+    MR_enter_instrumentation();
+
+  #ifdef MR_DEEP_PROFILING_LOWLEVEL_DEBUG
+    if (MR_calldebug && MR_lld_print_enabled) {
+        MR_print_deep_prof_vars(stdout, ""increment_coverage_point_count"");
+        printf("", ProcLayout: 0x%x, CPIndex: %d\\n"", ProcLayout, CPIndex);
+    }
+  #endif
+
+    pl = (const MR_ProcLayout *) ProcLayout;
+
+    MR_deep_assert(NULL, NULL, NULL, pl != NULL);
+    ps = pl->MR_sle_proc_static;
+    MR_deep_assert(NULL, pl, NULL, ps != NULL);
+
+    MR_deep_assert(NULL, pl, ps, 
+        CPIndex >= ps->MR_ps_num_coverage_points);
+    MR_deep_assert(NULL, pl, ps, ps->MR_ps_coverage_points != NULL);
+
+    ps->MR_ps_coverage_points[CPIndex]++;
+
+    /*
+     * This procedure doesn't collect statistics about the deep profiler as
+     * they can be generated by the profiling data it's self.
+     */
+
+    MR_leave_instrumentation();
+#else
+    MR_fatal_error(
+        ""increment_coverage_point_count: deep profiling not enabled"");
+#endif /* MR_DEEP_PROFILING */
+}".
+
 %-----------------------------------------------------------------------------%
 
 :- func this_file = string.
Index: compiler/goal_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/goal_util.m,v
retrieving revision 1.157
diff -u -u -r1.157 goal_util.m
--- compiler/goal_util.m	27 Feb 2008 07:23:05 -0000	1.157
+++ compiler/goal_util.m	1 Mar 2008 06:52:02 -0000
@@ -229,6 +229,12 @@
     %
 :- pred flatten_conj(hlds_goals::in, hlds_goals::out) is det.
 
+    % Create a conjunction of the specified type using the specified goals,
+    % This fills in the hlds_goal_info.
+    %
+:- pred create_conj_from_list(list(hlds_goal)::in, conj_type::in,
+    hlds_goal::out) is det.
+
     % Create a conjunction of the specified type using the specified two goals.
     % This fills in the hlds_goal_info.
     %
@@ -1324,7 +1330,15 @@
 %-----------------------------------------------------------------------------%
 
 create_conj(GoalA, GoalB, Type, ConjGoal) :-
-    GoalsInConj = [ GoalA, GoalB ],
+    create_conj_from_list([GoalA, GoalB], Type, ConjGoal).
+
+create_conj_from_list(GoalsInConj, Type, ConjGoal) :-
+    (
+        GoalsInConj = [ GoalA | _ ]
+    ;
+        GoalsInConj = [],
+        unexpected(this_file, "create_conj_from_list: empty conjunction")
+    ),
     ConjGoalExpr = conj(Type, GoalsInConj),
     goal_list_nonlocals(GoalsInConj, NonLocals),
     goal_list_instmap_delta(GoalsInConj, InstMapDelta),
Index: compiler/handle_options.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.317
diff -u -u -r1.317 handle_options.m
--- compiler/handle_options.m	23 Jan 2008 13:12:15 -0000	1.317
+++ compiler/handle_options.m	1 Mar 2008 06:52:02 -0000
@@ -1096,6 +1096,11 @@
 
         option_implies(target_debug, strip, bool(no), !Globals),
 
+
+        % Coverage profiling requires deep profiling.
+        option_implies(coverage_profiling, profile_deep, bool(yes),
+            !Globals),
+        
         % Inlining happens before the deep profiling transformation, so if
         % we allowed inlining to happen, then we would lose all profiling
         % information about the inlined calls - this is not usually what we
@@ -2022,6 +2027,7 @@
         true
     ).
 
+    
     % option_implies(SourceBoolOption, ImpliedOption, ImpliedOptionValue):
     % If the SourceBoolOption is set to yes, then the ImpliedOption is set
     % to ImpliedOptionValue.
@@ -2756,9 +2762,12 @@
 
 :- pred convert_dump_alias(string::in, string::out) is semidet.
 
-convert_dump_alias("ALL", "abcdfgilmnprstuvzBCDIMPRSTUZ").
-convert_dump_alias("allD", "abcdfgilmnprstuvzBCDMPT").
-convert_dump_alias("all", "abcdfgilmnprstuvzBCMPSTZ").
+%
+% none of the 'all' aliases actually include all the options,
+%
+convert_dump_alias("ALL", "abcdEfgilmnprstuvzBCDIMPRSTUZ").
+convert_dump_alias("allD", "abcdEfgilmnprstuvzBCDMPT").
+convert_dump_alias("all", "abcdEfgilmnprstuvzBCMPSTZ").
 convert_dump_alias("most", "bcdfgilmnprstuvzP").
 convert_dump_alias("trans", "bcdglmnstuvz").
 convert_dump_alias("mintrans", "bcdglmnstvz").
Index: compiler/hlds_goal.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/hlds_goal.m,v
retrieving revision 1.189
diff -u -u -r1.189 hlds_goal.m
--- compiler/hlds_goal.m	27 Feb 2008 07:23:06 -0000	1.189
+++ compiler/hlds_goal.m	1 Mar 2008 06:52:02 -0000
@@ -1054,6 +1054,25 @@
 
 :- type missed_message == string.
 
+
+    % Information used by the deep profilier to preform coverage profiling.
+    % Predicates to operate on these types exist in deep_profiling.m
+    %
+:- type goal_trivial
+    --->    goal_is_trivial
+    ;       goal_is_nontrivial.
+   
+:- type goal_has_port_counts
+    --->    goal_has_port_counts
+    ;       goal_doesnot_have_port_counts.
+
+:- type dp_goal_info
+    --->    dp_goal_info(
+                goal_trivial,
+                goal_has_port_counts
+            ).
+
+
 :- pred goal_info_init(hlds_goal_info::out) is det.
 :- pred goal_info_init(prog_context::in, hlds_goal_info::out) is det.
 :- pred goal_info_init(set(prog_var)::in, instmap_delta::in, determinism::in,
@@ -1087,6 +1106,7 @@
 :- func goal_info_get_maybe_lfu(hlds_goal_info) = maybe(set(prog_var)).
 :- func goal_info_get_maybe_lbu(hlds_goal_info) = maybe(set(prog_var)).
 :- func goal_info_get_maybe_reuse(hlds_goal_info) = maybe(reuse_description).
+:- func goal_info_get_maybe_dp_info(hlds_goal_info) = maybe(dp_goal_info).
 
 :- pred goal_info_set_determinism(determinism::in,
     hlds_goal_info::in, hlds_goal_info::out) is det.
@@ -1120,6 +1140,8 @@
     hlds_goal_info::out) is det.
 :- pred goal_info_set_reuse(reuse_description::in, hlds_goal_info::in,
     hlds_goal_info::out) is det.
+:- pred goal_info_set_maybe_dp_info(maybe(dp_goal_info)::in, hlds_goal_info::in,
+    hlds_goal_info::out) is det.
 
     % The following functions produce an 'unexpected' error when the
     % requested values have not been set.
@@ -1128,6 +1150,7 @@
 :- func goal_info_get_lfu(hlds_goal_info) = set(prog_var).
 :- func goal_info_get_lbu(hlds_goal_info) = set(prog_var).
 :- func goal_info_get_reuse(hlds_goal_info) = reuse_description.
+:- func goal_info_get_dp_info(hlds_goal_info) = dp_goal_info.
 
 :- pred goal_info_get_occurring_vars(hlds_goal_info::in, set(prog_var)::out)
     is det.
@@ -1705,7 +1728,9 @@
 
                 egi_maybe_rbmm          :: maybe(rbmm_goal_info),
 
-                egi_maybe_mode_constr   :: maybe(mode_constr_goal_info)
+                egi_maybe_mode_constr   :: maybe(mode_constr_goal_info),
+
+                egi_maybe_dp            :: maybe(dp_goal_info)
             ).
 
 :- pragma inline(goal_info_init/1).
@@ -1752,7 +1777,7 @@
 
 hlds_goal_extra_info_init(Context) = ExtraInfo :-
     HO_Values = map.init,
-    ExtraInfo = extra_goal_info(Context, HO_Values, no, no, no).
+    ExtraInfo = extra_goal_info(Context, HO_Values, no, no, no, no).
 
 :- func ctgc_goal_info_init = ctgc_goal_info.
 
@@ -1774,6 +1799,7 @@
 goal_info_get_maybe_mode_constr(GoalInfo) =
     GoalInfo ^ gi_extra ^ egi_maybe_mode_constr.
 goal_info_get_maybe_ctgc(GoalInfo) = GoalInfo ^ gi_extra ^ egi_maybe_ctgc.
+goal_info_get_maybe_dp_info(GoalInfo) = GoalInfo ^ gi_extra ^ egi_maybe_dp.
 
 goal_info_set_determinism(Determinism, !GoalInfo) :-
     !GoalInfo ^ gi_determinism := Determinism.
@@ -1799,6 +1825,8 @@
     !GoalInfo ^ gi_extra ^ egi_maybe_mode_constr := ModeConstrInfo.
 goal_info_set_maybe_ctgc(CTGCInfo, !GoalInfo) :-
     !GoalInfo ^ gi_extra ^ egi_maybe_ctgc := CTGCInfo.
+goal_info_set_maybe_dp_info(DPInfo, !GoalInfo) :-
+    !GoalInfo ^ gi_extra ^ egi_maybe_dp := DPInfo.
 
     % The code-gen non-locals are always the same as the
     % non-locals when structure reuse is not being performed.
@@ -2068,6 +2096,17 @@
             "Requesting reuse information while CTGC field not set.")
     ).
 
+goal_info_get_dp_info(GoalInfo) = DPInfo :-
+    MaybeDPInfo = goal_info_get_maybe_dp_info(GoalInfo),
+    (
+        MaybeDPInfo = yes(DPInfo)
+    ;
+        MaybeDPInfo = no,
+        unexpected(this_file,
+            "Requesting dp_info while maybe_dp_info field not set.")
+    ).
+
+
 %-----------------------------------------------------------------------------%
 
 goal_get_purity(hlds_goal(_GoalExpr, GoalInfo)) =
@@ -2416,7 +2455,7 @@
     ),
 
     ExtraInfo0 = extra_goal_info(Context, HO_Values, MaybeCTGC0, MaybeRBMM0,
-        MaybeMCI0),
+        MaybeMCI0, MaybeDPInfo0),
     (
         MaybeCTGC0 = no,
         MaybeCTGC = no
@@ -2474,8 +2513,9 @@
             MakeVisible, NeedVisible),
         MaybeMCI = yes(MCI)
     ),
+    MaybeDPInfo = MaybeDPInfo0,
     ExtraInfo = extra_goal_info(Context, HO_Values, MaybeCTGC, MaybeRBMM,
-        MaybeMCI),
+        MaybeMCI, MaybeDPInfo),
 
     !:GoalInfo = goal_info(Detism, InstMapDelta, NonLocals, Purity,
         Features, GoalPath, CodeGenInfo, ExtraInfo).
Index: compiler/hlds_out.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/hlds_out.m,v
retrieving revision 1.445
diff -u -u -r1.445 hlds_out.m
--- compiler/hlds_out.m	27 Feb 2008 08:35:16 -0000	1.445
+++ compiler/hlds_out.m	1 Mar 2008 06:52:02 -0000
@@ -1429,6 +1429,32 @@
     ;
         true
     ),
+    ( string.contains_char(Verbose, 'E') ->
+        MaybeDPInfo = goal_info_get_maybe_dp_info(GoalInfo),
+        (
+            MaybeDPInfo = yes(dp_goal_info(Trivial, HasPortCounts)),
+            write_indent(Indent, !IO),
+            (
+                Trivial = goal_is_trivial,
+                io.write_string("% Goal is trivial, ", !IO)
+            ;
+                Trivial = goal_is_nontrivial,
+                io.write_string("% Goal is non-trivial, ", !IO)
+            ),
+            (
+                HasPortCounts = goal_has_port_counts,
+                io.write_string("Goal has port counts avalible.\n", !IO)
+            ;
+                HasPortCounts = goal_doesnot_have_port_counts,
+                io.write_string("Goal does not have port counts avalible.\n", 
+                    !IO)
+            )
+        ;
+            MaybeDPInfo = no
+        )
+    ;
+        true
+    ),
     write_goal_2(GoalExpr, ModuleInfo, VarSet, AppendVarNums, Indent, Follow,
         TypeQual, !IO),
     ( string.contains_char(Verbose, 'i') ->
Index: compiler/hlds_pred.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/hlds_pred.m,v
retrieving revision 1.239
diff -u -u -r1.239 hlds_pred.m
--- compiler/hlds_pred.m	27 Feb 2008 08:35:16 -0000	1.239
+++ compiler/hlds_pred.m	1 Mar 2008 06:52:02 -0000
@@ -1675,7 +1675,8 @@
                 proc_static_file_name   :: string,
                 proc_static_line_number :: int,
                 proc_is_in_interface    :: bool,
-                call_site_statics       :: list(call_site_static_data)
+                call_site_statics       :: list(call_site_static_data),
+                coverage_points         :: list(coverage_point_info) 
             ).
 
     % The hlds_deep_excp_vars gives the variables that hold the values returned
Index: compiler/layout.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/layout.m,v
retrieving revision 1.37
diff -u -u -r1.37 layout.m
--- compiler/layout.m	12 Sep 2007 06:21:06 -0000	1.37
+++ compiler/layout.m	1 Mar 2008 06:52:02 -0000
@@ -253,7 +253,9 @@
     ;       module_common_layout(module_name)
     ;       module_layout(module_name)
     ;       proc_static(rtti_proc_label)
-    ;       proc_static_call_sites(rtti_proc_label).
+    ;       proc_static_call_sites(rtti_proc_label)
+    ;       proc_static_coverage_point_static(rtti_proc_label)
+    ;       proc_static_coverage_point_dynamic(rtti_proc_label).
 
 :- type label_layout_details
     --->    label_layout_details(proc_label, int, label_vars).
Index: compiler/layout_out.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/layout_out.m,v
retrieving revision 1.95
diff -u -u -r1.95 layout_out.m
--- compiler/layout_out.m	27 Feb 2008 07:23:08 -0000	1.95
+++ compiler/layout_out.m	1 Mar 2008 06:52:02 -0000
@@ -438,6 +438,18 @@
         ProcLabel = make_proc_label_from_rtti(RttiProcLabel),
         output_proc_label_no_prefix(ProcLabel, !IO)
     ;
+        Data = proc_static_coverage_point_static(RttiProcLabel),
+        io.write_string(mercury_data_prefix, !IO),
+        io.write_string("_proc_static_coverage_points_static__", !IO),
+        ProcLabel = make_proc_label_from_rtti(RttiProcLabel),
+        output_proc_label_no_prefix(ProcLabel, !IO)
+    ;
+        Data = proc_static_coverage_point_dynamic(RttiProcLabel),
+        io.write_string(mercury_data_prefix, !IO),
+        io.write_string("_proc_static_coverage_points_dynamic__", !IO),
+        ProcLabel = make_proc_label_from_rtti(RttiProcLabel),
+        output_proc_label_no_prefix(ProcLabel, !IO)
+    ;
         Data = table_io_decl(RttiProcLabel),
         io.write_string(mercury_data_prefix, !IO),
         io.write_string("_table_io_decl__", !IO),
@@ -611,6 +623,16 @@
         output_layout_name(Name, !IO),
         io.write_string("[]", !IO)
     ;
+        Name = proc_static_coverage_point_static(_RttiProcLabel),
+        io.write_string("static const MR_CoveragePointStatic ", !IO),
+        output_layout_name(Name, !IO),
+        io.write_string("[]", !IO)
+    ;
+        Name = proc_static_coverage_point_dynamic(_RttiProcLabel),
+        io.write_string("static MR_Unsigned ", !IO),
+        output_layout_name(Name, !IO),
+        io.write_string("[]", !IO)
+    ;
         Name = table_io_decl(_RttiProcLabel),
         io.write_string("static const MR_TableIoDecl ", !IO),
         output_layout_name(Name, !IO)
@@ -649,6 +671,8 @@
 layout_name_would_include_code_addr(module_layout(_)) = no.
 layout_name_would_include_code_addr(proc_static(_)) = no.
 layout_name_would_include_code_addr(proc_static_call_sites(_)) = no.
+layout_name_would_include_code_addr(proc_static_coverage_point_static(_)) = no.
+layout_name_would_include_code_addr(proc_static_coverage_point_dynamic(_)) = no.
 layout_name_would_include_code_addr(table_io_decl(_)) = no.
 
 :- func label_vars_to_type(label_vars) = string.
@@ -2097,9 +2121,18 @@
     ProcLayoutProcStatic = proc_layout_proc_static(HLDSProcStatic,
         DeepExcpVars),
     HLDSProcStatic = hlds_proc_static(FileName, LineNumber, IsInInterface,
-        CallSites),
+        CallSites, CoveragePoints),
+   
+    % Write out data the proc static will reference.
     list.foldl2(output_call_site_static_decl, CallSites, !DeclSet, !IO),
     output_call_site_static_array(RttiProcLabel, CallSites, !DeclSet, !IO),
+    output_coverage_point_static_array(RttiProcLabel, CoveragePoints, !DeclSet,
+        !IO),
+    length(CoveragePoints, NumCoveragePoints),
+    output_coverage_point_dynamic_array(RttiProcLabel, NumCoveragePoints, 
+        !DeclSet, !IO),
+
+    % Write out the proc static.
     LayoutName = proc_static(RttiProcLabel),
     io.write_string("\n", !IO),
     output_layout_name_storage_type_name(LayoutName, yes, !IO),
@@ -2131,7 +2164,16 @@
     io.write_int(MiddleCSDSlot, !IO),
     io.write_string(",\n", !IO),
     io.write_int(OldOutermostSlot, !IO),
-    io.write_string("\n};\n", !IO),
+    io.write_string(",\n", !IO),
+    io.write_int(NumCoveragePoints, !IO),
+    io.write_string(",\n", !IO),
+    CoveragePointStaticName = proc_static_coverage_point_static(RttiProcLabel),
+    output_layout_name(CoveragePointStaticName, !IO),
+    io.write_string(",\n", !IO),
+    CoveragePointDynamicName = 
+        proc_static_coverage_point_dynamic(RttiProcLabel),
+    output_layout_name(CoveragePointDynamicName, !IO),
+    io.write_string("};\n", !IO),
     decl_set_insert(decl_data_addr(layout_addr(LayoutName)), !DeclSet).
 
 :- pred output_call_site_static_array(rtti_proc_label::in,
@@ -2212,6 +2254,52 @@
 
 %-----------------------------------------------------------------------------%
 
+
+% Write out a C representation of the coverage point static data.
+:- pred output_coverage_point_static_array(rtti_proc_label::in, 
+    list(coverage_point_info)::in, decl_set::in, decl_set::out,
+    io::di, io::uo) is det.
+
+output_coverage_point_static_array(RttiProcLabel, CoveragePoints, !DeclSet, !IO) :-
+    LayoutName = proc_static_coverage_point_static(RttiProcLabel),
+    io.write_string("\n", !IO),
+    output_layout_name_storage_type_name(LayoutName, yes, !IO),
+    io.write_string(" = {\n", !IO),
+    list.foldl(output_coverage_point_static, CoveragePoints, !IO),
+    io.write_string("};\n", !IO),
+    decl_set_insert(decl_data_addr(layout_addr(LayoutName)), !DeclSet).
+
+
+:- pred output_coverage_point_static(coverage_point_info::in, io::di, io::uo) 
+    is det.
+
+output_coverage_point_static(coverage_point_info(GoalPath, CPType), !IO) :-
+    io.write_string("{ """, !IO),
+    GoalPathString = goal_path_to_string(GoalPath),
+    io.write_string(GoalPathString, !IO),
+    io.write_string(""", ", !IO),
+    coverage_point_type_num(CPType, CPTypeNum),
+    CPTypeCValue = string(CPTypeNum),
+    io.write_string(CPTypeCValue, !IO),
+    io.write_string(" },\n", !IO).
+
+
+:- pred output_coverage_point_dynamic_array(rtti_proc_label::in, int::in, 
+    decl_set::in, decl_set::out, io::di, io::uo) is det.
+
+output_coverage_point_dynamic_array(RttiProcLabel, NumCoveragePoints, !DeclSet, !IO) :-
+    LayoutName = proc_static_coverage_point_dynamic(RttiProcLabel),
+    io.write_string("\n", !IO),
+    output_layout_name_storage_type_name(LayoutName, yes, !IO),
+    io.write_string(" = {\n", !IO),
+    duplicate(NumCoveragePoints, "0,", Zeros),
+    io.write_strings(Zeros, !IO),
+    io.write_string("};\n", !IO),
+    decl_set_insert(decl_data_addr(layout_addr(LayoutName)), !DeclSet).
+
+
+%-----------------------------------------------------------------------------%
+
 :- pred output_table_io_decl(rtti_proc_label::in, proc_layout_kind::in,
     int::in, rval::in, rval::in, decl_set::in, decl_set::out,
     io::di, io::uo) is det.
Index: compiler/opt_debug.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/opt_debug.m,v
retrieving revision 1.206
diff -u -u -r1.206 opt_debug.m
--- compiler/opt_debug.m	11 Feb 2008 21:26:05 -0000	1.206
+++ compiler/opt_debug.m	1 Mar 2008 06:52:02 -0000
@@ -564,6 +564,12 @@
     "proc_static(" ++ dump_rttiproclabel(RttiProcLabel) ++ ")".
 dump_layout_name(proc_static_call_sites(RttiProcLabel)) =
     "proc_static_call_sites(" ++ dump_rttiproclabel(RttiProcLabel) ++ ")".
+dump_layout_name(proc_static_coverage_point_static(RttiProcLabel)) =
+    "proc_static_coverage_point_static(" ++ dump_rttiproclabel(RttiProcLabel) 
+        ++ ")".
+dump_layout_name(proc_static_coverage_point_dynamic(RttiProcLabel)) =
+    "proc_static_coverage_point_dynamic(" ++ dump_rttiproclabel(RttiProcLabel) 
+        ++ ")".
 dump_layout_name(table_io_decl(RttiProcLabel)) =
     "table_io_decl(" ++ dump_rttiproclabel(RttiProcLabel) ++ ")".
 
Index: compiler/options.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.613
diff -u -u -r1.613 options.m
--- compiler/options.m	29 Jan 2008 02:38:26 -0000	1.613
+++ compiler/options.m	1 Mar 2008 06:52:02 -0000
@@ -291,6 +291,21 @@
             % cycle detection should be used for deep profiling. Actually,
             % we only want to use the `yes' value, but we keep support for
             % the `no' value for benchmarks for the paper.
+    
+            % Perform coverage profiling, (enables deep profiling).
+    ;       coverage_profiling
+   
+            % What types of coverage points to instrument the code with,
+    ;       profile_deep_coverage_may_fail
+    ;       profile_deep_coverage_multi
+    ;       profile_deep_coverage_any
+    ;       profile_deep_coverage_branch_ite
+    ;       profile_deep_coverage_branch_switch
+    ;       profile_deep_coverage_branch_disj
+
+            % Tunables for the coverage profiling pass.
+    ;       profile_deep_coverage_use_portcounts
+    ;       profile_deep_coverage_use_trivial
 
     ;       use_zeroing_for_ho_cycles
     ;       use_lots_of_ho_specialization
@@ -1125,6 +1140,15 @@
     profile_memory                      -   bool(no),
     profile_deep                        -   bool(no),
     use_activation_counts               -   bool(no),
+    profile_deep_coverage_may_fail      -   bool(yes),
+    profile_deep_coverage_multi         -   bool(yes),
+    profile_deep_coverage_any           -   bool(yes),
+    profile_deep_coverage_branch_ite    -   bool(yes),
+    profile_deep_coverage_branch_switch -   bool(yes),
+    profile_deep_coverage_branch_disj   -   bool(yes),
+    coverage_profiling                  -   bool(no),
+    profile_deep_coverage_use_portcounts -  bool(yes),
+    profile_deep_coverage_use_trivial   -   bool(yes),
     use_zeroing_for_ho_cycles           -   bool(yes),
     use_lots_of_ho_specialization       -   bool(no),
     deep_profile_tail_recursion         -   bool(no),
@@ -1931,6 +1955,24 @@
 long_option("profile-memory",       profile_memory).
 long_option("profile-deep",         profile_deep).
 long_option("use-activation-counts",    use_activation_counts).
+long_option("profile-deep-coverage-may-fail",
+                    profile_deep_coverage_may_fail).
+long_option("profile-deep-coverage-multi", 
+                    profile_deep_coverage_multi).
+long_option("profile-deep-coverage-any", 
+                    profile_deep_coverage_any).
+long_option("profile-deep-coverage-branch-ite",
+                    profile_deep_coverage_branch_ite).
+long_option("profile-deep-coverage-branch-switch",
+                    profile_deep_coverage_branch_switch).
+long_option("profile-deep-coverage-branch-disj",
+                    profile_deep_coverage_branch_disj).
+long_option("coverage-profiling", 
+                    coverage_profiling).
+long_option("profile-deep-coverage-use-portcounts",
+                    profile_deep_coverage_use_portcounts).
+long_option("profile-deep-coverage-use-trivial",
+                    profile_deep_coverage_use_trivial).
 long_option("use-zeroing-for-ho-cycles",
                     use_zeroing_for_ho_cycles).
 long_option("use-lots-of-ho-specialization",
@@ -3831,6 +3873,36 @@
 %       "--profile-memory\t\t(grade modifier: `.profmem')",
 %       "\tSimilar to `--memory-profiling', except that it only",
 %       "\tgathers memory usage information, not call counts.",
+        
+        "--coverage-profiling",
+        "\tEnable coverage profiling, implies --deep-profiling (above).",
+
+%       "Switches to effect coverage profiling (part of deep profiling). ",
+%       "they enable different types of coverage points.",
+
+%       "--profile-deep-coverage-may-fail",
+%       "\tEnable coverage points after goals that may fail.",
+%       "--profile-deep-coverage-multi",
+%       "\tEnable coverage points after goals that may succeed more than ",
+%       "\tonce.",
+%       "--profile-deep-coverage-any",
+%       "\tEnable coverage points after goals that may succeed more than ",
+%       "\tonce or fail.",
+%       "--profile-deep-coverage-branch-if",
+%       "\tEnable coverage points at the beginning of if branches.",
+%       "--profile-deep-coverage-branch-switch",
+%       "\tEnable coverage points at the beginning of switch branches.",
+%       "--profile-deep-coverage-branch-disj",
+%       "\tEnable coverage points at the beginning of disjunction branches.",
+
+%       "Switches to tune the coverage profiling pass, useful for ",
+%       "debugging.",
+%       
+%       "--no-profile-deep-coverage-use-portcounts",
+%       "\tTurn off usage of port counts in the deep profilier to provide",
+%       "\tsome coverage information.",
+%       "--no-profile-deep-coverage-use-trivial",
+%       "\tTurn off usage of trivial goal information",
 
         "--record-term-sizes-as-words\t\t(grade modifier: `.tsw')",
         "\tAugment each heap cells with its size in words.",
Index: deep_profiler/dump.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/deep_profiler/dump.m,v
retrieving revision 1.13
diff -u -u -r1.13 dump.m
--- deep_profiler/dump.m	17 Feb 2008 06:48:38 -0000	1.13
+++ deep_profiler/dump.m	1 Mar 2008 06:52:02 -0000
@@ -536,7 +536,8 @@
         )
     ->
         ProcStatic = proc_static(Id, DeclModule, RefinedId, RawId,
-            FileName, LineNumber, InInterface, Sites, IsZeroed),
+            FileName, LineNumber, InInterface, Sites, CoveragePoints, 
+            IsZeroed),
         IdStr = dump_proc_id(Id),
         io.format("ps%d:\n", [i(Index)], !IO),
         io.format("\tps_id\t\t= %s", [s(IdStr)], !IO),
@@ -572,6 +573,7 @@
         ),
         io.format("\t%s\n", [s(IsZeroStr)], !IO),
         array_foldl_from_0(dump_proc_static_call_sites, Sites, !IO),
+        array_foldl_from_0(dump_coverage_point, CoveragePoints, !IO),
         io.nl(!IO)
     ;
         true
@@ -584,6 +586,17 @@
     CSSPtr = call_site_static_ptr(CSSI),
     io.format("\tps_site[%d]: css%d\n", [i(Slot), i(CSSI)], !IO).
 
+
+:- pred dump_coverage_point(int::in, coverage_point::in, io::di, io::uo) 
+    is det.
+
+dump_coverage_point(Num, CoveragePoint, !IO) :-
+    CoveragePoint = coverage_point(Count, coverage_point_info(Path, Type)),
+    goal_path_to_string(Path) = PathString,
+    io.format("\tcoverage_point[%d]: %s, %s: %d\n", 
+        [i(Num), s(string(Type)), s(PathString), i(Count)], !IO).
+
+
 %----------------------------------------------------------------------------%
 
 :- func dump_proc_id(string_proc_label) = string.
Index: deep_profiler/profile.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/deep_profiler/profile.m,v
retrieving revision 1.17
diff -u -u -r1.17 profile.m
--- deep_profiler/profile.m	12 Sep 2007 06:21:10 -0000	1.17
+++ deep_profiler/profile.m	1 Mar 2008 06:52:02 -0000
@@ -162,15 +162,16 @@
 
 :- type proc_static
     --->    proc_static(
-                ps_id           :: string_proc_label, % procedure ID
-                ps_decl_module  :: string,      % declaring module
-                ps_refined_id   :: string,      % refined procedure id
-                ps_raw_id       :: string,      % raw procedure id
-                ps_file_name    :: string,      % file name of proc
-                ps_line_number  :: int,         % line number of proc
-                ps_in_interface :: bool,        % is in interface?
-                ps_sites        :: array(call_site_static_ptr),
-                ps_is_zeroed    :: is_zeroed
+                ps_id               :: string_proc_label, % procedure ID
+                ps_decl_module      :: string,      % declaring module
+                ps_refined_id       :: string,      % refined procedure id
+                ps_raw_id           :: string,      % raw procedure id
+                ps_file_name        :: string,      % file name of proc
+                ps_line_number      :: int,         % line number of proc
+                ps_in_interface     :: bool,        % is in interface?
+                ps_sites            :: array(call_site_static_ptr),
+                ps_coverage_points  :: array(coverage_point),
+                ps_is_zeroed        :: is_zeroed
             ).
 
 :- type call_site_dynamic
Index: deep_profiler/read_profile.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/deep_profiler/read_profile.m,v
retrieving revision 1.22
diff -u -u -r1.22 read_profile.m
--- deep_profiler/read_profile.m	23 Nov 2007 07:35:52 -0000	1.22
+++ deep_profiler/read_profile.m	1 Mar 2008 06:52:02 -0000
@@ -31,6 +31,7 @@
 :- implementation.
 
 :- import_module array_util.
+:- import_module exception.
 :- import_module io_combinator.
 :- import_module measurements.
 :- import_module mdbcomp.
@@ -135,7 +136,7 @@
 % This must the same string as the one written by MR_write_out_deep_id_string
 % in runtime/mercury_deep_profiling.c.
 
-deep_id_string = "Mercury deep profiler data version 4\n".
+deep_id_string = "Mercury deep profiler data version 5\n".
 
 :- func init_deep(int, int, int, int, int, int, int, int, int, int, int)
     = initial_deep.
@@ -167,7 +168,7 @@
             )),
         array.init(MaxPS + 1,
             proc_static(dummy_proc_id, "", "", "", "", -1, no,
-                array([]), not_zeroed))
+                array([]), array([]), not_zeroed))
     ).
 
 :- pred read_nodes(initial_deep::in, maybe_error(initial_deep)::out,
@@ -290,45 +291,54 @@
     trace [compile_time(flag("debug_read_profdeep")), io(!IO)] (
         io.write_string("reading proc_static.\n", !IO)
     ),
-    io_combinator.maybe_error_sequence_6(
+    io_combinator.maybe_error_sequence_7(
         read_ptr(ps),
         read_proc_id,
         read_string,
         read_num,
         read_deep_byte,
         read_num,
+        read_num,
         (pred(PSI0::in, Id0::in, F0::in, L0::in, I0::in,
-                N0::in, Stuff0::out) is det :-
-            Stuff0 = ok({PSI0, Id0, F0, L0, I0, N0})
+                NCS0::in, NCP0::in, Stuff0::out) is det :-
+            Stuff0 = ok({PSI0, Id0, F0, L0, I0, NCS0, NCP0})
         ),
         Res1, !IO),
     (
-        Res1 = ok({PSI, Id, FileName, LineNumber, Interface, N}),
-        read_n_things(N, read_ptr(css), Res2, !IO),
+        Res1 = ok({PSI, Id, FileName, LineNumber, Interface, NCS, NCP}),
+        read_n_things(NCS, read_ptr(css), Res2, !IO),
         (
             Res2 = ok(CSSIs),
-            CSSPtrs = list.map(make_cssptr, CSSIs),
-            DeclModule = decl_module(Id),
-            RefinedStr = refined_proc_id_to_string(Id),
-            RawStr = raw_proc_id_to_string(Id),
-            ( Interface = 0 ->
-                IsInInterface = no
+            read_n_things(NCP, read_coverage_point, Res3, !IO), 
+            (
+                Res3 = ok(CoveragePoints),
+                CSSPtrs = list.map(make_cssptr, CSSIs),
+                DeclModule = decl_module(Id),
+                RefinedStr = refined_proc_id_to_string(Id),
+                RawStr = raw_proc_id_to_string(Id),
+                ( Interface = 0 ->
+                    IsInInterface = no
+                ;
+                    IsInInterface = yes
+                ),
+                % The `not_zeroed' for whether the procedure's proc_static
+                % is ever zeroed is the default. The startup phase will set it
+                % to `zeroed' in the proc_statics which are ever zeroed.
+                ProcStatic = proc_static(Id, DeclModule,
+                    RefinedStr, RawStr, FileName, LineNumber,
+                    IsInInterface, array(CSSPtrs), array(CoveragePoints), 
+                    not_zeroed),
+                Res = ok2(ProcStatic, PSI),
+                trace [compile_time(flag("debug_read_profdeep")), io(!IO)] (
+                    io.write_string("read proc_static ", !IO),
+                    io.write_int(PSI, !IO),
+                    io.write_string(": ", !IO),
+                    io.write(ProcStatic, !IO),
+                    io.write_string("\n", !IO)
+                )
             ;
-                IsInInterface = yes
-            ),
-            % The `not_zeroed' for whether the procedure's proc_static
-            % is ever zeroed is the default. The startup phase will set it
-            % to `zeroed' in the proc_statics which are ever zeroed.
-            ProcStatic = proc_static(Id, DeclModule,
-                RefinedStr, RawStr, FileName, LineNumber,
-                IsInInterface, array(CSSPtrs), not_zeroed),
-            Res = ok2(ProcStatic, PSI),
-            trace [compile_time(flag("debug_read_profdeep")), io(!IO)] (
-                io.write_string("read proc_static ", !IO),
-                io.write_int(PSI, !IO),
-                io.write_string(": ", !IO),
-                io.write(ProcStatic, !IO),
-                io.write_string("\n", !IO)
+                Res3 = error(Err),
+                Res = error2(Err)
             )
         ;
             Res2 = error(Err),
@@ -402,6 +412,26 @@
         ),
         Res, !IO).
 
+:- pred read_coverage_point(maybe_error(coverage_point)::out, io::di, io::uo) 
+    is det.
+
+read_coverage_point(Res, !IO) :-
+    io_combinator.maybe_error_sequence_3(
+        read_string,
+        read_deep_byte,
+        read_num,
+        (pred(GoalPathString::in, CPTypeNum::in, CPCount::in, CP::out) is det :-
+            ( coverage_point_type_num(CPType, CPTypeNum) ->
+                goal_path_from_string_det(GoalPathString, GoalPath),
+                CPInfo = coverage_point_info(GoalPath, CPType),
+                CP = ok(coverage_point(CPCount, CPInfo))
+            ;
+                throw("Coverage point type " ++ string(CPTypeNum) ++ " unknown")
+            )
+        ),
+        Res, !IO).
+
+
 :- func raw_proc_id_to_string(string_proc_label) = string.
 
 raw_proc_id_to_string(str_special_proc_label(TypeName, TypeModule, _DefModule,
Index: library/profiling_builtin.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/profiling_builtin.m,v
retrieving revision 1.20
diff -u -u -r1.20 profiling_builtin.m
--- library/profiling_builtin.m	31 May 2007 03:03:37 -0000	1.20
+++ library/profiling_builtin.m	1 Mar 2008 06:52:02 -0000
@@ -107,6 +107,8 @@
 
 :- impure pred reset_activation_info_sr(proc_dynamic::in) is det.
 
+:- impure pred increment_coverage_point_count(proc_layout::in, int::in) is det.
+
 :- type call_site_nums_2
     --->    call_site_nums_2(int, int).
 
@@ -803,6 +805,23 @@
 }").
 
 %---------------------------------------------------------------------------%
+% instance of increment_coverage_point_counto
+%---------------------------------------------------------------------------%
+
+:- pragma foreign_proc("C",
+    increment_coverage_point_count(_ProcLayout::in, _CPIndex::in),
+    [thread_safe, will_not_call_mercury],
+"{
+/*
+ * This builtin is only ever used when code is instrumented with an inline
+ * version,  from complier/deep_profiling.m
+ */
+MR_fatal_error(
+    ""increment_coverage_point_count: builtin cannot be called normally"");
+}").
+
+
+%---------------------------------------------------------------------------%
 % instances of save_recursion_depth_N
 %---------------------------------------------------------------------------%
 
Index: mdbcomp/program_representation.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/mdbcomp/program_representation.m,v
retrieving revision 1.29
diff -u -u -r1.29 program_representation.m
--- mdbcomp/program_representation.m	27 Feb 2008 07:23:56 -0000	1.29
+++ mdbcomp/program_representation.m	1 Mar 2008 06:52:02 -0000
@@ -474,6 +474,40 @@
 
 %-----------------------------------------------------------------------------%
 
+:- type coverage_point
+    --->    coverage_point(
+                % The number of times execution reached this point,
+                int,
+                
+                % Meta-information about the coverage point.
+                coverage_point_info
+            ).
+
+:- type coverage_point_info
+    --->    coverage_point_info(
+                % Identifies the gaol that this coverage point info structure
+                % is relevant for.
+                goal_path,
+                % The type of this coverage point.
+                cp_type
+            ).
+
+% This enumeration specifies the type of coverage point.  A branch arm is an
+% arm of an if-then-else, switch or disj goal, the type can be determined by
+% the goal_path above.
+:- type cp_type
+    --->    cp_type_solns_may_fail
+    ;       cp_type_solns_multi
+    ;       cp_type_solns_any
+    ;       cp_type_branch_arm.
+
+:- pred coverage_point_type_num(cp_type, int) is det.
+:- mode coverage_point_type_num(in, out) is det.
+:- mode coverage_point_type_num(out, in) is semidet.
+
+
+%-----------------------------------------------------------------------------%
+
 :- implementation.
 
 :- import_module char.
@@ -1405,4 +1439,14 @@
     }
 ").
 
+
+%-----------------------------------------------------------------------------%
+
+
+coverage_point_type_num(cp_type_solns_may_fail, 0).
+coverage_point_type_num(cp_type_solns_multi, 1).
+coverage_point_type_num(cp_type_solns_any, 2).
+coverage_point_type_num(cp_type_branch_arm, 3).
+
+
 %-----------------------------------------------------------------------------%
Index: runtime/mercury_deep_profiling.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_deep_profiling.c,v
retrieving revision 1.29
diff -u -u -r1.29 mercury_deep_profiling.c
--- runtime/mercury_deep_profiling.c	23 Dec 2007 23:57:18 -0000	1.29
+++ runtime/mercury_deep_profiling.c	1 Mar 2008 06:52:02 -0000
@@ -287,6 +287,8 @@
 #define MR_FIXED_SIZE_INT_BYTES 4
 
 static  void    MR_write_csd_ptr(FILE *fp, const MR_CallSiteDynamic *csd);
+static  void    MR_write_out_coverage_point(FILE *fp, 
+    const MR_CoveragePointStatic *cp_static, const MR_Unsigned *cp);
 static  void    MR_write_ptr(FILE *fp, MR_NodeKind kind, const int node_id);
 static  void    MR_write_kind(FILE *fp, MR_CallSiteKind kind);
 static  void    MR_write_byte(FILE *fp, const char byte);
@@ -682,7 +684,7 @@
 MR_write_out_deep_id_string(FILE *fp)
 {
     /* Must be the same as deep_id_string in deep_profiler/read_profile.m */
-    const char  *id_string = "Mercury deep profiler data version 4\n";
+    const char  *id_string = "Mercury deep profiler data version 5\n";
 
     fputs(id_string, fp);
 }
@@ -897,7 +899,12 @@
     MR_write_num(deep_fp, ps->MR_ps_line_number);
     MR_write_byte(deep_fp, ps->MR_ps_is_in_interface);
     MR_write_num(deep_fp, ps->MR_ps_num_call_sites);
+    MR_write_num(deep_fp, ps->MR_ps_num_coverage_points);
 
+    /*
+     * Write out pointers to Call Site Statics.  These are read in with the
+     * proc static.
+     */
     for (i = 0; i < ps->MR_ps_num_call_sites; i++) {
         (void) MR_insert_call_site_static(&ps->MR_ps_call_sites[i], &css_id,
             NULL, MR_FALSE);
@@ -913,6 +920,29 @@
         MR_write_ptr(deep_fp, kind_css, css_id);
     }
 
+    /*
+     * Write out coverage points.  This is read in as part of the proc static.
+     */
+    /* TODO: Don't know if MR_Unsigned will work with MR_write_num() will work
+     * on 64bit machines, depends on size of unsigned. */
+    for (i = 0; i < ps->MR_ps_num_coverage_points; i++)
+    {
+#ifdef MR_DEEP_PROFILING_DEBUG
+        if (debug_fp != NULL) {
+            fprintf(debug_fp, "in proc_static %p/%p/%d, coverage point %d\n",
+                proc_layout, ps, ps_id, i);
+        }
+#endif
+        
+        MR_write_out_coverage_point(deep_fp, 
+            &ps->MR_ps_coverage_points_static[i], &ps->MR_ps_coverage_points[i]);
+    }
+    
+    
+    /*
+     * Write out the actual call site statics,  These are read in after the
+     * proc static, not as part of it.
+     */
     for (i = 0; i < ps->MR_ps_num_call_sites; i++) {
 #ifdef MR_DEEP_PROFILING_DEBUG
         if (debug_fp != NULL) {
@@ -1331,6 +1361,25 @@
     MR_write_ptr(fp, kind_csd, csd_id);
 }
 
+
+static void
+MR_write_out_coverage_point(FILE *fp, const MR_CoveragePointStatic *cp_static,
+    const MR_Unsigned *cp)
+{
+#ifdef  MR_DEEP_PROFILING_DETAIL_DEBUG
+    if (debug_fp != NULL) {
+        fprintf(debug_fp, "coverage point: %s,%d: %d\n", 
+            cp_static->MR_cp_goal_path, cp_static->MR_cp_type, *cp);
+    }
+#endif
+
+    MR_write_string(fp, cp_static->MR_cp_goal_path),
+    MR_write_byte(fp, cp_static->MR_cp_type),
+
+    MR_write_num(fp, *cp);
+}
+
+
 static void
 MR_write_ptr(FILE *fp, MR_NodeKind kind, int node_id)
 {
Index: runtime/mercury_deep_profiling.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_deep_profiling.h,v
retrieving revision 1.18
diff -u -u -r1.18 mercury_deep_profiling.h
--- runtime/mercury_deep_profiling.h	12 Sep 2007 06:21:15 -0000	1.18
+++ runtime/mercury_deep_profiling.h	1 Mar 2008 06:52:02 -0000
@@ -55,8 +55,15 @@
 #endif
 };
 
+
+typedef struct {
+	const char				*MR_cp_goal_path;
+	const char	 			MR_cp_type;
+} MR_CoveragePointStatic;
+
+
 struct MR_CallSiteStatic_Struct {
-    	MR_CallSiteKind				MR_css_kind;
+	MR_CallSiteKind				MR_css_kind;
 	MR_ProcLayout				*MR_css_callee_ptr_if_known;
 	MR_ConstString				MR_css_type_subst_if_known;
 	MR_ConstString				MR_css_file_name;
@@ -69,7 +76,7 @@
 	int					MR_ps_line_number;
 	int					MR_ps_is_in_interface;
 	int					MR_ps_num_call_sites;
-	const MR_CallSiteStatic			*MR_ps_call_sites;
+	const MR_CallSiteStatic 		*MR_ps_call_sites;
 #ifdef MR_USE_ACTIVATION_COUNTS
 	int					MR_ps_activation_count;
 #endif
@@ -77,6 +84,15 @@
 	int					MR_ps_cur_csd_stack_slot;
 	int					MR_ps_next_csd_stack_slot;
 	int					MR_ps_old_outermost_stack_slot;
+
+	/*
+	 * The number of coverage points in a procedure is limited statically
+	 * at compile time, so it's associated with proc statics rather than
+	 * proc dynamics.
+	 */
+	const MR_Unsigned			MR_ps_num_coverage_points;
+	const MR_CoveragePointStatic * const	MR_ps_coverage_points_static;
+	MR_Unsigned * const			MR_ps_coverage_points;
 };
 
 struct MR_CallSiteDynamic_Struct {
Index: tools/bootcheck
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/tools/bootcheck,v
retrieving revision 1.204
diff -u -u -r1.204 bootcheck
--- tools/bootcheck	20 Feb 2008 03:10:00 -0000	1.204
+++ tools/bootcheck	1 Mar 2008 06:52:02 -0000
@@ -1571,6 +1571,7 @@
             benchmarks
             debugger
             debugger/declarative
+            deep_profiler
             dppd
             general
             general/accumulator



--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list