annotate src/fftw-3.3.5/genfft/schedule.ml @ 84:08ae793730bd

Add null config files
author Chris Cannam
date Mon, 02 Mar 2020 14:03:47 +0000
parents 2cd0e3b3e1fd
children
rev   line source
Chris@42 1 (*
Chris@42 2 * Copyright (c) 1997-1999 Massachusetts Institute of Technology
Chris@42 3 * Copyright (c) 2003, 2007-14 Matteo Frigo
Chris@42 4 * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology
Chris@42 5 *
Chris@42 6 * This program is free software; you can redistribute it and/or modify
Chris@42 7 * it under the terms of the GNU General Public License as published by
Chris@42 8 * the Free Software Foundation; either version 2 of the License, or
Chris@42 9 * (at your option) any later version.
Chris@42 10 *
Chris@42 11 * This program is distributed in the hope that it will be useful,
Chris@42 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@42 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@42 14 * GNU General Public License for more details.
Chris@42 15 *
Chris@42 16 * You should have received a copy of the GNU General Public License
Chris@42 17 * along with this program; if not, write to the Free Software
Chris@42 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Chris@42 19 *
Chris@42 20 *)
Chris@42 21
Chris@42 22 (* This file contains the instruction scheduler, which finds an
Chris@42 23 efficient ordering for a given list of instructions.
Chris@42 24
Chris@42 25 The scheduler analyzes the DAG (directed acyclic graph) formed by
Chris@42 26 the instruction dependencies, and recursively partitions it. The
Chris@42 27 resulting schedule data structure expresses a "good" ordering
Chris@42 28 and structure for the computation.
Chris@42 29
Chris@42 30 The scheduler makes use of utilties in Dag and other packages to
Chris@42 31 manipulate the Dag and the instruction list. *)
Chris@42 32
Chris@42 33 open Dag
Chris@42 34 (*************************************************
Chris@42 35 * Dag scheduler
Chris@42 36 *************************************************)
Chris@42 37 let to_assignment node = (Expr.Assign (node.assigned, node.expression))
Chris@42 38 let makedag l = Dag.makedag
Chris@42 39 (List.map (function Expr.Assign (v, x) -> (v, x)) l)
Chris@42 40
Chris@42 41 let return x = x
Chris@42 42 let has_color c n = (n.color = c)
Chris@42 43 let set_color c n = (n.color <- c)
Chris@42 44 let has_either_color c1 c2 n = (n.color = c1 || n.color = c2)
Chris@42 45
Chris@42 46 let infinity = 100000
Chris@42 47
Chris@42 48 let cc dag inputs =
Chris@42 49 begin
Chris@42 50 Dag.for_all dag (fun node ->
Chris@42 51 node.label <- infinity);
Chris@42 52
Chris@42 53 (match inputs with
Chris@42 54 a :: _ -> bfs dag a 0
Chris@42 55 | _ -> failwith "connected");
Chris@42 56
Chris@42 57 return
Chris@42 58 ((List.map to_assignment (List.filter (fun n -> n.label < infinity)
Chris@42 59 (Dag.to_list dag))),
Chris@42 60 (List.map to_assignment (List.filter (fun n -> n.label == infinity)
Chris@42 61 (Dag.to_list dag))))
Chris@42 62 end
Chris@42 63
Chris@42 64 let rec connected_components alist =
Chris@42 65 let dag = makedag alist in
Chris@42 66 let inputs =
Chris@42 67 List.filter (fun node -> Util.null node.predecessors)
Chris@42 68 (Dag.to_list dag) in
Chris@42 69 match cc dag inputs with
Chris@42 70 (a, []) -> [a]
Chris@42 71 | (a, b) -> a :: connected_components b
Chris@42 72
Chris@42 73 let single_load node =
Chris@42 74 match (node.input_variables, node.predecessors) with
Chris@42 75 ([x], []) ->
Chris@42 76 Variable.is_constant x ||
Chris@42 77 (!Magic.locations_are_special && Variable.is_locative x)
Chris@42 78 | _ -> false
Chris@42 79
Chris@42 80 let loads_locative node =
Chris@42 81 match (node.input_variables, node.predecessors) with
Chris@42 82 | ([x], []) -> Variable.is_locative x
Chris@42 83 | _ -> false
Chris@42 84
Chris@42 85 let partition alist =
Chris@42 86 let dag = makedag alist in
Chris@42 87 let dag' = Dag.to_list dag in
Chris@42 88 let inputs =
Chris@42 89 List.filter (fun node -> Util.null node.predecessors) dag'
Chris@42 90 and outputs =
Chris@42 91 List.filter (fun node -> Util.null node.successors) dag'
Chris@42 92 and special_inputs = List.filter single_load dag' in
Chris@42 93 begin
Chris@42 94
Chris@42 95 let c = match !Magic.schedule_type with
Chris@42 96 | 1 -> RED; (* all nodes in the input partition *)
Chris@42 97 | -1 -> BLUE; (* all nodes in the output partition *)
Chris@42 98 | _ -> BLACK; (* node color determined by bisection algorithm *)
Chris@42 99 in Dag.for_all dag (fun node -> node.color <- c);
Chris@42 100
Chris@42 101 Util.for_list inputs (set_color RED);
Chris@42 102
Chris@42 103 (*
Chris@42 104 The special inputs are those input nodes that load a single
Chris@42 105 location or twiddle factor. Special inputs can end up either
Chris@42 106 in the blue or in the red part. These inputs are special
Chris@42 107 because they inherit a color from their neighbors: If a red
Chris@42 108 node needs a special input, the special input becomes red, but
Chris@42 109 if all successors of a special input are blue, the special
Chris@42 110 input becomes blue. Outputs are always blue, whether they be
Chris@42 111 special or not.
Chris@42 112
Chris@42 113 Because of the processing of special inputs, however, the final
Chris@42 114 partition might end up being composed only of blue nodes (which
Chris@42 115 is incorrect). In this case we manually reset all inputs
Chris@42 116 (whether special or not) to be red.
Chris@42 117 *)
Chris@42 118
Chris@42 119 Util.for_list special_inputs (set_color YELLOW);
Chris@42 120
Chris@42 121 Util.for_list outputs (set_color BLUE);
Chris@42 122
Chris@42 123 let rec loopi donep =
Chris@42 124 match (List.filter
Chris@42 125 (fun node -> (has_color BLACK node) &&
Chris@42 126 List.for_all (has_either_color RED YELLOW) node.predecessors)
Chris@42 127 dag') with
Chris@42 128 [] -> if (donep) then () else loopo true
Chris@42 129 | i ->
Chris@42 130 begin
Chris@42 131 Util.for_list i (fun node ->
Chris@42 132 begin
Chris@42 133 set_color RED node;
Chris@42 134 Util.for_list node.predecessors (set_color RED);
Chris@42 135 end);
Chris@42 136 loopo false;
Chris@42 137 end
Chris@42 138
Chris@42 139 and loopo donep =
Chris@42 140 match (List.filter
Chris@42 141 (fun node -> (has_either_color BLACK YELLOW node) &&
Chris@42 142 List.for_all (has_color BLUE) node.successors)
Chris@42 143 dag') with
Chris@42 144 [] -> if (donep) then () else loopi true
Chris@42 145 | o ->
Chris@42 146 begin
Chris@42 147 Util.for_list o (set_color BLUE);
Chris@42 148 loopi false;
Chris@42 149 end
Chris@42 150
Chris@42 151 in loopi false;
Chris@42 152
Chris@42 153 (* fix the partition if it is incorrect *)
Chris@42 154 if not (List.exists (has_color RED) dag') then
Chris@42 155 Util.for_list inputs (set_color RED);
Chris@42 156
Chris@42 157 return
Chris@42 158 ((List.map to_assignment (List.filter (has_color RED) dag')),
Chris@42 159 (List.map to_assignment (List.filter (has_color BLUE) dag')))
Chris@42 160 end
Chris@42 161
Chris@42 162 type schedule =
Chris@42 163 Done
Chris@42 164 | Instr of Expr.assignment
Chris@42 165 | Seq of (schedule * schedule)
Chris@42 166 | Par of schedule list
Chris@42 167
Chris@42 168
Chris@42 169
Chris@42 170 (* produce a sequential schedule determined by the user *)
Chris@42 171 let rec sequentially = function
Chris@42 172 [] -> Done
Chris@42 173 | a :: b -> Seq (Instr a, sequentially b)
Chris@42 174
Chris@42 175 let schedule =
Chris@42 176 let rec schedule_alist = function
Chris@42 177 | [] -> Done
Chris@42 178 | [a] -> Instr a
Chris@42 179 | alist -> match connected_components alist with
Chris@42 180 | ([a]) -> schedule_connected a
Chris@42 181 | l -> Par (List.map schedule_alist l)
Chris@42 182
Chris@42 183 and schedule_connected alist =
Chris@42 184 match partition alist with
Chris@42 185 | (a, b) -> Seq (schedule_alist a, schedule_alist b)
Chris@42 186
Chris@42 187 in fun x ->
Chris@42 188 let () = Util.info "begin schedule" in
Chris@42 189 let res = schedule_alist x in
Chris@42 190 let () = Util.info "end schedule" in
Chris@42 191 res
Chris@42 192
Chris@42 193
Chris@42 194 (* partition a dag into two parts:
Chris@42 195
Chris@42 196 1) the set of loads from locatives and their successors,
Chris@42 197 2) all other nodes
Chris@42 198
Chris@42 199 This step separates the ``body'' of the dag, which computes the
Chris@42 200 actual fft, from the ``precomputations'' part, which computes e.g.
Chris@42 201 twiddle factors.
Chris@42 202 *)
Chris@42 203 let partition_precomputations alist =
Chris@42 204 let dag = makedag alist in
Chris@42 205 let dag' = Dag.to_list dag in
Chris@42 206 let loads = List.filter loads_locative dag' in
Chris@42 207 begin
Chris@42 208
Chris@42 209 Dag.for_all dag (set_color BLUE);
Chris@42 210 Util.for_list loads (set_color RED);
Chris@42 211
Chris@42 212 let rec loop () =
Chris@42 213 match (List.filter
Chris@42 214 (fun node -> (has_color RED node) &&
Chris@42 215 List.exists (has_color BLUE) node.successors)
Chris@42 216 dag') with
Chris@42 217 [] -> ()
Chris@42 218 | i ->
Chris@42 219 begin
Chris@42 220 Util.for_list i
Chris@42 221 (fun node ->
Chris@42 222 Util.for_list node.successors (set_color RED));
Chris@42 223 loop ()
Chris@42 224 end
Chris@42 225
Chris@42 226 in loop ();
Chris@42 227
Chris@42 228 return
Chris@42 229 ((List.map to_assignment (List.filter (has_color BLUE) dag')),
Chris@42 230 (List.map to_assignment (List.filter (has_color RED) dag')))
Chris@42 231 end
Chris@42 232
Chris@42 233 let isolate_precomputations_and_schedule alist =
Chris@42 234 let (a, b) = partition_precomputations alist in
Chris@42 235 Seq (schedule a, schedule b)
Chris@42 236