blob: 455d9384a11f2cdad8d75c8d26ff3cc8b57dee64 [file] [log] [blame]
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can
* be found in the LICENSE file.
*
*/
#pragma once
//
//
//
#include "macros.h"
#include "handle.h"
#include "extent_cl_12.h"
#include "device_cl_12.h"
//
// FIXME -- THIS DOCUMENTATION IS STALE NOW THAT A REFERENCE COUNT REP
// IS A {HOST:DEVICE} PAIR.
//
// Host-side handle pool
//
// The bulk size of the three extents is currently 6 bytes of overhead
// per number of host handles. The number of host handles is usually
// less than the number of blocks in the pool. Note that the maximum
// number of blocks is 2^27.
//
// A practical instantiation might provide a combined 2^20 path and
// raster host handles. This would occupy 6 MB of host RAM for the
// 32-bit handle, 8-bit reference count and 8-bit handle-to-grid map.
//
// Also note that we could use isolated/separate path and raster block
// pools. Worst case, this would double the memory footprint of SKC.
//
// Host-side handle reference count
//
// [0 ] : release
// [1..UMAX] : retain
//
// In a garbage-collected environment we might want to rely on an
// existing mechanism for determing whether a handle is live.
//
// Otherwise, we probably want to have a 16 or 32-bit ref count.
//
// The handle reference count is defensive and will not allow the host
// to underflow a handle that's still retained by the pipeline.
//
// The single reference counter is split into host and device counts.
//
union skc_handle_refcnt
{
skc_ushort hd; // host and device
struct {
skc_uchar h; // host
skc_uchar d; // device
};
};
SKC_STATIC_ASSERT(SKC_MEMBER_SIZE(union skc_handle_refcnt,hd) ==
SKC_MEMBER_SIZE(union skc_handle_refcnt,h) +
SKC_MEMBER_SIZE(union skc_handle_refcnt,d));
//
//
//
struct skc_handle_bih
{
skc_uint block;
skc_uint rem;
skc_handle_t * handles;
};
struct skc_handle_reclaim
{
struct skc_handle_bih bih;
cl_kernel kernel;
skc_device_kernel_id kernel_id;
};
union skc_handle_reclaim_rec
{
// ELEMENT 0
struct skc_runtime * runtime;
// ELEMENT 1
struct {
skc_uint rem; // # of available records
skc_uint head; // index of first record
};
// ELEMENTS 2+
struct {
skc_uint index; // index of this record -- never modified
union {
skc_uint next; // index of next record
skc_uint block; // block index of reclaimed handles
};
};
};
SKC_STATIC_ASSERT(sizeof(union skc_handle_reclaim_rec) == sizeof(skc_uint2));
//
//
//
typedef enum skc_handle_reclaim_type_e {
SKC_HANDLE_RECLAIM_TYPE_PATH,
SKC_HANDLE_RECLAIM_TYPE_RASTER,
SKC_HANDLE_RECLAIM_TYPE_COUNT
} skc_handle_reclaim_type_e;
struct skc_handle_pool
{
//
// FIXME -- should we be pedantic and make these always-host-side
// allocations "extents" as well? I think it's OK not being an
// extent structure for now and is mostly consistent with the rest
// of the code.
//
// FIXME -- the cbs[] array is a little idiosyncratic but the intent
// is to avoid storing the 64-bit backpointer inside of every single
// record. This can be harmonized later. Note that only a few
// hundred outstanding callbacks would represent many many subgroups
// of work and would fully occupy the GPU (if we allow it).
//
//
struct skc_extent_pdrw map; // device-managed extent mapping a host handle to device block id
struct {
skc_handle_t * indices; // array of individual host handles -- fragmented into blocks
union skc_handle_refcnt * refcnts; // array of reference counts indexed by an individual handle
skc_uint count;
} handle;
struct {
skc_uint * indices; // stack of indices to fixed-size blocks of host handles
skc_uint count; // number of handles -- valid from [0,size)
skc_uint width; // width of a fixed-size block of handles
skc_uint tos; // grows upward / push++ / --pop / # fixed-size blocks for reading
skc_uint bos; // grows downward / --push / pop++ / # fixed-size blocks for writing
} block;
union skc_handle_reclaim_rec * recs; // array of reclaim records
struct skc_handle_bih acquire;
struct skc_handle_reclaim reclaim[SKC_HANDLE_RECLAIM_TYPE_COUNT];
};
//
//
//
void
skc_handle_pool_create(struct skc_runtime * const runtime,
struct skc_handle_pool * const handle_pool,
skc_uint const size,
skc_uint const width,
skc_uint const recs);
void
skc_handle_pool_dispose(struct skc_runtime * const runtime,
struct skc_handle_pool * const handle_pool);
//
//
//