forked from nils.hoelscher/RTSA-lab01-CacheAnalysis
WIP
This commit is contained in:
parent
1a9c1ccefb
commit
be3904a256
|
@ -4,6 +4,21 @@
|
|||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "LLDB cnt",
|
||||
"program": "/usr/bin/opt",
|
||||
"args": [
|
||||
"-load-pass-plugin",
|
||||
"${workspaceFolder}/build/libCacheAnalysisPass.so",
|
||||
"-passes=lru-misses",
|
||||
"${workspaceFolder}/test/cnt.ll",
|
||||
"-o",
|
||||
"/dev/null"
|
||||
],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
|
|
|
@ -46,52 +46,6 @@ using namespace llvm;
|
|||
// everything in an anonymous namespace.
|
||||
namespace {
|
||||
|
||||
std::string typeToName(Type::TypeID Id) {
|
||||
switch (Id) {
|
||||
case Type::TypeID::ArrayTyID:
|
||||
return "ArrayTy";
|
||||
case Type::TypeID::BFloatTyID:
|
||||
return "BFloatTy";
|
||||
case Type::TypeID::FloatTyID:
|
||||
return "FloatTy";
|
||||
case Type::TypeID::DoubleTyID:
|
||||
return "DoubleTy";
|
||||
case Type::TypeID::FixedVectorTyID:
|
||||
return "FixedVectorTy";
|
||||
case Type::TypeID::FP128TyID:
|
||||
return "FP128Ty";
|
||||
case Type::TypeID::FunctionTyID:
|
||||
return "FunctionTy";
|
||||
case Type::TypeID::HalfTyID:
|
||||
return "HalfTy";
|
||||
case Type::TypeID::IntegerTyID:
|
||||
return "IntegerTy";
|
||||
case Type::TypeID::LabelTyID:
|
||||
return "LabelTy";
|
||||
case Type::TypeID::MetadataTyID:
|
||||
return "MetadataTy";
|
||||
case Type::TypeID::PointerTyID:
|
||||
return "PointerTy";
|
||||
case Type::TypeID::PPC_FP128TyID:
|
||||
return "PPC_FP128Ty";
|
||||
case Type::TypeID::ScalableVectorTyID:
|
||||
return "ScalableVectorTy";
|
||||
case Type::TypeID::StructTyID:
|
||||
return "StructTy";
|
||||
case Type::TypeID::TokenTyID:
|
||||
return "TokenTy";
|
||||
case Type::TypeID::VoidTyID:
|
||||
return "VoidTy";
|
||||
case Type::TypeID::X86_AMXTyID:
|
||||
return "X86_AMXTy";
|
||||
case Type::TypeID::X86_FP80TyID:
|
||||
return "X86_FP80Ty";
|
||||
case Type::TypeID::X86_MMXTyID:
|
||||
return "X86_MMXTy";
|
||||
}
|
||||
// should not reach here
|
||||
return nullptr;
|
||||
}
|
||||
// New PM implementation
|
||||
|
||||
struct CacheAnalysisPass : PassInfoMixin<CacheAnalysisPass> {
|
||||
|
@ -100,7 +54,7 @@ struct CacheAnalysisPass : PassInfoMixin<CacheAnalysisPass> {
|
|||
bool PrintAddresses = false;
|
||||
bool PrintEdges = false;
|
||||
bool PrintEdgesPost = false;
|
||||
bool DumpToDot = false;
|
||||
bool DumpToDot = true;
|
||||
bool DumpNodes = false;
|
||||
|
||||
// Assume a 4kB Cache
|
||||
|
@ -278,6 +232,7 @@ struct CacheAnalysisPass : PassInfoMixin<CacheAnalysisPass> {
|
|||
AC.dumpEdges();
|
||||
if (DumpToDot)
|
||||
AC.dumpDotFile();
|
||||
AC.unrollLoops();
|
||||
AC.fillAbstractCache(EntryAddress);
|
||||
if (DumpNodes)
|
||||
AC.dumpNodes();
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <utility>
|
||||
|
@ -29,6 +30,7 @@ public: // everything is public, because IDGAF
|
|||
// map keys are instruction Addresses.
|
||||
std::map<unsigned int, std::list<unsigned int>> Edges;
|
||||
std::map<unsigned int, AbstractState> Nodes;
|
||||
unsigned int NumberOfNodes = 0;
|
||||
|
||||
AbstractCache() {}
|
||||
|
||||
|
@ -44,17 +46,112 @@ public: // everything is public, because IDGAF
|
|||
Nodes[Suc].Predecessors.push_back(Pre);
|
||||
}
|
||||
|
||||
void addEmptyNode(unsigned int NodeAddr) {
|
||||
Nodes[NodeAddr] = AbstractState(NodeAddr);
|
||||
unsigned int addEmptyNode(unsigned int NodeAddr) {
|
||||
Nodes[NumberOfNodes++] = AbstractState(NodeAddr);
|
||||
return NumberOfNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unroll Loops.
|
||||
*
|
||||
* @param NodeNr
|
||||
*/
|
||||
void unrollLoops() {
|
||||
for (auto NodePair : Nodes) {
|
||||
unsigned int NodeNr = NodePair.first;
|
||||
if (NodeNr == 34) {
|
||||
llvm::outs() << "HI\n";
|
||||
}
|
||||
bool IsLoopHead = false;
|
||||
bool FoundLoopBody = false;
|
||||
bool Verbose = true;
|
||||
std::list<unsigned int> LoopBody;
|
||||
if (Nodes[NodeNr].Predecessors.size() > 1) {
|
||||
IsLoopHead = true;
|
||||
// is loop head?
|
||||
for (unsigned int Pre : Nodes[NodeNr].Predecessors) {
|
||||
if (Pre > NodeNr) {
|
||||
// Might be loop head.
|
||||
// check if all States between Pre and NodeNr are a coherent set.
|
||||
for (uint I = NodeNr; I < Pre; I++) {
|
||||
LoopBody.push_back(I);
|
||||
for (uint Succ : Nodes[I].Successors) {
|
||||
if (Succ > Pre) {
|
||||
// Set is not coherent
|
||||
IsLoopHead = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
FoundLoopBody = true;
|
||||
}
|
||||
LoopBody.push_back(Pre);
|
||||
} else if (!FoundLoopBody) {
|
||||
// If no coherent Loopbody exist we cannot unroll.
|
||||
LoopBody.clear();
|
||||
IsLoopHead = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IsLoopHead && Verbose) {
|
||||
llvm::outs() << "Found LoopHead @: " << NodeNr << "\n";
|
||||
llvm::outs() << "With Body: {\n";
|
||||
int I = 1;
|
||||
for (auto Node : LoopBody) {
|
||||
llvm::outs() << Node << ", ";
|
||||
if (!(I++ % 5)) {
|
||||
llvm::outs() << "\n";
|
||||
}
|
||||
}
|
||||
llvm::outs() << "}\n";
|
||||
}
|
||||
// Found Loop Head and Body!
|
||||
// TODO: Now unroll
|
||||
// Add empty unrolled Nodes
|
||||
// Map points from OrigNode To Unrolled Node.
|
||||
std::map<unsigned int, unsigned int> OrigNodeToUnrolledNode;
|
||||
for (auto Node : LoopBody) {
|
||||
// Node to unroll
|
||||
AbstractState UnrolledNode(Nodes[Node]);
|
||||
UnrolledNode.setUnrolled(1);
|
||||
Nodes[NumberOfNodes++] = UnrolledNode;
|
||||
OrigNodeToUnrolledNode[Node] = NumberOfNodes;
|
||||
}
|
||||
|
||||
unsigned int LoopHead = LoopBody.front();
|
||||
LoopBody.pop_front();
|
||||
unsigned int LoopTail = LoopBody.back();
|
||||
LoopBody.pop_back();
|
||||
for (auto Node : LoopBody) {
|
||||
for (auto Succ : Nodes[Node].Successors) {
|
||||
// Add All successors to unrolled Node
|
||||
Nodes[OrigNodeToUnrolledNode[Node]].Successors.push_back(
|
||||
OrigNodeToUnrolledNode[Succ]);
|
||||
}
|
||||
for (auto Pre : Nodes[Node].Predecessors) {
|
||||
// Add All predecessors to unrolled Node
|
||||
Nodes[OrigNodeToUnrolledNode[Node]].Successors.push_back(
|
||||
OrigNodeToUnrolledNode[Pre]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Idea fill the graph with the node and perform loop unrolling.
|
||||
*
|
||||
* @param NodeNr
|
||||
*/
|
||||
void fillAbstractCache(unsigned int NodeNr) {
|
||||
// if(isLoopHead(NodeNr))
|
||||
// unrollLoop(NodeNr);
|
||||
Nodes[NodeNr].Computed = true;
|
||||
for (unsigned int SuccNr : Nodes[NodeNr].Successors) {
|
||||
Nodes[SuccNr];
|
||||
if (Nodes[SuccNr].Computed) {
|
||||
// Join don't call
|
||||
Nodes[SuccNr].mustJoin(Nodes[NodeNr]);
|
||||
// TODO fix Join
|
||||
Nodes[SuccNr].mustJoin(Nodes[NodeNr]); // maybe fill
|
||||
Nodes[SuccNr].mustJoin(AbstractState(NodeNr));
|
||||
} else {
|
||||
// Update and fill Succ
|
||||
|
@ -107,13 +204,20 @@ public: // everything is public, because IDGAF
|
|||
}
|
||||
|
||||
void dumpDotFile() {
|
||||
bool PrintOld = true;
|
||||
std::ofstream DotFile;
|
||||
DotFile.open("out.dot");
|
||||
DotFile << "digraph g {"
|
||||
<< "\n";
|
||||
for (auto const &E : Edges) {
|
||||
for (unsigned int To : E.second) {
|
||||
DotFile << E.first << " -> " << To << "\n";
|
||||
if (PrintOld) {
|
||||
DotFile << E.first << " -> " << To << "\n";
|
||||
} else {
|
||||
DotFile << Nodes[E.first].Addr << "." << Nodes[E.first].Unrolled
|
||||
<< " -> " << Nodes[To].Addr << "." << Nodes[To].Unrolled
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
DotFile << "}\n";
|
||||
|
|
|
@ -27,6 +27,7 @@ public: // everything is public, because IDGAF
|
|||
std::list<unsigned int> Predecessors;
|
||||
|
||||
unsigned int Addr;
|
||||
unsigned int Unrolled;
|
||||
|
||||
bool Computed = false;
|
||||
|
||||
|
@ -57,6 +58,8 @@ public: // everything is public, because IDGAF
|
|||
std::map<unsigned int, Set> Sets;
|
||||
|
||||
AbstractState(AbstractState const &Copy) {
|
||||
Addr = Copy.Addr;
|
||||
Unrolled = Copy.Unrolled;
|
||||
for (auto S : Copy.Sets) {
|
||||
unsigned int SetNr = S.first;
|
||||
for (auto E : S.second.Associativity) {
|
||||
|
@ -70,12 +73,22 @@ public: // everything is public, because IDGAF
|
|||
|
||||
AbstractState() {}
|
||||
|
||||
AbstractState(unsigned int AddressIn) { Addr = AddressIn; }
|
||||
|
||||
AbstractState(Address Addr) {
|
||||
Sets[Addr.Index].Associativity[0] = {{Addr.Tag}};
|
||||
AbstractState(unsigned int AddressIn) {
|
||||
Addr = AddressIn;
|
||||
Unrolled = 0;
|
||||
}
|
||||
|
||||
AbstractState(unsigned int AddressIn, unsigned int UnrolledIn) {
|
||||
Addr = AddressIn;
|
||||
Unrolled = UnrolledIn;
|
||||
}
|
||||
|
||||
// AbstractState(Address Addr) {
|
||||
// Sets[Addr.Index].Associativity[0] = {{Addr.Tag}};
|
||||
// }
|
||||
|
||||
void setUnrolled(unsigned int In) { Unrolled = In; }
|
||||
|
||||
/**
|
||||
* @brief Executes an Must LRU Join on the AbstractCacheState
|
||||
*
|
||||
|
@ -111,9 +124,11 @@ public: // everything is public, because IDGAF
|
|||
* @param Addr , Address
|
||||
*/
|
||||
void update(Address Addr) {
|
||||
// This loopages all entries by one. 3 <-2, 2<-1, 1<-0
|
||||
for (int I = 3; I > 0; I--) {
|
||||
Sets[Addr.Index].Associativity[I] = Sets[Addr.Index].Associativity[I - 1];
|
||||
}
|
||||
// entry at age 0 is updated with current address.
|
||||
Sets[Addr.Index].Associativity[0].Blocks = {Addr.Tag};
|
||||
}
|
||||
|
||||
|
@ -126,7 +141,7 @@ public: // everything is public, because IDGAF
|
|||
for (auto S : UpdateState.Sets) {
|
||||
unsigned int Index = S.first;
|
||||
for (auto E : S.second.Associativity) {
|
||||
unsigned int Age = E.first + 1;
|
||||
unsigned int Age = E.first;
|
||||
// If updated age is greater 4 The Tag is no longer in Cache.
|
||||
// Due to associativity of 4 per set.
|
||||
if (Age >= 4)
|
||||
|
@ -139,17 +154,18 @@ public: // everything is public, because IDGAF
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Fills the AbstractState PreState and PreAddress.
|
||||
* @brief Fills the AbstractState PreState and updates with PreAddress.
|
||||
*
|
||||
* @param PreState, State that fills this state.
|
||||
*
|
||||
* @param PreAddr Address of PreState
|
||||
*/
|
||||
void fill(AbstractState PreState, Address PreAddr) {
|
||||
// copy Pre State into this.
|
||||
for (auto S : PreState.Sets) {
|
||||
unsigned int Index = S.first;
|
||||
for (auto E : S.second.Associativity) {
|
||||
unsigned int Age = E.first + 1;
|
||||
unsigned int Age = E.first;
|
||||
// If updated age is greater 4 The Tag is no longer in Cache.
|
||||
// Due to associativity of 4 per set.
|
||||
if (Age >= 4)
|
||||
|
@ -159,11 +175,13 @@ public: // everything is public, because IDGAF
|
|||
}
|
||||
}
|
||||
}
|
||||
Sets[PreAddr.Index].Associativity[0].Blocks.push_back(PreAddr.Tag);
|
||||
// update this with PreAddr
|
||||
this->update(PreAddr);
|
||||
}
|
||||
|
||||
void dump() {
|
||||
llvm::outs() << Addr << " {\n";
|
||||
llvm::outs() << "Unrolled: " << Unrolled << "\n";
|
||||
llvm::outs() << "Predecessors: ";
|
||||
for (auto PreNr : Predecessors) {
|
||||
llvm::outs() << PreNr << " ";
|
||||
|
|
Reference in New Issue