Home My Page Projects Code Snippets Project Openings diderot
Summary Activity Tracker Tasks SCM

SCM Repository

[diderot] Annotation of /branches/vis12-cl/src/compiler/cl-target/gen-output.sml
ViewVC logotype

Annotation of /branches/vis12-cl/src/compiler/cl-target/gen-output.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3088 - (view) (download)

1 : jhr 2648 (* gen-output.sml
2 :     *
3 :     * COPYRIGHT (c) 2014 The Diderot Project (http://diderot-language.cs.uchicago.edu)
4 :     * All rights reserved.
5 :     *
6 :     * Generate strand output functions for the OpenCL target. The output formats always have
7 :     * a single axis for the data elements followed by one, or more, axes for the output structure.
8 :     * There are two cases that we handle:
9 :     *
10 :     * grid, fixed-size elements:
11 :     * nrrd has object axis followed by grid axes
12 :     *
13 :     * collection, fixed-size elements
14 :     * nrrd has object axis followed by a single axis
15 :     *
16 :     * NOTE: the C target also supports dynamic-sized elements (i.e., dynamic sequences), but the
17 :     * OpenCL target does not support these yet.
18 :     *
19 :     * The object axis kind depends on the output type, but it will either be one of the tensor types
20 :     * that Teem knows about or else nrrdKindList. In any case, the data elements are written as a
21 :     * flat vector following the in-memory layout. The other axes in the file will have nrrdKindSpace
22 :     * as their kind.
23 :     *
24 :     * TODO: some of this code is common with c-target/gen-output.sml (e.g., writing outputs to
25 :     * files), so we should refactor it.
26 :     *
27 :     * TODO: for sequences of tensors (e.g., tensor[3]{2}), we should use a separate axis for the
28 :     * sequence dimension with kind nrrdKindList.
29 :     *)
30 :    
31 :     structure GenOutput : sig
32 :    
33 :     (* gen (props, nAxes) outputs
34 :     * returns code for getting the output/snapshot nrrds from the program state.
35 :     * The arguments are:
36 :     * props - the target information
37 :     * nAxes - the number of axes in the grid of strands (NONE for a collection)
38 :     * outputs - the list of output state variables paired with their TreeIL types
39 :     * The return value is a record {kernels, getFns}, where
40 :     * kernels - list of OpenCL kernels used to get output variables
41 :     * getFns - list of function declarations that implement the public
42 :     * output and snapshot queries.
43 :     *)
44 : jhr 2699 val gen : Properties.props * int option -> (TreeIL.Ty.ty * string) list -> CLang.decl list
45 : jhr 2648
46 : jhr 2762 val genKernels : Properties.props * CLang.ty * int option
47 :     -> (TreeIL.Ty.ty * string) list
48 :     -> (string * CLang.decl) list
49 : jhr 2699
50 : jhr 2648 end = struct
51 :    
52 :     structure IL = TreeIL
53 :     structure V = IL.Var
54 :     structure Ty = IL.Ty
55 :     structure CL = CLang
56 : jhr 2743 structure RN = RuntimeNames
57 : jhr 2648 structure Nrrd = NrrdEnums
58 :     structure U = CLUtil
59 :    
60 :     fun mapi f l = let
61 :     fun mapf (i, [], l) = List.rev l
62 :     | mapf (i, x::xs, l) = mapf (i+1, xs, f(i, x)::l)
63 :     in
64 :     mapf (0, l, [])
65 :     end
66 :    
67 :     val nrrdPtrTy = CL.T_Ptr(CL.T_Named "Nrrd")
68 :     val sizeTy = CL.T_Named "size_t"
69 : jhr 2743 fun globPtr tgt = CL.T_Ptr(CL.T_Named(CLNames.globalsTy tgt))
70 : jhr 2762 fun schedPtr tgt = CL.T_Ptr(CL.T_Named(CLNames.schedTy tgt))
71 : jhr 2648 fun mkInt i = CL.mkInt(IntInf.fromInt i)
72 : jhr 2694
73 : jhr 2648 (* variables in the generated code *)
74 :     val wrldV = CL.mkVar "wrld"
75 :     val sizesV = CL.mkVar "sizes"
76 : jhr 2712 val nDataV = CL.mkVar "nData"
77 : jhr 2648
78 : jhr 2712 (* utility functions for initializing the sizes array *)
79 :     fun sizes i = CL.mkSubscript(sizesV, mkInt i)
80 :     fun setSizes (i, v) = CL.mkAssign(sizes i, v)
81 :    
82 : jhr 2648 (* create a kernel for copying the given output state variable to the output
83 :     * buffer.
84 :     *)
85 :     (* NOTES: if the output is a grid, then we want to use the grid indices as a guide for processing
86 :     * the output. Otherwise, the order does not matter, but we do need to worry about synchronizing
87 :     * writes to the output buffer.
88 :     *)
89 : jhr 2762 fun mkCopyKernel tgt strandTy (ty : TreeIL.Ty.ty, name) = let
90 :     val (ty', nElems) = CLTyTranslate.toOutputType ty
91 :     val body = CL.mkBlock[
92 :     CL.mkDeclInit(CL.uint32, "idx",
93 :     CL.mkBinOp(
94 :     CL.mkBinOp(CL.mkApply("get_group_id", [CL.mkInt 0]), CL.#*, CL.mkVar "BLK_SZ"),
95 :     CL.#+,
96 : jhr 2770 CL.mkApply("get_local_id", [CL.mkInt 0]))),
97 : jhr 2762 CL.mkDeclInit(CL.uint32, "offset",
98 :     CL.mkBinOp(CL.mkApply("get_num_groups", [CL.mkInt 0]), CL.#*, CL.mkVar "BLK_SZ")),
99 :     CL.S_Decl(["__global"], strandTy, "state", SOME(CL.I_Exp(CL.mkIndirect(CL.mkVar "sched", "state")))),
100 :     CL.mkWhile (CL.mkBinOp(CL.mkVar "idx", CL.#<, CL.mkVar "nStrands"),
101 :     CL.mkBlock(
102 :     CL.S_Decl(["__global"], CL.T_Ptr ty', "dst",
103 :     SOME(CL.I_Exp(CL.mkBinOp(CL.mkVar "outBuf", CL.#+,
104 : jhr 2770 CL.mkBinOp(CL.mkInt(IntInf.fromInt nElems), CL.#*, CL.mkVar "idx"))))) ::
105 : jhr 2762 CLTyTranslate.copyToOutput{
106 :     ty = ty,
107 :     dst = CL.mkVar "dst",
108 :     src = CL.mkSelect(CL.mkSubscript(CL.mkVar "state", CL.mkVar "idx"), name)
109 :     } @
110 :     [CL.mkAssign' (CL.mkVar "idx", CL.+=, CL.mkVar "offset")]))
111 :     ]
112 :     val kName = name ^ "Kern"
113 :     val kern = U.mkKernel(
114 :     kName,
115 :     [U.globalParam(schedPtr tgt, "sched"), U.globalParam(CL.T_Ptr ty', "outBuf"), U.clParam(CL.uint32, "nStrands")],
116 :     body)
117 : jhr 2648 in
118 : jhr 2762 (kName, kern)
119 : jhr 2648 end
120 :    
121 : jhr 2694 (* create the body of an output function for fixed-size outputs. The structure of the
122 :     * function body is:
123 :     *
124 :     * declare and compute sizes array
125 : jhr 2712 * allocate GPU data object
126 :     * invoke kernel to copy data from strand state into data buffer
127 : jhr 2694 * allocate nrrd nData
128 : jhr 2712 * copy data from GPU to nrrd
129 : jhr 2694 *)
130 : jhr 2712 fun genFixedOutput (tgt, snapshot, nAxes, ty, name) = let
131 :     val (elemCTy, nrrdType, axisKind, nElems) = OutputUtil.infoOf (tgt, ty)
132 : jhr 2773 val (nAxes, domAxisKind) = (case nAxes
133 :     of NONE => (1, Nrrd.KindList)
134 :     | SOME n => (n, Nrrd.KindSpace)
135 : jhr 2712 (* end case *))
136 :     val nDataAxes = if (axisKind = Nrrd.KindScalar) then 0 else 1
137 : jhr 2773 val sizesDim = nAxes + nDataAxes
138 : jhr 2712 (* generate the sizes initialization code *)
139 :     val initSizes = let
140 :     val dimSizes = let
141 : jhr 2764 val dcl = CL.mkDecl(CL.T_Array(sizeTy, SOME sizesDim), "sizes", NONE)
142 : jhr 2712 in
143 :     if (axisKind = Nrrd.KindScalar)
144 :     then [dcl]
145 :     else [dcl, setSizes(0, mkInt nElems)]
146 :     end
147 :     in
148 : jhr 2773 if #isArray tgt
149 : jhr 2712 then dimSizes @
150 :     List.tabulate (nAxes, fn i =>
151 :     setSizes(i+nDataAxes, CL.mkSubscript(CL.mkIndirect(wrldV, "size"), mkInt(nAxes-i-1))))
152 :     else raise Fail "output for collection is unimplemented"
153 :     end
154 :     (* code to copy the data from the GPU *)
155 :     val copyCode = [] (* FIXME *)
156 :     (* the function body *)
157 :     val stms =
158 :     CL.mkComment["Compute sizes of nrrd file"] ::
159 :     initSizes @
160 : jhr 2770 [CL.mkReturn(SOME(CL.mkApply("OutputGridFixed", [
161 : jhr 2764 CL.mkVar "wrld", CL.mkInt(IntInf.fromInt sizesDim), CL.mkVar "sizes",
162 : jhr 2770 CL.mkVar(NrrdEnums.tyToEnum nrrdType),
163 : jhr 2764 CL.mkIndirect(CL.mkVar "wrld", name ^ "Kern"), CL.mkVar "nData"
164 :     ])))]
165 : jhr 2712 in
166 :     ([CL.PARAM([], nrrdPtrTy, "nData")], CL.mkBlock stms)
167 :     end
168 : jhr 2694
169 :     fun gen (tgt : Properties.props, nAxes) = let
170 :     fun getFn snapshot (ty, name) = let
171 :     val funcName = if snapshot
172 : jhr 2743 then RN.snapshotGet(tgt, name)
173 :     else RN.outputGet(tgt, name)
174 : jhr 2694 fun mkFunc (params, body) =
175 : jhr 3088 CL.D_Func([], CL.boolTy, funcName, CL.PARAM([], N.worldPtrTy tgt, "wrld")::params, body)
176 : jhr 2694 in
177 :     case ty
178 :     of Ty.DynSeqTy ty' => raise Fail "dynamic sequences not supported for OpenCL"
179 :     | _ => mkFunc (genFixedOutput(tgt, snapshot, nAxes, ty, name))
180 :     (* end case *)
181 :     end
182 :     fun gen' outputs = let
183 :     val getFns = List.map (getFn false) outputs
184 :     val allFns = if (#exec tgt)
185 :     then getFns @ OutputUtil.genOutput(tgt, outputs)
186 :     else if (#snapshot tgt)
187 :     then List.map (getFn true) outputs @ getFns
188 :     else getFns
189 :     in
190 : jhr 2699 allFns
191 : jhr 2694 end
192 :     in
193 :     gen'
194 :     end
195 :    
196 : jhr 2762 (* TODO: we should provide a command-line option to batch output; i.e., to deal with all output
197 :     * variables in one kernel call.
198 :     *)
199 :     fun genKernels (tgt : Properties.props, strandTy, nAxes) = List.map (mkCopyKernel tgt strandTy)
200 : jhr 2694
201 : jhr 2648 end

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0