| Index: src/IceGlobalContext.h
|
| diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
|
| index ac321e68860704d746e07f75b322c9e4adfc11df..04f08a2dbffa3191633fb39343b9e6e03f1ef1e0 100644
|
| --- a/src/IceGlobalContext.h
|
| +++ b/src/IceGlobalContext.h
|
| @@ -83,6 +83,35 @@ class GlobalContext {
|
| uint32_t Fills;
|
| };
|
|
|
| + // TimerList is a vector of TimerStack objects, with extra methods
|
| + // to initialize and merge these vectors.
|
| + class TimerList : public std::vector<TimerStack> {
|
| + public:
|
| + // initInto() initializes a target list of timers based on the
|
| + // current list. In particular, it creates the same number of
|
| + // timers, in the same order, with the same names, but initially
|
| + // empty of timing data.
|
| + void initInto(TimerList &Dest) const {
|
| + if (!ALLOW_DUMP)
|
| + return;
|
| + Dest.clear();
|
| + for (const TimerStack &Stack : *this) {
|
| + Dest.push_back(TimerStack(Stack.getName()));
|
| + }
|
| + }
|
| + void mergeFrom(TimerList &Src) {
|
| + if (!ALLOW_DUMP)
|
| + return;
|
| + assert(size() == Src.size());
|
| + size_type i = 0;
|
| + for (TimerStack &Stack : *this) {
|
| + assert(Stack.getName() == Src[i].getName());
|
| + Stack.mergeFrom(Src[i]);
|
| + ++i;
|
| + }
|
| + }
|
| + };
|
| +
|
| // ThreadContext contains thread-local data. This data can be
|
| // combined/reduced as needed after all threads complete.
|
| class ThreadContext {
|
| @@ -92,7 +121,7 @@ class GlobalContext {
|
| public:
|
| ThreadContext() {}
|
| CodeStats StatsFunction;
|
| - std::vector<TimerStack> Timers;
|
| + TimerList Timers;
|
| };
|
|
|
| public:
|
| @@ -211,14 +240,20 @@ public:
|
| // These are predefined TimerStackIdT values.
|
| enum TimerStackKind { TSK_Default = 0, TSK_Funcs, TSK_Num };
|
|
|
| + // newTimerStackID() creates a new TimerStack in the global space.
|
| + // It does not affect any TimerStack objects in TLS.
|
| TimerStackIdT newTimerStackID(const IceString &Name);
|
| + // dumpTimers() dumps the global timer data. As such, one probably
|
| + // wants to call mergeTimerStacks() as a prerequisite.
|
| + void dumpTimers(TimerStackIdT StackID = TSK_Default,
|
| + bool DumpCumulative = true);
|
| + // The following methods affect only the calling thread's TLS timer
|
| + // data.
|
| TimerIdT getTimerID(TimerStackIdT StackID, const IceString &Name);
|
| - void pushTimer(TimerIdT ID, TimerStackIdT StackID = TSK_Default);
|
| - void popTimer(TimerIdT ID, TimerStackIdT StackID = TSK_Default);
|
| + void pushTimer(TimerIdT ID, TimerStackIdT StackID);
|
| + void popTimer(TimerIdT ID, TimerStackIdT StackID);
|
| void resetTimer(TimerStackIdT StackID);
|
| void setTimerName(TimerStackIdT StackID, const IceString &NewName);
|
| - void dumpTimers(TimerStackIdT StackID = TSK_Default,
|
| - bool DumpCumulative = true);
|
|
|
| // Adds a newly parsed and constructed function to the Cfg work
|
| // queue. Notifies any idle workers that a new function is
|
| @@ -235,8 +270,10 @@ public:
|
|
|
| void startWorkerThreads() {
|
| size_t NumWorkers = getFlags().NumTranslationThreads;
|
| + auto Timers = getTimers();
|
| for (size_t i = 0; i < NumWorkers; ++i) {
|
| ThreadContext *WorkerTLS = new ThreadContext();
|
| + Timers->initInto(WorkerTLS->Timers);
|
| AllThreadContexts.push_back(WorkerTLS);
|
| TranslationThreads.push_back(std::thread(
|
| &GlobalContext::translateFunctionsWrapper, this, WorkerTLS));
|
| @@ -254,6 +291,11 @@ public:
|
| }
|
| TranslationThreads.clear();
|
| // TODO(stichnot): join the emitter thread.
|
| + if (ALLOW_DUMP) {
|
| + auto Timers = getTimers();
|
| + for (ThreadContext *TLS : AllThreadContexts)
|
| + Timers->mergeFrom(TLS->Timers);
|
| + }
|
| }
|
|
|
| // Translation thread startup routine.
|
| @@ -301,7 +343,7 @@ private:
|
| ICE_CACHELINE_BOUNDARY;
|
| // Managed by getTimers()
|
| GlobalLockType TimerLock;
|
| - std::vector<TimerStack> Timers;
|
| + TimerList Timers;
|
|
|
| ICE_CACHELINE_BOUNDARY;
|
| // StrLock is a global lock on the dump and emit output streams.
|
| @@ -331,8 +373,8 @@ private:
|
| LockedPtr<CodeStats> getStatsCumulative() {
|
| return LockedPtr<CodeStats>(&StatsCumulative, &StatsLock);
|
| }
|
| - LockedPtr<std::vector<TimerStack>> getTimers() {
|
| - return LockedPtr<std::vector<TimerStack>>(&Timers, &TimerLock);
|
| + LockedPtr<TimerList> getTimers() {
|
| + return LockedPtr<TimerList>(&Timers, &TimerLock);
|
| }
|
|
|
| std::vector<ThreadContext *> AllThreadContexts;
|
| @@ -357,24 +399,31 @@ class TimerMarker {
|
| TimerMarker &operator=(const TimerMarker &) = delete;
|
|
|
| public:
|
| - TimerMarker(TimerIdT ID, GlobalContext *Ctx)
|
| - : ID(ID), Ctx(Ctx), Active(false) {
|
| - if (ALLOW_DUMP) {
|
| - Active = Ctx->getFlags().SubzeroTimingEnabled;
|
| - if (Active)
|
| - Ctx->pushTimer(ID);
|
| - }
|
| + TimerMarker(TimerIdT ID, GlobalContext *Ctx,
|
| + TimerStackIdT StackID = GlobalContext::TSK_Default)
|
| + : ID(ID), Ctx(Ctx), StackID(StackID), Active(false) {
|
| + if (ALLOW_DUMP)
|
| + push();
|
| + }
|
| + TimerMarker(TimerIdT ID, const Cfg *Func,
|
| + TimerStackIdT StackID = GlobalContext::TSK_Default)
|
| + : ID(ID), Ctx(nullptr), StackID(StackID), Active(false) {
|
| + // Ctx gets set at the beginning of pushCfg().
|
| + if (ALLOW_DUMP)
|
| + pushCfg(Func);
|
| }
|
| - TimerMarker(TimerIdT ID, const Cfg *Func);
|
|
|
| ~TimerMarker() {
|
| if (ALLOW_DUMP && Active)
|
| - Ctx->popTimer(ID);
|
| + Ctx->popTimer(ID, StackID);
|
| }
|
|
|
| private:
|
| - TimerIdT ID;
|
| - GlobalContext *const Ctx;
|
| + void push();
|
| + void pushCfg(const Cfg *Func);
|
| + const TimerIdT ID;
|
| + GlobalContext *Ctx;
|
| + const TimerStackIdT StackID;
|
| bool Active;
|
| };
|
|
|
|
|