File: compute-freq.sml

package info (click to toggle)
mlton 20210117%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 58,464 kB
  • sloc: ansic: 27,682; sh: 4,455; asm: 3,569; lisp: 2,879; makefile: 2,347; perl: 1,169; python: 191; pascal: 68; javascript: 7
file content (136 lines) | stat: -rw-r--r-- 5,009 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
(*
 * This module computes frequencies when given branch probabilities.
 * Bug fix: 
 *   This module didn't work on irreducible flowgraphs!
 *   The problem was caused 
 *
 * -- Allen
 *)

functor ComputeFrequencies
    (structure Loop : LOOP_STRUCTURE
     structure Freq : FREQ
    ) : COMPUTE_FREQUENCIES =
struct

   structure Loop = Loop
   structure Dom  = Loop.Dom
   structure G    = Graph
   structure S    = BitSet  
   structure W    = Freq
   structure A    = Array
   structure H    = HashArray

   val op div = W.div

   fun compute_frequencies
         {cfg,loop,loopMultiplier,nodeFreq,edgeFreq,branchProb,isTakenBranch} =
   let val G.GRAPH cfg          = cfg
       val Loop as G.GRAPH loop = loop 
       val ENTRY                = case #entries cfg () of
                                     [ENTRY] => ENTRY
                                   | _ => raise Graph.NotSingleEntry
       val N                    = #capacity cfg ()
       val marked               = S.create N
       val number_of_entries    = length(#out_edges cfg ENTRY)     
       val entry_weight         = W.*(W.fromInt 100,number_of_entries)

          (* indexed by headers *)
       val likely_exits         = H.array(N,[])
       val exit_counts          = H.array(N,0)

          (* indexed by nodes *)
       val entry_edges          = A.tabulate(N,#in_edges cfg)
       val header_of            = Loop.header Loop
       val nodeFreqs            = A.array(N,0)
       val branchProbs          = A.array(N,0)
       val TIMES                = 20
 
       val _ = #forall_nodes cfg (fn (b,b') =>
                  (A.update(nodeFreqs,b,!(nodeFreq b'));
                   A.update(branchProbs,b,branchProb b')
                  ))

       fun is_exit_edge (e as (i,j,_)) = 
            List.exists (fn (i',j',_) => i = i' andalso j = j')
               (H.sub(likely_exits,A.sub(header_of,i)))

       val sum = List.foldr (fn ((_,_,e),m) => !(edgeFreq e) + m) 0

       fun exit_weight_of i = 
       let val h = A.sub(header_of,i)
           val w = A.sub(nodeFreqs,h)
       in  w div (loopMultiplier * H.sub(exit_counts,h))
       end

       val entryEdges = Loop.entryEdges Loop

       fun preprocess(header,Loop.LOOP{exits,...}) = 
       let val real_exits = 
               List.filter (fn (i,_,_) => A.sub(branchProbs,i) > 0) exits
       in  H.update(likely_exits,header,real_exits);
           H.update(exit_counts,header,length real_exits);
           A.update(entry_edges,header,entryEdges header) 
       end

       fun propagate(0,_) = (print "Out of time\n")
         | propagate(n,[]) = ()
         | propagate(n,i::worklist) =
       let val _ = S.reset(marked,i)
           val old_weight = A.sub(nodeFreqs,i)
           val new_weight = sum(A.sub(entry_edges,i))
           val new_weight = if i = ENTRY then entry_weight
                            else (case H.sub(likely_exits,i) of
                                   [] => new_weight (* not a real loop! *)
                                 | _ => W.*(new_weight,loopMultiplier) 
                                 )
       in  if old_weight = new_weight then
                propagate(n,worklist)
           else (A.update(nodeFreqs,i,new_weight);
                 propagate_edge_weight(#out_edges cfg i,new_weight,[]);
                 propagate'(n,#out_edges cfg i,worklist)
                )
       end

       and propagate'(n,[],worklist) = propagate(n,worklist)
         | propagate'(n,(i,j,_)::es,worklist) =
           if S.markAndTest(marked,j) then 
                propagate'(n,es,worklist)
           else propagate'(Int.-(n,1),es,j::worklist)

       and propagate_edge_weight([],W,es') = process_non_exits(W,es')
         | propagate_edge_weight((edge as (i,_,e))::es,W,es') =
           if is_exit_edge edge then 
              let val exit_weight = exit_weight_of(A.sub(header_of,i))
                  val w = edgeFreq e
              in  w := exit_weight; 
                  propagate_edge_weight(es,W-exit_weight,es')
              end
           else
              propagate_edge_weight(es,W,edge::es')

       and process_non_exits(W,[]) = ()
         | process_non_exits(W,[(_,_,e)]) = edgeFreq e := W
         | process_non_exits(W,es as [edge1 as (i,_,e1),(_,_,e2)]) =
           if i = ENTRY then divide_evenly(W,es) else
           let val w = edgeFreq e1
               val w' = edgeFreq e2
               val (w_F,w_T) = if isTakenBranch edge1 then (w',w) else (w,w')
               val p = A.sub(branchProbs,i)
           in  w_T := W.*(W,p) div 100;
               w_F := W - !w_T
           end
         | process_non_exits(W,es) = divide_evenly(W,es)

       and divide_evenly(W,es) = 
           let val W' = W div (length es)
           in  app (fn (_,_,e) => edgeFreq e := W') es
           end

   in
       #forall_nodes loop preprocess;
       propagate(TIMES * N, [ENTRY]);
       #forall_nodes cfg (fn (b,b') => nodeFreq b' := A.sub(nodeFreqs,b))
   end handle Overflow => print "[Overflow]\n"

end