source: icGREP/icgrep-devel/icgrep/kernels/streamset.h @ 5856

Last change on this file since 5856 was 5856, checked in by nmedfort, 15 months ago

Revised pipeline structure to better control I/O rates

File size: 15.8 KB
Line 
1/*
2 *  Copyright (c) 2016 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 */
5
6#ifndef STREAMSET_H
7#define STREAMSET_H
8
9#include <llvm/IR/Type.h>  // for Type
10namespace IDISA { class IDISA_Builder; }
11namespace llvm { class Value; }
12namespace kernel { class Kernel; }
13namespace kernel { class KernelBuilder; }
14
15namespace parabix {
16   
17class StreamSetBuffer {
18    friend class kernel::Kernel;
19    friend class kernel::KernelBuilder;
20public:
21
22    enum class BufferKind : unsigned {
23        SourceBuffer
24        , ExternalBuffer
25        , CircularBuffer
26        , CircularCopybackBuffer
27        , SwizzledCopybackBuffer
28        , ExpandableBuffer
29        , DynamicBuffer
30    };
31
32    BufferKind getBufferKind() const {
33        return mBufferKind;
34    }
35   
36    std::string getUniqueID() const {
37        return mUniqueID;
38    }
39
40    llvm::Type * getType() const {
41        return mType;
42    }
43   
44    llvm::Type * getBaseType() const {
45        return mBaseType;
46    }
47
48    // Return the number of streams for a static stream set or 0 for an expandable stream set.
49    unsigned getNumOfStreams () const {
50        if (mBufferKind == BufferKind::ExpandableBuffer) return 0;
51        size_t numStreams = 1;
52        if (mBaseType->isArrayTy()) {
53            numStreams = mBaseType->getArrayNumElements();
54        }
55        return numStreams;
56    }
57   
58    unsigned getStreamFieldWidth () const {
59        if (mBaseType->isArrayTy()) {
60            return mBaseType->getArrayElementType()->getScalarSizeInBits();
61        }
62        return mBaseType->getScalarSizeInBits();
63    }
64   
65    unsigned getAddressSpace() const {
66        return mAddressSpace;
67    }
68
69    llvm::PointerType * getPointerType() const {
70        return getType()->getPointerTo(getAddressSpace());
71    }
72
73    size_t getBufferBlocks() const {
74        return mBufferBlocks;
75    }
76
77    llvm::Value * getStreamSetHandle() const {
78        return mStreamSetBufferPtr;
79    }
80   
81    virtual llvm::Type * getStreamSetBlockType() const;
82   
83    virtual void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb);
84
85    virtual void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const;
86
87    virtual llvm::Value * getStreamBlockPtr(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * addr, llvm::Value * streamIndex, llvm::Value * blockIndex, const bool readOnly) const;
88
89    virtual llvm::Value * getStreamPackPtr(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * addr, llvm::Value * streamIndex, llvm::Value * blockIndex, llvm::Value * packIndex, const bool readOnly) const;
90   
91    virtual llvm::Value * getStreamSetCount(IDISA::IDISA_Builder * const b, llvm::Value * handle) const;
92
93    virtual llvm::Value * getRawItemPointer(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * absolutePosition) const;
94
95    virtual void setBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * addr, llvm::Value *) const;
96
97    virtual void setBufferedSize(IDISA::IDISA_Builder * const b, llvm::Value * size, llvm::Value *) const;
98   
99    virtual llvm::Value * getBufferedSize(IDISA::IDISA_Builder * const b, llvm::Value * handle) const;
100   
101    virtual void setCapacity(IDISA::IDISA_Builder * const b, llvm::Value * size, llvm::Value *) const;
102   
103    virtual llvm::Value * getCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle) const;
104   
105    // The number of items that cam be linearly accessed from a given logical stream position.
106    virtual llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPos, llvm::Value * avail, bool reverse = false) const;
107
108    void createBlockCopy(IDISA::IDISA_Builder * const b, llvm::Value * targetBlockPtr, llvm::Value * sourceBlockPtr, llvm::Value * blocksToCopy) const;
109
110    virtual void createBlockAlignedCopy(IDISA::IDISA_Builder * const b, llvm::Value * targetBlockPtr, llvm::Value * sourceBlockPtr, llvm::Value * itemsToCopy, const unsigned alignment = 1) const;
111
112    virtual llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * consumed, bool reverse = false) const;
113   
114    virtual void doubleCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle) const;
115
116    bool supportsCopyBack() const {
117        return mOverflowBlocks != 0;
118    }
119
120    size_t overflowSize() const {
121        return mOverflowBlocks;
122    }
123   
124    virtual ~StreamSetBuffer() = 0;
125
126    kernel::Kernel * getProducer() const {
127        return mProducer;
128    }
129
130    const std::vector<kernel::Kernel *> & getConsumers() const {
131        return mConsumers;
132    }
133
134
135
136protected:
137
138    StreamSetBuffer(BufferKind k, llvm::Type * baseType, llvm::Type * resolvedType, unsigned BufferBlocks, unsigned OverflowBlocks, unsigned AddressSpace);
139
140    virtual llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockNo) const;
141
142    bool isCapacityGuaranteed(const llvm::Value * const index, const size_t capacity) const;
143
144    llvm::Value * modBufferSize(IDISA::IDISA_Builder * const b, llvm::Value * const offset) const;
145
146    virtual llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle) const;
147
148    void setProducer(kernel::Kernel * const producer) {
149        assert (producer);
150        mProducer = producer;
151    }
152
153    void addConsumer(kernel::Kernel * const consumer) {
154        assert (consumer);
155        mConsumers.push_back(consumer);
156    }
157
158protected:
159    const BufferKind                 mBufferKind;
160    llvm::Type * const               mType;
161    const size_t                     mBufferBlocks;
162    size_t                           mOverflowBlocks;    /* Number of data blocks of additional space at the end of the buffer for writing only. */
163    const unsigned                   mAddressSpace;
164    llvm::Value *                    mStreamSetBufferPtr;
165    llvm::Type * const               mBaseType;
166    std::string                      mUniqueID;
167    kernel::Kernel *                 mProducer;
168    std::vector<kernel::Kernel *>    mConsumers;
169};   
170
171class SourceBuffer final : public StreamSetBuffer {
172public:
173    static inline bool classof(const StreamSetBuffer * b) {
174        return b->getBufferKind() == BufferKind::SourceBuffer;
175    }
176
177    SourceBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, unsigned MemoryAddressSpace = 0, unsigned StructAddressSpace = 0);
178
179    void setBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * addr) const override;
180
181    void setBufferedSize(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * size) const override;
182
183    void setCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * c) const override;
184
185    llvm::Value * getBufferedSize(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
186   
187    llvm::Value * getCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
188   
189    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override;
190
191    llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * consumed, bool reverse = false) const override;
192
193    llvm::Type * getStreamSetBlockType() const override;
194
195    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) override;
196
197    void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override;
198
199protected:
200   
201    enum class Field {BaseAddress, BufferedSize, Capacity};
202
203    llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
204
205};
206
207class ExternalBuffer final : public StreamSetBuffer {
208public:
209    static inline bool classof(const StreamSetBuffer * b) {
210        return b->getBufferKind() == BufferKind::ExternalBuffer;
211    }
212
213    ExternalBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, llvm::Value * addr, unsigned AddressSpace = 0);
214
215    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override;
216   
217    llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * consumed, bool reverse = false) const override;
218
219    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override;
220
221    void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override;
222
223    llvm::Value * getCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
224};
225
226class CircularBuffer : public StreamSetBuffer {
227public:
228    static inline bool classof(const StreamSetBuffer * b) {
229        return b->getBufferKind() == BufferKind::CircularBuffer;
230    }
231   
232    CircularBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace = 0);
233
234    llvm::Value * getRawItemPointer(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * absolutePosition) const final;
235
236protected:
237
238    CircularBuffer(const BufferKind kind, const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, size_t overflowBlocks, unsigned AddressSpace);
239
240    llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockIndex) const final;
241};
242   
243
244//
245//  A CircularCopybackBuffer operates as a circular buffer buffer with an overflow area
246//  for temporary use by the kernel that writes to it.   If the kernel uses the overflow
247//  area, it must perform the doCopyBack action before releasing the buffer for use by
248//  subsequent kernels.
249//  Kernels that read from a CircularCopybackBuffer must not access the overflow area.
250//
251class CircularCopybackBuffer final : public CircularBuffer {
252public:
253    static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::CircularCopybackBuffer;}
254   
255    CircularCopybackBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, size_t overflowBlocks, unsigned AddressSpace = 0);
256       
257    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override;
258
259};
260   
261class SwizzledCopybackBuffer final : public StreamSetBuffer {
262public:
263    static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::SwizzledCopybackBuffer;}
264   
265    SwizzledCopybackBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, size_t overflowBlocks, unsigned fieldwidth = 64, unsigned AddressSpace = 0);
266       
267    void createBlockAlignedCopy(IDISA::IDISA_Builder * const b, llvm::Value * targetBlockPtr, llvm::Value * sourceBlockPtr, llvm::Value * itemsToCopy, const unsigned alignment = 1) const override;
268
269    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override;
270
271protected:
272    llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockIndex) const override;
273private:
274    unsigned mFieldWidth;
275   
276};
277
278// ExpandableBuffers do not allow access to the base stream set but will automatically increase the number of streams
279// within their set whenever the index exceeds its capacity
280//
281class ExpandableBuffer final : public StreamSetBuffer {
282public:
283    static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::ExpandableBuffer;}
284
285    ExpandableBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace = 0);
286
287    llvm::Value * getStreamBlockPtr(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * addr, llvm::Value * streamIndex, llvm::Value * blockIndex, const bool readOnly) const override;
288
289    llvm::Value * getStreamPackPtr(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * addr, llvm::Value * streamIndex, llvm::Value * blockIndex, llvm::Value * packIndex, const bool readOnly) const override;
290
291    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override;
292   
293    llvm::Value * getStreamSetCount(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
294
295    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override;
296
297    void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override;
298
299protected:
300
301    llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
302
303    llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * blockIndex, llvm::Value *) const override;
304
305private:
306
307    std::pair<llvm::Value *, llvm::Value *> getInternalStreamBuffer(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * streamIndex, llvm::Value * blockIndex, const bool readOnly) const;
308
309private:
310
311    const uint64_t  mInitialCapacity;
312
313};
314   
315// Dynamically allocated circular buffers: TODO: add copyback, swizzle support, dynamic allocation, producer, consumer, length
316class DynamicBuffer final : public StreamSetBuffer {
317public:
318    static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::DynamicBuffer;}
319   
320    DynamicBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t initialCapacity, size_t overflowBlocks = 0, unsigned swizzleFactor = 1, unsigned addrSpace = 0);
321   
322    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override;
323   
324    llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * consumed, bool reverse = false) const override;
325   
326    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override;
327
328    void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) const override;
329
330    llvm::Value * getRawItemPointer(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * absolutePosition) const override;
331   
332    llvm::Value * getBufferedSize(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
333   
334    void doubleCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle)  const final;
335
336protected:
337    llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
338   
339    llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockIndex) const override;
340
341   
342private:
343    /* Static data */
344    llvm::Type * mBufferStructType;      /* The type of the buffer struct. */
345    unsigned   mSwizzleFactor;     /* Number of streams swizzled together per block.  Must be a small power of 2. Default: 1. */
346   
347    /* Dynamic data fields stored in the buffer struct */
348   
349    enum class Field {BaseAddress, PriorBaseAddress, AllocatedCapacity, WorkingBlocks, Length, ProducedPosition, ConsumedPosition, FieldCount};
350   
351    /* BaseAddress - the physical base address of the memory area for stream set data.
352     PriorBaseAddress - the physical base address of the previous memory area for stream set data
353     (the immediately prior memory area is preserved in case any users in other threads
354     are accessing it).
355     WorkingBlocks - the physical size of the buffer for use in reading and writing data.
356     AllocatedCapacity - physical size available for expansion in place
357     Length - actual final length of stream set or -1 for unknown
358     ProducedPosition - the total number of items ever generated and stored in the buffer
359     ConsumedPosition - the number of buffer items that are known to have been fully processed by all users
360     */
361   
362};
363
364
365}
366#endif // STREAMSET_H
Note: See TracBrowser for help on using the repository browser.