source: icGREP/icgrep-devel/icgrep/kernels/mmap_kernel.cpp @ 5421

Last change on this file since 5421 was 5421, checked in by nmedfort, 2 years ago

Bug fix for mmap-ing 0-length files

File size: 5.8 KB
Line 
1/*
2 *  Copyright (c) 2017 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 */
5#include "mmap_kernel.h"
6#include <llvm/IR/Module.h>
7#include <IR_Gen/idisa_builder.h>
8#include <kernels/streamset.h>
9
10using namespace llvm;
11
12namespace kernel {
13
14void MMapSourceKernel::generateInitializeMethod() {
15    BasicBlock * emptyFile = CreateBasicBlock("EmptyFile");
16    BasicBlock * nonEmptyFile = CreateBasicBlock("NonEmptyFile");
17    BasicBlock * exit = CreateBasicBlock("Exit");
18
19    Value * fd = getScalarField("fileDescriptor");
20    Value * fileSize = iBuilder->CreateFileSize(fd);
21    if (mCodeUnitWidth > 8) {
22        fileSize = iBuilder->CreateUDiv(fileSize, iBuilder->getSize(mCodeUnitWidth / 8));
23    }
24    Value * const isEmpty = iBuilder->CreateICmpEQ(fileSize, ConstantInt::getNullValue(fileSize->getType()));
25    iBuilder->CreateUnlikelyCondBr(isEmpty, emptyFile, nonEmptyFile);
26    // we cannot mmap a 0 length file; just create a 1-page sized fake file buffer for simplicity
27    iBuilder->SetInsertPoint(emptyFile);
28    Constant * pageSize = ConstantInt::get(fileSize->getType(), getpagesize());
29    Value * fakeFileBuffer = iBuilder->CreateAnonymousMMap(pageSize);
30    iBuilder->CreateBr(exit);
31
32    iBuilder->SetInsertPoint(nonEmptyFile);
33    Value * fileBackedBuffer = iBuilder->CreateFileSourceMMap(fd, fileSize);
34    iBuilder->CreateBr(exit);
35
36    iBuilder->SetInsertPoint(exit);
37    PHINode * buffer = iBuilder->CreatePHI(fileBackedBuffer->getType(), 2);
38    buffer->addIncoming(fakeFileBuffer, emptyFile);
39    buffer->addIncoming(fileBackedBuffer, nonEmptyFile);
40    PHINode * size = iBuilder->CreatePHI(fileSize->getType(), 2);
41    size->addIncoming(pageSize, emptyFile);
42    size->addIncoming(fileSize, nonEmptyFile);
43
44    setBaseAddress("sourceBuffer", buffer);
45    setBufferedSize("sourceBuffer", size);
46    setScalarField("readableBuffer", buffer);
47    setScalarField("fileSize", fileSize);
48    iBuilder->CreateMAdvise(buffer, fileSize, CBuilder::ADVICE_WILLNEED);
49
50}
51
52void MMapSourceKernel::generateDoSegmentMethod() {
53
54    BasicBlock * dropPages = CreateBasicBlock("dropPages");
55    BasicBlock * produceData = CreateBasicBlock("produceData");
56    BasicBlock * setTermination = CreateBasicBlock("setTermination");
57    BasicBlock * mmapSourceExit = CreateBasicBlock("mmapSourceExit");
58
59    // instruct the OS that it can safely drop any fully consumed pages
60    Value * consumed = getConsumedItemCount("sourceBuffer");
61    Type * const consumedTy = consumed->getType();
62    Type * const voidPtrTy = iBuilder->getVoidPtrTy();
63
64    // multiply the consumed count by the code unit size then mask off any partial pages
65    if (mCodeUnitWidth > 8) {
66        consumed = iBuilder->CreateMul(consumed, iBuilder->getSize(mCodeUnitWidth / 8));
67    }
68    const auto pageSize = getpagesize();
69    if (LLVM_LIKELY((pageSize & (pageSize - 1)) == 0)) {
70        consumed = iBuilder->CreateAnd(consumed, ConstantExpr::getNot(ConstantInt::get(consumedTy, pageSize - 1)));
71    } else {
72        consumed = iBuilder->CreateSub(consumed, iBuilder->CreateURem(consumed, ConstantInt::get(consumedTy, pageSize)));
73    }
74    Value * sourceBuffer = getBaseAddress("sourceBuffer");
75    sourceBuffer = iBuilder->CreatePtrToInt(sourceBuffer, consumedTy);
76    Value * consumedBuffer = iBuilder->CreateAdd(sourceBuffer, consumed);
77    Value * readableBuffer = getScalarField("readableBuffer");
78    readableBuffer = iBuilder->CreatePtrToInt(readableBuffer, consumedTy);
79    Value * unnecessaryBytes = iBuilder->CreateSub(consumedBuffer, readableBuffer);
80    // avoid calling madvise unless an actual page table change could occur
81    Value * hasPagesToDrop = iBuilder->CreateICmpEQ(unnecessaryBytes, ConstantInt::getNullValue(unnecessaryBytes->getType()));
82    iBuilder->CreateLikelyCondBr(hasPagesToDrop, produceData, dropPages);
83
84    iBuilder->SetInsertPoint(dropPages);
85    iBuilder->CreateMAdvise(iBuilder->CreateIntToPtr(readableBuffer, voidPtrTy), unnecessaryBytes, CBuilder::ADVICE_DONTNEED);   
86    readableBuffer = iBuilder->CreateIntToPtr(iBuilder->CreateAdd(readableBuffer, unnecessaryBytes), voidPtrTy);
87    setScalarField("readableBuffer", readableBuffer);
88    iBuilder->CreateBr(produceData);
89
90    // determine whether or not we've exhausted the file buffer
91    iBuilder->SetInsertPoint(produceData);
92    ConstantInt * segmentItems = iBuilder->getSize(mSegmentBlocks * iBuilder->getBitBlockWidth());
93    Value * const fileSize = getScalarField("fileSize");
94    Value * produced = getProducedItemCount("sourceBuffer");
95    produced = iBuilder->CreateAdd(produced, segmentItems);
96
97    Value * lessThanFullSegment = iBuilder->CreateICmpULT(fileSize, produced);
98    iBuilder->CreateCondBr(lessThanFullSegment, setTermination, mmapSourceExit);
99    iBuilder->SetInsertPoint(setTermination);
100
101    setTerminationSignal();
102    iBuilder->CreateBr(mmapSourceExit);
103
104    // finally, set the "produced" count to reflect current position in the file
105    iBuilder->SetInsertPoint(mmapSourceExit);
106    PHINode * itemsRead = iBuilder->CreatePHI(produced->getType(), 2);
107    itemsRead->addIncoming(produced, produceData);
108    itemsRead->addIncoming(fileSize, setTermination);
109    setProducedItemCount("sourceBuffer", itemsRead);
110}
111
112void MMapSourceKernel::generateFinalizeMethod() {
113    iBuilder->CreateMUnmap(getBaseAddress("sourceBuffer"), getBufferedSize("sourceBuffer"));
114}
115
116MMapSourceKernel::MMapSourceKernel(IDISA::IDISA_Builder * iBuilder, unsigned blocksPerSegment, unsigned codeUnitWidth)
117    : SegmentOrientedKernel(iBuilder, "Parabix:mmap_source" + std::to_string(blocksPerSegment) + "@" + std::to_string(codeUnitWidth),
118    {},
119    {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "sourceBuffer"}},
120    {Binding{iBuilder->getInt32Ty(), "fileDescriptor"}}, {Binding{iBuilder->getSizeTy(), "fileSize"}}, {Binding{iBuilder->getVoidPtrTy(), "readableBuffer"}})
121, mSegmentBlocks(blocksPerSegment)
122, mCodeUnitWidth(codeUnitWidth) {
123
124}
125
126}
Note: See TracBrowser for help on using the repository browser.