Chromium Code Reviews| Index: src/IceGlobalContext.cpp |
| diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp |
| index 319e18a9d6a3c6ecac74d7bc3454b44eed6bbaad..52a943ff3de60b88e87ce6a5a8d4d3412881c52d 100644 |
| --- a/src/IceGlobalContext.cpp |
| +++ b/src/IceGlobalContext.cpp |
| @@ -115,6 +115,98 @@ public: |
| UndefPool Undefs; |
| }; |
| +class TimerStack { |
| + TimerStack(const TimerStack &) LLVM_DELETED_FUNCTION; |
| + TimerStack &operator=(const TimerStack &) LLVM_DELETED_FUNCTION; |
| + |
| +public: |
| + TimerStack(const IceString &TopLevelName) |
| + : FirstTimestamp(timestamp()), LastTimestamp(FirstTimestamp), |
| + StateChanges(0) { |
| + push(TopLevelName); |
| + } |
| + void push(const IceString &Name) { |
| + update(); |
| + Stack.push_back(Name); |
| + // Construct the new node's recursive name by appending .Name to |
| + // the previous top-of-stack's recursive name. |
| + IceString Prefix = ""; |
| + if (!FullNames.empty()) |
| + Prefix = FullNames.back() + "."; |
| + FullNames.push_back(Prefix + Name); |
|
Karl
2014/09/29 16:55:07
Minor nit. There is a lot of string building going
Jim Stichnoth
2014/09/30 17:50:50
Good point, and it does turn into a real performan
|
| + } |
| + void pop(const IceString &Name) { |
| + update(); |
| + assert(!Stack.empty()); |
| + assert(Stack.back() == Name); |
| + (void)Name; |
| + Stack.pop_back(); |
| + FullNames.pop_back(); |
| + } |
| + void dump(Ostream &Str); |
| + |
| +private: |
| + typedef std::map<IceString, double> MapType; |
|
Karl
2014/09/29 16:55:07
Using string as the key can be quite expensive. Co
Jim Stichnoth
2014/09/30 17:50:50
Done, see the comment above.
|
| + void update(); |
| + void dumpHelper(Ostream &Str, const MapType &Map, double TotalTime); |
| + static double timestamp() { |
| + // TODO: Implement in terms of std::chrono for C++11. |
| + return llvm::TimeRecord::getCurrentTime(false).getWallTime(); |
| + } |
| + const double FirstTimestamp; |
| + volatile double LastTimestamp; |
| + std::vector<IceString> Stack; |
| + std::vector<IceString> FullNames; |
| + MapType RecursiveTime; |
| + MapType LeafTime; |
| + uint64_t StateChanges; |
| +}; |
| + |
| +void TimerStack::update() { |
| + ++StateChanges; |
| + // Whenever the stack is about to change, we grab the time delta |
| + // since the last change and add it to all active recursive elements |
| + // and to the non-recursive element for the top of the stack. |
| + double Current = timestamp(); |
| + double Delta = Current - LastTimestamp; |
| + LastTimestamp = Current; |
| + for (size_t i = 0; i < FullNames.size(); ++i) { |
| + RecursiveTime[FullNames[i]] += Delta; |
| + } |
| + if (!Stack.empty()) { |
| + LeafTime[Stack.back()] += Delta; |
| + } |
| +} |
| + |
| +void TimerStack::dumpHelper(Ostream &Str, const MapType &Map, |
| + double TotalTime) { |
| + // Dump the items in reverse order of their time contribution. |
| + typedef std::multimap<double, IceString> RMapType; |
| + RMapType MultiMap; |
| + for (MapType::const_iterator I = Map.begin(), E = Map.end(); I != E; ++I) { |
| + MultiMap.insert(std::make_pair(I->second, I->first)); |
| + } |
| + for (RMapType::const_reverse_iterator I = MultiMap.rbegin(), |
| + E = MultiMap.rend(); |
| + I != E; ++I) { |
| + char buf[80]; |
| + snprintf(buf, llvm::array_lengthof(buf), " %10.6f (%4.1f%%): ", I->first, |
| + I->first * 100 / TotalTime); |
| + Str << buf << I->second << "\n"; |
| + } |
| +} |
| + |
| +void TimerStack::dump(Ostream &Str) { |
| + update(); |
| + double TotalTime = LastTimestamp - FirstTimestamp; |
| + assert(TotalTime); |
| + Str << "Recursive function times:\n"; |
| + dumpHelper(Str, RecursiveTime, TotalTime); |
| + Str << "Non-recursive function times:\n"; |
| + dumpHelper(Str, LeafTime, TotalTime); |
| + Str << "Number of timer updates: " << StateChanges << "\n"; |
| +} |
| + |
| GlobalContext::GlobalContext(llvm::raw_ostream *OsDump, |
| llvm::raw_ostream *OsEmit, VerboseMask Mask, |
| TargetArch Arch, OptLevel Opt, |
| @@ -122,7 +214,7 @@ GlobalContext::GlobalContext(llvm::raw_ostream *OsDump, |
| : StrDump(OsDump), StrEmit(OsEmit), VMask(Mask), |
| ConstPool(new ConstantPool()), Arch(Arch), Opt(Opt), |
| TestPrefix(TestPrefix), Flags(Flags), HasEmittedFirstMethod(false), |
| - RNG("") {} |
| + RNG(""), Timers(new TimerStack("main")) {} |
| // Scan a string for S[0-9A-Z]*_ patterns and replace them with |
| // S<num>_ where <num> is the next base-36 value. If a type name |
| @@ -384,6 +476,12 @@ ConstantList GlobalContext::getConstantPool(Type Ty) const { |
| llvm_unreachable("Unknown type"); |
| } |
| +void GlobalContext::pushTimer(const IceString &Name) { |
| + Timers.get()->push(Name); |
| +} |
| + |
| +void GlobalContext::popTimer(const IceString &Name) { Timers.get()->pop(Name); } |
| + |
| void GlobalContext::dumpStats(const IceString &Name, bool Final) { |
| if (Flags.DumpStats) { |
| if (Final) { |
| @@ -395,12 +493,6 @@ void GlobalContext::dumpStats(const IceString &Name, bool Final) { |
| } |
| } |
| -void Timer::printElapsedUs(GlobalContext *Ctx, const IceString &Tag) const { |
| - if (Ctx->isVerbose(IceV_Timing)) { |
| - // Prefixing with '#' allows timing strings to be included |
| - // without error in textual assembly output. |
| - Ctx->getStrDump() << "# " << getElapsedUs() << " usec " << Tag << "\n"; |
| - } |
| -} |
| +void GlobalContext::dumpTimers() { Timers.get()->dump(getStrDump()); } |
| } // end of namespace Ice |