1 /* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can 5 * be found in the LICENSE file. 6 * 7 */ 8 9 #pragma once 10 11 // 12 // 13 // 14 15 #include "macros.h" 16 #include "handle.h" 17 #include "extent_cl_12.h" 18 #include "device_cl_12.h" 19 20 // 21 // FIXME -- THIS DOCUMENTATION IS STALE NOW THAT A REFERENCE COUNT REP 22 // IS A {HOST:DEVICE} PAIR. 23 // 24 // Host-side handle pool 25 // 26 // The bulk size of the three extents is currently 6 bytes of overhead 27 // per number of host handles. The number of host handles is usually 28 // less than the number of blocks in the pool. Note that the maximum 29 // number of blocks is 2^27. 30 // 31 // A practical instantiation might provide a combined 2^20 path and 32 // raster host handles. This would occupy 6 MB of host RAM for the 33 // 32-bit handle, 8-bit reference count and 8-bit handle-to-grid map. 34 // 35 // Also note that we could use isolated/separate path and raster block 36 // pools. Worst case, this would double the memory footprint of SKC. 37 // 38 // Host-side handle reference count 39 // 40 // [0 ] : release 41 // [1..UMAX] : retain 42 // 43 // In a garbage-collected environment we might want to rely on an 44 // existing mechanism for determing whether a handle is live. 45 // 46 // Otherwise, we probably want to have a 16 or 32-bit ref count. 47 // 48 // The handle reference count is defensive and will not allow the host 49 // to underflow a handle that's still retained by the pipeline. 50 // 51 // The single reference counter is split into host and device counts. 52 // 53 54 union skc_handle_refcnt 55 { 56 skc_ushort hd; // host and device 57 58 struct { 59 skc_uchar h; // host 60 skc_uchar d; // device 61 }; 62 }; 63 64 SKC_STATIC_ASSERT(SKC_MEMBER_SIZE(union skc_handle_refcnt,hd) == 65 SKC_MEMBER_SIZE(union skc_handle_refcnt,h) + 66 SKC_MEMBER_SIZE(union skc_handle_refcnt,d)); 67 68 // 69 // 70 // 71 72 struct skc_handle_bih 73 { 74 skc_uint block; 75 skc_uint rem; 76 skc_handle_t * handles; 77 }; 78 79 struct skc_handle_reclaim 80 { 81 struct skc_handle_bih bih; 82 83 cl_kernel kernel; 84 skc_device_kernel_id kernel_id; 85 }; 86 87 union skc_handle_reclaim_rec 88 { 89 // ELEMENT 0 90 struct skc_runtime * runtime; 91 92 // ELEMENT 1 93 struct { 94 skc_uint rem; // # of available records 95 skc_uint head; // index of first record 96 }; 97 98 // ELEMENTS 2+ 99 struct { 100 skc_uint index; // index of this record -- never modified 101 union { 102 skc_uint next; // index of next record 103 skc_uint block; // block index of reclaimed handles 104 }; 105 }; 106 }; 107 108 SKC_STATIC_ASSERT(sizeof(union skc_handle_reclaim_rec) == sizeof(skc_uint2)); 109 110 // 111 // 112 // 113 114 typedef enum skc_handle_reclaim_type_e { 115 116 SKC_HANDLE_RECLAIM_TYPE_PATH, 117 SKC_HANDLE_RECLAIM_TYPE_RASTER, 118 119 SKC_HANDLE_RECLAIM_TYPE_COUNT 120 121 } skc_handle_reclaim_type_e; 122 123 struct skc_handle_pool 124 { 125 // 126 // FIXME -- should we be pedantic and make these always-host-side 127 // allocations "extents" as well? I think it's OK not being an 128 // extent structure for now and is mostly consistent with the rest 129 // of the code. 130 // 131 // FIXME -- the cbs[] array is a little idiosyncratic but the intent 132 // is to avoid storing the 64-bit backpointer inside of every single 133 // record. This can be harmonized later. Note that only a few 134 // hundred outstanding callbacks would represent many many subgroups 135 // of work and would fully occupy the GPU (if we allow it). 136 // 137 // 138 struct skc_extent_pdrw map; // device-managed extent mapping a host handle to device block id 139 140 struct { 141 skc_handle_t * indices; // array of individual host handles -- fragmented into blocks 142 union skc_handle_refcnt * refcnts; // array of reference counts indexed by an individual handle 143 skc_uint count; 144 } handle; 145 146 struct { 147 skc_uint * indices; // stack of indices to fixed-size blocks of host handles 148 skc_uint count; // number of handles -- valid from [0,size) 149 skc_uint width; // width of a fixed-size block of handles 150 skc_uint tos; // grows upward / push++ / --pop / # fixed-size blocks for reading 151 skc_uint bos; // grows downward / --push / pop++ / # fixed-size blocks for writing 152 } block; 153 154 union skc_handle_reclaim_rec * recs; // array of reclaim records 155 156 struct skc_handle_bih acquire; 157 struct skc_handle_reclaim reclaim[SKC_HANDLE_RECLAIM_TYPE_COUNT]; 158 }; 159 160 // 161 // 162 // 163 164 void 165 skc_handle_pool_create(struct skc_runtime * const runtime, 166 struct skc_handle_pool * const handle_pool, 167 skc_uint const size, 168 skc_uint const width, 169 skc_uint const recs); 170 171 void 172 skc_handle_pool_dispose(struct skc_runtime * const runtime, 173 struct skc_handle_pool * const handle_pool); 174 175 // 176 // 177 // 178