source: icGREP/icgrep-devel/icgrep/kernels/stdout_kernel.cpp @ 5415

Last change on this file since 5415 was 5415, checked in by cameron, 2 years ago

Speed-up file output using new temporary files; unlinking old files

File size: 8.7 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#include "stdout_kernel.h"
6#include <llvm/IR/Module.h>
7#include <IR_Gen/idisa_builder.h>
8#include <kernels/streamset.h>
9namespace llvm { class Type; }
10
11using namespace llvm;
12using namespace parabix;
13
14namespace kernel {
15
16// Rather than using doBlock logic to write one block at a time, this custom
17// doSegment method attempts to write the entire segment with a single write call.
18// However, if the segment spans two memory areas (e.g., because of wraparound),
19// then two write calls are made.
20void StdOutKernel::generateDoSegmentMethod(Value *doFinal, const std::vector<Value *> &producerPos) {
21    PointerType * i8PtrTy = iBuilder->getInt8PtrTy();
22
23    Constant * blockItems = iBuilder->getSize(iBuilder->getBitBlockWidth() - 1);
24    Constant * itemBytes = iBuilder->getSize(mCodeUnitWidth / 8);
25    Value * processed = getProcessedItemCount("codeUnitBuffer");
26    Value * itemsToDo = iBuilder->CreateSub(producerPos[0], processed);
27    // There may be two memory areas if we are at the physical end of a circular buffer.
28    const auto b  = getInputStreamSetBuffer("codeUnitBuffer");
29    Value * wraparound = nullptr;
30    if (isa<CircularBuffer>(b) || isa<CircularCopybackBuffer>(b)) {
31        Value * instance = getStreamSetBufferPtr("codeUnitBuffer");
32        Value * accessible = b->getLinearlyAccessibleItems(instance, processed);
33        wraparound = iBuilder->CreateICmpULT(accessible, itemsToDo);
34        itemsToDo = iBuilder->CreateSelect(wraparound, accessible, itemsToDo);
35    }
36   
37    Value * byteOffset = iBuilder->CreateMul(iBuilder->CreateAnd(processed, blockItems), itemBytes);
38    Value * bytePtr = iBuilder->CreatePointerCast(getInputStreamBlockPtr("codeUnitBuffer", iBuilder->getInt32(0)), i8PtrTy);
39    bytePtr = iBuilder->CreateGEP(bytePtr, byteOffset);
40
41    iBuilder->CreateWriteCall(iBuilder->getInt32(1), bytePtr, iBuilder->CreateMul(itemsToDo, itemBytes));
42
43    processed = iBuilder->CreateAdd(processed, itemsToDo);
44    setProcessedItemCount("codeUnitBuffer", processed);
45   
46    // Now we may process the second area (if required).
47    if (isa<CircularBuffer>(b) || isa<CircularCopybackBuffer>(b)) {
48        BasicBlock * wrapAroundWrite = CreateBasicBlock("wrapAroundWrite");
49        BasicBlock * stdoutExit = CreateBasicBlock("stdoutExit");
50        iBuilder->CreateCondBr(wraparound, wrapAroundWrite, stdoutExit);
51        iBuilder->SetInsertPoint(wrapAroundWrite);
52       
53        // Calculate from the updated value of processed;
54        byteOffset = iBuilder->CreateMul(iBuilder->CreateAnd(processed, blockItems), itemBytes);
55        Value * bytePtr = iBuilder->CreatePointerCast(getInputStreamBlockPtr("codeUnitBuffer", iBuilder->getInt32(0)), i8PtrTy);
56        bytePtr = iBuilder->CreateGEP(bytePtr, byteOffset);
57
58        itemsToDo = iBuilder->CreateSub(producerPos[0], processed);
59        iBuilder->CreateWriteCall(iBuilder->getInt32(1), bytePtr, iBuilder->CreateMul(itemsToDo, itemBytes));
60        processed = iBuilder->CreateAdd(processed, itemsToDo);
61        setProcessedItemCount("codeUnitBuffer", producerPos[0]);
62        iBuilder->CreateBr(stdoutExit);
63        iBuilder->SetInsertPoint(stdoutExit);
64    }
65}
66
67StdOutKernel::StdOutKernel(IDISA::IDISA_Builder * iBuilder, unsigned codeUnitWidth)
68: SegmentOrientedKernel(iBuilder, "stdout", {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {}, {}, {}, {})
69, mCodeUnitWidth(codeUnitWidth) {
70    setNoTerminateAttribute(true);
71}
72
73void FileSink::generateInitMethod() {
74    BasicBlock * setTerminationOnFailure = CreateBasicBlock("setTerminationOnFailure");
75    BasicBlock * fileSinkInitExit = CreateBasicBlock("fileSinkInitExit");
76    Value * fileName = getScalarField("fileName");
77    Value * fileNameLength = iBuilder->CreateStrlenCall(fileName);
78    // Make a temporary file name template with the characters "XXXXXX" appended
79    // as required by mkstemp.
80    Constant * suffixPlusNullLength = iBuilder->getSize(7);
81    Value * tmpFileNamePtr = iBuilder->CreatePointerCast(iBuilder->CreateMalloc(iBuilder->CreateAdd(fileNameLength, suffixPlusNullLength)), iBuilder->getInt8PtrTy());
82    setScalarField("tmpFileName", tmpFileNamePtr);
83    iBuilder->CreateMemCpy(tmpFileNamePtr, fileName, fileNameLength, 1);
84#ifdef BACKUP_OLDFILE
85    iBuilder->CreateMemCpy(iBuilder->CreateGEP(tmpFileNamePtr, fileNameLength), iBuilder->CreateGlobalStringPtr(".saved"), suffixPlusNullLength, 1);
86    iBuilder->CreateRenameCall(fileName, tmpFileNamePtr);
87#else
88    iBuilder->CreateUnlinkCall(fileName);
89#endif
90    iBuilder->CreateMemCpy(iBuilder->CreateGEP(tmpFileNamePtr, fileNameLength), iBuilder->CreateGlobalStringPtr("XXXXXX"), suffixPlusNullLength, 1);
91    Value * fileDes = iBuilder->CreateMkstempCall(tmpFileNamePtr);
92    setScalarField("fileDes", fileDes);
93    Value * failure = iBuilder->CreateICmpEQ(fileDes, iBuilder->getInt32(-1));
94    iBuilder->CreateCondBr(failure, setTerminationOnFailure, fileSinkInitExit);
95    iBuilder->SetInsertPoint(setTerminationOnFailure);
96    setTerminationSignal();
97    iBuilder->CreateBr(fileSinkInitExit);
98    iBuilder->SetInsertPoint(fileSinkInitExit);
99}
100
101void FileSink::generateDoSegmentMethod(Value *doFinal, const std::vector<Value *> &producerPos) {
102
103    PointerType * i8PtrTy = iBuilder->getInt8PtrTy();
104
105    BasicBlock * closeFile = CreateBasicBlock("closeFile");
106    BasicBlock * fileOutExit = CreateBasicBlock("fileOutExit");
107    Constant * blockItems = iBuilder->getSize(iBuilder->getBitBlockWidth());
108    Constant * itemBytes = iBuilder->getSize(mCodeUnitWidth/8);
109
110    Value * fileDes = getScalarField("fileDes");
111    Value * available = getAvailableItemCount("codeUnitBuffer");
112    Value * processed = getProcessedItemCount("codeUnitBuffer");
113    Value * itemsToDo = iBuilder->CreateSub(available, processed);
114    // There may be two memory areas if we are at the physical end of a circular buffer.
115    const auto b  = getInputStreamSetBuffer("codeUnitBuffer");
116    Value * wraparound = nullptr;
117    if (isa<CircularBuffer>(b) || isa<CircularCopybackBuffer>(b)) {
118        Value * instance = getStreamSetBufferPtr("codeUnitBuffer");
119        Value * accessible = b->getLinearlyAccessibleItems(instance, processed);
120        wraparound = iBuilder->CreateICmpULT(accessible, itemsToDo);
121        itemsToDo = iBuilder->CreateSelect(wraparound, accessible, itemsToDo);
122    }
123   
124    Value * byteOffset = iBuilder->CreateMul(iBuilder->CreateURem(processed, blockItems), itemBytes);
125    Value * bytePtr = iBuilder->CreatePointerCast(getInputStreamBlockPtr("codeUnitBuffer", iBuilder->getInt32(0)), i8PtrTy);
126    bytePtr = iBuilder->CreateGEP(bytePtr, byteOffset);
127    iBuilder->CreateWriteCall(fileDes, bytePtr, iBuilder->CreateMul(itemsToDo, itemBytes));
128   
129    processed = iBuilder->CreateAdd(processed, itemsToDo);
130    setProcessedItemCount("codeUnitBuffer", processed);
131   
132    // Now we may process the second area (if required).
133    if (isa<CircularBuffer>(b) || isa<CircularCopybackBuffer>(b)) {
134        BasicBlock * wrapAroundWrite = CreateBasicBlock("wrapAroundWrite");
135        BasicBlock * checkFinal = CreateBasicBlock("checkFinal");
136        iBuilder->CreateCondBr(wraparound, wrapAroundWrite, checkFinal);
137        iBuilder->SetInsertPoint(wrapAroundWrite);
138       
139        // Calculate from the updated value of processed;
140        byteOffset = iBuilder->CreateMul(iBuilder->CreateURem(processed, blockItems), itemBytes);
141        Value * bytePtr = iBuilder->CreatePointerCast(getInputStreamBlockPtr("codeUnitBuffer", iBuilder->getInt32(0)), i8PtrTy);
142        bytePtr = iBuilder->CreateGEP(bytePtr, byteOffset);
143        itemsToDo = iBuilder->CreateSub(available, processed);
144        iBuilder->CreateWriteCall(fileDes, bytePtr, iBuilder->CreateMul(itemsToDo, itemBytes));
145        processed = iBuilder->CreateAdd(processed, itemsToDo);
146        setProcessedItemCount("codeUnitBuffer", available);
147        iBuilder->CreateBr(checkFinal);
148        iBuilder->SetInsertPoint(checkFinal);
149    }
150    iBuilder->CreateCondBr(doFinal, closeFile, fileOutExit);
151
152    iBuilder->SetInsertPoint(closeFile);
153    iBuilder->CreateCloseCall(fileDes);
154    Value * newFileNamePtr = getScalarField("fileName");
155    Value * tmpFileNamePtr = getScalarField("tmpFileName");
156    iBuilder->CreateRenameCall(tmpFileNamePtr, newFileNamePtr);
157    iBuilder->CreateFree(tmpFileNamePtr);
158   
159    iBuilder->CreateBr(fileOutExit);
160
161    iBuilder->SetInsertPoint(fileOutExit);
162}
163
164FileSink::FileSink(IDISA::IDISA_Builder * iBuilder, unsigned codeUnitWidth)
165: SegmentOrientedKernel(iBuilder, "filesink", {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {},
166                {Binding{iBuilder->getInt8PtrTy(), "fileName"}}, {}, {Binding{iBuilder->getInt8PtrTy(), "tmpFileName"}, Binding{iBuilder->getInt32Ty(), "fileDes"}})
167, mCodeUnitWidth(codeUnitWidth) {
168}
169
170}
171
172
173
174
Note: See TracBrowser for help on using the repository browser.