Changeset 5612


Ignore:
Timestamp:
Aug 15, 2017, 12:19:01 AM (6 weeks ago)
Author:
cameron
Message:

Dynamic buffer capacity doubling - initial check-in

Location:
icGREP/icgrep-devel/icgrep/kernels
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • icGREP/icgrep-devel/icgrep/kernels/streamset.cpp

    r5597 r5612  
    655655}
    656656
     657Value * DynamicBuffer::getBufferedSize(IDISA::IDISA_Builder * const iBuilder, Value * self) const {
     658    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), iBuilder->getInt32(int(Field::WorkingBlocks))});
     659    return iBuilder->CreateMul(iBuilder->CreateLoad(ptr), iBuilder->getSize(iBuilder->getBitBlockWidth()));
     660}
     661
     662
     663
    657664void DynamicBuffer::allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) {
    658665    Value * handle = b->CreateCacheAlignedAlloca(mBufferStructType);
     
    665672    bufSize = b->CreateRoundUp(bufSize, b->getSize(b->getCacheAlignment()));
    666673    Value * bufBasePtrField = b->CreateGEP(handle, {b->getInt32(0), b->getInt32(int(Field::BaseAddress))});
    667     Value * bufPtr = b->CreatePointerCast(b->CreateCacheAlignedMalloc(bufSize), bufBasePtrField->getType()->getPointerElementType());
     674    Type * bufPtrType = bufBasePtrField->getType()->getPointerElementType();
     675    Value * bufPtr = b->CreatePointerCast(b->CreateCacheAlignedMalloc(bufSize), bufPtrType);
    668676    b->CreateStore(bufPtr, bufBasePtrField);
     677    b->CreateStore(ConstantPointerNull::getNullValue(bufPtrType), b->CreateGEP(handle, {b->getInt32(0), b->getInt32(int(DynamicBuffer::Field::PriorBaseAddress))}));
    669678    b->CreateStore(bufSize, b->CreateGEP(handle, {b->getInt32(0), b->getInt32(int(Field::AllocatedCapacity))}));
    670679    b->CreateStore(b->getSize(mBufferBlocks), b->CreateGEP(handle, {b->getInt32(0), b->getInt32(int(Field::WorkingBlocks))}));
     
    676685
    677686void DynamicBuffer::releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) const {
     687    Value * handle = mStreamSetBufferPtr;
    678688    /* Free the dynamically allocated buffer, but not the stack-allocated buffer struct. */
    679     b->CreateFree(b->CreateLoad(b->CreateGEP(mStreamSetBufferPtr, {b->getInt32(0), b->getInt32(int(Field::BaseAddress))})));
    680 }
    681 
     689    Value * bufBasePtrField = b->CreateGEP(handle, {b->getInt32(0), b->getInt32(int(DynamicBuffer::Field::BaseAddress))});
     690    Type * bufPtrType = bufBasePtrField->getType()->getPointerElementType();
     691    Value * priorBasePtrField = b->CreateGEP(handle, {b->getInt32(0), b->getInt32(int(DynamicBuffer::Field::PriorBaseAddress))});
     692    BasicBlock * freePrior = b->CreateBasicBlock("freePrior");
     693    BasicBlock * freeCurrent = b->CreateBasicBlock("freeCurrent");
     694    Value * priorBuf = b->CreateLoad(priorBasePtrField);
     695    Value * priorBufIsNonNull = b->CreateICmpNE(priorBuf, ConstantPointerNull::get(cast<PointerType>(bufPtrType)));
     696    b->CreateCondBr(priorBufIsNonNull, freePrior, freeCurrent);
     697    b->SetInsertPoint(freePrior);
     698    b->CreateFree(priorBuf);
     699    b->CreateBr(freeCurrent);
     700    b->SetInsertPoint(freeCurrent);
     701    b->CreateFree(b->CreateLoad(bufBasePtrField));
     702}
     703
     704//
     705//  Simple capacity doubling.  Use the circular buffer property: duplicating buffer data
     706//  ensures that we have correct data.   TODO: consider optimizing based on actual
     707//  consumer and producer positions.
     708//
     709void DynamicBuffer::doubleCapacity(IDISA::IDISA_Builder * const b, Value * handle) {
     710    size_t numStreams = 1;
     711    if (isa<ArrayType>(mBaseType)) {
     712        numStreams = mBaseType->getArrayNumElements();
     713    }
     714    const auto fieldWidth = mBaseType->getArrayElementType()->getScalarSizeInBits();
     715    Constant * blockBytes = b->getSize(b->getBitBlockWidth() * numStreams * fieldWidth/8);
     716    Value * bufBasePtrField = b->CreateGEP(handle, {b->getInt32(0), b->getInt32(int(DynamicBuffer::Field::BaseAddress))});
     717    Type * bufPtrType = bufBasePtrField->getType()->getPointerElementType();
     718    Value * priorBasePtrField = b->CreateGEP(handle, {b->getInt32(0), b->getInt32(int(DynamicBuffer::Field::PriorBaseAddress))});
     719    Value * workingBlocksField = b->CreateGEP(handle, {b->getInt32(0), b->getInt32(int(DynamicBuffer::Field::WorkingBlocks))});
     720    Value * capacityField = b->CreateGEP(handle, {b->getInt32(0), b->getInt32(int(DynamicBuffer::Field::AllocatedCapacity))});
     721   
     722    Value * oldBufPtr = b->CreateLoad(bufBasePtrField);
     723    Value * const currentWorkingBlocks = b->CreateLoad(workingBlocksField);
     724    Value * workingBytes = b->CreateMul(currentWorkingBlocks, blockBytes);
     725    Value * const curAllocated = b->CreateLoad(capacityField);
     726    Value * neededCapacity = b->CreateAdd(workingBytes, workingBytes);
     727    if (mOverflowBlocks > 0) {
     728        Constant * overflowBytes = b->getSize(mOverflowBlocks * b->getBitBlockWidth() * numStreams * fieldWidth/8);
     729        neededCapacity = b->CreateAdd(neededCapacity, overflowBytes);
     730    }
     731    neededCapacity = b->CreateRoundUp(neededCapacity, b->getSize(b->getCacheAlignment()));
     732    BasicBlock * doubleEntry = b->GetInsertBlock();
     733    BasicBlock * doRealloc = b->CreateBasicBlock("doRealloc");
     734    BasicBlock * doCopy2 = b->CreateBasicBlock("doCopy2");
     735    b->CreateCondBr(b->CreateICmpULT(curAllocated, neededCapacity), doRealloc, doCopy2);
     736    b->SetInsertPoint(doRealloc);
     737    // If there is a non-null priorBasePtr, free it.
     738    Value * priorBuf = b->CreateLoad(priorBasePtrField);
     739    Value * priorBufIsNonNull = b->CreateICmpNE(priorBuf, ConstantPointerNull::get(cast<PointerType>(bufPtrType)));
     740    BasicBlock * deallocatePrior = b->CreateBasicBlock("deallocatePrior");
     741    BasicBlock * allocateNew = b->CreateBasicBlock("allocateNew");
     742    b->CreateCondBr(priorBufIsNonNull, deallocatePrior, allocateNew);
     743    b->SetInsertPoint(deallocatePrior);
     744    b->CreateFree(priorBuf);
     745    b->CreateBr(allocateNew);
     746    b->SetInsertPoint(allocateNew);
     747    b->CreateStore(oldBufPtr, priorBasePtrField);
     748    Value * newBufPtr = b->CreatePointerCast(b->CreateCacheAlignedMalloc(neededCapacity), bufPtrType);
     749    b->CreateStore(newBufPtr, bufBasePtrField);
     750    createBlockCopy(b, newBufPtr, oldBufPtr, currentWorkingBlocks);
     751    b->CreateStore(neededCapacity, capacityField);
     752    b->CreateBr(doCopy2);
     753    b->SetInsertPoint(doCopy2);
     754    PHINode * bufPtr = b->CreatePHI(oldBufPtr->getType(), 2);
     755    bufPtr->addIncoming(oldBufPtr, doubleEntry);
     756    bufPtr->addIncoming(newBufPtr, doRealloc);
     757    createBlockCopy(b, b->CreateGEP(bufPtr, currentWorkingBlocks), bufPtr, currentWorkingBlocks);
     758    b->CreateStore(b->CreateAdd(currentWorkingBlocks, currentWorkingBlocks), workingBlocksField);
     759}
    682760
    683761DynamicBuffer::DynamicBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, Type * type, size_t initialCapacity, size_t overflow, unsigned swizzle, unsigned addrSpace)
    684762: StreamSetBuffer(BufferKind::DynamicBuffer, type, resolveStreamSetType(b, type), initialCapacity, addrSpace)
    685 , mBufferStructType(StructType::get(resolveStreamSetType(b, type)->getPointerTo(addrSpace),
     763, mBufferStructType(StructType::get(resolveStreamSetType(b, type)->getPointerTo(addrSpace), resolveStreamSetType(b, type)->getPointerTo(addrSpace),
    686764                                    b->getSizeTy(), b->getSizeTy(), b->getSizeTy(), b->getSizeTy(), b->getSizeTy(), nullptr))
    687765, mSwizzleFactor(swizzle)
  • icGREP/icgrep-devel/icgrep/kernels/streamset.h

    r5597 r5612  
    319319
    320320    llvm::Value * getRawItemPointer(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * streamIndex, llvm::Value * absolutePosition) const override;
     321   
     322    llvm::Value * getBufferedSize(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const override;
     323   
     324    void doubleCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle);
     325
    321326
    322327protected:
     
    324329   
    325330    llvm::Value * getStreamSetBlockPtr(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockIndex) const override;
     331
    326332   
    327333private:
     
    333339    /* Dynamic data fields stored in the buffer struct */
    334340   
    335     enum class Field {BaseAddress, AllocatedCapacity, WorkingBlocks, Length, ProducedPosition, ConsumedPosition, FieldCount};
     341    enum class Field {BaseAddress, PriorBaseAddress, AllocatedCapacity, WorkingBlocks, Length, ProducedPosition, ConsumedPosition, FieldCount};
    336342   
    337343    /* BaseAddress - the physical base address of the memory area for stream set data.
     344     PriorBaseAddress - the physical base address of the previous memory area for stream set data
     345     (the immediately prior memory area is preserved in case any users in other threads
     346     are accessing it).
    338347     WorkingBlocks - the physical size of the buffer for use in reading and writing data.
    339348     AllocatedCapacity - physical size available for expansion in place
Note: See TracChangeset for help on using the changeset viewer.