Get cpu cycles of LLVM IR using CostModel - llvm

Since LLVM 3.0, there is CostModel.cpp under Analysis directory. Referring to its doc, it says
This file defines the cost model analysis. It provides a very basic cost estimation for LLVM-IR. This analysis uses the services of the codegen to approximate the cost of any IR instruction when lowered to machine instructions. The cost results are unit-less and the cost number represents the throughput of the machine assuming that all loads hit the cache, all branches are predicted, etc. The cost numbers can be added in order to compare two or more transformation alternatives.
I am wondering how should I compile and use this pass on IR files. A concrete example with appropriate commands would be perfect.

Below is the sample which is working for me :
Main Function File to test
#include <iostream>
#include <string>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/ErrorOr.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/Bitcode/BitcodeReader.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/Analysis/Passes.h>
#include <llvm/Analysis/TargetTransformInfo.h>
#include <llvm/Analysis/CostModelDummy.h>
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/SourceMgr.h"
using namespace llvm;
int main(int argc, char *argv[]) {
StringRef filename = "FILE_NAME";
LLVMContext context;
ErrorOr<std::unique_ptr<MemoryBuffer>> fileOrErr =
MemoryBuffer::getFileOrSTDIN(filename);
if (std::error_code ec = fileOrErr.getError()) {
std::cerr << " Error opening input file: " + ec.message() << std::endl;
return 2;
}
Expected<std::unique_ptr<Module>> moduleOrErr =
parseBitcodeFile(fileOrErr.get()->getMemBufferRef(), context);
if (std::error_code ec = fileOrErr.getError()) {
std::cerr << "Error reading Moduule: " + ec.message() << std::endl;
return 3;
}
llvm::SMDiagnostic Err;
llvm::LLVMContext Context;
std::unique_ptr<llvm::Module> m(parseIRFile(filename, Err, Context));
if (!m)
return 4;
std::cout << "Successfully read Module:" << std::endl;
std::cout << " Name: " << m->getName().str() << std::endl;
std::cout << " Target triple: " << m->getTargetTriple() << std::endl;
for (auto iter1 = m->getFunctionList().begin(); iter1 != m->getFunctionList().end(); iter1++) {
Function &f = *iter1;
CostModelAnalysisDummy obj;
std::cout << " STEP: 1 Function: " << f.getName().str() << std::endl;
obj.runOnFunction(f);
std::cout << " STEP: 2 Function: " << f.getName().str() << std::endl;
for (auto iter2 = f.getBasicBlockList().begin(); iter2 != f.getBasicBlockList().end(); iter2++) {
BasicBlock &bb = *iter2;
std::cout << " BasicBlock: " << bb.getName().str() << std::endl;
for (auto iter3 = bb.begin(); iter3 != bb.end(); iter3++) {
Instruction &inst = *iter3;
std::cout << std::endl << " Number of Cycles" << obj.getInstructionCost(&inst) << std::endl;
std::cout << " Instruction " << &inst << " : " << inst.getOpcodeName();
unsigned int i = 0;
unsigned int opnt_cnt = inst.getNumOperands();
for (; i < opnt_cnt; ++i)
{
Value *opnd = inst.getOperand(i);
std::string o;
// raw_string_ostream os(o);
// opnd->print(os);
//opnd->printAsOperand(os, true, m);
if (opnd->hasName()) {
o = opnd->getName();
std::cout << " " << o << ",";
}
else {
std::cout << " ptr" << opnd << ",";
}
}
std::cout << std::endl;
}
}
}
return 0;
}
Source File
//===- CostModel.cpp ------ Cost Model Analysis ---------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the cost model analysis. It provides a very basic cost
// estimation for LLVM-IR. This analysis uses the services of the codegen
// to approximate the cost of any IR instruction when lowered to machine
// instructions. The cost results are unit-less and the cost number represents
// the throughput of the machine assuming that all loads hit the cache, all
// branches are predicted, etc. The cost numbers can be added in order to
// compare two or more transformation alternatives.
//
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/CostModelDummy.h"
using namespace llvm;
// Register this pass.
char CostModelAnalysisDummy::ID = 0;
static const char cm_name[] = "Cost Model Analysis";
INITIALIZE_PASS_BEGIN(CostModelAnalysisDummy, CM_NAME, cm_name, false, true)
INITIALIZE_PASS_END(CostModelAnalysisDummy, CM_NAME, cm_name, false, true)
static cl::opt<bool> EnableReduxCost("costmodel-reduxcost-Dummy", cl::init(false),
cl::Hidden,
cl::desc("Recognize reduction patterns."));
FunctionPass *createCostModelAnalysisDummyPass() {
return new CostModelAnalysisDummy();
}
void
CostModelAnalysisDummy::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
}
bool
CostModelAnalysisDummy::runOnFunction(Function &F) {
this->F = &F;
PMDataManager *DM = getAsPMDataManager();
AnalysisResolver *AR = new AnalysisResolver(*DM);
setResolver(AR);
setTopLevelManager(new CostModelAnalysisDummy());
recordAvailableAnalysis(new TargetTransformInfoWrapperPass());
auto *TTIWP = getAnalysisIfAvailable<TargetTransformInfoWrapperPass>();
TTI = TTIWP ? &TTIWP->getTTI(F) : nullptr;
return false;
}
static bool isReverseVectorMask(ArrayRef<int> Mask) {
for (unsigned i = 0, MaskSize = Mask.size(); i < MaskSize; ++i)
if (Mask[i] >= 0 && Mask[i] != (int)(MaskSize - 1 - i))
return false;
return true;
}
static bool isSingleSourceVectorMask(ArrayRef<int> Mask) {
bool Vec0 = false;
bool Vec1 = false;
for (unsigned i = 0, NumVecElts = Mask.size(); i < NumVecElts; ++i) {
if (Mask[i] >= 0) {
if ((unsigned)Mask[i] >= NumVecElts)
Vec1 = true;
else
Vec0 = true;
}
}
return !(Vec0 && Vec1);
}
static bool isZeroEltBroadcastVectorMask(ArrayRef<int> Mask) {
for (unsigned i = 0; i < Mask.size(); ++i)
if (Mask[i] > 0)
return false;
return true;
}
static bool isAlternateVectorMask(ArrayRef<int> Mask) {
bool isAlternate = true;
unsigned MaskSize = Mask.size();
// Example: shufflevector A, B, <0,5,2,7>
for (unsigned i = 0; i < MaskSize && isAlternate; ++i) {
if (Mask[i] < 0)
continue;
isAlternate = Mask[i] == (int)((i & 1) ? MaskSize + i : i);
}
if (isAlternate)
return true;
isAlternate = true;
// Example: shufflevector A, B, <4,1,6,3>
for (unsigned i = 0; i < MaskSize && isAlternate; ++i) {
if (Mask[i] < 0)
continue;
isAlternate = Mask[i] == (int)((i & 1) ? i : MaskSize + i);
}
return isAlternate;
}
static TargetTransformInfo::OperandValueKind getOperandInfo(Value *V) {
TargetTransformInfo::OperandValueKind OpInfo =
TargetTransformInfo::OK_AnyValue;
// Check for a splat of a constant or for a non uniform vector of constants.
if (isa<ConstantVector>(V) || isa<ConstantDataVector>(V)) {
OpInfo = TargetTransformInfo::OK_NonUniformConstantValue;
if (cast<Constant>(V)->getSplatValue() != nullptr)
OpInfo = TargetTransformInfo::OK_UniformConstantValue;
}
// Check for a splat of a uniform value. This is not loop aware, so return
// true only for the obviously uniform cases (argument, globalvalue)
const Value *Splat = getSplatValue(V);
if (Splat && (isa<Argument>(Splat) || isa<GlobalValue>(Splat)))
OpInfo = TargetTransformInfo::OK_UniformValue;
return OpInfo;
}
static bool matchPairwiseShuffleMask(ShuffleVectorInst *SI, bool IsLeft,
unsigned Level) {
// We don't need a shuffle if we just want to have element 0 in position 0 of
// the vector.
if (!SI && Level == 0 && IsLeft)
return true;
else if (!SI)
return false;
SmallVector<int, 32> Mask(SI->getType()->getVectorNumElements(), -1);
// Build a mask of 0, 2, ... (left) or 1, 3, ... (right) depending on whether
// we look at the left or right side.
for (unsigned i = 0, e = (1 << Level), val = !IsLeft; i != e; ++i, val += 2)
Mask[i] = val;
SmallVector<int, 16> ActualMask = SI->getShuffleMask();
return Mask == ActualMask;
}
static bool matchPairwiseReductionAtLevel(const BinaryOperator *BinOp,
unsigned Level, unsigned NumLevels) {
// Match one level of pairwise operations.
// %rdx.shuf.0.0 = shufflevector <4 x float> %rdx, <4 x float> undef,
// <4 x i32> <i32 0, i32 2 , i32 undef, i32 undef>
// %rdx.shuf.0.1 = shufflevector <4 x float> %rdx, <4 x float> undef,
// <4 x i32> <i32 1, i32 3, i32 undef, i32 undef>
// %bin.rdx.0 = fadd <4 x float> %rdx.shuf.0.0, %rdx.shuf.0.1
if (BinOp == nullptr)
return false;
assert(BinOp->getType()->isVectorTy() && "Expecting a vector type");
unsigned Opcode = BinOp->getOpcode();
Value *L = BinOp->getOperand(0);
Value *R = BinOp->getOperand(1);
ShuffleVectorInst *LS = dyn_cast<ShuffleVectorInst>(L);
if (!LS && Level)
return false;
ShuffleVectorInst *RS = dyn_cast<ShuffleVectorInst>(R);
if (!RS && Level)
return false;
// On level 0 we can omit one shufflevector instruction.
if (!Level && !RS && !LS)
return false;
// Shuffle inputs must match.
Value *NextLevelOpL = LS ? LS->getOperand(0) : nullptr;
Value *NextLevelOpR = RS ? RS->getOperand(0) : nullptr;
Value *NextLevelOp = nullptr;
if (NextLevelOpR && NextLevelOpL) {
// If we have two shuffles their operands must match.
if (NextLevelOpL != NextLevelOpR)
return false;
NextLevelOp = NextLevelOpL;
} else if (Level == 0 && (NextLevelOpR || NextLevelOpL)) {
// On the first level we can omit the shufflevector <0, undef,...>. So the
// input to the other shufflevector <1, undef> must match with one of the
// inputs to the current binary operation.
// Example:
// %NextLevelOpL = shufflevector %R, <1, undef ...>
// %BinOp = fadd %NextLevelOpL, %R
if (NextLevelOpL && NextLevelOpL != R)
return false;
else if (NextLevelOpR && NextLevelOpR != L)
return false;
NextLevelOp = NextLevelOpL ? R : L;
} else
return false;
// Check that the next levels binary operation exists and matches with the
// current one.
BinaryOperator *NextLevelBinOp = nullptr;
if (Level + 1 != NumLevels) {
if (!(NextLevelBinOp = dyn_cast<BinaryOperator>(NextLevelOp)))
return false;
else if (NextLevelBinOp->getOpcode() != Opcode)
return false;
}
// Shuffle mask for pairwise operation must match.
if (matchPairwiseShuffleMask(LS, true, Level)) {
if (!matchPairwiseShuffleMask(RS, false, Level))
return false;
} else if (matchPairwiseShuffleMask(RS, true, Level)) {
if (!matchPairwiseShuffleMask(LS, false, Level))
return false;
} else
return false;
if (++Level == NumLevels)
return true;
// Match next level.
return matchPairwiseReductionAtLevel(NextLevelBinOp, Level, NumLevels);
}
static bool matchPairwiseReduction(const ExtractElementInst *ReduxRoot,
unsigned &Opcode, Type *&Ty) {
if (!EnableReduxCost)
return false;
// Need to extract the first element.
ConstantInt *CI = dyn_cast<ConstantInt>(ReduxRoot->getOperand(1));
unsigned Idx = ~0u;
if (CI)
Idx = CI->getZExtValue();
if (Idx != 0)
return false;
BinaryOperator *RdxStart = dyn_cast<BinaryOperator>(ReduxRoot->getOperand(0));
if (!RdxStart)
return false;
Type *VecTy = ReduxRoot->getOperand(0)->getType();
unsigned NumVecElems = VecTy->getVectorNumElements();
if (!isPowerOf2_32(NumVecElems))
return false;
// We look for a sequence of shuffle,shuffle,add triples like the following
// that builds a pairwise reduction tree.
//
// (X0, X1, X2, X3)
// (X0 + X1, X2 + X3, undef, undef)
// ((X0 + X1) + (X2 + X3), undef, undef, undef)
//
// %rdx.shuf.0.0 = shufflevector <4 x float> %rdx, <4 x float> undef,
// <4 x i32> <i32 0, i32 2 , i32 undef, i32 undef>
// %rdx.shuf.0.1 = shufflevector <4 x float> %rdx, <4 x float> undef,
// <4 x i32> <i32 1, i32 3, i32 undef, i32 undef>
// %bin.rdx.0 = fadd <4 x float> %rdx.shuf.0.0, %rdx.shuf.0.1
// %rdx.shuf.1.0 = shufflevector <4 x float> %bin.rdx.0, <4 x float> undef,
// <4 x i32> <i32 0, i32 undef, i32 undef, i32 undef>
// %rdx.shuf.1.1 = shufflevector <4 x float> %bin.rdx.0, <4 x float> undef,
// <4 x i32> <i32 1, i32 undef, i32 undef, i32 undef>
// %bin.rdx8 = fadd <4 x float> %rdx.shuf.1.0, %rdx.shuf.1.1
// %r = extractelement <4 x float> %bin.rdx8, i32 0
if (!matchPairwiseReductionAtLevel(RdxStart, 0, Log2_32(NumVecElems)))
return false;
Opcode = RdxStart->getOpcode();
Ty = VecTy;
return true;
}
static std::pair<Value *, ShuffleVectorInst *>
getShuffleAndOtherOprd(BinaryOperator *B) {
Value *L = B->getOperand(0);
Value *R = B->getOperand(1);
ShuffleVectorInst *S = nullptr;
if ((S = dyn_cast<ShuffleVectorInst>(L)))
return std::make_pair(R, S);
S = dyn_cast<ShuffleVectorInst>(R);
return std::make_pair(L, S);
}
static bool matchVectorSplittingReduction(const ExtractElementInst *ReduxRoot,
unsigned &Opcode, Type *&Ty) {
if (!EnableReduxCost)
return false;
// Need to extract the first element.
ConstantInt *CI = dyn_cast<ConstantInt>(ReduxRoot->getOperand(1));
unsigned Idx = ~0u;
if (CI)
Idx = CI->getZExtValue();
if (Idx != 0)
return false;
BinaryOperator *RdxStart = dyn_cast<BinaryOperator>(ReduxRoot->getOperand(0));
if (!RdxStart)
return false;
unsigned RdxOpcode = RdxStart->getOpcode();
Type *VecTy = ReduxRoot->getOperand(0)->getType();
unsigned NumVecElems = VecTy->getVectorNumElements();
if (!isPowerOf2_32(NumVecElems))
return false;
// We look for a sequence of shuffles and adds like the following matching one
// fadd, shuffle vector pair at a time.
//
// %rdx.shuf = shufflevector <4 x float> %rdx, <4 x float> undef,
// <4 x i32> <i32 2, i32 3, i32 undef, i32 undef>
// %bin.rdx = fadd <4 x float> %rdx, %rdx.shuf
// %rdx.shuf7 = shufflevector <4 x float> %bin.rdx, <4 x float> undef,
// <4 x i32> <i32 1, i32 undef, i32 undef, i32 undef>
// %bin.rdx8 = fadd <4 x float> %bin.rdx, %rdx.shuf7
// %r = extractelement <4 x float> %bin.rdx8, i32 0
unsigned MaskStart = 1;
Value *RdxOp = RdxStart;
SmallVector<int, 32> ShuffleMask(NumVecElems, 0);
unsigned NumVecElemsRemain = NumVecElems;
while (NumVecElemsRemain - 1) {
// Check for the right reduction operation.
BinaryOperator *BinOp;
if (!(BinOp = dyn_cast<BinaryOperator>(RdxOp)))
return false;
if (BinOp->getOpcode() != RdxOpcode)
return false;
Value *NextRdxOp;
ShuffleVectorInst *Shuffle;
std::tie(NextRdxOp, Shuffle) = getShuffleAndOtherOprd(BinOp);
// Check the current reduction operation and the shuffle use the same value.
if (Shuffle == nullptr)
return false;
if (Shuffle->getOperand(0) != NextRdxOp)
return false;
// Check that shuffle masks matches.
for (unsigned j = 0; j != MaskStart; ++j)
ShuffleMask[j] = MaskStart + j;
// Fill the rest of the mask with -1 for undef.
std::fill(&ShuffleMask[MaskStart], ShuffleMask.end(), -1);
SmallVector<int, 16> Mask = Shuffle->getShuffleMask();
if (ShuffleMask != Mask)
return false;
RdxOp = NextRdxOp;
NumVecElemsRemain /= 2;
MaskStart *= 2;
}
Opcode = RdxOpcode;
Ty = VecTy;
return true;
}
unsigned CostModelAnalysisDummy::getInstructionCost(const Instruction *I) const {
if (!TTI)
return -1;
switch (I->getOpcode()) {
case Instruction::GetElementPtr:
return TTI->getUserCost(I);
case Instruction::Ret:
case Instruction::PHI:
case Instruction::Br: {
return TTI->getCFInstrCost(I->getOpcode());
}
case Instruction::Add:
case Instruction::FAdd:
case Instruction::Sub:
case Instruction::FSub:
case Instruction::Mul:
case Instruction::FMul:
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::FDiv:
case Instruction::URem:
case Instruction::SRem:
case Instruction::FRem:
case Instruction::Shl:
case Instruction::LShr:
case Instruction::AShr:
case Instruction::And:
case Instruction::Or:
case Instruction::Xor: {
TargetTransformInfo::OperandValueKind Op1VK =
getOperandInfo(I->getOperand(0));
TargetTransformInfo::OperandValueKind Op2VK =
getOperandInfo(I->getOperand(1));
SmallVector<const Value*, 2> Operands(I->operand_values());
return TTI->getArithmeticInstrCost(I->getOpcode(), I->getType(), Op1VK,
Op2VK, TargetTransformInfo::OP_None,
TargetTransformInfo::OP_None,
Operands);
}
case Instruction::Select: {
const SelectInst *SI = cast<SelectInst>(I);
Type *CondTy = SI->getCondition()->getType();
return TTI->getCmpSelInstrCost(I->getOpcode(), I->getType(), CondTy);
}
case Instruction::ICmp:
case Instruction::FCmp: {
Type *ValTy = I->getOperand(0)->getType();
return TTI->getCmpSelInstrCost(I->getOpcode(), ValTy);
}
case Instruction::Store: {
const StoreInst *SI = cast<StoreInst>(I);
Type *ValTy = SI->getValueOperand()->getType();
return TTI->getMemoryOpCost(I->getOpcode(), ValTy,
SI->getAlignment(),
SI->getPointerAddressSpace());
}
case Instruction::Load: {
const LoadInst *LI = cast<LoadInst>(I);
return TTI->getMemoryOpCost(I->getOpcode(), I->getType(),
LI->getAlignment(),
LI->getPointerAddressSpace());
}
case Instruction::ZExt:
case Instruction::SExt:
case Instruction::FPToUI:
case Instruction::FPToSI:
case Instruction::FPExt:
case Instruction::PtrToInt:
case Instruction::IntToPtr:
case Instruction::SIToFP:
case Instruction::UIToFP:
case Instruction::Trunc:
case Instruction::FPTrunc:
case Instruction::BitCast:
case Instruction::AddrSpaceCast: {
Type *SrcTy = I->getOperand(0)->getType();
return TTI->getCastInstrCost(I->getOpcode(), I->getType(), SrcTy);
}
case Instruction::ExtractElement: {
const ExtractElementInst * EEI = cast<ExtractElementInst>(I);
ConstantInt *CI = dyn_cast<ConstantInt>(I->getOperand(1));
unsigned Idx = -1;
if (CI)
Idx = CI->getZExtValue();
// Try to match a reduction sequence (series of shufflevector and vector
// adds followed by a extractelement).
unsigned ReduxOpCode;
Type *ReduxType;
if (matchVectorSplittingReduction(EEI, ReduxOpCode, ReduxType))
return TTI->getArithmeticReductionCost(ReduxOpCode, ReduxType, false);
else if (matchPairwiseReduction(EEI, ReduxOpCode, ReduxType))
return TTI->getArithmeticReductionCost(ReduxOpCode, ReduxType, true);
return TTI->getVectorInstrCost(I->getOpcode(),
EEI->getOperand(0)->getType(), Idx);
}
case Instruction::InsertElement: {
const InsertElementInst * IE = cast<InsertElementInst>(I);
ConstantInt *CI = dyn_cast<ConstantInt>(IE->getOperand(2));
unsigned Idx = -1;
if (CI)
Idx = CI->getZExtValue();
return TTI->getVectorInstrCost(I->getOpcode(),
IE->getType(), Idx);
}
case Instruction::ShuffleVector: {
const ShuffleVectorInst *Shuffle = cast<ShuffleVectorInst>(I);
Type *VecTypOp0 = Shuffle->getOperand(0)->getType();
unsigned NumVecElems = VecTypOp0->getVectorNumElements();
SmallVector<int, 16> Mask = Shuffle->getShuffleMask();
if (NumVecElems == Mask.size()) {
if (isReverseVectorMask(Mask))
return TTI->getShuffleCost(TargetTransformInfo::SK_Reverse, VecTypOp0,
0, nullptr);
if (isAlternateVectorMask(Mask))
return TTI->getShuffleCost(TargetTransformInfo::SK_SELECT,
VecTypOp0, 0, nullptr);
if (isZeroEltBroadcastVectorMask(Mask))
return TTI->getShuffleCost(TargetTransformInfo::SK_Broadcast,
VecTypOp0, 0, nullptr);
if (isSingleSourceVectorMask(Mask))
return TTI->getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc,
VecTypOp0, 0, nullptr);
return TTI->getShuffleCost(TargetTransformInfo::SK_PermuteTwoSrc,
VecTypOp0, 0, nullptr);
}
return -1;
}
case Instruction::Call:
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
SmallVector<Value *, 4> Args;
for (unsigned J = 0, JE = II->getNumArgOperands(); J != JE; ++J)
Args.push_back(II->getArgOperand(J));
FastMathFlags FMF;
if (auto *FPMO = dyn_cast<FPMathOperator>(II))
FMF = FPMO->getFastMathFlags();
return TTI->getIntrinsicInstrCost(II->getIntrinsicID(), II->getType(),
Args, FMF);
}
return -1;
default:
// We don't have any information on this instruction.
return -1;
}
}
void CostModelAnalysisDummy::print(raw_ostream &OS, const Module*) const {
if (!F)
return;
for (BasicBlock &B : *F) {
for (Instruction &Inst : B) {
unsigned Cost = getInstructionCost(&Inst);
if (Cost != (unsigned)-1)
OS << "Cost Model: Found an estimated cost of " << Cost;
else
OS << "Cost Model: Unknown cost";
OS << " for instruction: " << Inst << "\n";
}
}
}
Header File
#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/VectorUtils.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Value.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <iostream>
#include "llvm/IR/LegacyPassManagers.h"
using namespace llvm;
#define CM_NAME "cost-model-sanji"
#define DEBUG_TYPE CM_NAME
class CostModelAnalysisDummy : public PMDataManager, public FunctionPass, public PMTopLevelManager {
public:
static char ID; // Class identification, replacement for typeinfo
CostModelAnalysisDummy() : FunctionPass(ID), PMDataManager(), PMTopLevelManager(new FPPassManager()), F(nullptr), TTI(nullptr) {
llvm::initializeCostModelAnalysisDummyPass(
*PassRegistry::getPassRegistry());
}
/// Returns the expected cost of the instruction.
/// Returns -1 if the cost is unknown.
/// Note, this method does not cache the cost calculation and it
/// can be expensive in some cases.
unsigned getInstructionCost(const Instruction *I) const;
bool runOnFunction(Function &F) override;
PMDataManager *getAsPMDataManager() override { return this; }
Pass *getAsPass() override { return this; }
PassManagerType getTopLevelPassManagerType() override {
return PMT_BasicBlockPassManager;
}
FPPassManager *getContainedManager(unsigned N) {
assert(N < PassManagers.size() && "Pass number out of range!");
FPPassManager *FP = static_cast<FPPassManager *>(PassManagers[N]);
return FP;
}
private:
void getAnalysisUsage(AnalysisUsage &AU) const override;
void print(raw_ostream &OS, const Module*) const override;
/// The function that we analyze.
Function *F;
/// Target information.
const TargetTransformInfo *TTI;
};
FunctionPass *createCostModelAnalysisDummyPass();

Related

How to make sorting work with a large vector size?

I need to get the running time of several sorts.Here, for example, are 2 of them:
void bubble_sort() {
auto start = getCurrentTime();
for (int i = container.size(); i > 0; --i) {
for (int j = 0; j < i - 1; ++j) {
if (container[j] > container[j + 1])
std::swap(container[j], container[j + 1]);
}
}
auto end = getCurrentTime();
time = duration_cast<milliseconds>(end - start);
//auto result = duration_cast<milliseconds>(end - start);
//std::cout << result.count();
}
void cocktail_sort() {
auto starting = getCurrentTime();
bool swapped{ true };
int start = 0;
int end = std::size(container) - 1;
while (swapped) {
swapped = false;
for (int i = start; i < end; ++i)
if (container[i] > container[i + 1]) {
swapped = true;
std::swap(container[i], container[i + 1]);
}
--end;
swapped = false;
for (int i = end; i > start; --i)
if (container[i] < container[i - 1]) {
swapped = true;
std::swap(container[i], container[i - 1]);
}
++start;
}
auto ending = getCurrentTime();
time = duration_cast<milliseconds>(ending - starting);
}
Everything works when the array size is a couple of thousand and random values are also from 0 to several thousand.
But next I need to sort an array with a size of 200 000(buble sort) and random numbers in the same range.And then the program just works for a very long time, I waited a few minutes(I have a good processor and the result should be no more than 30 seconds) and finished, tried with another(cocktail sort) and the same result.I work in VS and I see that as if the processor is not working at full capacity, through the task manager, too, a couple of percent on VS.What can I do to make sorting work normally?
algClass.h
#pragma once
#include <iostream>
#include <vector>
#include <random>
#include <algorithm>
#include <bitset>
#include <set>
#include <queue>
#include <iterator>
#include "contain.h"
#include <chrono>
#include <fstream>
#include "random_helper.h"
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::duration;
using std::chrono::milliseconds;
using std::chrono::nanoseconds;
class allSorting {
private:
std::size_t size;
std::vector<int> container;
std::chrono::milliseconds time;
/*
template< typename T >
void print_container(T&& container) {
for (auto&& curr : container) {
std::cout << curr << " ";
}
//std::copy(std::begin(container), std::end(container), std::ostream_iterator<typename T::value_type>(std::cout, " "));
}
*/
template<typename Iter >
void Q_sort_help(Iter left, Iter right) {
if (right - left <= 1) return;
auto separator = *(left + (right - left) / 2);
auto t_left = left, t_right = right - 1;
while (t_left < t_right) {
while (*t_left < separator) ++t_left;
while (*t_right > separator) --t_right;
if (t_left <= t_right) {
std::swap(*t_left, *t_right);
++t_left;
--t_right;
}
if (left < t_right) Q_sort_help(left, t_right + 1);
if (t_left < right) Q_sort_help(t_left, right);
}
}
public:
allSorting(std::size_t new_size) {
size = new_size;
container.resize(size);
}
allSorting() {
size = 0;
container.resize(size);
}
void fill_random_number(int left_b = 0, int right_b = 100) {
fill_container(container, left_b, right_b);
}
void resize(int newSize) {
container.resize(newSize);
}
int sizeOfVector() {
return container.size();
}
void addValue(int value) {
container.push_back(value);
}
void bubble_sort() {
auto start = getCurrentTime();
for (int i = container.size(); i > 0; --i) {
for (int j = 0; j < i - 1; ++j) {
if (container[j] > container[j + 1])
std::swap(container[j], container[j + 1]);
}
}
auto end = getCurrentTime();
time = duration_cast<milliseconds>(end - start);
//auto result = duration_cast<milliseconds>(end - start);
//std::cout << result.count();
}
void cocktail_sort() {
auto starting = getCurrentTime();
bool swapped{ true };
int start = 0;
int end = std::size(container) - 1;
while (swapped) {
swapped = false;
for (int i = start; i < end; ++i)
if (container[i] > container[i + 1]) {
swapped = true;
std::swap(container[i], container[i + 1]);
}
--end;
swapped = false;
for (int i = end; i > start; --i)
if (container[i] < container[i - 1]) {
swapped = true;
std::swap(container[i], container[i - 1]);
}
++start;
}
auto ending = getCurrentTime();
time = duration_cast<milliseconds>(ending - starting);
}
void Q_sort() {
auto starting = getCurrentTime();
Q_sort_help(container.begin(), container.end());
auto ending = getCurrentTime();
time = duration_cast<milliseconds>(ending - starting);
}
void Counting_sort() {
auto starting = getCurrentTime();
auto max = *std::max_element(std::begin(container), std::end(container));
auto min = *std::min_element(std::begin(container), std::end(container));
auto new_size{ max - min + 1 };
std::vector<int> t_v(new_size);
for (auto& curr : container)
++t_v[curr - min];
auto iter = std::begin(container);
for (std::size_t i = 0; i < new_size; ++i) {
std::size_t shift = t_v[i];
if (shift != 0) {
std::fill_n(iter, shift, i + min);
std::advance(iter, shift);
}
}
auto ending = getCurrentTime();
time = duration_cast<milliseconds>(ending - starting);
}
std::chrono::high_resolution_clock::time_point getCurrentTime() {
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::duration;
using std::chrono::milliseconds;
return high_resolution_clock::now();
}
long long getresultTime(std::chrono::steady_clock::time_point start, std::chrono::steady_clock::time_point end) {
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::duration;
using std::chrono::milliseconds;
auto result = duration_cast<milliseconds>(end - start);
//return duration_cast<milliseconds>(end - start).count();
return 0;
}
void print_container() {
for (auto& curr : container) {
std::cout << curr << " ";
}
//std::copy(std::begin(container), std::end(container), std::ostream_iterator<typename T::value_type>(std::cout, " "));
}
long long getLastSortingTime() {
return time.count();
}
void printTime() {
std::cout << "The time: " << time.count() << " ms\n";
}
void writeTofile() {
std::ofstream file("result.txt") ;
for (const auto& e : container) {
file << e << "\n";
}
}
};
Main
#include <iostream>
#include <vector>
#include <random>
#include <algorithm>
#include <bitset>
#include <set>
#include <queue>
#include <iterator>
#include "contain.h"
#include "algClass.h"
int main()
{
int menu{ -1 };
allSorting testSorting = allSorting();
constexpr std::string_view str_menu[]{
};
auto print_menu = [&]() constexpr {
for (auto&& element : str_menu) {
std::cout << element << std::endl;
}
};
auto get_file_path = []() {
std::string file_path;
std::cout << "file name: ";
std::cin >> file_path;
return file_path;
};
auto enter_numb = [&](auto number) {
std::cout << "input number:";
std::cin >> number;
if (std::cin.fail()) {
std::cin.clear();
std::cin.ignore((std::numeric_limits<std::streamsize>::max)(), '\n');
throw std::exception("error ");
}
else {
return number;
}
};
print_menu();
while (menu) {
std::cout << "choose state: "; std::cin >> menu;
switch (menu)
{
case 1:
{
int size{};
size = enter_numb(size);
testSorting.resize(size);
}
break;
case 2:
{
int rightBorder{}, leftBorder{};
std::cout << "input left and right border" << std::endl;
std::cin >> leftBorder >> rightBorder;
testSorting.fill_random_number(leftBorder, rightBorder);
}
break;
case 3:
{
testSorting.print_container();
std::cout << std::endl;
}
break;
case 4:
{
std::cout << "input sieze: ";
int size{ };
std::cin >> size;
std::cout << "input sizeŠ°: ";
std::cout << std::endl;
for (size_t i = 0; i < size; i++)
{
int number{ };
std::cin >> number;
testSorting.addValue(number);
}
}
break;
case 5:
{
testSorting.bubble_sort();
}
break;
case 6:
{
testSorting.cocktail_sort();
}
break;
case 7:
{
testSorting.Q_sort();
}
break;
case 8:
{
testSorting.Counting_sort();
}
break;
case 9:
{
auto time = testSorting.getLastSortingTime();
std::cout << time << std::endl;
}
break;
case 10:
{
testSorting.writeTofile();
}
break;
case 0:
break;
default:
std::cout << "error" << std::endl;
}
}
}
random_helper.h
#include <iostream>
#include <random>
#include <algorithm>
namespace detail {
template<typename T, typename Always = void>
struct uniform_distribution_impl {
static_assert(sizeof(T) == 0, "T must be integral of floating point");
};
template <typename T>
struct uniform_distribution_impl<
T, std::enable_if_t<std::is_integral_v<T>>>
{
using type = std::uniform_int_distribution<T>;
};
template <typename T>
struct uniform_distribution_impl<
T, std::enable_if_t<std::is_floating_point_v<T>>>
{
using type = std::uniform_real_distribution<T>;
};
}
template <typename T>
using uniform_distribution = typename detail::uniform_distribution_impl<T>::type;
template<typename t, typename cont_type = typename t::value_type>
void fill_container(t& container, int left_b = 0, int right_b = 100) {
auto randomnumberbetween = [](int low, int high)
{
auto randomfunc = [distribution_ = uniform_distribution<cont_type>(low, high),
random_engine_ = std::mt19937{ std::random_device{}() }]() mutable
{
return distribution_(random_engine_);
};
return randomfunc;
};
std::generate(std::begin(container), std::end(container), randomnumberbetween(left_b, right_b));
}

Migrating to unique_ptr from a dynamic array and failing to convert to std::span

I'm trying to encrypt and decrypt a file, basically exercising std::span and std::unique_ptr. The issues are commented in the code.
2nd parameter of rc4 is std::span but my parameters are vector<uint8_t> for the encryption and unique_ptr<uint8_t> for the decryption, which I'm unable to convert to.
*output++ = elem ^ s[(s[i] + s[j]) % 256]; cannot be done with unique_ptr.
const auto log_data = read_log_file(log_path);
const auto log_size = static_cast<std::size_t>(std::filesystem::file_size(log_path));
// Generate a random key
std::uint8_t key[32];
generate_random_key(key);
// Encrypt
const auto result = std::make_unique<std::uint8_t>(log_size);
rc4_context context{};
rc4(&context, log_data, key, std::move(result)); // TODO: log_data: Cannot convert lvalue of type const std::vector<uint8_t> to parameter type const std::span<uint8_t>
// Decrypt
const auto result2 = std::make_unique<std::uint8_t>(log_size);
rc4(&context, std::move(result), key, std::move(result2)); // TODO: Again the second parameter cannot be casted from unique_ptr<unsigned char> to span<uint8_t>
std::vector<std::uint8_t> read_log_file(const std::wstring& path)
{
std::ifstream ifs(path, std::ios::binary | std::ios::ate);
if (!ifs)
throw std::runtime_error("Could not load file.");
const auto end = ifs.tellg();
ifs.seekg(0, std::ios::beg);
const auto size = static_cast<std::size_t>(end - ifs.tellg());
if (size == 0)
return {};
std::vector<std::uint8_t> buffer(size);
if (!ifs.read(reinterpret_cast<char*>(buffer.data()), buffer.size()))
throw std::runtime_error("Could not read file.");
return buffer;
}
int rc4(rc4_context* context, const std::span<std::uint8_t>& data, const std::span<std::uint8_t>& key, const std::unique_ptr<std::uint8_t>& output)
{
// INITIALIZATION
std::uint32_t i, j;
// Check parameters
if (!context || !key.empty())
return ERROR_INVALID_PARAMETER;
// Clear context
context->i = 0;
context->j = 0;
// Initialize the S array with identity permutation
for (i = 0; i < 256; i++)
{
context->s[i] = static_cast<std::uint8_t>(i);
}
// S is then processed for 256 iterations
for (i = 0, j = 0; i < 256; i++)
{
// Randomize the permutations using the supplied key
j = (j + context->s[i] + key[i % key.size()]) % 256;
// Swap the values of S[i] and S[j]
const auto temp = context->s[i];
context->s[i] = context->s[j];
context->s[j] = temp;
}
// MAIN LOGIC PART
// Restore context
i = context->i;
j = context->j;
auto* s = context->s;
// Encryption loop
for (auto elem : data)
{
// Adjust indices
i = (i + 1) % 256;
j = (j + s[i]) % 256;
// Swap the values of S[i] and S[j]
std::swap(s[i], s[j]);
// Valid output?
if (output)
{
// XOR the input data with the RC4 stream
*output++ = elem ^ s[(s[i] + s[j]) % 256]; // TODO: error happens here, because of *output++
}
}
// Save context
context->i = i;
context->j = j;
return NO_ERROR;
}
I recommend using std::vector<uint8_t> for result too, but here's how you can fix the code you've got. I've made it minimal in the answer to focus on the issues.
#include <cstdint>
#include <iostream>
#include <memory>
#include <span>
#include <vector>
// rc4's span should be over const uint8_t's:
void rc4(const std::span<const std::uint8_t>& data) {
std::cout << data.size() << '\n';
}
int main() {
size_t log_size = 100;
const std::vector<uint8_t> log_data{1, 2, 3}; // ... since this is const
rc4(log_data);
// you should allocate an array, not a single uint8_t here:
const auto result = std::make_unique<std::uint8_t[]>(log_size);
// and you can create the span like this in your argument list:
rc4( {result.get(), log_size} );
}
Output:
3
100
An alternative using vectors for both input and output:
#include <cstdint>
#include <iostream>
#include <memory>
#include <utility>
#include <vector>
int rc4(const std::vector<std::uint8_t>& data,
std::vector<std::uint8_t>& output)
{
output.clear();
output.reserve(data.size());
for(auto byte : data) {
output.push_back(0xFF - byte); // a simple algoritm
}
return 0; // NO_ERROR;
}
int main() {
const std::vector<uint8_t> log_data{'A', 'B', 'C'};
std::vector<std::uint8_t> result;
rc4(log_data, result); // encrypt
for(auto byte : result) {
std::cout << std::hex << (int)byte << '\n'; // probably be, bd, bc
}
std::cout << '\n';
std::vector<std::uint8_t> result2;
rc4(result, result2); // decrypt
for(auto byte : result2) {
std::cout << byte; // prints ABC
}
std::cout << '\n';
}

LLVM `opt` gives pass error: "Value::~Value(): Assertion `use_empty() && "Uses remain when a value is destroyed!"

When I run the LLVM pass below using opt, I get the following error message:
While deleting: i32 %
Use still stuck around after Def is destroyed: %indexLoc = alloca i32
opt: /home/nlykkei/llvm/src/lib/IR/Value.cpp:85: virtual llvm::Value::~Value(): Assertion `use_empty() && "Uses remain when a value is destroyed!"' failed.
I invoke opt as: opt -load build/flatten/libFlattenPass.so -opCounter loop.rll.
I follow the example for inserting instructions into BB's in http://llvm.org/docs/ProgrammersManual.html#creating-and-inserting-new-instructions.
I don't really see what is wrong with my code? Should I explicitly delete the AllocaInst pointer or?
Program:
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Instructions.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
#include <string>
using namespace llvm;
namespace {
struct CountOp : public FunctionPass {
std::map<std::string, int> opCounter;
std::map<std::string, int> bbNameToId;
static char ID;
LLVMContext ctx;
CountOp() : FunctionPass(ID) {}
virtual bool runOnFunction(Function &F) {
std::string bbName("bb");
int bbId = 0;
errs() << "Function " << F.getName() << '\n';
for (Function::iterator bb = F.begin(), e = F.end(); bb != e; ++bb) {
// assign integer ids to BasicBlock's
if (bb->hasName()) {
bbNameToId[bb->getName()] = bbId++;
} else {
bb->setName(Twine(bbName + std::to_string(bbId)));
bbNameToId[bb->getName()] = bbId++;
}
for (BasicBlock::iterator i = bb->begin(), e = bb->end(); i != e; ++i) {
if(opCounter.find(i->getOpcodeName()) == opCounter.end()) {
opCounter[i->getOpcodeName()] = 1;
} else {
opCounter[i->getOpcodeName()] += 1;
}
}
}
AllocaInst* pa = new AllocaInst(Type::getInt32Ty(ctx), 0, "indexLoc");
BasicBlock& firstBB = F.getBasicBlockList().front();
Instruction& firstInst = firstBB.front();
pa->insertBefore(&firstInst);
std::map <std::string, int>::iterator i = opCounter.begin();
std::map <std::string, int>::iterator e = opCounter.end();
while (i != e) {
errs() << i->first << ": " << i->second << "\n";
i++;
}
i = bbNameToId.begin();
e = bbNameToId.end();
while (i != e) {
errs() << i->first << ": " << i->second << "\n";
i++;
}
errs() << "\n";
opCounter.clear();
return false;
}
};
}
char CountOp::ID = 0;
static RegisterPass<CountOp> X("opCounter", "Counts opcodes per functions");

Determine conversion factors of strings describing units

In one of my project I need to determine the conversion factors of fairly complex units. I was able to write a static conversion function in case of statically defined units using the excellent boost library Boost.Units.
In my case the user enters the type of a conversion at run-time, so that I need a dynamic conversion function. A nice solution should use the already implemented functions in Boost.Units. Is this possible?
My own final solution
After some thoughts I was able to derive the following partial solution to my problem, which is sufficient for my needs. I'm relying on boost-spirit to parse the unit string, making this task indeed very easy. Great library!
Parsing unit strings might be a common task, that others might be interested in. Hence, I'm posting my final solution here including some tests for illustration.
The most important function is here convertUnit computing the conversion factor from one unit to another, if this conversion is possible.
UnitParser.cpp
#include "UnitParser.h"
#pragma warning(push)
#pragma warning(disable: 4512 4100 4503 4127 4348 4459)
#include <map>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_symbols.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <vector>
#include <algorithm>
using namespace boost;
namespace {
struct modifier_ : spirit::qi::symbols<char, int> {
modifier_() { add("m", -4)("c", -3)("k", 4); }
} modifier;
struct baseUnit_ : spirit::qi::symbols<char, UnitParser::UnitType> {
baseUnit_() {
add
("g", UnitParser::UnitType::GRAM)
("m", UnitParser::UnitType::METER)
("s", UnitParser::UnitType::SECONDS)
("rad", UnitParser::UnitType::RADIANS)
("deg", UnitParser::UnitType::DEGREE)
("N", UnitParser::UnitType::NEWTON)
;
}
} baseUnit;
class UnitParserImpl : public spirit::qi::grammar<std::string::iterator, UnitParser::Units()>
{
public:
UnitParserImpl() : UnitParserImpl::base_type(unitsTop_)
{
using namespace boost::spirit::qi;
unitsTop_ = units_.alias();
units_ = (unit_ % '*');
unit_ = (-(modifier >> &baseUnit) >> baseUnit >> -(lexeme["^"] >> int_ ))[_val = boost::phoenix::construct<UnitParser::Unit>(_2, _3, _1)];
}
spirit::qi::rule<std::string::iterator, UnitParser::Units()> unitsTop_;
spirit::qi::rule<std::string::iterator, UnitParser::Units()> units_;
spirit::qi::rule<std::string::iterator, UnitParser::Unit()> unit_;
};
}
boost::optional<UnitParser::Units> UnitParser::parse(const std::string& expression, std::string&& errorMessage)
{
boost::optional<UnitParser::Units> result;
try {
Units units;
std::string formula = expression;
auto b = formula.begin();
auto e = formula.end();
UnitParserImpl parser;
bool ok = spirit::qi::phrase_parse(b, e, parser, spirit::qi::space, units);
if (!ok || b != e) {
return result;
}
result = units;
return result;
}
catch (const spirit::qi::expectation_failure<std::string::iterator>& except) {
errorMessage = except.what();
return result;
}
}
std::map<UnitParser::UnitType, UnitParser::Dimension> dimMap() {
std::map<UnitParser::UnitType, UnitParser::Dimension> ret;
ret[UnitParser::UnitType::SECONDS] = UnitParser::Dimension({ 0,1,0,0 });
ret[UnitParser::UnitType::METER] = UnitParser::Dimension({ 1,0,0,0 });
ret[UnitParser::UnitType::DEGREE] = UnitParser::Dimension({ 0,0,1,0 });
ret[UnitParser::UnitType::RADIANS] = UnitParser::Dimension({ 0,0,1,0 });
ret[UnitParser::UnitType::GRAM] = UnitParser::Dimension({ 0,0,0,1 });
ret[UnitParser::UnitType::NEWTON] = UnitParser::Dimension({ 1,-2,0,1 });
return ret;
}
UnitParser::Dimension UnitParser::getDimension(const UnitParser::Units& units)
{
auto map = dimMap();
UnitParser::Dimension ret;
for (auto unit : units) {
if (map.find(unit.unitType) != map.end()) {
auto dim=map[unit.unitType];
auto exp = unit.exponent;
ret.length += exp*dim.length;
ret.time += exp*dim.time;
ret.weigth += exp*dim.weigth;
ret.planarAngle += exp*dim.planarAngle;
}
}
return ret;
}
bool UnitParser::equalDimension(const Units& u1, const Units& u2)
{
return getDimension(u1) == getDimension(u2);
}
bool UnitParser::checkDimension(const UnitParser::Units& u1, const UnitParser::Units& u2)
{
return true;
}
// Bezogen auf die Einheiten: m,s,kg,rad
std::pair<double,int> UnitParser::getScale(const Units& units)
{
double ret = 1.;
int exp = 0;
for (auto unit : units) {
double scale = 1;
int e = 0;
if (unit.unitType==UnitType::DEGREE) {
scale = 180./boost::math::constants::pi<double>();
}
if (unit.unitType == UnitType::GRAM) {
e = unit.exponent*(unit.modifier-4);
}
else {
e = unit.exponent*unit.modifier;
}
exp += e;
ret *= scale;
}
return{ ret, exp };
}
boost::optional<double> UnitParser::convertUnit(const std::string& unitString1, const std::string& unitString2, std::string&& errorMessage)
{
boost::optional<double> ret;
auto unit1 = parse(unitString1);
auto unit2 = parse(unitString2);
if (!unit1) { errorMessage = unitString1 + " is not valid!"; return ret; }
if (!unit2) { errorMessage = unitString2 + " is not valid!"; return ret; }
if (!equalDimension(*unit1, *unit2)) {
errorMessage = "Dimensions of " + unitString1 + " and " + unitString2 + " mismatch!"; return ret;
}
auto s1 = getScale(*unit1);
auto s2 = getScale(*unit2);
int exp = s1.second - s2.second;
double scale = s1.first / s2.first;
ret = scale*std::pow(10, exp);
return ret;
}
UnitParser.h
#pragma once
#include <boost/optional.hpp>
#include <vector>
namespace UnitParser {
enum class UnitType {
SECONDS, METER, DEGREE, RADIANS, GRAM, NEWTON
};
struct Unit {
Unit() {}
Unit(const UnitType& unitType, const boost::optional<int> exponent, const boost::optional<int>& modifier) : unitType(unitType), exponent(exponent.value_or(1)), modifier(modifier.value_or(0)) {}
UnitType unitType;
int exponent;
int modifier;
};
typedef std::vector<Unit> Units;
struct Dimension {
Dimension() {};
Dimension(int length, int time, int planarAngle, int weigth) : length(length), time(time), planarAngle(planarAngle), weigth(weigth) {}
int length = 0;
int time = 0;
int planarAngle = 0;
int weigth = 0;
bool operator==(const UnitParser::Dimension& dim) {
return length == dim.length && planarAngle == dim.planarAngle && time == dim.time && weigth == dim.weigth;
}
};
boost::optional<Units> parse(const std::string& string, std::string&& errorMessage=std::string());
Dimension getDimension(const Units& units);
bool equalDimension(const Units& u1, const Units& u2);
bool checkDimension(const Units& u1, const Units& u2);
std::pair<double,int> getScale(const Units& u1);
boost::optional<double> convertUnit(const std::string& unitString1, const std::string& unitString2, std::string&& errorMessage=std::string());
}
UnitParserCatch.cpp
#define CATCH_CONFIG_MAIN
#include "catch.h"
#include "UnitParser.h"
#include <boost/math/constants/constants.hpp>
using namespace UnitParser;
TEST_CASE("ConvertUnit", "[UnitParser]") {
SECTION("Simple") {
auto s = convertUnit("mm^2", "cm^2"); // 1*mm^2 = 0.01*cm^2
REQUIRE(s);
CHECK(*s == 0.01);
}
SECTION("Newton") {
auto s = convertUnit("N", "kg*m*s^-2");
REQUIRE(s);
CHECK(*s == 1.);
}
SECTION("Wrong") {
std::string err;
auto s = convertUnit("m", "m*kg", std::move(err));
REQUIRE(!s);
CHECK(!err.empty());
}
}
TEST_CASE("Dimension", "[UnitParser]") {
SECTION("Simple") {
auto a=*parse("mm^2");
auto dim=getDimension(a);
CHECK(dim == Dimension(2, 0, 0, 0));
}
SECTION("Newton") {
auto a = *parse("mN^2");
auto dim = getDimension(a);
CHECK(dim == Dimension(2, -4, 0, 2));
}
SECTION("Fits") {
auto a = *parse("mm^2");
auto b = *parse("cm^2");
auto fits = equalDimension(a, b);
CHECK(fits);
}
SECTION("Newton") {
auto a = *parse("N");
auto b = *parse("kg*m*s^-2");
auto fits = equalDimension(a, b);
CHECK(fits);
}
SECTION("NoFit") {
auto a = *parse("mm^2*g");
auto b = *parse("cm^2");
auto fits = equalDimension(a, b);
CHECK(!fits);
}
}
TEST_CASE("Scale", "[UnitParser]") {
SECTION("Length") {
auto s = getScale(*parse("mm^2")); // 1*mm^2=1e-8*m^2
CHECK(s == std::make_pair(1., -8));
}
SECTION("Degree") {
auto s = getScale(*parse("deg"));
CHECK(s == std::make_pair(180. / boost::math::constants::pi<double>(),0));
}
SECTION("Complex") {
auto s = getScale(*parse("km^2*kg"));
CHECK(s == std::make_pair(1., 8));
}
}
TEST_CASE("Simple", "[UnitParser]") {
SECTION("Complex") {
SECTION("Full") {
auto u = parse("mm^2");
CHECK(u);
}
SECTION("Many") {
auto u = parse("mm^2*ms^-1");
CHECK(u);
}
}
SECTION("Units") {
SECTION("Newton") {
auto u = parse("N");
CHECK(u);
}
SECTION("Meter") {
auto u = parse("m");
CHECK(u);
}
SECTION("Seconds") {
auto u = parse("s");
CHECK(u);
SECTION("Exponent") {
CHECK(parse("s^2"));
CHECK(parse("ms^-2"));
CHECK(parse("ks^-3"));
}
}
SECTION("PlanarAngle") {
auto u = parse("deg");
CHECK(u);
}
}
}

BOOST graph cc1plus: out of memory allocating

I'm using BOOST for a graph mining problem, but when I compile it I got this error:
cc1plus: out of memory allocating 1677721600 bytes after a total of
6270976 bytes
How can I solve it? and how can I improve this code to be faster and avoid memory problems?
Here is the code:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/vf2_sub_graph_iso.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <ctime>
#include <queue> // std::queue
// for mmap:
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
using namespace boost;
//==========STRUCTURES==========
// vertex
struct VertexProperties {
int id;
int label;
VertexProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
};
// edge
struct EdgeProperties {
unsigned id;
unsigned label;
EdgeProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
};
// Graph
struct GraphProperties {
unsigned id;
unsigned label;
GraphProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
};
// adjency list
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties,
GraphProperties> Graph;
// descriptors
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_t;
typedef std::pair<boost::graph_traits<Graph>::edge_descriptor, bool> edge_t;
// iterators
typedef graph_traits<Graph>::vertex_iterator vertex_iter;
typedef graph_traits<Graph>::edge_iterator edge_iter;
typedef std::pair<edge_iter, edge_iter> edge_pair;
//=================callback used fro subgraph_iso=================================================================
struct my_callback {
template <typename CorrespondenceMap1To2, typename CorrespondenceMap2To1>
bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1 g) const {
return false;
}
};
//==========handle_error==========
void handle_error(const char *msg) {
perror(msg);
exit(255);
}
//============READ ALL THE FILE AND RETURN A STRING===================
const char *readfromfile(const char *fname, size_t &length) {
int fd = open(fname, O_RDONLY);
if (fd == -1)
handle_error("open");
// obtain file size
struct stat sb;
if (fstat(fd, &sb) == -1)
handle_error("fstat");
length = sb.st_size;
const char *addr = static_cast<const char *>(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0u));
if (addr == MAP_FAILED)
handle_error("mmap");
// TODO close fd at some point in time, call munmap(...)
return addr;
}
//==========SPLIT THE STRING BY NEWLINE (\n) ==========
vector<string> splitstringtolines(string const& str) {
vector<string> split_vector;
split(split_vector, str, is_any_of("\n"));
return split_vector;
}
//============Get a string starting from pos============
string getpos(int const& pos, string const& yy) {
size_t i = pos;
string str;
for (; yy[i] != ' ' && i < yy.length(); i++)
str += yy[i];
return str;
}
//==================read string vector and return graphs vector===================
std::vector<Graph> creategraphs(std::vector<string> const& fichlines) {
std::vector<Graph> dataG;
int compide = 0; // compteur de id edge
for (string yy : fichlines) {
switch (yy[0]) {
case 't': {
string str2 = getpos(4, yy);
unsigned gid = atoi(str2.c_str());
dataG.emplace_back(GraphProperties(gid, gid));
compide = 0;
} break;
case 'v': {
assert(!dataG.empty()); // assert will terminate the program if its argument turns out to be false
// cout<<yy<<endl;
int vId, vLabel;
string vvv = getpos(2, yy);
vId = atoi(vvv.c_str());
string vvvv = getpos((int)vvv.length() + 3, yy);
// cout<<vvvv<<endl;
vLabel = atoi(vvvv.c_str());
boost::add_vertex(VertexProperties(vId, vLabel), dataG.back());
}
break;
case 'e': { // cout<<yy<<endl;
assert(!dataG.empty()); // assert will terminate the program if its argument turns out to be false
int fromId, toId, eLabel;
string eee = getpos(2, yy);
// cout<<eee<<endl;
fromId = atoi(eee.c_str());
string eee2 = getpos((int)eee.length() + 3, yy);
// cout<<eee2<<endl;
toId = atoi(eee2.c_str());
int c = (int)eee.length() + (int)eee2.length() + 4;
// cout<<c<<endl;
string eee3 = getpos(c, yy);
// cout<<eee3<<endl;
eLabel = atoi(eee3.c_str());
boost::add_edge(fromId, toId, EdgeProperties(compide, eLabel), dataG.back());
compide++;
} break;
}
}
return dataG;
}
//============test if the graph connectivity========================================================
bool graphconnexe(Graph const& g) {
return num_edges(g) >= num_vertices(g) - 1;
}
//====================print the graph information========================================================
void printgraph(Graph const& gr) {
typedef std::pair<edge_iter, edge_iter> edge_pair;
std::cout << " contains " << num_vertices(gr) << " vertices, and " << num_edges(gr) << " edges " << std::endl;
if (graphconnexe(gr)) {
// Vertex list
if (num_vertices(gr) != 0) {
std::cout << " Vertex list: " << std::endl;
for (size_t i = 0; i < num_vertices(gr); ++i) // size_t vertice number in the graph
{
std::cout << " v[" << i << "] ID: " << gr[i].id << ", Label: " << gr[i].label << std::endl;
}
}
// Edge list
if (num_edges(gr) != 0) {
std::cout << " Edge list: " << std::endl;
edge_pair ep;
for (ep = edges(gr); ep.first != ep.second; ++ep.first) // ep edge number
{
vertex_t from = source(*ep.first, gr);
vertex_t to = target(*ep.first, gr);
edge_t edg = edge(from, to, gr);
std::cout << " e(" << gr[from].id << "," << gr[to].id << ") ID: " << gr[edg.first].id
<< " , Label: " << gr[edg.first].label << std::endl;
}
}
std::cout << "\n\n" << std::endl;
} else {
cout << "Please check this graph connectivity." << endl;
}
}
//=========================================================
/*bool gUe(Graph &g, edge_iter ep, Graph t) {
vertex_t from = source(*ep, t);
vertex_t to = target(*ep, t);
Graph::edge_descriptor copied_edge = boost::add_edge(from, to, t[*ep], g).first;
g[source(copied_edge, g)] = t[from];
g[target(copied_edge, g)] = t[to];
if (graphconnexe(g) && graphconnexe(t)) {
return vf2_subgraph_iso(g, t, my_callback());
} else {
return false;
}
}*/
//=================test if the given vertice exist in the graph=========================
bool verticeexist(Graph const& g, int const& vId, int const& vlabel) {
int cpt = 0;
if (num_edges(g) != 0) {
for (size_t i = 0; i < num_vertices(g); ++i) // size_t vertice number in the graph
{
if ((g[i].id == vId) && (g[i].label == vlabel)) {
cpt++;
}
}
}
return cpt != 0;
}
//=============test if the given edge exist in the graph===========================
bool edgeexist(Graph const& g, int const& fromid, int const& toid, unsigned const& elabel) {
int bn = 0;
if (graphconnexe(g)) {
if (num_edges(g) != 0) {
edge_pair ep;
for (ep = edges(g); ep.first != ep.second; ++ep.first) // ep edge number
{
vertex_t from = source(*ep.first, g);
vertex_t to = target(*ep.first, g);
edge_t edg = edge(from, to, g);
if ((g[from].id == fromid) && (g[to].id == toid) && (g[edg.first].label == elabel)) {
bn++;
}
}
}
}
return (bn != 0);
}
// =============test if thoses vertices are neighbours============================
bool verticesareneighbours(Graph const& g, int const& a, int const& b) {
int bn = 0;
if (graphconnexe(g)) {
if (num_edges(g) != 0) {
edge_pair ep;
for (ep = edges(g); ep.first != ep.second; ++ep.first) // ep edge number
{
vertex_t from = source(*ep.first, g);
vertex_t to = target(*ep.first, g);
if (((g[from].id == a) || (g[to].id == a)) && ((g[from].id == b) || (g[to].id == b))) {
bn++;
}
}
}
}
return (bn != 0);
}
//=============test if those edges are neighbours=============================
template <typename Graph, typename E = typename boost::graph_traits<Graph>::edge_descriptor>
bool edgesareneighbours(Graph const& g, E e1, E e2) {
std::set<vertex_t> vertex_set {
source(e1, g), target(e1, g),
source(e2, g), target(e2, g),
};
return graphconnexe(g) && vertex_set.size() < 4;
}
//===============if the graph is empty add the edge with vertices===========================
void emptygraphaddedge(Graph &g, int fromId, int toId, int eLabel) {
if (num_edges(g) == 0) {
boost::add_edge(fromId, toId, EdgeProperties(num_edges(g) + 1, eLabel), g);
}
}
//==============================M A I N P R O G R A M =======================================
int main() {
clock_t start = std::clock();
size_t length;
std::vector<Graph> dataG = creategraphs(splitstringtolines(readfromfile("testgUe.txt", length)));
typedef std::pair<edge_iter, edge_iter> edge_pair;
if (!dataG.empty()) {
cout<<"graphconnexe?"<<graphconnexe(dataG[0])<<endl;
cout<<"verticeexist?"<<verticeexist(dataG[0],1,4);
cout<<"verticeexist?"<<verticeexist(dataG[0],4,2);
cout<<"verticesareneighbours?"<<verticesareneighbours(dataG[0],1,4)<<endl;
cout<<"verticesareneighbours?"<<verticesareneighbours(dataG[0],4,2)<<endl;
cout<<"edgeexist?"<<edgeexist(dataG[0],1,4,16)<<endl;
cout<<"edgeexist?"<<edgeexist(dataG[0],1,4,12)<<endl;
edge_pair ep = edges(dataG[0]);
if (size(ep) >= 2) {
Graph::edge_descriptor e1 = *ep.first++;
Graph::edge_descriptor e2 = *ep.first++;
cout << "edgesareneighbours?" << edgesareneighbours(dataG[0], e1, e2) << endl;
}
}
// end and time
cout << "FILE Contains " << dataG.size() << " graphs.\nTIME: " << (std::clock() - start) / (double)CLOCKS_PER_SEC
<< "s" << endl; // fin du programme.
}
Here's an estimation of the lowerbound on amount of memory required live on Coliru:
16 megabytes:
g++: internal compiler error: Killed (program cc1plus)
libbacktrace could not find executable to open
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.
32 megabytes:
/usr/local/libexec/gcc/x86_64-unknown-linux-gnu/4.9.2/cc1plus: error while loading shared libraries: libc.so.6: failed to map segment from shared object: Cannot allocate memory
64 megabytes:
virtual memory exhausted: Cannot allocate memory
128 megabytes:
virtual memory exhausted: Cannot allocate memory
256 megabytes:
virtual memory exhausted: Cannot allocate memory
512 megabytes:
graphconnexe?1
verticeexist?0verticeexist?0verticesareneighbours?0
verticesareneighbours?0
edgeexist?0
edgeexist?0
edgesareneighbours?1
FILE Contains 1 graphs.
TIME: 0s
It looks like 512 megabytes should not be a problem. Fix your compiler setup
computer with enough resources
reasonably up-to-date compiler
check the flags (try more and less optimization, debug information etc.)
On my system, gcc 4.9 with -std=c++11 -Wall -pedantic -g -O0 -m32 works starting from 32 megabytes:
$ bash -c '{ ulimit -v $((1024*32)); make -Bsn; }' /usr/lib/gcc-snapshot/bin/g++ -std=c++11 -Wall -pedantic -g -O0 -m32 -isystem /home/sehe/custom/boost -march=native test.cpp -o test