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

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

Changes towards separate compilation

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