[m-rev.] for post-commit review: Coverage Profiling completed.

Paul Bone pbone at csse.unimelb.edu.au
Sat Sep 27 21:46:58 AEST 2008


On Fri, Sep 26, 2008 at 05:06:19PM +1000, Zoltan Somogyi wrote:
> 
> Post-commit review of Paul's latest change to coverage profiling, together
> with some misc cleanups.
> 
> compiler/options.m:
> 	Add the new option --coverage-profiling-use-calls.
> 
> compiler/deep_profiling.m:
> 	Fix some misleading variable names and some misleading comments.
> 
> 	Make some comments more readable.
> 
> 	Group related predicates together.
> 
> 	Mark suspect code and unrevealing documentation with XXXs.
> 
> 	Fix an old bug: increment_coverage_point_counter does not bind its
> 	arguments.
> 
> 	Implement the new option.
> 
> library/profiling_builtin.m:
> 	Add a real body for increment_coverage_point_counter, since the new
> 	option needs it.
> 
> Index: compiler/deep_profiling.m
> ===================================================================
> RCS file: /home/mercury/mercury1/repository/mercury/compiler/deep_profiling.m,v
> retrieving revision 1.87
> diff -u -b -r1.87 deep_profiling.m
> --- compiler/deep_profiling.m	25 Sep 2008 13:44:48 -0000	1.87
> +++ compiler/deep_profiling.m	26 Sep 2008 06:53:39 -0000
> @@ -2236,6 +2252,7 @@
>      % Perform the coverage profiling transformation for conjuncts.  The goal
>      % list represents the list of goals within a conjunction minus 'Pos' goals
>      % removed from the head.
> +    % XXX What does that mean?
>      %
>  :- pred coverage_prof_second_pass_conj(conj_type::in,
>      list(hlds_goal)::in, list(hlds_goal)::out,

Fixed.

> @@ -2274,37 +2289,42 @@
>      proc_coverage_info::in, proc_coverage_info::out, bool::out) is det.
>  
>  coverage_prof_second_pass_disj(DPInfo, CoverageBeforeKnown,
> -        NextCoverageBeforeKnown, Disjs0, Disjs, !Info, AddedImpurity) :-
> +        NextCoverageBeforeKnown, Disjuncts0, Disjuncts, !Info,
> +        AddedImpurity) :-
>      % If the disjunction was introduced by the deep profiling pass, it has two
> -    % disjuncts and it's second disjunct has 'failure' determinism, then
> +    % disjuncts and its second disjunct has 'failure' determinism, then
>      % perform the coverage profiling pass on the first disjunct as if this
>      % is the only goal. 
>      (
>          DPInfo = dp_goal_info(goal_is_mdprof_inst, _),
> -        Disjs0 = [FirstDisj0, SecondDisj],
> -        SecondDisj ^ hlds_goal_info ^ goal_info_get_determinism = detism_failure
> +        Disjuncts0 = [FirstDisjunct0, SecondDisjunct],
> +        goal_info_get_determinism(SecondDisjunct ^ hlds_goal_info) =
> +            detism_failure
> +        % XXX Would this be a better test here?
> +        % goal_has_feature(SecondDisjunct, feature_preserve_backtrack_into)
>      ->
> -        coverage_prof_second_pass_goal(FirstDisj0, FirstDisj,
> +        coverage_prof_second_pass_goal(FirstDisjunct0, FirstDisjunct,
>              CoverageBeforeKnown, NextCoverageBeforeKnown, !Info,

I've added a comment here describing that the deep profiling
transformation doesn't appear to add this feature annotation to these
goals, but it probably should.

> @@ -2374,59 +2393,61 @@
>  
>  coverage_prof_second_pass_switchcase_2(_, _, [], [], _, _,
>          !CoverageAfterSwitchKnown, !Info, no). 
> -
>  coverage_prof_second_pass_switchcase_2(DPInfo, SwitchCanFail,
>          [Case0 | Cases0], [Case | Cases], CoverageBeforeSwitchKnown,
>          CoverageBeforeEveryCaseKnown, !CoverageAfterSwitchKnown, !Info,
>          AddedImpurity) :-
> -    Goal0 = Case0 ^ case_goal,
> +    Case0 = case(MainConsId, OtherConsIds, Goal0),
>  
> -    % If the switch cannot fail and this is the last case then the coverage
> -    % at the beginning of this case can be computed from the coverage before the
> -    % entire switch and coverage information for the tail of the switch such as
> -    % branch coverage points.
> +    % If the switch cannot fail and this is the last case, then the coverage
> +    % at the beginning of this case can be computed from the coverage before
> +    % the entire switch and coverage information for the tail of the switch
> +    % such as branch coverage points.
> +    % XXX The last part of that sentence does not make sense.
>      (
>          Cases0 = [],

Fixed.

> @@ -2778,18 +2753,19 @@
>      ;
>          GoalExpr0 = conj(ConjType, Goals0),
>          map_foldl2(coverage_prof_first_pass_conj(CPOptions), Goals0, Goals,
> -            goal_is_trivial, Trivial0, PortCountsCoverageAfterBefore,
> -            PortCountsCoverageAfterDirect),
> +            goal_is_trivial, Trivial0,
> +            PortCountsCoverageAfterBefore, PortCountsCoverageAfterDirect),
>          GoalExpr = conj(ConjType, Goals)
>      ;
>          GoalExpr0 = disj(Goals0),
> -        coverage_prof_first_pass_disj(CPOptions, Goals0, Goals,
> -            Trivial0, PortCountsCoverageAfterBefore,
> -            PortCountsCoverageAfterDirect0),
> +        coverage_prof_first_pass_disj(CPOptions, Goals0, Goals, Trivial0,
> +            PortCountsCoverageAfterBefore, PortCountsCoverageAfterDirect0),
>          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.
> +        % XXX What port counts? A disjunct need not contain a call.
> +        % do you mean coverage information from the end of each disjunct?
>          Detism = goal_info_get_determinism(GoalInfo0),
>          determinism_components(Detism, CanFail, _),
>          (

Not only is my earlier comment unclear, it's also false,  I've removed
it ad the code it refers to.

> @@ -2916,6 +2892,7 @@
>      !PortCountsCoverageAfter).
>  coverage_prof_first_pass_disj(CPOptions, [Goal0 | Goals0], [Goal | Goals],
>          Trivial, PortCountsCoverageAfterBefore, PortCountsCoverageAfter) :-
> +    % XXX What kind of name is PortCountsCoverageAfterBefore?
>      coverage_prof_first_pass(CPOptions, Goal0, Goal,
>          PortCountsCoverageAfterBefore,
>          dp_coverage_goal_info(TrivialGoal, PortCountsCoverageAfterGoal)),

Urgh,  Fixed.

In the future I'd like to add two extra types since I'm using
coverage_before_known in some places to express weather coverage is
known after a given goal, and port_counts_give_coverage_after to refer
to the coverage after a goal.


> @@ -2929,6 +2906,10 @@
>      % how often execution will enter the first case, so this also cannot use
>      % the portcount of a goal before it.
>      %
> +    % XXX This is wrong: there should be more differences than that, since you
> +    % a failure in one switch arm doesn't cause a jump to the start of the next
> +    % arm.
> +    %
>  :- pred coverage_prof_first_pass_switchcase(coverage_profiling_options::in,
>      list(case)::in, list(case)::out, goal_trivial::out,
>      port_counts_give_coverage_after::out) is det.

I've re-worded this.

> @@ -2977,14 +2977,26 @@
>          proc_static_cons_id(!.CoverageInfo, ProcStaticConsId),
>          generate_unify(ProcStaticConsId, ProcLayoutVar, GoalUnifyProcLayout),
>  
> -        !:CoverageInfo = !.CoverageInfo ^ ci_var_info := !.VarInfo
> +        !CoverageInfo ^ ci_var_info := !.VarInfo
>      ),
>  
>      % Build a call to the instrumentation code.
>  
> +    UseCalls = CPOptions ^ cpo_use_calls,
>      ModuleInfo = !.CoverageInfo ^ ci_module_info,
> -    get_deep_profile_builtin_ppid(ModuleInfo, "increment_coverage_point_count",
> -        2, PredId, ProcId),
> +    PredName = "increment_coverage_point_count",
> +    PredArity = 2,
> +    ArgVars = [ProcLayoutVar, CPIndexVar],
> +    % XXX The body of increment_coverage_point_count includes several
> +    % assertions. If these are enabled, then bodily including the C code
> +    % at EVERY coverage point will cause significant code bloat. Generating
> +    % a call to a predicate with the same code in library/profiling_builtin.m
> +    % should then yield smaller code, and due to cache effects, it will
> +    % probably yield faster code as well.
> +    (
> +        UseCalls = no,
> +        get_deep_profile_builtin_ppid(ModuleInfo, PredName, PredArity,
> +            PredId, ProcId),
>      Ground = ground(shared, none),
>      make_foreign_args([ProcLayoutVar, CPIndexVar],
>          [(yes("ProcLayout" - (Ground -> Ground)) - native_if_possible),

I've changed the "XXX" above to "Note", since this item doesn't require
any action, AIUI.

> @@ -3050,6 +3065,11 @@
>      some [!ForeignProcAttrs] (
>          % I don't think this would be thread safe but the cost of the mutexes
>          % may be too high.
> +        % XXX Correctness is more important than cost. The right solution
> +        % would be to add a mechanism that, in par grades, allows us to replace
> +        % the general foreign code mutex with one that guards only the data
> +        % coverage data structure we are updating, since that would yield
> +        % a LOT less contention.
>          !:ForeignProcAttrs = default_attributes(lang_c),
>          set_may_call_mercury(proc_will_not_call_mercury, !ForeignProcAttrs),
>          set_purity(purity_impure, !ForeignProcAttrs),

I agree, I think that what I meant when I wrote this was that you don't
want to pay for the cost of the mutexes in non parallel grades, (one of
Mercury's design principals), which I now understand is mostly what the
'par' grades enable.

I've added the 'not_thread_safe' attribute and modified this comment.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mercurylang.org/archives/reviews/attachments/20080927/a3d42db1/attachment.sig>


More information about the reviews mailing list