| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /** |
| * @author Nikolay A. Sidelnikov |
| */ |
| #include <cstring> |
| #include "Ia32IRManager.h" |
| |
| namespace Jitrino |
| { |
| namespace Ia32{ |
| |
| template<class T> struct AttrDesc { |
| T value; |
| const char * name; |
| }; |
| |
| struct BBStats { |
| int64 * bbExecCount; |
| U_32 * counters; |
| |
| BBStats() : bbExecCount(NULL), counters(NULL) {} |
| }; |
| |
| struct MethodStats { |
| std::string methodName; |
| StlMap<int, BBStats> bbStats; //bbID, bbExecCount, array of counters |
| MethodStats(std::string s, MemoryManager& mm) : methodName(s), bbStats(mm) {} |
| }; |
| |
| typedef StlVector<MethodStats *> Statistics; |
| |
| template<class T> class FilterAttr { |
| public: |
| T value; |
| bool isInitialized; |
| bool isNegative; |
| |
| FilterAttr(T v, bool i = false, bool n = false) : value(v), isInitialized(i), isNegative(n) {}; |
| |
| FilterAttr& operator=(const FilterAttr& c) { |
| FilterAttr& f = *this; |
| f.value = c.value; |
| f.isInitialized = c.isInitialized; |
| f.isNegative = c.isNegative; |
| return f; |
| } |
| }; |
| |
| struct OpndFilter { |
| bool isInitialized; |
| int opNum; |
| FilterAttr<Inst::OpndRole> opndRole; |
| FilterAttr<OpndKind> opndKind; |
| FilterAttr<RegName> regName; |
| FilterAttr<MemOpndKind> memOpndKind; |
| |
| OpndFilter() : isInitialized(false), opNum(-1), opndRole(Inst::OpndRole_Null), opndKind(OpndKind_Null), regName(RegName_Null), memOpndKind(MemOpndKind_Null) {} |
| |
| OpndFilter& operator=(const OpndFilter& c) { |
| OpndFilter& f = *this; |
| f.isInitialized = c.isInitialized; |
| f.opNum = c.opNum; |
| f.opndRole =c.opndRole; |
| f.opndKind =c.opndKind; |
| f.regName =c.regName; |
| f.memOpndKind =c.memOpndKind; |
| return f; |
| } |
| |
| }; |
| |
| struct Filter { |
| bool isInitialized; |
| bool isNegative; |
| bool isOR; |
| |
| FilterAttr<Mnemonic> mnemonic; |
| FilterAttr<I_32> operandNumber; |
| FilterAttr<Opnd::RuntimeInfo::Kind> rtKind; |
| FilterAttr<VM_RT_SUPPORT> rtHelperID; |
| FilterAttr<std::string> rtIntHelperName; |
| FilterAttr<bool> isNative; |
| FilterAttr<bool> isStatic; |
| FilterAttr<bool> isSynchronized; |
| FilterAttr<bool> isNoInlining; |
| FilterAttr<bool> isInstance; |
| FilterAttr<bool> isFinal; |
| FilterAttr<bool> isVirtual; |
| FilterAttr<bool> isAbstract; |
| FilterAttr<bool> isClassInitializer; |
| FilterAttr<bool> isInstanceInitializer; |
| FilterAttr<bool> isStrict; |
| FilterAttr<bool> isInitLocals; |
| |
| StlMap<int, OpndFilter> operandFilters; |
| |
| Filter() : isInitialized(false), isNegative(false), isOR(false), mnemonic(Mnemonic_NULL), operandNumber(-1), rtKind(Opnd::RuntimeInfo::Kind_Null), rtHelperID(VM_RT_UNKNOWN), rtIntHelperName("none"), isNative(false), isStatic(false), isSynchronized(false), isNoInlining(false), isInstance(false), isFinal(false), isVirtual(false), isAbstract(false), isClassInitializer(false), isInstanceInitializer(false), isStrict(false), isInitLocals(false), operandFilters(Jitrino::getGlobalMM()) {} |
| |
| Filter& operator=(const Filter& c) { |
| Filter& f = *this; |
| f.isNegative = c.isNegative; |
| f.isInitialized = c.isInitialized; |
| f.isOR = c.isOR; |
| f.mnemonic=c.mnemonic; |
| f.operandNumber=c.operandNumber; |
| f.rtKind=c.rtKind; |
| f.rtHelperID=c.rtHelperID; |
| f.rtIntHelperName=c.rtIntHelperName; |
| f.isNative=c.isNative; |
| f.isStatic=c.isStatic; |
| f.isSynchronized=c.isSynchronized; |
| f.isNoInlining = c.isNoInlining; |
| f.isInstance = c.isInstance; |
| f.isFinal = c.isFinal; |
| f.isVirtual = c.isVirtual; |
| f.isAbstract = c.isAbstract; |
| f.isClassInitializer = c.isClassInitializer; |
| f.isInstanceInitializer = c.isInstanceInitializer; |
| f.isStrict = c.isStrict; |
| f.isInitLocals = c.isInitLocals; |
| |
| for(StlMap<int, OpndFilter>::const_iterator it = c.operandFilters.begin(); it !=c.operandFilters.end(); it++) { |
| f.operandFilters[it->first] = it->second; |
| } |
| return f; |
| } |
| }; |
| |
| struct Counter { |
| std::string name; |
| std::string title; |
| bool isSorting; |
| Filter filter; |
| |
| Counter() : isSorting(false) {} |
| }; |
| |
| class Config { |
| public: |
| StlVector<Counter> counters; |
| |
| bool printBBStats; |
| Config(MemoryManager& mm) : counters(mm), printBBStats(false) {}; |
| }; |
| |
| |
| //======================================================================================== |
| // class InternalProfiler |
| //======================================================================================== |
| /** |
| class InternalProfiler collects information about methods |
| |
| */ |
| |
| class InternalProfilerAct : public Action { |
| public: |
| void init(); |
| void deinit() { dumpIt(); config = NULL; } |
| |
| protected: |
| void readConfig(Config * config); |
| void dumpIt(); |
| |
| Config * config; |
| Statistics * statistics; |
| |
| friend class InternalProfiler; |
| }; |
| |
| |
| class InternalProfiler : public SessionAction { |
| public: |
| void runImpl(); |
| |
| protected: |
| void addCounters(MethodDesc& methodDesc); |
| |
| bool passFilter(Inst * inst, Filter& filter); |
| bool passOpndFilter(Inst * inst, Opnd * opnd, Filter& filter, OpndFilter& opndFltr); |
| }; |
| |
| const AttrDesc<Inst::OpndRole> opndRoles[] = { |
| {Inst::OpndRole_Null,"Null"}, |
| {Inst::OpndRole_Use,"Use"}, |
| {Inst::OpndRole_Def, "Def"}, |
| {Inst::OpndRole_UseDef,"UseDef"}, |
| {Inst::OpndRole_FromEncoder, "FromEncoder"}, |
| {Inst::OpndRole_Explicit, "Explicit"}, |
| {Inst::OpndRole_Auxilary, "Auxilary"}, |
| {Inst::OpndRole_Changeable, "Changeable"}, |
| {Inst::OpndRole_Implicit, "Implicit"}, |
| {Inst::OpndRole_InstLevel, "InstLevel"}, |
| {Inst::OpndRole_MemOpndSubOpnd, "MemOpndSubOpnd"}, |
| {Inst::OpndRole_OpndLevel, "OpndLevel"}, |
| {Inst::OpndRole_ForIterator, "ForIterator"}, |
| {Inst::OpndRole_All, "All"}, |
| {Inst::OpndRole_AllDefs, "AllDefs"}, |
| {Inst::OpndRole_AllUses, "AllUses"}, |
| }; |
| |
| const AttrDesc<MemOpndKind> memOpndKinds[] = { |
| {MemOpndKind_Null, "Null"}, |
| {MemOpndKind_StackAutoLayout, "StackAutoLayout"}, |
| {MemOpndKind_StackManualLayout, "StackManualLayout"}, |
| {MemOpndKind_Stack, "Stack"}, |
| {MemOpndKind_Heap, "Heap"}, |
| {MemOpndKind_ConstantArea, "ConstantArea"}, |
| {MemOpndKind_Any, "Any"}, |
| }; |
| |
| const AttrDesc<Opnd::RuntimeInfo::Kind> rtKinds[] = { |
| {Opnd::RuntimeInfo::Kind_Null, "Null"}, |
| {Opnd::RuntimeInfo::Kind_AllocationHandle, "AllocationHandle"}, |
| {Opnd::RuntimeInfo::Kind_TypeRuntimeId, "TypeRuntimeId" }, |
| {Opnd::RuntimeInfo::Kind_MethodRuntimeId,"MethodRuntimeId" }, |
| {Opnd::RuntimeInfo::Kind_StringDescription, "StringDescription" }, |
| {Opnd::RuntimeInfo::Kind_Size, "Size" }, |
| {Opnd::RuntimeInfo::Kind_HelperAddress, "HelperAddress"}, |
| {Opnd::RuntimeInfo::Kind_InternalHelperAddress, "InternalHelperAddress"}, |
| {Opnd::RuntimeInfo::Kind_StaticFieldAddress,"StaticFieldAddress"}, |
| {Opnd::RuntimeInfo::Kind_FieldOffset,"FieldOffset"}, |
| {Opnd::RuntimeInfo::Kind_VTableAddrOffset,"VTableAddrOffset"}, |
| {Opnd::RuntimeInfo::Kind_VTableConstantAddr,"VTableConstantAddr"}, |
| {Opnd::RuntimeInfo::Kind_MethodVtableSlotOffset,"MethodVtableSlotOffset"}, |
| {Opnd::RuntimeInfo::Kind_MethodIndirectAddr,"MethodIndirectAddr"}, |
| {Opnd::RuntimeInfo::Kind_MethodDirectAddr,"MethodDirectAddr"}, |
| {Opnd::RuntimeInfo::Kind_ConstantAreaItem,"ConstantAreaItem"}, |
| }; |
| |
| static ActionFactory<InternalProfiler, InternalProfilerAct> _iprof("iprof"); |
| |
| void InternalProfilerAct::init() { |
| MemoryManager& mm = Jitrino::getGlobalMM(); |
| config = new(mm) Config(mm); |
| statistics = new(mm) Statistics(mm); |
| readConfig(config); |
| } |
| |
| void InternalProfilerAct::readConfig(Config * config) { |
| std::string configString; |
| std::ifstream configFile; |
| const char* fname; |
| if ((fname = getArg("config")) == 0) |
| fname = "iprof.cfg"; |
| configFile.open(fname, std::ios::in); |
| |
| bool rc = false; |
| if (configFile.is_open()) { |
| std::string line; |
| U_32 ln = 0; |
| bool opened = false; |
| int num = -1; |
| while (std::getline(configFile, line)) { |
| ln++; |
| if(!line.empty() && (line.find("#")!= 0)) { |
| const char * c_line = line.c_str(); |
| if(std::strstr(c_line, "Config") == c_line) { |
| if(((int)line.find("PrintBBStats") != -1) && ((int)line.find("true")!=-1)) |
| config->printBBStats = true; |
| } else if (line.find("Counter.") == 0) { |
| if(!opened) { |
| opened = true; |
| num = (int)config->counters.size(); |
| config->counters.push_back(Counter()); |
| int pos1 = (int)line.find("."); |
| int pos2 = (int)line.find_first_of(".=" , pos1+1); |
| |
| config->counters[num].name = line.substr(pos1+1, pos2-pos1-1); |
| } |
| if((int)line.find(".Title=")!=-1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| config->counters[num].title=std::string(val); |
| } else if (((int)line.find(".IsOR=")!=-1) && ((int)line.find("true")!=-1)) { |
| config->counters[num].filter.isOR=true; |
| } else if ((int)line.find(std::string(config->counters[num].name)+"=")!=-1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| for(U_32 i = 0; i < config->counters.size(); i++) { |
| if(std::string(config->counters[i].name) == val) { |
| config->counters[num].filter = config->counters[i].filter; |
| break; |
| } |
| } |
| } else if((int)line.find(".Mnemonic")!=-1) { |
| char * mnem = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(mnem) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.mnemonic.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.mnemonic.value=EncoderBase::str2mnemonic(mnem); |
| config->counters[num].filter.mnemonic.isInitialized=true; |
| } |
| } else if (std::strstr(line.c_str(), ".OpndNumber")) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.operandNumber.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.operandNumber.value=atoi(val); |
| config->counters[num].filter.operandNumber.isInitialized=true; |
| } |
| } else if ((int)line.find(".Operand.") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| int pos = int(line.find(".Operand.")+9); |
| std::string v = line.substr(pos, line.find_first_of(".", pos)-pos); |
| int opNum; |
| if(v == "*") |
| opNum = -1; |
| else |
| opNum = atoi(v.c_str()); |
| config->counters[num].filter.operandFilters[opNum].opNum = opNum; |
| config->counters[num].filter.operandFilters[opNum].isInitialized = true; |
| if ((int)line.find(".OpndRole") != -1) { |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.operandFilters[opNum].opndRole.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.operandFilters[opNum].opndRole.isInitialized=true; |
| for (U_32 i = 0; i<lengthof(opndRoles); i++) { |
| if(std::string(opndRoles[i].name) == val) |
| config->counters[num].filter.operandFilters[opNum].opndRole.value=opndRoles[i].value; |
| } |
| } |
| } else if ((int)line.find(".OpndKind") != -1) { |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.operandFilters[opNum].opndKind.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.operandFilters[opNum].opndKind.isInitialized=true; |
| config->counters[num].filter.operandFilters[opNum].opndKind.value=getOpndKind(val); |
| } |
| } else if ((int)line.find(".RegName") != -1) { |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.operandFilters[opNum].opndRole.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.operandFilters[opNum].regName.isInitialized=true; |
| config->counters[num].filter.operandFilters[opNum].regName.value = getRegName(val); |
| } |
| } else if ((int)line.find(".MemOpndKind") != -1) { |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.operandFilters[opNum].memOpndKind.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.operandFilters[opNum].memOpndKind.isInitialized=true; |
| for (U_32 i = 0; i<lengthof(memOpndKinds); i++) { |
| if(std::string(memOpndKinds[i].name) == val) |
| config->counters[num].filter.operandFilters[opNum].memOpndKind.value=memOpndKinds[i].value; |
| } |
| } |
| } |
| } else if ((int)line.find(".RuntimeInfo.Kind") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.rtKind.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| for (U_32 i = 0; i<lengthof(rtKinds); i++) { |
| if(std::string(rtKinds[i].name) == val) |
| config->counters[num].filter.rtKind.value=rtKinds[i].value; |
| } |
| //CompilationInterface::str2rid(val); |
| config->counters[num].filter.rtKind.isInitialized=true; |
| } |
| } else if ((int)line.find(".RuntimeInfo.HelperID") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.rtHelperID.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.rtHelperID.value=CompilationInterface::str2rid(val); |
| config->counters[num].filter.rtHelperID.isInitialized=true; |
| } |
| } else if ((int)line.find(".RuntimeInfo.IntHelperName") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.rtIntHelperName.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.rtIntHelperName.value=std::string(val); |
| config->counters[num].filter.rtIntHelperName.isInitialized=true; |
| } |
| } else if ((int)line.find(".isNative") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.isNative.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.isNative.value=(std::string(val) == "true")? true : false; |
| config->counters[num].filter.isNative.isInitialized=true; |
| } |
| } else if ((int)line.find(".isStatic") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.isStatic.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.isStatic.value=(std::string(val) == "true")? true : false; |
| config->counters[num].filter.isStatic.isInitialized=true; |
| } |
| } else if ((int)line.find(".isSynchronized") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.isSynchronized.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.isSynchronized.value=(std::string(val) == "true")? true : false; |
| config->counters[num].filter.isSynchronized.isInitialized=true; |
| } |
| } else if ((int)line.find(".isNoInlining") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.isNoInlining.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.isNoInlining.value=(std::string(val) == "true")? true : false; |
| config->counters[num].filter.isNoInlining.isInitialized=true; |
| } |
| } else if ((int)line.find(".isInstance") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.isInstance.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.isInstance.value=(std::string(val) == "true")? true : false; |
| config->counters[num].filter.isInstance.isInitialized=true; |
| } |
| } else if ((int)line.find(".isFinal") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.isFinal.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.isFinal.value=(std::string(val) == "true")? true : false; |
| config->counters[num].filter.isFinal.isInitialized=true; |
| } |
| } else if ((int)line.find(".isVirtual") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.isVirtual.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.isVirtual.value=(std::string(val) == "true")? true : false; |
| config->counters[num].filter.isVirtual.isInitialized=true; |
| } |
| } else if ((int)line.find(".isAbstract") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.isAbstract.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.isAbstract.value=(std::string(val) == "true")? true : false; |
| config->counters[num].filter.isAbstract.isInitialized=true; |
| } |
| } else if ((int)line.find(".isClassInitializer") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.isClassInitializer.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.isClassInitializer.value=(std::string(val) == "true")? true : false; |
| config->counters[num].filter.isClassInitializer.isInitialized=true; |
| } |
| } else if ((int)line.find(".isInstanceInitializer") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.isInstanceInitializer.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.isInstanceInitializer.value=(std::string(val) == "true")? true : false; |
| config->counters[num].filter.isInstanceInitializer.isInitialized=true; |
| } |
| } else if ((int)line.find(".isStrict") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.isStrict.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.isStrict.value=(std::string(val) == "true")? true : false; |
| config->counters[num].filter.isStrict.isInitialized=true; |
| } |
| } else if ((int)line.find(".isInitLocals") != -1) { |
| char * val = (char *)std::strstr(line.c_str(),"=")+1; |
| if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { |
| config->counters[num].filter.isInitLocals.isNegative=true; |
| } else { |
| config->counters[num].filter.isInitialized=true; |
| config->counters[num].filter.isInitLocals.value=(std::string(val) == "true")? true : false; |
| config->counters[num].filter.isInitLocals.isInitialized=true; |
| } |
| } |
| } else if (std::strstr(c_line, "[begin]") == c_line) { |
| } else if (std::strstr(c_line, "[end]") == c_line) { |
| opened = false; |
| } else if (std::strstr(c_line, "#") == c_line) { |
| } else { |
| ::std::cerr<<"iprof: BAD LINE("<<ln<<") in configuration file"<<::std::endl; |
| exit(1); |
| } |
| configString+=line+"\n"; |
| } |
| } |
| rc = !configString.empty(); |
| } |
| if (!rc) { |
| ::std::cerr<<"iprof: Can't read configuration"<<::std::endl; |
| } |
| } |
| |
| void InternalProfilerAct::dumpIt() { |
| if(!config || !config->counters.size()) |
| return; |
| const char* fname; |
| if ((fname = getArg("out")) == 0) |
| fname = "iprof.stat"; |
| std::ofstream outFile(fname, std::ios::ate); |
| outFile << "Method name\t"; |
| for(U_32 i = 0; i < config->counters.size(); i++) { |
| std::string fName = config->counters[i].title != "" ? config->counters[i].title : config->counters[i].name; |
| outFile << fName << "\t"; |
| } |
| outFile << "\n"; |
| |
| for(Statistics::const_iterator it = statistics->begin(); it != statistics->end(); it++) { |
| MethodStats * stats = *it; |
| outFile << stats->methodName.c_str() << "\t"; |
| BBStats bbs = stats->bbStats[-1]; |
| for(U_32 i = 0; i < config->counters.size(); i++) { |
| int64 count; |
| std::string name = config->counters[i].name; |
| if((name == "ByteCodeSize") || (name == "ExcHandlersNum")) { |
| count = bbs.counters[i]; |
| } else if (name == "MaxBBExec") { |
| count = 0; |
| for(StlMap<int, BBStats>::iterator iter = stats->bbStats.begin(); iter != stats->bbStats.end(); iter++) { |
| if(iter->second.counters[i]*(*(iter->second.bbExecCount)) > count) { |
| count = iter->second.counters[i] * (*(iter->second.bbExecCount)) ; |
| } |
| } |
| } else if (name == "HottestBBNum") { |
| int64 c = 0; |
| count = 0; |
| for(StlMap<int, BBStats>::iterator iter = stats->bbStats.begin(); iter != stats->bbStats.end(); iter++) { |
| if(iter->first != -1) { |
| int64 j = iter->second.counters[i]*(*(iter->second.bbExecCount)) ; |
| if(j > c) { |
| c = iter->second.counters[i] * (*(iter->second.bbExecCount)) ; |
| count = iter->first; |
| } |
| } |
| } |
| } else if (name == "MethodExec") { |
| count = *(stats->bbStats[0].bbExecCount); |
| } else { |
| count = 0; |
| for(StlMap<int, BBStats>::iterator iter = stats->bbStats.begin(); iter != stats->bbStats.end(); iter++) { |
| if(iter->first != -1) |
| count += iter->second.counters[i] * (*(iter->second.bbExecCount)) ; |
| } |
| } |
| outFile << count << "\t"; |
| } |
| outFile << std::endl; |
| if(config->printBBStats) { |
| for(StlMap<int, BBStats>::iterator iter = stats->bbStats.begin(); iter != stats->bbStats.end(); iter++) { |
| if(iter->first == -1) |
| continue; |
| outFile << "BB_" << iter->first << "_" << stats->methodName.c_str() << "\t"; |
| for(U_32 i = 0; i < config->counters.size(); i++) { |
| int64 outValue = iter->second.counters[i] * (*(iter->second.bbExecCount)); |
| outFile << outValue << "\t"; |
| } |
| outFile << std::endl; |
| } |
| } |
| } |
| } |
| |
| void InternalProfiler::runImpl() { |
| addCounters(irManager->getMethodDesc()); |
| } |
| |
| void InternalProfiler::addCounters(MethodDesc& methodDesc) { |
| MemoryManager& mm = Jitrino::getGlobalMM(); |
| MethodStats* ms = new(mm) MethodStats(std::string(methodDesc.getParentType()->getName())+"::"+methodDesc.getName()+methodDesc.getSignatureString(), mm); |
| |
| InternalProfilerAct& storage = *static_cast<InternalProfilerAct*>(getAction()); |
| storage.statistics->push_back(ms); |
| //method external properties, no need to count |
| U_32 cSize = (U_32)storage.config->counters.size(); |
| if (!cSize) |
| return; |
| ms->bbStats[-1].counters= new(mm) U_32[cSize]; |
| for(U_32 i = 0; i < cSize ; i++) { |
| ms->bbStats[-1].counters[i] = 0; |
| } |
| ms->bbStats[-1].bbExecCount= new(mm) int64[1]; |
| *(ms->bbStats[-1].bbExecCount) = 0; |
| for(U_32 i = 0; i < cSize ; i++) { |
| Counter c = storage.config->counters[i]; |
| if(c.name == std::string("ByteCodeSize")) { |
| ms->bbStats[-1].bbExecCount= new(mm) int64[1]; |
| *(ms->bbStats[-1].bbExecCount) = 0; |
| |
| ms->bbStats[-1].counters[i] = methodDesc.getByteCodeSize(); |
| } else if (c.name == std::string("ExcHandlersNum")) { |
| int n = methodDesc.getNumHandlers(); |
| ms->bbStats[-1].counters[i] = n; |
| } |
| } |
| //cycle by all insts |
| IRManager & irm=getIRManager(); |
| const Nodes& nodes = irm.getFlowGraph()->getNodes(); |
| for (Nodes::const_iterator it = nodes.begin(),end = nodes.end();it!=end; ++it) { |
| Node* node = *it; |
| if (node->isBlockNode()){ |
| ms->bbStats[node->getId()].counters= new(mm) U_32[cSize]; |
| for(U_32 i = 0; i < cSize ; i++) { |
| ms->bbStats[node->getId()].counters[i] = 0; |
| } |
| for (Inst * inst=(Inst*)node->getFirstInst(); inst!=NULL; inst=inst->getNextInst()){ |
| if(!inst->hasKind(Inst::Kind_PseudoInst) || inst->hasKind(Inst::Kind_EntryPointPseudoInst)) { |
| for(U_32 i = 0; i < cSize ; i++) { |
| Counter c = storage.config->counters[i]; |
| if(std::string(c.name) == "MaxBBExec" || std::string(c.name) == "HottestBBNum" || std::string(c.name) == "BBExec" ) { |
| ms->bbStats[node->getId()].counters[i] =1; |
| } else { |
| bool matched = passFilter(inst, c.filter); |
| if (matched) { |
| ms->bbStats[node->getId()].counters[i]++; |
| ms->bbStats[-1].counters[i]++; |
| } |
| } |
| } |
| } |
| } |
| ms->bbStats[node->getId()].bbExecCount= new(mm) int64[1]; |
| *(ms->bbStats[node->getId()].bbExecCount) = 0; |
| node->prependInst(irManager->newInst(Mnemonic_POPFD)); |
| #ifndef _EM64T_ |
| node->prependInst(irManager->newInst(Mnemonic_ADC, irManager->newMemOpnd(irManager->getTypeFromTag(Type::Int32), MemOpndKind_Heap, NULL, int((U_8*)(ms->bbStats[node->getId()].bbExecCount) + 4)), irManager->newImmOpnd(irManager->getTypeFromTag(Type::Int32),0))); |
| |
| node->prependInst(irManager->newInst(Mnemonic_ADD, irManager->newMemOpnd(irManager->getTypeFromTag(Type::Int32), MemOpndKind_Heap, NULL, int(ms->bbStats[node->getId()].bbExecCount)), irManager->newImmOpnd(irManager->getTypeFromTag(Type::Int32),1))); |
| #endif |
| node->prependInst(irManager->newInst(Mnemonic_PUSHFD)); |
| } |
| } |
| #ifndef _EM64T_ |
| ((BasicBlock *)irManager->getFlowGraph()->getEntryNode())->prependInst(irManager->newInst(Mnemonic_ADD, irManager->newMemOpnd(irManager->getTypeFromTag(Type::Int32), MemOpndKind_Heap, NULL, int(ms->bbStats[-1].bbExecCount)), irManager->newImmOpnd(irManager->getTypeFromTag(Type::Int32),1))); |
| #endif |
| |
| } |
| bool InternalProfiler::passOpndFilter(Inst * inst, Opnd * opnd, Filter& filter, OpndFilter& opndFltr) { |
| bool res = false; |
| if(opndFltr.opndKind.isInitialized) { |
| res = opnd->isPlacedIn(opndFltr.opndKind.value); |
| if(opndFltr.opndKind.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(opndFltr.opndRole.isInitialized) { |
| res = inst->getOpndRoles(opndFltr.opNum) & opndFltr.opndRole.value; |
| if(opndFltr.opndRole.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(opndFltr.regName.isInitialized) { |
| res = opndFltr.regName.value == opnd->getRegName(); |
| if(opndFltr.regName.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(opndFltr.memOpndKind.isInitialized) { |
| res = opndFltr.memOpndKind.value == opnd->getMemOpndKind(); |
| if(opndFltr.memOpndKind.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| return filter.isOR ? false : true; |
| } |
| |
| bool InternalProfiler::passFilter(Inst * inst, Filter& filter) { |
| if(!filter.isInitialized) |
| return false; |
| bool res = false; |
| if(filter.mnemonic.isInitialized) { |
| res = (filter.mnemonic.value == inst->getMnemonic()) || (filter.mnemonic.value == Mnemonic_Null); |
| if(filter.mnemonic.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.operandNumber.isInitialized) { |
| res = filter.operandNumber.value == (int)inst->getOpndCount(); |
| if(filter.operandNumber.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| |
| if(filter.operandFilters.size()) { |
| for(StlMap<int, OpndFilter>::const_iterator it = filter.operandFilters.begin(); it !=filter.operandFilters.end(); it++) { |
| OpndFilter opndFltr = it->second; |
| if(!opndFltr.isInitialized) |
| continue; |
| if(opndFltr.opNum == -1) { |
| for(U_32 i = 0; i < inst->getOpndCount(Inst::OpndRole_All) ; i++) { |
| Opnd * opnd = inst->getOpnd(i); |
| res = passOpndFilter(inst, opnd, filter, opndFltr); |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| } else if (opndFltr.opNum >= 0) { |
| Opnd * opnd = opndFltr.opNum<(int)inst->getOpndCount(Inst::OpndRole_All) ? inst->getOpnd(opndFltr.opNum) : NULL; |
| if(!opnd) |
| return false; |
| res = passOpndFilter(inst, opnd, filter, opndFltr); |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } else { |
| return false; |
| } |
| } |
| } |
| Opnd::RuntimeInfo * rt = NULL; |
| if (inst->getMnemonic() == Mnemonic_CALL) { |
| rt = inst->getOpnd(((ControlTransferInst*)inst)->getTargetOpndIndex())->getRuntimeInfo(); |
| } |
| |
| if(filter.rtKind.isInitialized) { |
| if(!rt) |
| return false; |
| res = filter.rtKind.value == rt->getKind(); |
| if(filter.rtKind.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.rtHelperID.isInitialized) { |
| if(!rt) |
| return false; |
| res = filter.rtHelperID.value == (VM_RT_SUPPORT)(POINTER_SIZE_INT)rt->getValue(0); |
| if(filter.rtHelperID.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.rtIntHelperName.isInitialized) { |
| if(!rt) |
| return false; |
| res = filter.rtIntHelperName.value == (char*)irManager->getInternalHelperInfo((const char*)rt->getValue(0))->pfn; |
| if(filter.rtIntHelperName.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.isNative.isInitialized) { |
| if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) |
| return false; |
| res = filter.isNative.value == ((MethodDesc *)rt->getValue(0))->isNative(); |
| if(filter.isNative.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.isStatic.isInitialized) { |
| if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) |
| return false; |
| res = filter.isStatic.value == ((MethodDesc *)rt->getValue(0))->isStatic(); |
| if(filter.isStatic.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.isSynchronized.isInitialized) { |
| if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) |
| return false; |
| res = filter.isSynchronized.value == ((MethodDesc *)rt->getValue(0))->isSynchronized(); |
| if(filter.isSynchronized.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.isNoInlining.isInitialized) { |
| if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) |
| return false; |
| res = filter.isNoInlining.value == ((MethodDesc *)rt->getValue(0))->isNoInlining(); |
| if(filter.isNoInlining.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.isInstance.isInitialized) { |
| if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) |
| return false; |
| res = filter.isInstance.value == ((MethodDesc *)rt->getValue(0))->isInstance(); |
| if(filter.isInstance.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.isFinal.isInitialized) { |
| if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) |
| return false; |
| res = filter.isFinal.value == ((MethodDesc *)rt->getValue(0))->isFinal(); |
| if(filter.isFinal.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.isVirtual.isInitialized) { |
| if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) |
| return false; |
| res = filter.isVirtual.value == ((MethodDesc *)rt->getValue(0))->isVirtual(); |
| if(filter.isVirtual.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.isAbstract.isInitialized) { |
| if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) |
| return false; |
| res = filter.isAbstract.value == ((MethodDesc *)rt->getValue(0))->isAbstract(); |
| if(filter.isAbstract.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.isClassInitializer.isInitialized) { |
| if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) |
| return false; |
| res = filter.isClassInitializer.value == ((MethodDesc *)rt->getValue(0))->isClassInitializer(); |
| if(filter.isClassInitializer.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.isInstanceInitializer.isInitialized) { |
| if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) |
| return false; |
| res = filter.isInstanceInitializer.value == ((MethodDesc *)rt->getValue(0))->isInstanceInitializer(); |
| if(filter.isInstanceInitializer.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.isStrict.isInitialized) { |
| if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) |
| return false; |
| res = filter.isStrict.value == ((MethodDesc *)rt->getValue(0))->isStrict(); |
| if(filter.isStrict.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| if(filter.isInitLocals.isInitialized) { |
| if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) |
| return false; |
| res = filter.isInitLocals.value == false; |
| if(filter.isInitLocals.isNegative) |
| res = !res; |
| |
| if(filter.isOR && res) |
| return true; |
| if(!(filter.isOR || res)) |
| return false; |
| } |
| |
| return filter.isOR ? false : true; |
| } |
| |
| }}; // namespace Ia32 |