浏览代码

Merge pull request #6541 from richardkchapman/stats-activity-times-rebased2

HPCC-12391 Refactor activity timers to track start/end time too

Reviewed-by: Gavin Halliday <ghalliday@hpccsystems.com>
Gavin Halliday 10 年之前
父节点
当前提交
2f0369c68c
共有 65 个文件被更改,包括 980 次插入856 次删除
  1. 1 1
      common/thorhelper/roxiedebug.ipp
  2. 2 2
      common/thorhelper/roxiehelper.ipp
  3. 84 12
      common/thorhelper/thorcommon.hpp
  4. 9 82
      roxie/ccd/ccd.hpp
  5. 151 158
      roxie/ccd/ccdactivities.cpp
  6. 1 1
      roxie/ccd/ccdactivities.hpp
  7. 125 107
      roxie/ccd/ccdcontext.cpp
  8. 3 2
      roxie/ccd/ccdcontext.hpp
  9. 3 7
      roxie/ccd/ccdquery.cpp
  10. 1 2
      roxie/ccd/ccdquery.hpp
  11. 33 3
      roxie/ccd/ccdqueue.cpp
  12. 303 250
      roxie/ccd/ccdserver.cpp
  13. 3 1
      roxie/ccd/ccdserver.hpp
  14. 39 10
      system/jlib/jstats.cpp
  15. 6 1
      system/jlib/jstats.h
  16. 4 4
      thorlcr/activities/aggregate/thaggregateslave.cpp
  17. 2 2
      thorlcr/activities/aggregate/thgroupaggregateslave.cpp
  18. 1 1
      thorlcr/activities/apply/thapplyslave.cpp
  19. 5 5
      thorlcr/activities/catch/thcatchslave.cpp
  20. 7 7
      thorlcr/activities/choosesets/thchoosesetsslave.cpp
  21. 4 4
      thorlcr/activities/countproject/thcountprojectslave.cpp
  22. 2 2
      thorlcr/activities/csvread/thcsvrslave.cpp
  23. 3 3
      thorlcr/activities/degroup/thdegroupslave.cpp
  24. 10 10
      thorlcr/activities/diskread/thdiskreadslave.cpp
  25. 3 3
      thorlcr/activities/enth/thenthslave.cpp
  26. 2 2
      thorlcr/activities/fetch/thfetchslave.cpp
  27. 8 8
      thorlcr/activities/filter/thfilterslave.cpp
  28. 5 5
      thorlcr/activities/firstn/thfirstnslave.cpp
  29. 14 14
      thorlcr/activities/funnel/thfunnelslave.cpp
  30. 2 2
      thorlcr/activities/group/thgroupslave.cpp
  31. 12 12
      thorlcr/activities/hashdistrib/thhashdistribslave.cpp
  32. 10 10
      thorlcr/activities/indexread/thindexreadslave.cpp
  33. 4 4
      thorlcr/activities/iterate/thgroupiterateslave.cpp
  34. 8 8
      thorlcr/activities/iterate/thiterateslave.cpp
  35. 3 3
      thorlcr/activities/join/thjoinslave.cpp
  36. 2 2
      thorlcr/activities/keyedjoin/thkeyedjoinslave.cpp
  37. 4 4
      thorlcr/activities/limit/thlimitslave.cpp
  38. 4 4
      thorlcr/activities/lookupjoin/thlookupjoinslave.cpp
  39. 15 15
      thorlcr/activities/loop/thloopslave.cpp
  40. 5 5
      thorlcr/activities/merge/thmergeslave.cpp
  41. 5 5
      thorlcr/activities/msort/thgroupsortslave.cpp
  42. 2 2
      thorlcr/activities/msort/thmsortslave.cpp
  43. 6 6
      thorlcr/activities/normalize/thnormalizeslave.cpp
  44. 8 9
      thorlcr/activities/nsplitter/thnsplitterslave.cpp
  45. 4 4
      thorlcr/activities/null/thnullslave.cpp
  46. 2 2
      thorlcr/activities/nullaction/thnullactionslave.cpp
  47. 2 2
      thorlcr/activities/parse/thparseslave.cpp
  48. 4 4
      thorlcr/activities/piperead/thprslave.cpp
  49. 4 4
      thorlcr/activities/project/thprojectslave.cpp
  50. 2 2
      thorlcr/activities/pull/thpullslave.cpp
  51. 8 8
      thorlcr/activities/rollup/throllupslave.cpp
  52. 2 2
      thorlcr/activities/sample/thsampleslave.cpp
  53. 2 2
      thorlcr/activities/selectnth/thselectnthslave.cpp
  54. 2 2
      thorlcr/activities/selfjoin/thselfjoinslave.cpp
  55. 4 4
      thorlcr/activities/soapcall/thsoapcallslave.cpp
  56. 2 2
      thorlcr/activities/spill/thspillslave.cpp
  57. 2 2
      thorlcr/activities/temptable/thtmptableslave.cpp
  58. 2 2
      thorlcr/activities/topn/thtopnslave.cpp
  59. 2 2
      thorlcr/activities/when/thwhenslave.cpp
  60. 2 2
      thorlcr/activities/wuidread/thwuidreadslave.cpp
  61. 2 2
      thorlcr/activities/xmlparse/thxmlparseslave.cpp
  62. 2 2
      thorlcr/activities/xmlread/thxmlreadslave.cpp
  63. 1 2
      thorlcr/graph/thgraphslave.cpp
  64. 3 2
      thorlcr/graph/thgraphslave.hpp
  65. 2 2
      thorlcr/slave/slave.cpp

+ 1 - 1
common/thorhelper/roxiedebug.ipp

@@ -220,7 +220,7 @@ class RoxiePacketHeader;
 
 interface IRoxieQueryPacket;
 
-interface IDebuggableContext : extends IActivityTimer
+interface IDebuggableContext : public IInterface
 {
 // Called by program being debugged
     virtual void debugInitialize(const char *id, const char *queryName, bool breakAtStart) = 0;

+ 2 - 2
common/thorhelper/roxiehelper.ipp

@@ -57,9 +57,9 @@ enum TracingCategory
 {
     LOG_TRACING,
     LOG_ERROR,
-    LOG_TIMING,
-    LOG_STATISTICS,
     LOG_STATVALUES,
+    LOG_CHILDSTATS,
+    LOG_CHILDCOUNT,
 };
 
 class LogItem;

+ 84 - 12
common/thorhelper/thorcommon.hpp

@@ -21,6 +21,7 @@
 #include "jiface.hpp"
 #include "jcrc.hpp"
 #include "jsort.hpp"
+#include "jdebug.hpp"
 #include "eclhelper.hpp"
 #include "thorhelper.hpp"
 #include "thorxmlwrite.hpp"
@@ -126,39 +127,106 @@ extern THORHELPER_API void testDiskSort();
 
 
 #define TIME_ACTIVITIES
-interface IActivityTimer : extends IInterface
+class ActivityTimeAccumulator
 {
-    virtual unsigned __int64 getCyclesAdjustment() const = 0;
+    friend class ActivityTimer;
+public:
+    ActivityTimeAccumulator()
+    {
+        startCycles = 0;
+        totalCycles = 0;
+        endCycles = 0;
+        firstRow = 0;
+        firstExitCycles = 0;
+    }
+public:
+    cycle_t startCycles; // Wall clock time of first entry to this activity
+    cycle_t totalCycles; // Time spent in this activity
+    cycle_t endCycles;   // Wall clock time of last entry to this activity
+    unsigned __int64 firstRow; // Timestamp of first row (nanoseconds since epoch)
+    cycle_t firstExitCycles;    // Wall clock time of first exit from this activity
+
+    // Return the total amount of time (in nanoseconds) spent in this activity (first entry to last exit)
+    inline unsigned __int64 elapsed() const { return cycle_to_nanosec(endCycles-startCycles); }
+    // Return the total amount of time (in nanoseconds) spent in the first call of this activity (first entry to first exit)
+    inline unsigned __int64 latency() const { return cycle_to_nanosec(firstExitCycles-startCycles); }
+
+    void addStatistics(IStatisticGatherer & builder) const
+    {
+        if (totalCycles)
+        {
+            builder.addStatistic(StWhenFirstRow, firstRow);
+            builder.addStatistic(StTimeElapsed, elapsed());
+            builder.addStatistic(StTimeTotalExecute, cycle_to_nanosec(totalCycles));
+            builder.addStatistic(StTimeFirstExecute, latency());
+        }
+    }
 };
+
 #ifdef TIME_ACTIVITIES
 #include "jdebug.hpp"
+
 class ActivityTimer
 {
     unsigned __int64 startCycles;
-    unsigned __int64 &accumulator;
+    ActivityTimeAccumulator &accumulator;
 protected:
     const bool enabled;
-    IActivityTimer *iActivityTimer;
+    bool isFirstRow;
 public:
-    inline ActivityTimer(unsigned __int64 &_accumulator, const bool _enabled, IActivityTimer *_iActivityTimer) : accumulator(_accumulator), enabled(_enabled), iActivityTimer(_iActivityTimer)
+    ActivityTimer(ActivityTimeAccumulator &_accumulator, const bool _enabled)
+    : accumulator(_accumulator), enabled(_enabled), isFirstRow(false)
     {
         if (enabled)
         {
             startCycles = get_cycles_now();
-            if (iActivityTimer)
-                startCycles -= iActivityTimer->getCyclesAdjustment();
+            if (!accumulator.firstRow)
+            {
+                isFirstRow = true;
+                accumulator.startCycles = startCycles;
+                accumulator.firstRow = getTimeStampNowValue();
+            }
         }
         else
             startCycles = 0;
     }
 
-    inline ~ActivityTimer()
+    ~ActivityTimer()
     {
         if (enabled)
         {
-            unsigned __int64 elapsedCycles = get_cycles_now() - startCycles;
-            if (iActivityTimer)
-                elapsedCycles -= iActivityTimer->getCyclesAdjustment();
+            cycle_t nowCycles = get_cycles_now();
+            accumulator.endCycles = nowCycles;
+            cycle_t elapsedCycles = nowCycles - startCycles;
+            accumulator.totalCycles += elapsedCycles;
+            if (isFirstRow)
+                accumulator.firstExitCycles = nowCycles;
+        }
+    }
+};
+
+class SimpleActivityTimer
+{
+    cycle_t startCycles;
+    cycle_t &accumulator;
+protected:
+    const bool enabled;
+public:
+    inline SimpleActivityTimer(cycle_t &_accumulator, const bool _enabled)
+    : accumulator(_accumulator), enabled(_enabled)
+    {
+        if (enabled)
+            startCycles = get_cycles_now();
+        else
+            startCycles = 0;
+    }
+
+    inline ~SimpleActivityTimer()
+    {
+        if (enabled)
+        {
+            cycle_t nowCycles = get_cycles_now();
+            cycle_t elapsedCycles = nowCycles - startCycles;
             accumulator += elapsedCycles;
         }
     }
@@ -166,7 +234,11 @@ public:
 #else
 struct ActivityTimer
 {
-    inline ActivityTimer(unsigned __int64 &_accumulator, const bool _enabled, IActivityTimer *_iActivityTimer) { }
+    inline ActivityTimer(ActivityTimeAccumulator &_accumulator, const bool _enabled) { }
+};
+struct SimpleActivityTimer
+{
+    inline SimpleActivityTimer(unsigned __int64 &_accumulator, const bool _enabled) { }
 };
 #endif
 

+ 9 - 82
roxie/ccd/ccd.hpp

@@ -511,9 +511,9 @@ public:
         {
         case LOG_TRACING: return "TRACE";
         case LOG_ERROR: return "ERROR";
-        case LOG_TIMING: return "TIMING";
-        case LOG_STATISTICS: return "STATISTICS";
         case LOG_STATVALUES: return "STATVALUES";
+        case LOG_CHILDSTATS: return "CHILDSTATS";
+        case LOG_CHILDCOUNT: return "CHILDCOUNT";
         default: return "UNKNOWN";
         }
     }
@@ -547,84 +547,6 @@ public:
 
 };
 
-// Used as a base class by classes that want to intercept statistics but pass on other logging (i.e. slave or server activity classes)
-// Note that the stats are upmerged on destruction
-// Also note that we assume single-threaded access to stats.
-
-class IndirectContextLogger : public CInterface, implements IRoxieContextLogger
-{
-protected:
-    const IRoxieContextLogger *logctx;
-    bool aborted;
-    mutable CRuntimeStatisticCollection stats;
-
-public:
-    IMPLEMENT_IINTERFACE;
-
-    IndirectContextLogger(const IRoxieContextLogger *_logctx, const StatisticsMapping & _statsMapping)
-    : logctx(_logctx), stats(_statsMapping)
-    {
-        aborted = false;
-    }
-    ~IndirectContextLogger()
-    {
-        if (logctx)
-            logctx->mergeStats(stats);
-    }
-    inline void abort()
-    {
-        aborted = true;
-    }
-    virtual void noteStatistic(StatisticKind kind, unsigned __int64 value) const
-    {
-        if (aborted)
-            throw MakeStringException(ROXIE_ABORT_ERROR, "Roxie server requested abort for running activity");
-        stats.addStatistic(kind, value);
-    }
-    virtual void mergeStats(const CRuntimeStatisticCollection &from) const
-    {
-        stats.merge(from);
-    }
-    virtual const CRuntimeStatisticCollection &queryStats() const
-    {
-        return stats;
-    }
-
-    // The rest are passthroughs
-
-    virtual unsigned queryTraceLevel() const
-    {
-        return logctx ? logctx->queryTraceLevel() : traceLevel;
-    }
-    virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
-    {
-        return logctx ? logctx->getLogPrefix(ret) : ret;
-    }
-    virtual bool isIntercepted() const
-    {
-        return logctx ? logctx->isIntercepted() : false;
-    }
-    virtual void CTXLOGa(TracingCategory category, const char *prefix, const char *text) const
-    {
-        if (logctx)
-            logctx->CTXLOGa(category, prefix, text);
-    }
-    virtual void CTXLOGaeva(IException *E, const char *file, unsigned line, const char *prefix, const char *format, va_list args) const
-    {
-        if (logctx)
-            logctx->CTXLOGaeva(E, file, line, prefix, format, args);
-    }
-    virtual void CTXLOGl(LogItem *log) const
-    {
-        if (logctx)
-            logctx->CTXLOGl(log);
-    }
-    virtual bool isBlind() const
-    {
-        return logctx ? logctx->isBlind() : blindLogging;
-    }
-};
-
 // MORE - this code probably should be commoned up with some of the new stats code
 extern void putStatsValue(IPropertyTree *node, const char *statName, const char *statType, unsigned __int64 val);
 extern void putStatsValue(StringBuffer &reply, const char *statName, const char *statType, unsigned __int64 val);
@@ -786,8 +708,7 @@ public:
 class SlaveContextLogger : public StringContextLogger
 {
     Owned<IMessagePacker> output;
-    bool anyOutput;
-    bool traceActivityTimes;
+    mutable bool anyOutput; // messy
     bool debuggerActive;
     bool checkingHeap;
     IpAddress ip;
@@ -796,6 +717,8 @@ public:
     SlaveContextLogger();
     SlaveContextLogger(IRoxieQueryPacket *packet);
     void set(IRoxieQueryPacket *packet);
+    void putStatProcessed(unsigned subGraphId, unsigned actId, unsigned idx, unsigned processed) const;
+    void putStats(unsigned subGraphId, unsigned actId, const CRuntimeStatisticCollection &stats) const;
     void flush();
     inline bool queryDebuggerActive() const { return debuggerActive; }
     inline const CRuntimeStatisticCollection &queryStats() const
@@ -806,5 +729,9 @@ public:
     {
         return wuid.get();
     }
+    inline void abort()
+    {
+        aborted = true;
+    }
 };
 #endif

文件差异内容过多而无法显示
+ 151 - 158
roxie/ccd/ccdactivities.cpp


+ 1 - 1
roxie/ccd/ccdactivities.hpp

@@ -62,7 +62,7 @@ interface IRoxieSlaveActivity : extends IInterface
 
 interface ISlaveActivityFactory : extends IActivityFactory
 {
-    virtual IRoxieSlaveActivity *createActivity(IRoxieContextLogger &logctx, IRoxieQueryPacket *packet) const = 0;
+    virtual IRoxieSlaveActivity *createActivity(SlaveContextLogger &logctx, IRoxieQueryPacket *packet) const = 0;
     virtual StringBuffer &toString(StringBuffer &ret) const = 0;
     virtual const char *queryQueryName() const = 0;
     virtual void addChildQuery(unsigned id, ActivityArray *childQuery) = 0;

+ 125 - 107
roxie/ccd/ccdcontext.cpp

@@ -1013,9 +1013,11 @@ public:
 
 //---------------------------------------------------------------------------------------
 
-class CSlaveContext : public CInterface, implements IRoxieSlaveContext, implements ICodeContext, implements roxiemem::ITimeLimiter, implements IRowAllocatorMetaActIdCacheCallback
+class CRoxieContextBase : public CInterface, implements IRoxieSlaveContext, implements ICodeContext, implements roxiemem::ITimeLimiter, implements IRowAllocatorMetaActIdCacheCallback
 {
 protected:
+    Owned<IConstWUGraphProgress> progress;  // These need to be destroyed very late (particularly, after the childgraphs)
+    Owned<IWUGraphStats> graphStats;
     mutable Owned<IRowAllocatorMetaActIdCache> allocatorMetaCache;
     Owned<IRowManager> rowManager; // NOTE: the order of destruction here is significant. For leak check to work destroy this BEFORE allAllocators, but after most other things
     Owned <IDebuggableContext> debugContext;
@@ -1025,7 +1027,6 @@ protected:
     Owned<IActivityGraph> graph;
     StringBuffer authToken;
     Owned<IPropertyTree> probeQuery;
-    RoxiePacketHeader *header;
     unsigned lastWuAbortCheck;
     unsigned startTime;
     unsigned totSlavesReplyLen;
@@ -1096,34 +1097,15 @@ protected:
 
 public:
     IMPLEMENT_IINTERFACE;
-    CSlaveContext(const IQueryFactory *_factory, const IRoxieContextLogger &_logctx, IRoxieQueryPacket *_packet, bool _hasChildren)
+    CRoxieContextBase(const IQueryFactory *_factory, const IRoxieContextLogger &_logctx)
         : factory(_factory), logctx(_logctx), options(factory->queryOptions())
     {
-        bool debuggerActive = false;
-        if (_packet)
-        {
-            header = &_packet->queryHeader();
-            const byte *traceInfo = _packet->queryTraceInfo();
-            options.setFromSlaveLoggingFlags(*traceInfo);
-            debuggerActive = (*traceInfo & LOGGING_DEBUGGERACTIVE) != 0 && _hasChildren;  // No option to debug simple remote activity
-        }
-        else
-            header = NULL;
         startTime = lastWuAbortCheck = msTick();
         persists = NULL;
         temporaries = NULL;
         deserializedResultStore = NULL;
         rereadResults = NULL;
         xmlStoredDatasetReadFlags = ptr_none;
-        if (debuggerActive)
-        {
-            assertex(header);
-            CSlaveDebugContext *slaveDebugContext = new CSlaveDebugContext(this, logctx, *header);
-            slaveDebugContext->init(_packet);
-            debugContext.setown(slaveDebugContext);
-            probeManager.setown(createDebugManager(debugContext, "slaveDebugger"));
-        }
-
         aborted = false;
         exceptionLogged = false;
         totSlavesReplyLen = 0;
@@ -1133,7 +1115,7 @@ public:
         //MORE: If checking heap required then should have
         //rowManager.setown(createCheckingHeap(rowManager)) or something similar.
     }
-    ~CSlaveContext()
+    ~CRoxieContextBase()
     {
         ::Release(rereadResults);
         ::Release(persists);
@@ -1208,41 +1190,6 @@ public:
         return logctx.queryTraceLevel();
     }
 
-    virtual void noteProcessed(const IRoxieContextLogger &activityContext, const IRoxieServerActivity *activity, unsigned _idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const
-    {
-        if (options.traceActivityTimes)
-        {
-            StringBuffer text, prefix;
-            text.appendf("%s outputIdx %d processed %d total %d us local %d us",
-                getActivityText(activity->getKind()), _idx, _processed, (unsigned) (cycle_to_nanosec(_totalCycles)/1000), (unsigned)(cycle_to_nanosec(_localCycles)/1000));
-            activityContext.getLogPrefix(prefix);
-            CTXLOGa(LOG_TIMING, prefix.str(), text.str());
-        }
-        if (graphStats)
-        {
-            IStatisticGatherer & builder = graphStats->queryStatsBuilder();
-            StatsSubgraphScope graphScope(builder, activity->querySubgraphId());
-
-            {
-                StatsActivityScope scope(builder, activity->queryId());
-                //MORE: This is potentially problematic if noteProcessed is called for multiple edges => check if totalCycles is 0.
-                //There should really be two separate functions - one to update activity statistics, and another for edge statistics
-                if (_totalCycles)
-                {
-                    builder.addStatistic(StTimeTotalExecute, cycle_to_nanosec(_totalCycles));
-                    builder.addStatistic(StTimeLocalExecute, cycle_to_nanosec(_localCycles));
-                }
-                //MORE: Should this be done via a callback instead - so the activity can add stats for when started + other interesting info
-            }
-
-            if (_processed)
-            {
-                StatsEdgeScope scope(builder, activity->queryId(), _idx);
-                builder.addStatistic(StNumRowsProcessed, _processed);
-            }
-        }
-    }
-
     virtual void checkAbort()
     {
         // MORE - really should try to apply limits at slave end too
@@ -1360,9 +1307,6 @@ public:
         }
     }
 
-    Owned<IConstWUGraphProgress> progress;
-    Owned<IWUGraphStats> graphStats;
-
     void beginGraph(const char *graphName)
     {
         if (debugContext)
@@ -1522,47 +1466,11 @@ public:
         return (const char *) dll->getResource(id);
     }
 
-    virtual const IResolvedFile *resolveLFN(const char *filename, bool isOpt)
-    {
-        CDateTime cacheDate; // Note - this is empty meaning we don't know...
-        return querySlaveDynamicFileCache()->lookupDynamicFile(*this, filename, cacheDate, 0, header, isOpt, false);
-    }
-
-    virtual IRoxieWriteHandler *createLFN(const char *filename, bool overwrite, bool extend, const StringArray &clusters)
-    {
-        throwUnexpected(); // only support writing on the server
-    }
-
-    virtual void onFileCallback(const RoxiePacketHeader &header, const char *lfn, bool isOpt, bool isLocal)
-    {
-        // On a slave, we need to request info using our own header (not the one passed in) and need to get global rather than just local info
-        // (possibly we could get just local if the channel matches but not sure there is any point)
-        Owned<const IResolvedFile> dFile = resolveLFN(lfn, isOpt);
-        if (dFile)
-        {
-            MemoryBuffer mb;
-            mb.append(sizeof(RoxiePacketHeader), &header);
-            mb.append(lfn);
-            dFile->serializePartial(mb, header.channel, isLocal);
-            ((RoxiePacketHeader *) mb.toByteArray())->activityId = ROXIE_FILECALLBACK;
-            Owned<IRoxieQueryPacket> reply = createRoxiePacket(mb);
-            reply->queryHeader().retries = 0;
-            ROQ->sendPacket(reply, *this); // MORE - the caller's log context might be better? Should we unicast? Note that this does not release the packet
-            return;
-        }
-        ROQ->sendAbortCallback(header, lfn, *this);
-        throwUnexpected();
-    }
     virtual ICodeContext *queryCodeContext()
     {
         return this;
     }
 
-    virtual IRoxieServerContext *queryServerContext()
-    {
-        return NULL;
-    }
-
     virtual IProbeManager *queryProbeManager() const
     {
         return probeManager;
@@ -1593,7 +1501,7 @@ public:
     virtual IEngineContext *queryEngineContext() { return NULL; }
     virtual char *getDaliServers() { throwUnexpected(); }
 
-    // The following from ICodeContext should never be executed in slave activity. If we are on Roxie server (or in child query on slave), they will be implemented by more derived CRoxieServerContext class
+    // The following from ICodeContext should never be executed in slave activity. If we are on Roxie server, they will be implemented by more derived CRoxieServerContext class
     virtual void setResultBool(const char *name, unsigned sequence, bool value) { throwUnexpected(); }
     virtual void setResultData(const char *name, unsigned sequence, int len, const void * data) { throwUnexpected(); }
     virtual void setResultDecimal(const char * stepname, unsigned sequence, int len, int precision, bool isSigned, const void *val) { throwUnexpected(); }
@@ -2360,11 +2268,94 @@ protected:
     }
 };
 
-IRoxieSlaveContext *createSlaveContext(const IQueryFactory *_factory, const IRoxieContextLogger &_logctx, IRoxieQueryPacket *packet, bool hasChildren)
+//-----------------------------------------------------------------------------------------------
+
+class CSlaveContext : public CRoxieContextBase
+{
+protected:
+    RoxiePacketHeader *header;
+
+public:
+    CSlaveContext(const IQueryFactory *_factory, const SlaveContextLogger &_logctx, IRoxieQueryPacket *_packet, bool _hasChildren)
+    : CRoxieContextBase(_factory, _logctx)
+    {
+        header = &_packet->queryHeader();
+        const byte *traceInfo = _packet->queryTraceInfo();
+        options.setFromSlaveLoggingFlags(*traceInfo);
+        bool debuggerActive = (*traceInfo & LOGGING_DEBUGGERACTIVE) != 0 && _hasChildren;  // No option to debug simple remote activity
+        if (debuggerActive)
+        {
+            CSlaveDebugContext *slaveDebugContext = new CSlaveDebugContext(this, logctx, *header);
+            slaveDebugContext->init(_packet);
+            debugContext.setown(slaveDebugContext);
+            probeManager.setown(createDebugManager(debugContext, "slaveDebugger"));
+        }
+    }
+    virtual void beforeDispose()
+    {
+        // NOTE: This is needed to ensure that owned activities are destroyed BEFORE I am,
+        // to avoid pure virtual calls when they come to call noteProcessed()
+        childGraphs.kill();
+    }
+
+    virtual IRoxieServerContext *queryServerContext()
+    {
+        return NULL;
+    }
+
+    virtual const IResolvedFile *resolveLFN(const char *filename, bool isOpt)
+    {
+        CDateTime cacheDate; // Note - this is empty meaning we don't know...
+        return querySlaveDynamicFileCache()->lookupDynamicFile(*this, filename, cacheDate, 0, header, isOpt, false);
+    }
+
+    virtual IRoxieWriteHandler *createLFN(const char *filename, bool overwrite, bool extend, const StringArray &clusters)
+    {
+        throwUnexpected(); // only support writing on the server
+    }
+
+    virtual void onFileCallback(const RoxiePacketHeader &header, const char *lfn, bool isOpt, bool isLocal)
+    {
+        // On a slave, we need to request info using our own header (not the one passed in) and need to get global rather than just local info
+        // (possibly we could get just local if the channel matches but not sure there is any point)
+        Owned<const IResolvedFile> dFile = resolveLFN(lfn, isOpt);
+        if (dFile)
+        {
+            MemoryBuffer mb;
+            mb.append(sizeof(RoxiePacketHeader), &header);
+            mb.append(lfn);
+            dFile->serializePartial(mb, header.channel, isLocal);
+            ((RoxiePacketHeader *) mb.toByteArray())->activityId = ROXIE_FILECALLBACK;
+            Owned<IRoxieQueryPacket> reply = createRoxiePacket(mb);
+            reply->queryHeader().retries = 0;
+            ROQ->sendPacket(reply, *this); // MORE - the caller's log context might be better? Should we unicast? Note that this does not release the packet
+            return;
+        }
+        ROQ->sendAbortCallback(header, lfn, *this);
+        throwUnexpected();
+    }
+
+    virtual void noteProcessed(unsigned subgraphId, unsigned activityId, unsigned _idx, unsigned _processed) const
+    {
+        const SlaveContextLogger &slaveLogCtx = static_cast<const SlaveContextLogger &>(logctx);
+        slaveLogCtx.putStatProcessed(subgraphId, activityId, _idx, _processed);
+    }
+
+    virtual void mergeActivityStats(const CRuntimeStatisticCollection &fromStats, unsigned subgraphId, unsigned activityId, const ActivityTimeAccumulator &_totalCycles, unsigned __int64 _localCycles) const
+    {
+        const SlaveContextLogger &slaveLogCtx = static_cast<const SlaveContextLogger &>(logctx);
+        slaveLogCtx.putStats(subgraphId, activityId, fromStats);
+    }
+
+};
+
+IRoxieSlaveContext *createSlaveContext(const IQueryFactory *_factory, const SlaveContextLogger &_logctx, IRoxieQueryPacket *packet, bool hasChildren)
 {
     return new CSlaveContext(_factory, _logctx, packet, hasChildren);
 }
 
+//-----------------------------------------------------------------------------------------------
+
 class CRoxieServerDebugContext : extends CBaseServerDebugContext
 {
     // Some questions:
@@ -2503,7 +2494,7 @@ public:
 
 };
 
-class CRoxieServerContext : public CSlaveContext, implements IRoxieServerContext, implements IGlobalCodeContext
+class CRoxieServerContext : public CRoxieContextBase, implements IRoxieServerContext, implements IGlobalCodeContext
 {
     const IQueryFactory *serverQueryFactory;
     CriticalSection daliUpdateCrit;
@@ -2633,7 +2624,7 @@ public:
     IMPLEMENT_IINTERFACE;
 
     CRoxieServerContext(const IQueryFactory *_factory, const IRoxieContextLogger &_logctx)
-        : CSlaveContext(_factory, _logctx, NULL, false), serverQueryFactory(_factory)
+        : CRoxieContextBase(_factory, _logctx), serverQueryFactory(_factory)
     {
         init();
         rowManager->setMemoryLimit(options.memoryLimit);
@@ -2642,7 +2633,7 @@ public:
     }
 
     CRoxieServerContext(IConstWorkUnit *_workUnit, const IQueryFactory *_factory, const ContextLogger &_logctx)
-        : CSlaveContext(_factory, _logctx, NULL, false), serverQueryFactory(_factory)
+        : CRoxieContextBase(_factory, _logctx), serverQueryFactory(_factory)
     {
         init();
         workUnit.set(_workUnit);
@@ -2657,7 +2648,7 @@ public:
     }
 
     CRoxieServerContext(IPropertyTree *_context, const IQueryFactory *_factory, SafeSocket &_client, TextMarkupFormat _mlFmt, bool _isRaw, bool _isBlocked, HttpHelper &httpHelper, bool _trim, const ContextLogger &_logctx, PTreeReaderOptions _xmlReadFlags, const char *_querySetName)
-        : CSlaveContext(_factory, _logctx, NULL, false), serverQueryFactory(_factory), querySetName(_querySetName)
+        : CRoxieContextBase(_factory, _logctx), serverQueryFactory(_factory), querySetName(_querySetName)
     {
         init();
         context.set(_context);
@@ -2696,9 +2687,36 @@ public:
         rowManager->setMemoryLimit(options.memoryLimit);
         authToken.append(httpHelper.queryAuthToken());
         workflow.setown(_factory->createWorkflowMachine(workUnit, false, logctx));
+    }
+
+    virtual void noteProcessed(unsigned subgraphId, unsigned activityId, unsigned _idx, unsigned _processed) const
+    {
+        if (_processed)
+        {
+            if (graphStats)
+            {
+                IStatisticGatherer & builder = graphStats->queryStatsBuilder();
+                StatsSubgraphScope graphScope(builder, subgraphId);
+                StatsEdgeScope scope(builder, activityId, _idx);
+                builder.addStatistic(StNumRowsProcessed, _processed);
+            }
+            logctx.noteStatistic(StNumRowsProcessed, _processed);
+        }
+    }
 
-        if (options.traceActivityTimes)
-            options.timeActivities = true;
+    virtual void mergeActivityStats(const CRuntimeStatisticCollection &fromStats, unsigned subgraphId, unsigned activityId, const ActivityTimeAccumulator &_totalCycles, unsigned __int64 _localCycles) const
+    {
+        if (graphStats)
+        {
+            IStatisticGatherer & builder = graphStats->queryStatsBuilder();
+            StatsSubgraphScope graphScope(builder, subgraphId);
+            StatsActivityScope scope(builder, activityId);
+            _totalCycles.addStatistics(builder);
+            if (_localCycles)
+                builder.addStatistic(StTimeLocalExecute, cycle_to_nanosec(_localCycles));
+            fromStats.recordStatistics(builder);
+        }
+        logctx.mergeStats(fromStats);
     }
 
     virtual roxiemem::IRowManager &queryRowManager()
@@ -2716,7 +2734,7 @@ public:
 
     virtual void checkAbort()
     {
-        CSlaveContext::checkAbort();
+        CRoxieContextBase::checkAbort();
         unsigned ticksNow = msTick();
         if (options.warnTimeLimit)
         {
@@ -3479,7 +3497,7 @@ public:
     virtual void endGraph(cycle_t startCycles, bool aborting)
     {
         fileCache.kill();
-        CSlaveContext::endGraph(startCycles, aborting);
+        CRoxieContextBase::endGraph(startCycles, aborting);
     }
 
     virtual void onFileCallback(const RoxiePacketHeader &header, const char *lfn, bool isOpt, bool isLocal)

+ 3 - 2
roxie/ccd/ccdcontext.hpp

@@ -58,7 +58,8 @@ interface IRoxieSlaveContext : extends IRoxieContextLogger
     virtual IRoxieWriteHandler *createLFN(const char *filename, bool overwrite, bool extend, const StringArray &clusters) = 0;
     virtual void onFileCallback(const RoxiePacketHeader &header, const char *lfn, bool isOpt, bool isLocal) = 0;
     virtual IActivityGraph * getLibraryGraph(const LibraryCallFactoryExtra &extra, IRoxieServerActivity *parentActivity) = 0;
-    virtual void noteProcessed(const IRoxieContextLogger &_activityContext, const IRoxieServerActivity *activity, unsigned _idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const = 0;
+    virtual void noteProcessed(unsigned subgraphId, unsigned activityId, unsigned _idx, unsigned _processed) const = 0;
+    virtual void mergeActivityStats(const CRuntimeStatisticCollection &fromStats, unsigned subgraphId, unsigned activityId, const ActivityTimeAccumulator &_totalCycles, unsigned __int64 _localCycles) const = 0;
     virtual IProbeManager *queryProbeManager() const = 0;
     virtual IDebuggableContext *queryDebugContext() const = 0;
     virtual void printResults(IXmlWriter *output, const char *name, unsigned sequence) = 0;
@@ -105,7 +106,7 @@ typedef IEclProcess* (* EclProcessFactory)();
 class CRoxieWorkflowMachine;
 
 extern IDeserializedResultStore *createDeserializedResultStore();
-extern IRoxieSlaveContext *createSlaveContext(const IQueryFactory *factory, const IRoxieContextLogger &logctx, IRoxieQueryPacket *packet, bool hasRemoteChildren);
+extern IRoxieSlaveContext *createSlaveContext(const IQueryFactory *factory, const SlaveContextLogger &logctx, IRoxieQueryPacket *packet, bool hasRemoteChildren);
 extern IRoxieServerContext *createRoxieServerContext(IPropertyTree *context, const IQueryFactory *factory, SafeSocket &client, bool isXml, bool isRaw, bool isBlocked, HttpHelper &httpHelper, bool trim, const ContextLogger &logctx, PTreeReaderOptions xmlReadFlags, const char *querySetName);
 extern IRoxieServerContext *createOnceServerContext(const IQueryFactory *factory, const IRoxieContextLogger &_logctx);
 extern IRoxieServerContext *createWorkUnitServerContext(IConstWorkUnit *wu, const IQueryFactory *factory, const ContextLogger &logctx);

+ 3 - 7
roxie/ccd/ccdquery.cpp

@@ -288,7 +288,6 @@ QueryOptions::QueryOptions()
     enableFieldTranslation = fieldTranslationEnabled;
     skipFileFormatCrcCheck = false;
     stripWhitespaceFromStoredDataset = ((ptr_ignoreWhiteSpace & defaultXmlReadFlags) != 0);
-    traceActivityTimes = false;   // No global default for this
     timeActivities = defaultTimeActivities;
 }
 
@@ -313,7 +312,6 @@ QueryOptions::QueryOptions(const QueryOptions &other)
     skipFileFormatCrcCheck = other.skipFileFormatCrcCheck;
     stripWhitespaceFromStoredDataset = other.stripWhitespaceFromStoredDataset;
     timeActivities =other.timeActivities;
-    traceActivityTimes = other.traceActivityTimes;
 }
 
 void QueryOptions::setFromWorkUnit(IConstWorkUnit &wu, const IPropertyTree *stateInfo)
@@ -347,7 +345,6 @@ void QueryOptions::setFromWorkUnit(IConstWorkUnit &wu, const IPropertyTree *stat
     updateFromWorkUnit(skipFileFormatCrcCheck, wu, "skipFileFormatCrcCheck");
     updateFromWorkUnit(stripWhitespaceFromStoredDataset, wu, "stripWhitespaceFromStoredDataset");
     updateFromWorkUnit(timeActivities, wu, "timeActivities");
-    updateFromWorkUnit(traceActivityTimes, wu, "traceActivityTimes");
 }
 
 void QueryOptions::updateFromWorkUnitM(memsize_t &value, IConstWorkUnit &wu, const char *name)
@@ -391,7 +388,6 @@ void QueryOptions::setFromContext(const IPropertyTree *ctx)
         updateFromContext(skipFileFormatCrcCheck, ctx, "_SkipFileFormatCrcCheck", "@skipFileFormatCrcCheck");
         updateFromContext(stripWhitespaceFromStoredDataset, ctx, "_StripWhitespaceFromStoredDataset", "@stripWhitespaceFromStoredDataset");
         updateFromContext(timeActivities, ctx, "@timeActivities", "_TimeActivities");
-        updateFromContext(traceActivityTimes, ctx, "@timing", "_TraceActivityTimes");
     }
 }
 
@@ -437,7 +433,7 @@ void QueryOptions::setFromSlaveLoggingFlags(unsigned loggingFlags)
 {
     // MORE - priority/timelimit ?
     checkingHeap = (loggingFlags & LOGGING_CHECKINGHEAP) != 0;
-    traceActivityTimes = (loggingFlags & LOGGING_TIMEACTIVITIES) != 0;
+    timeActivities = (loggingFlags & LOGGING_TIMEACTIVITIES) != 0;
 }
 
 //----------------------------------------------------------------------------------------------
@@ -1449,7 +1445,7 @@ public:
         return strdup(result ? result : defaultValue);
     }
 
-    virtual IRoxieSlaveContext *createSlaveContext(const IRoxieContextLogger &logctx, IRoxieQueryPacket *packet, bool hasChildren) const
+    virtual IRoxieSlaveContext *createSlaveContext(const SlaveContextLogger &logctx, IRoxieQueryPacket *packet, bool hasChildren) const
     {
         throwUnexpected();   // only implemented in derived slave class
     }
@@ -1846,7 +1842,7 @@ public:
     {
     }
 
-    virtual IRoxieSlaveContext *createSlaveContext(const IRoxieContextLogger &logctx, IRoxieQueryPacket *packet, bool hasChildren) const
+    virtual IRoxieSlaveContext *createSlaveContext(const SlaveContextLogger &logctx, IRoxieQueryPacket *packet, bool hasChildren) const
     {
         return ::createSlaveContext(this, logctx, packet, hasChildren);
     }

+ 1 - 2
roxie/ccd/ccdquery.hpp

@@ -114,7 +114,6 @@ public:
     bool skipFileFormatCrcCheck;
     bool stripWhitespaceFromStoredDataset;
     bool timeActivities;
-    bool traceActivityTimes;
 
 private:
     static const char *findProp(const IPropertyTree *ctx, const char *name1, const char *name2);
@@ -130,7 +129,7 @@ private:
 
 interface IQueryFactory : extends IInterface
 {
-    virtual IRoxieSlaveContext *createSlaveContext(const IRoxieContextLogger &logctx, IRoxieQueryPacket *packet, bool hasChildren) const = 0;
+    virtual IRoxieSlaveContext *createSlaveContext(const SlaveContextLogger &logctx, IRoxieQueryPacket *packet, bool hasChildren) const = 0;
     virtual IActivityGraph *lookupGraph(const char *name, IProbeManager *probeManager, const IRoxieContextLogger &logctx, IRoxieServerActivity *parentActivity) const = 0;
     virtual ISlaveActivityFactory *getSlaveActivityFactory(unsigned id) const = 0;
     virtual IRoxieServerActivityFactory *getRoxieServerActivityFactory(unsigned id) const = 0;

+ 33 - 3
roxie/ccd/ccdqueue.cpp

@@ -466,7 +466,6 @@ void SlaveContextLogger::set(IRoxieQueryPacket *packet)
     intercept = false;
     debuggerActive = false;
     checkingHeap = false;
-    traceActivityTimes = false;
     stats.reset();
     start = msTick();
     if (packet)
@@ -487,8 +486,6 @@ void SlaveContextLogger::set(IRoxieQueryPacket *packet)
                 ctxTraceLevel = (*traceInfo++ - 1); // avoid null byte here in case anyone still thinks there's just a null-terminated string
                 traceLength--;
             }
-            if (loggingFlags & LOGGING_TIMEACTIVITIES)
-                traceActivityTimes = true;
             if (loggingFlags & LOGGING_BLIND)
                 blind = true;
             if (loggingFlags & LOGGING_CHECKINGHEAP)
@@ -533,6 +530,39 @@ void SlaveContextLogger::set(IRoxieQueryPacket *packet)
     }
 }
 
+
+void SlaveContextLogger::putStatProcessed(unsigned subGraphId, unsigned actId, unsigned idx, unsigned processed) const
+{
+    if (output && mergeSlaveStatistics)
+    {
+        MemoryBuffer buf;
+        buf.append((char) LOG_CHILDCOUNT); // A special log entry for the stats
+        buf.append(subGraphId);
+        buf.append(actId);
+        buf.append(idx);
+        buf.append(processed);
+    }
+}
+
+void SlaveContextLogger::putStats(unsigned subGraphId, unsigned actId, const CRuntimeStatisticCollection &stats) const
+{
+    if (output && mergeSlaveStatistics)
+    {
+        MemoryBuffer buf;
+        buf.append((char) LOG_CHILDSTATS); // A special log entry for the stats
+        buf.append(subGraphId);
+        buf.append(actId);
+        if (stats.serialize(buf))
+        {
+            unsigned len = buf.length();
+            void *ret = output->getBuffer(len, true);
+            memcpy(ret, buf.toByteArray(), len);
+            output->putBuffer(ret, len, true);
+            anyOutput = true;
+        }
+    }
+}
+
 void SlaveContextLogger::flush()
 {
     if (output)

文件差异内容过多而无法显示
+ 303 - 250
roxie/ccd/ccdserver.cpp


+ 3 - 1
roxie/ccd/ccdserver.hpp

@@ -200,7 +200,8 @@ interface IRoxieServerActivityFactory : extends IActivityFactory
     virtual IOutputMetaData *queryOutputMeta() const = 0;
     virtual IHThorArg &getHelper() const = 0;
     virtual IRoxieServerActivity *createFunction(IHThorArg &helper, IProbeManager *_probeManager) const = 0;
-    virtual void noteProcessed(unsigned idx, unsigned processed, unsigned __int64 totalCycles, unsigned __int64 localCycles) const = 0;
+    virtual void noteProcessed(unsigned idx, unsigned processed) const = 0;
+    virtual void mergeActivityStats(const CRuntimeStatisticCollection &fromStats, const ActivityTimeAccumulator &totalCycles, unsigned __int64 localCycles) const = 0;
     virtual void onCreateChildQueries(IRoxieSlaveContext *ctx, IHThorArg *colocalArg, IArrayOf<IActivityGraph> &childGraphs) const = 0;
     virtual void createChildQueries(IArrayOf<IActivityGraph> &childGraphs, IRoxieServerActivity *parentActivity, IProbeManager *_probeManager, const IRoxieContextLogger &_logctx) const = 0;
     virtual void noteStarted() const = 0;
@@ -212,6 +213,7 @@ interface IRoxieServerActivityFactory : extends IActivityFactory
     virtual IRoxieServerSideCache *queryServerSideCache() const = 0;
     virtual IDefRecordMeta *queryActivityMeta() const = 0;
     virtual unsigned numInputs() const = 0;
+    virtual const StatisticsMapping &queryStatsMapping() const = 0;
 };
 interface IGraphResult : public IInterface
 {

+ 39 - 10
system/jlib/jstats.cpp

@@ -499,6 +499,7 @@ static const StatisticMeta statsMetaData[StMax] = {
     { NUMSTAT(DiskAccepted) },
     { NUMSTAT(DiskRejected) },
     { TIMESTAT(Soapcall) },
+    { TIMESTAT(FirstExecute) },
 };
 
 
@@ -688,7 +689,24 @@ StatisticsMapping::StatisticsMapping(StatisticKind kind, ...)
         unsigned next  = va_arg(args, unsigned);
         if (!next)
             break;
-        indexToKind.append(next);
+        indexToKind.appendUniq(next);
+    }
+    va_end(args);
+    createMappings();
+}
+
+StatisticsMapping::StatisticsMapping(const StatisticsMapping &from, ...)
+{
+    ForEachItemIn(idx, from.indexToKind)
+        indexToKind.append(from.indexToKind.item(idx));
+    va_list args;
+    va_start(args, from);
+    for (;;)
+    {
+        unsigned next  = va_arg(args, unsigned);
+        if (!next)
+            break;
+        indexToKind.appendUniq(next);
     }
     va_end(args);
     createMappings();
@@ -1317,8 +1335,12 @@ void CRuntimeStatisticCollection::merge(const CRuntimeStatisticCollection & othe
     ForEachItemIn(i, other)
     {
         StatisticKind kind = other.getKind(i);
-        StatsMergeAction mergeAction = queryMergeMode(kind);
-        mergeStatistic(kind, other.getStatisticValue(kind), mergeAction);
+        unsigned __int64 value = other.getStatisticValue(kind);
+        if (value)
+        {
+            StatsMergeAction mergeAction = queryMergeMode(kind);
+            mergeStatistic(kind, other.getStatisticValue(kind), mergeAction);
+        }
     }
 }
 
@@ -1326,10 +1348,13 @@ void CRuntimeStatisticCollection::rollupStatistics(unsigned numTargets, IContext
 {
     ForEachItem(iStat)
     {
-        StatisticKind kind = getKind(iStat);
         unsigned __int64 value = values[iStat].getClear();
-        for (unsigned iTarget = 0; iTarget < numTargets; iTarget++)
-            targets[iTarget]->noteStatistic(kind, value);
+        if (value)
+        {
+            StatisticKind kind = getKind(iStat);
+            for (unsigned iTarget = 0; iTarget < numTargets; iTarget++)
+                targets[iTarget]->noteStatistic(kind, value);
+        }
     }
     reportIgnoredStats();
 }
@@ -1338,9 +1363,13 @@ void CRuntimeStatisticCollection::recordStatistics(IStatisticGatherer & target)
 {
     ForEachItem(i)
     {
-        StatisticKind kind = getKind(i);
-        StatsMergeAction mergeAction = queryMergeMode(kind);
-        target.updateStatistic(kind, values[i].get(), mergeAction);
+        unsigned __int64 value = values[i].get();
+        if (value)
+        {
+            StatisticKind kind = getKind(i);
+            StatsMergeAction mergeAction = queryMergeMode(kind);
+            target.updateStatistic(kind, values[i].get(), mergeAction);
+        }
     }
     reportIgnoredStats();
 }
@@ -1348,7 +1377,7 @@ void CRuntimeStatisticCollection::recordStatistics(IStatisticGatherer & target)
 void CRuntimeStatisticCollection::reportIgnoredStats() const
 {
     if (values[mapping.numStatistics()].getClear())
-        DBGLOG("Some statistics were addded but thrown away");
+        DBGLOG("Some statistics were added but thrown away");
 }
 
 StringBuffer & CRuntimeStatisticCollection::toXML(StringBuffer &str) const

+ 6 - 1
system/jlib/jstats.h

@@ -98,7 +98,7 @@ enum StatisticMeasure
     St ## NodeMax ## y = (St ## x ## y | StNodeMax),
 
 //The values in this enumeration are stored persistently.  The associated values must not be changed.
-//If you add an entry here you must also update queryMeasure(), queryStatisticName() and queryTreeTag()
+//If you add an entry here you must also update statsMetaData
 //NOTE: All statistic names should be unique with the type prefix removed. Since the prefix is replaced with Skew/Min/etc.
 enum StatisticKind
 {
@@ -160,6 +160,7 @@ enum StatisticKind
     StNumDiskRejected,
 
     StTimeSoapcall,                     // Time spent waiting for soapcalls
+    StTimeFirstExecute,                 // Time waiting for first record from this activity
 
     StMax,
 
@@ -406,6 +407,8 @@ class jlib_decl StatisticsMapping
 public:
     //Takes a list of StatisticKind terminated by StKindNone
     StatisticsMapping(StatisticKind kind, ...);
+    //Takes an existing Mapping, and extends it with a list of StatisticKind terminated by StKindNone
+    StatisticsMapping(const StatisticsMapping &, ...);
     //Accepts all StatisticKind values
     StatisticsMapping();
 
@@ -475,11 +478,13 @@ public:
     inline CRuntimeStatistic & queryStatistic(StatisticKind kind)
     {
         unsigned index = queryMapping().getIndex(kind);
+        dbgassertex(index < mapping.numStatistics());
         return values[index];
     }
     inline const CRuntimeStatistic & queryStatistic(StatisticKind kind) const
     {
         unsigned index = queryMapping().getIndex(kind);
+        dbgassertex(index < mapping.numStatistics());
         return values[index];
     }
 

+ 4 - 4
thorlcr/activities/aggregate/thaggregateslave.cpp

@@ -154,7 +154,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         doStart();
         eof = false;
         dataLinkStart();
@@ -166,7 +166,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (abortSoon || eof)
             return NULL;
         eof = true;
@@ -265,7 +265,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         doStart();
         aggrowif.setown(createRowInterfaces(helper->queryAggregateRecordSize(),queryActivityId(),queryCodeContext()));
         partResult.setAllocator(aggrowif->queryRowAllocator()).ensureRow();
@@ -283,7 +283,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (inputStopped)
             return NULL;
         OwnedConstThorRow row = input->ungroupedNextRow();

+ 2 - 2
thorlcr/activities/aggregate/thgroupaggregateslave.cpp

@@ -42,7 +42,7 @@ public:
 
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         eof = false;
         input=inputs.item(0);
         startInput(input);
@@ -58,7 +58,7 @@ public:
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (abortSoon || eof)
             return NULL;
         RtlDynamicRowBuilder out(queryRowAllocator());

+ 1 - 1
thorlcr/activities/apply/thapplyslave.cpp

@@ -51,7 +51,7 @@ public:
                 helper->start();
             while(!abortSoon)
             {
-                ActivityTimer t(totalCycles, timeActivities, NULL);
+                ActivityTimer t(totalCycles, timeActivities);
                 OwnedConstThorRow r = input->ungroupedNextRow();
                 if (!r)
                     break;

+ 5 - 5
thorlcr/activities/catch/thcatchslave.cpp

@@ -67,12 +67,12 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         CCatchSlaveActivityBase::start();
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!eos)
         {
             try
@@ -110,7 +110,7 @@ public:
         {
             try
             {
-                ActivityTimer t(totalCycles, timeActivities, NULL);
+                ActivityTimer t(totalCycles, timeActivities);
                 OwnedConstThorRow ret = input->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
                 if (ret && wasCompleteMatch)
                     dataLinkIncrement();
@@ -216,14 +216,14 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         CCatchSlaveActivityBase::start();
         running = gathered = false;
         grouped = input->isGrouped();
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eos)
             return NULL;
         if (!gathered)

+ 7 - 7
thorlcr/activities/choosesets/thchoosesetsslave.cpp

@@ -68,7 +68,7 @@ public:
     LocalChooseSetsActivity(CGraphElementBase *container) : BaseChooseSetsActivity(container) { }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         BaseChooseSetsActivity::start();
         ActPrintLog("CHOOSESETS: Is Local");
         input.set(inputs.item(0));
@@ -85,7 +85,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         loop
         {
             OwnedConstThorRow row = input->ungroupedNextRow();
@@ -159,7 +159,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         ActPrintLog("CHOOSESETS: Is Global");
         BaseChooseSetsActivity::start();
         first = true;
@@ -188,7 +188,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (first) 
         {
             first = false;
@@ -301,7 +301,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         ActPrintLog("CHOOSESETS: Is Global");
         if (counts)
         {
@@ -423,7 +423,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (first) 
         {
             first = false;
@@ -502,7 +502,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (first) 
         {
             first = false;

+ 4 - 4
thorlcr/activities/countproject/thcountprojectslave.cpp

@@ -66,7 +66,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         ActPrintLog("COUNTPROJECT: Is Local");
         input.set(inputs.item(0));
         anyThisGroup = false;
@@ -75,7 +75,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         while (!abortSoon)
         {
             OwnedConstThorRow row(input->nextRow());
@@ -167,7 +167,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         ActPrintLog( "COUNTPROJECT: Is Global");
         first = true;
         prevRecCount = 0;
@@ -197,7 +197,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (first) 
         {
             first = false;

+ 2 - 2
thorlcr/activities/csvread/thcsvrslave.cpp

@@ -368,7 +368,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         OwnedConstThorRow row = out->nextRow();
         if (row)
         {
@@ -388,7 +388,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         CDiskReadSlaveActivityBase::start();
         if (headerLines)
         {

+ 3 - 3
thorlcr/activities/degroup/thdegroupslave.cpp

@@ -39,7 +39,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input = inputs.item(0);
 
         startInput(input);
@@ -53,7 +53,7 @@ public:
     }
     CATCH_NEXTROW()
     {   
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!abortSoon)
         {
             OwnedConstThorRow row = input->ungroupedNextRow();
@@ -73,7 +73,7 @@ public:
     }
     const void *nextRowGENoCatch(const void *seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra &stepExtra)
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!abortSoon)
         {
             OwnedConstThorRow row = input->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);

+ 10 - 10
thorlcr/activities/diskread/thdiskreadslave.cpp

@@ -449,7 +449,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         CDiskReadSlaveActivityRecord::start();
         out = createSequentialPartHandler(partHandler, partDescs, grouped); // **
         dataLinkStart();
@@ -469,7 +469,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (NULL == out) // guard against, but shouldn't happen
             return NULL;
         OwnedConstThorRow ret = out->nextRow();
@@ -605,7 +605,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         CDiskReadSlaveActivityRecord::start();
         out = createSequentialPartHandler(partHandler, partDescs, false);
         dataLinkStart();
@@ -624,7 +624,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!out)
             return NULL;
         OwnedConstThorRow ret = out->nextRow();
@@ -729,7 +729,7 @@ public:
     virtual bool isGrouped() { return false; }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         CDiskReadSlaveActivityRecord::start();
         eoi = hadElement = false;
         dataLinkStart();
@@ -742,7 +742,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eoi)
             return NULL;
         RtlDynamicRowBuilder row(allocator);
@@ -847,7 +847,7 @@ public:
     virtual bool isGrouped() { return false; }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         CDiskReadSlaveActivityRecord::start();
         eoi = false;
         if (!helper->canMatchAny())
@@ -865,7 +865,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eoi)
             return NULL;
         unsigned __int64 totalCount = 0;
@@ -962,7 +962,7 @@ public:
 // IThorDataLink
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         CDiskReadSlaveActivityRecord::start();
         gathered = eoi = false;
         localAggTable.setown(new RowAggregator(*helper, *helper));
@@ -984,7 +984,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eoi)
             return NULL;
         if (!gathered)

+ 3 - 3
thorlcr/activities/enth/thenthslave.cpp

@@ -83,7 +83,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         IHThorEnthArg *helper = static_cast <IHThorEnthArg *> (queryHelper());
         counter = 0;
         denominator = validRC(helper->getProportionDenominator());
@@ -147,7 +147,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (localCountReq)
         {
             localCountReq = false;
@@ -239,7 +239,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (first)
         {
             first = false;

+ 2 - 2
thorlcr/activities/fetch/thfetchslave.cpp

@@ -358,7 +358,7 @@ public:
 // IThorDataLink impl.
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         class CKeyFieldExtractBase : public CSimpleInterface, implements IRowStream
         {
         protected:
@@ -471,7 +471,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (abortSoon)
             return NULL;
 

+ 8 - 8
thorlcr/activities/filter/thfilterslave.cpp

@@ -77,14 +77,14 @@ public:
     }
     void start()
     {   
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         matched = 0;
         abortSoon = !helper->canMatchAny();
         CFilterSlaveActivityBase::start();
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         while(!abortSoon)
         {
             OwnedConstThorRow row = input->nextRow();
@@ -116,7 +116,7 @@ public:
     }
     const void *nextRowGENoCatch(const void *seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra &stepExtra)
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         while (!abortSoon)
         {
             OwnedConstThorRow ret = input->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
@@ -186,14 +186,14 @@ public:
     }
     void start()
     {   
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         abortSoon = !helper->canMatchAny();
         recordCount = 0;
         CFilterSlaveActivityBase::start();
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         while (!abortSoon)
         {
             OwnedConstThorRow row = input->nextRow();
@@ -257,13 +257,13 @@ public:
     }
     void start()
     {   
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         abortSoon = !helper->canMatchAny();
         CFilterSlaveActivityBase::start();
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         while (!abortSoon)
         {
             if (groupStream)
@@ -302,7 +302,7 @@ public:
     }
     const void *nextRowGENoCatch(const void *seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra &stepExtra)
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (abortSoon)
             return NULL;
 

+ 5 - 5
thorlcr/activities/firstn/thfirstnslave.cpp

@@ -56,7 +56,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input.set(inputs.item(0));
         startInput(input);
         stopped = false;
@@ -102,7 +102,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!abortSoon)
         {
             if (firstget)
@@ -153,7 +153,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!abortSoon)
         {
             loop
@@ -241,7 +241,7 @@ public:
     void start()
     {
         CFirstNSlaveBase::start(); // adds to totalTime (common to local and global firstn)
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         totallimit = (rowcount_t)helper->getLimit();
         limit = maxres = RCUNBOUND;
         skipCount = 0;
@@ -324,7 +324,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!abortSoon) {
             if (firstget)
             {

+ 14 - 14
thorlcr/activities/funnel/thfunnelslave.cpp

@@ -336,13 +336,13 @@ public:
                 virtual bool isGrouped() { return false; }
                 virtual void start()
                 {
-                    ActivityTimer s(activity.getTotalCyclesRef(), activity.queryTimeActivities(), NULL);
+                    ActivityTimer s(activity.getTotalCyclesRef(), activity.queryTimeActivities());
                     out.setown(createParallelFunnel(activity, inputs.getArray(), inputs.ordinality(), true, abortSoon));
                     dataLinkStart();
                 }
                 const void *nextRow()
                 {
-                    ActivityTimer t(activity.getTotalCyclesRef(), activity.queryTimeActivities(), NULL);
+                    ActivityTimer t(activity.getTotalCyclesRef(), activity.queryTimeActivities());
                     OwnedConstThorRow row = out->nextRow();
                     if (row)
                     {
@@ -375,7 +375,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         eogNext = false;
         stopped = 0;
         if (grouped)
@@ -461,7 +461,7 @@ public:
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (current)
         {
             if (grouped)
@@ -549,7 +549,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         eogNext = false;
         ForEachItemIn(i, inputs)
         {
@@ -571,7 +571,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         loop {
             bool eog = false;
             bool err = false;
@@ -652,7 +652,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         curinput = 0;
         eogNext = false;
         ForEachItemIn(i, inputs)
@@ -675,7 +675,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         unsigned n = inputs.ordinality();
         loop {
             if (curinput==n) {
@@ -771,7 +771,7 @@ public:
 // IThorDataLink
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         curinput = 0;
         anyThisGroup = anyThisInput = eogNext = false;
         ForEachItemIn(i, inputs)
@@ -795,7 +795,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eoi) 
             return NULL; 
         if (eogNext) { 
@@ -852,7 +852,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
 
         startInput(inputs.item(0));
 
@@ -898,7 +898,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!selectedInput)
             return NULL;
         OwnedConstThorRow ret = selectedInput->nextRow();
@@ -924,7 +924,7 @@ public:
     }
     const void *nextRowGENoCatch(const void *seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra &stepExtra)
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!selectedInput)
             return NULL;
         return selectedInput->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
@@ -973,7 +973,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         bool selectionIsAll;
         size32_t selectionLen;
         rtlDataAttr selection;

+ 2 - 2
thorlcr/activities/group/thgroupslave.cpp

@@ -68,7 +68,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         ActPrintLog(rolloverEnabled ? "GROUP: is global" : "GROUP: is local");
         eogNext = prevEog = eof = false;
         if (rolloverEnabled)
@@ -132,7 +132,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eogNext || eof)
         {
             eogNext = false;

+ 12 - 12
thorlcr/activities/hashdistrib/thhashdistribslave.cpp

@@ -1798,7 +1798,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         start(false);
     }
     void stop()
@@ -1831,7 +1831,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL); // careful not to call again in derivatives
+        ActivityTimer t(totalCycles, timeActivities); // careful not to call again in derivatives
         if (abortSoon||eofin) {
             eofin = true;
             return NULL;
@@ -2121,7 +2121,7 @@ public:
     {
         bool passthrough;
         {
-            ActivityTimer s(totalCycles, timeActivities, NULL);
+            ActivityTimer s(totalCycles, timeActivities);
             instrm.setown(partitioner->calc(this,inputs.item(0),passthrough));  // may return NULL
         }
         HashDistributeSlaveBase::start(passthrough);
@@ -2653,7 +2653,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         inputstopped = false;
         eos = lastEog = false;
         startInput(inputs.item(0));
@@ -2693,7 +2693,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eos)
             return NULL;
         // bucket handlers, stream out non-duplicates (1st entry in HT)
@@ -3261,7 +3261,7 @@ public:
     void start()
     {
         HashDedupSlaveActivityBase::start();
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         Owned<IRowInterfaces> myRowIf = getRowInterfaces(); // avoiding circular link issues
         instrm.setown(distributor->connect(myRowIf, input, iHash, iCompare));
         input = instrm.get();
@@ -3344,7 +3344,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         inputLstopped = true;
         inputRstopped = true;
         leftdone = false;
@@ -3455,7 +3455,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!eof) {
             OwnedConstThorRow row = joinhelper->nextRow();
             if (row) {
@@ -3666,7 +3666,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input = inputs.item(0);
         startInput(input);
         doNextGroup(); // or local set if !grouped
@@ -3696,7 +3696,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eos) return NULL;
         Owned<AggregateRowBuilder> next = localAggTable->nextResult();
         if (next)
@@ -3755,7 +3755,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input = inputs.item(0);
         input->start();
         dataLinkStart();
@@ -3768,7 +3768,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         OwnedConstThorRow row = input->ungroupedNextRow();
         if (!row)
             return NULL;

+ 10 - 10
thorlcr/activities/indexread/thindexreadslave.cpp

@@ -627,7 +627,7 @@ public:
 // IThorDataLink
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         first = true;
         eoi = false;
         keyedLimit = helperKeyedLimit;
@@ -677,7 +677,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eoi) 
             return NULL;
         if (RCMAX != keyedLimitCount)
@@ -798,7 +798,7 @@ public:
     virtual bool isGrouped() { return false; }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         localAggTable.setown(new RowAggregator(*helper, *helper));
         localAggTable->start(queryRowAllocator());
         gathered = eoi = false;
@@ -811,7 +811,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eoi) 
             return NULL;
         if (!gathered)
@@ -900,7 +900,7 @@ public:
     virtual bool isGrouped() { return false; }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         eoi = false;
         if (!helper->canMatchAny())
         {
@@ -917,7 +917,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eoi)
             return NULL;
         rowcount_t totalCount = 0;
@@ -1065,7 +1065,7 @@ public:
     virtual bool isGrouped() { return false; }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         keyedLimit = (rowcount_t)helper->getKeyedLimit();
         rowLimit = (rowcount_t)helper->getRowLimit();
         if (helper->getFlags() & TIRlimitskips)
@@ -1109,7 +1109,7 @@ public:
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eoi)
             return NULL;
 
@@ -1251,7 +1251,7 @@ public:
     virtual bool isGrouped() { return false; }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         eoi = hadElement = false;
         partn = 0;
         dataLinkStart();
@@ -1265,7 +1265,7 @@ public:
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eoi)
             return NULL;
         eoi = true;

+ 4 - 4
thorlcr/activities/iterate/thgroupiterateslave.cpp

@@ -49,7 +49,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         anyThisGroup = false;
         eogNext = false;    
         count = 0;
@@ -67,7 +67,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         loop {
             if(abortSoon)
                 break;          
@@ -144,7 +144,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         RtlDynamicRowBuilder r(rightAllocator);
         size32_t sz = helper->createInitialRight(r);  
         firstright.setown(r.finalizeRowClear(sz));
@@ -162,7 +162,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         loop {
             if(abortSoon)
                 break;          

+ 8 - 8
thorlcr/activities/iterate/thiterateslave.cpp

@@ -75,7 +75,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         count = 0;
         eof = nextPut = false;
         inrowif.set(::queryRowInterfaces(inputs.item(0)));
@@ -128,7 +128,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         loop {
             if (eof || abortSoon)
                 break;
@@ -214,7 +214,7 @@ public:
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         loop {
             if (eof || abortSoon)
                 break;
@@ -299,7 +299,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         eof = !container.queryLocalOrGrouped() && !firstNode();
         count = 0;
         dataLinkStart();
@@ -310,7 +310,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!eof) {
             if (count==0)
                 eof = !helper->first();
@@ -357,7 +357,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         dataLinkStart();
         dohere = container.queryLocalOrGrouped() || firstNode();
     }
@@ -367,7 +367,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (dohere) {
             OwnedConstThorRow row;
             row.set(helper->next()); // needs linking allegedly
@@ -435,7 +435,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eof || abortSoon)
             return NULL;
         assertex(rows);

+ 3 - 3
thorlcr/activities/join/thjoinslave.cpp

@@ -228,7 +228,7 @@ public:
 
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         rightpartition = (container.getKind()==TAKjoin)&&((helper->getJoinFlags()&JFpartitionright)!=0);
 
         Linked<IRowInterfaces> primaryRowIf, secondaryRowIf;
@@ -376,7 +376,7 @@ public:
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if(joinhelper) 
         {
             OwnedConstThorRow row = joinhelper->nextRow();
@@ -613,7 +613,7 @@ public:
     }
     const void *nextRowGENoCatch(const void *seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra &stepExtra)
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         bool matched = true;
         OwnedConstThorRow next = processor.nextGE(seek, numFields, matched, stepExtra);
         if (next)

+ 2 - 2
thorlcr/activities/keyedjoin/thkeyedjoinslave.cpp

@@ -2031,7 +2031,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         assertex(inputs.ordinality() == 1);
 
         eos = false;
@@ -2120,7 +2120,7 @@ public:
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!abortSoon && !eos)
         {
             loop

+ 4 - 4
thorlcr/activities/limit/thlimitslave.cpp

@@ -60,7 +60,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         resultSent = container.queryLocal(); // i.e. local, so don't send result to master
         eos = stopped = anyThisGroup = eogNext = false;
         input = inputs.item(0);
@@ -100,7 +100,7 @@ public:
     
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eos)
             return NULL;
         while (!abortSoon && !eogNext)
@@ -142,7 +142,7 @@ public:
     }
     const void *nextRowGENoCatch(const void *seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra &stepExtra)
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         OwnedConstThorRow ret = input->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
         if (ret)
         {
@@ -261,7 +261,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eof) 
             return NULL;
         if (!limitChecked)

+ 4 - 4
thorlcr/activities/lookupjoin/thlookupjoinslave.cpp

@@ -1822,7 +1822,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         PARENT::start();
 
         if (!isSmart())
@@ -1843,7 +1843,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!gotRHS)
         {
             getRHS(false);
@@ -2310,12 +2310,12 @@ public:
 // IThorSlaveActivity overloaded methods
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         PARENT::start();
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!gotRHS)
             getRHS(false);
         OwnedConstThorRow row = lookupNextRow();

+ 15 - 15
thorlcr/activities/loop/thloopslave.cpp

@@ -258,7 +258,7 @@ public:
 // IThorDataLink
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         dostart();
         eof = false;
         helper->createParentExtract(extractBuilder);
@@ -296,7 +296,7 @@ public:
     }
     const void *getNextRow()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!abortSoon && !eof)
         {
             unsigned emptyIterations = 0;
@@ -452,7 +452,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         dostart();
         executed = false;
         maxIterations = helper->numIterations();
@@ -538,7 +538,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         curRow = 0;
         abortSoon = false;
         assertex(container.queryResultsGraph());
@@ -563,7 +563,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!abortSoon)
         {
             OwnedConstThorRow row = resultStream->nextRow();
@@ -619,7 +619,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         lastNull = eoi = false;
         abortSoon = false;
         assertex(container.queryResultsGraph());
@@ -631,7 +631,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!abortSoon && !eoi)
             return NULL;
         OwnedConstThorRow row = inputs.item(0)->nextRow();
@@ -821,7 +821,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         selectedInput = container.whichBranch>=inputs.ordinality() ? NULL : inputs.item(container.whichBranch);
         if (selectedInput)
             startInput(selectedInput);
@@ -836,7 +836,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (abortSoon)
             return NULL;
         if (!selectedInput)
@@ -887,7 +887,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         started = false;
         eos = false;
         ok = false;
@@ -962,7 +962,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         eos = false;
         dataLinkStart();
     }
@@ -1016,7 +1016,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         gathered = eos = false;
         aggregated.clear();
         aggregated.setown(new RowAggregator(*helper, *helper));
@@ -1090,7 +1090,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         ok = false;
         numProcessedLastGroup = getDataLinkCount(); // is this right?
         lastInput.clear();
@@ -1179,7 +1179,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         abortSoon = false;
         unsigned sequence = helper->querySequence();
         if ((int)sequence >= 0)
@@ -1199,7 +1199,7 @@ public:
     virtual bool isGrouped() { return false; }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!abortSoon)
         {
             OwnedConstThorRow row = resultStream->nextRow();

+ 5 - 5
thorlcr/activities/merge/thmergeslave.cpp

@@ -282,7 +282,7 @@ public:
 // IThorDataLink
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         ForEachItemIn(i, inputs) {
             IThorDataLink * input = inputs.item(i);
             try {
@@ -435,7 +435,7 @@ public:
 // IThorDataLink
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         ForEachItemIn(i, inputs) {
             IThorDataLink * input = inputs.item(i);
             try { 
@@ -472,7 +472,7 @@ public:
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!abortSoon) {
             OwnedConstThorRow row = out->nextRow();
             if (row) {
@@ -565,7 +565,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         OwnedConstThorRow ret = merger.nextRow();
         if (ret)
         {
@@ -581,7 +581,7 @@ public:
     }
     const void *nextRowGENoCatch(const void *seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra &stepExtra)
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         OwnedConstThorRow ret = merger.nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
         if (ret)
         {

+ 5 - 5
thorlcr/activities/msort/thgroupsortslave.cpp

@@ -56,7 +56,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         dataLinkStart();
         input = inputs.item(0);
         unsigned spillPriority = container.queryGrouped() ? SPILL_PRIORITY_GROUPSORT : SPILL_PRIORITY_LARGESORT;
@@ -79,7 +79,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (abortSoon || eoi)
             return NULL;
         OwnedConstThorRow row = out->nextRow();
@@ -136,7 +136,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         dataLinkStart();
         input = inputs.item(0);
         startInput(input);
@@ -151,7 +151,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         OwnedConstThorRow ret = input->nextRow();
         if (ret && prev && icompare->docompare(prev, ret) > 0)
         {
@@ -170,7 +170,7 @@ public:
     }
     const void *nextRowGENoCatch(const void *seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra &stepExtra)
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         OwnedConstThorRow ret = input->nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
         if (ret && prev && stepCompare->docompare(prev, ret, numFields) > 0)
         {

+ 2 - 2
thorlcr/activities/msort/thmsortslave.cpp

@@ -83,7 +83,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input = inputs.item(0);
         try
         {
@@ -177,7 +177,7 @@ public:
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (abortSoon) 
             return NULL;
         OwnedConstThorRow row = output->nextRow();

+ 6 - 6
thorlcr/activities/normalize/thnormalizeslave.cpp

@@ -52,7 +52,7 @@ public:
     }
     void start()
     { 
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         numThisRow = 0;
         curRow = 0;
         anyThisGroup = false;
@@ -67,7 +67,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         loop
         {
             while (curRow == numThisRow)
@@ -137,7 +137,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input = inputs.item(0);
         startInput(input);
         anyThisGroup = false;
@@ -151,7 +151,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         loop {
             while(!curChildRow) {
                 curRow = 0;
@@ -235,7 +235,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input = inputs.item(0);
         startInput(input);
         anyThisGroup = false;
@@ -248,7 +248,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         loop
         {
             if (!curParent)

+ 8 - 9
thorlcr/activities/nsplitter/thnsplitterslave.cpp

@@ -28,14 +28,13 @@ class NSplitterSlaveActivity;
 class CSplitterOutputBase : public CSimpleInterface, implements IRowStream
 {
 protected:
-    unsigned __int64 totalCycles;
+    ActivityTimeAccumulator totalCycles;
 public:
     IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
-    CSplitterOutputBase() { totalCycles = 0; }
 
     virtual void start() = 0;
     virtual void getMetaInfo(ThorDataLinkMetaInfo &info) = 0;
-    virtual unsigned __int64 queryTotalCycles() const { return totalCycles; }
+    virtual unsigned __int64 queryTotalCycles() const { return totalCycles.totalCycles; }
 };
 
 class CSplitterOutput : public CSplitterOutputBase
@@ -160,13 +159,13 @@ class NSplitterSlaveActivity : public CSlaveActivity
         CInputWrapper(NSplitterSlaveActivity &_activity, IThorDataLink *_input) : activity(_activity), input(_input) { }
         virtual const void *nextRow()
         {
-            ActivityTimer t(totalCycles, activity.queryTimeActivities(), NULL);
+            ActivityTimer t(totalCycles, activity.queryTimeActivities());
             return input->nextRow();
         }
         virtual void stop() { input->stop(); }
         virtual void start()
         {
-            ActivityTimer s(totalCycles, activity.queryTimeActivities(), NULL);
+            ActivityTimer s(totalCycles, activity.queryTimeActivities());
             input->start();
         }
         virtual void getMetaInfo(ThorDataLinkMetaInfo &info)
@@ -312,7 +311,7 @@ public:
     }
     inline void more(rowcount_t &max)
     {
-        ActivityTimer t(totalCycles, queryTimeActivities(), NULL);
+        ActivityTimer t(totalCycles, queryTimeActivities());
         writer.more(max);
     }
     void prepareInput(unsigned output)
@@ -415,7 +414,7 @@ public:
     }
     unsigned __int64 queryTotalCycles() const
     {
-        unsigned __int64 _totalCycles = totalCycles; // more() time
+        unsigned __int64 _totalCycles = totalCycles.totalCycles; // more() time
         ForEachItemIn(o, outputs)
         {
             CDelayedInput *delayedInput = (CDelayedInput *)outputs.item(o);
@@ -441,7 +440,7 @@ CSplitterOutput::CSplitterOutput(NSplitterSlaveActivity &_activity, unsigned _ou
 // IThorDataLink
 void CSplitterOutput::start()
 {
-    ActivityTimer s(totalCycles, activity.queryTimeActivities(), NULL);
+    ActivityTimer s(totalCycles, activity.queryTimeActivities());
     rec = max = 0;
     activity.prepareInput(output);
     if (activity.startException)
@@ -459,7 +458,7 @@ const void *CSplitterOutput::nextRow()
 {
     if (rec == max)
         activity.more(max);
-    ActivityTimer t(totalCycles, activity.queryTimeActivities(), NULL);
+    ActivityTimer t(totalCycles, activity.queryTimeActivities());
     const void *row = activity.nextRow(output); // pass ptr to max if need more
     ++rec;
     return row;

+ 4 - 4
thorlcr/activities/null/thnullslave.cpp

@@ -58,7 +58,7 @@ public:
 // IThorDataLink
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         dataLinkStart();
     }
 
@@ -69,7 +69,7 @@ public:
 
     const void * nextRow() 
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         return NULL;
     }
 
@@ -104,7 +104,7 @@ public:
 // IThorDataLink
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         startInput(inputs.item(0));
         dataLinkStart();
     }
@@ -115,7 +115,7 @@ public:
     }
     const void * nextRow() 
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         return inputs.item(0)->nextRow();
     }
     virtual bool isGrouped()

+ 2 - 2
thorlcr/activities/nullaction/thnullactionslave.cpp

@@ -39,14 +39,14 @@ public:
     } 
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         dataLinkStart();
     }
     void stop() { dataLinkStop(); }
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         return NULL;
     }
     bool isGrouped() { return false; }

+ 2 - 2
thorlcr/activities/parse/thparseslave.cpp

@@ -68,7 +68,7 @@ public:
     } 
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input = inputs.item(0);
         startInput(input);
         dataLinkStart();
@@ -92,7 +92,7 @@ public:
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         while (!abortSoon) {
             if (rowIter->isValid()) {
                 anyThisGroup = true;

+ 4 - 4
thorlcr/activities/piperead/thprslave.cpp

@@ -194,7 +194,7 @@ public:
     }
     CATCH_NEXTROW()
     {   
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eof || abortSoon)
             return NULL;
         try
@@ -249,7 +249,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         eof = false;
         OwnedRoxieString pipeProgram(helper->getPipeProgram());
         openPipe(pipeProgram, "PIPEREAD");
@@ -366,7 +366,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         eof = anyThisGroup = inputExhausted = false;
         firstRead = true;
 
@@ -387,7 +387,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eof || abortSoon)
             return NULL;
         loop

+ 4 - 4
thorlcr/activities/project/thprojectslave.cpp

@@ -43,7 +43,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input = inputs.item(0);
         startInput(input);
         dataLinkStart();
@@ -55,7 +55,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         loop {
             OwnedConstThorRow row = input->nextRow();
             if (!row && !anyThisGroup)
@@ -254,7 +254,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input = inputs.item(0);
         startInput(input);
 
@@ -273,7 +273,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eof)
             return NULL;
         loop

+ 2 - 2
thorlcr/activities/pull/thpullslave.cpp

@@ -44,7 +44,7 @@ public:
 // IThorDataLink methods
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input.setown(createDataLinkSmartBuffer(this,inputs.item(0),PULL_SMART_BUFFER_SIZE,true,false,RCUNBOUND,NULL,false,&container.queryJob().queryIDiskUsage()));
         startInput(input);
         dataLinkStart();
@@ -57,7 +57,7 @@ public:
 
     const void * nextRow()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         OwnedConstThorRow row = input->nextRow();
         if (!row)
             return NULL;

+ 8 - 8
thorlcr/activities/rollup/throllupslave.cpp

@@ -299,7 +299,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         CDedupRollupBaseActivity::start();
         dataLinkStart();
     }
@@ -342,7 +342,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eos)
             return NULL;
         checkFirstRow();
@@ -416,7 +416,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         CDedupBaseSlaveActivity::start();
 
         lastEog = false;
@@ -427,7 +427,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eos)
             return NULL;
 
@@ -486,7 +486,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         CDedupRollupBaseActivity::start();
         dataLinkStart();
     }
@@ -503,7 +503,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (eos) return NULL;
         checkFirstRow();
         if (eog())
@@ -577,7 +577,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input = inputs.item(0);
         eoi = false;
         startInput(input);
@@ -590,7 +590,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!eoi)
         {
             CThorExpandingRowArray rows(*this, queryRowInterfaces(input));

+ 2 - 2
thorlcr/activities/sample/thsampleslave.cpp

@@ -42,7 +42,7 @@ public:
 
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input = inputs.item(0);
         startInput(input);
         eogNext = false;
@@ -63,7 +63,7 @@ public:
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         while(!abortSoon)
         {
             OwnedConstThorRow row = input->nextRow();

+ 2 - 2
thorlcr/activities/selectnth/thselectnthslave.cpp

@@ -83,7 +83,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
 
         lookaheadN = RCMAX;
         startN = 0; // set by initN()
@@ -135,7 +135,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         OwnedConstThorRow ret;
         Owned<IException> exception;
         if (first) // only return 1!

+ 2 - 2
thorlcr/activities/selfjoin/thselfjoinslave.cpp

@@ -160,7 +160,7 @@ public:
 // IThorDataLink
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input = inputs.item(0);
         startInput(input);
         dataLinkStart();
@@ -206,7 +206,7 @@ public:
     
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if(joinhelper) {
             OwnedConstThorRow row = joinhelper->nextRow();
             if (row) {

+ 4 - 4
thorlcr/activities/soapcall/thsoapcallslave.cpp

@@ -66,7 +66,7 @@ public:
     // IThorDataLink methods
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         eof = false;
         dataLinkStart();
         if (wscHelper)
@@ -80,7 +80,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (!eof && wscHelper.get())
         {
             OwnedConstThorRow row = wscHelper->getRow();
@@ -144,7 +144,7 @@ public:
     // IThorDataLink methods
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         eof = false;
         input = inputs.item(0);
         startInput(input);
@@ -159,7 +159,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         OwnedConstThorRow row = wscHelper->getRow();
         if (row)
         {

+ 2 - 2
thorlcr/activities/spill/thspillslave.cpp

@@ -155,7 +155,7 @@ public:
 // IThorDataLink
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         uncompressedBytesWritten = 0;
         if (!container.queryJob().queryUseCheckpoints())
             container.queryTempHandler()->registerFile(fileName.str(), container.queryOwner().queryGraphId(), usageCount, true);
@@ -177,7 +177,7 @@ public:
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (abortSoon) 
             return NULL;
 

+ 2 - 2
thorlcr/activities/temptable/thtmptableslave.cpp

@@ -55,7 +55,7 @@ public:
     }
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         dataLinkStart();
         __uint64 numRows = helper->numRows();
         // local when generated from a child query (the range is per node, don't split)
@@ -87,7 +87,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (abortSoon)
             return NULL;
         while (currentRow < maxRow) {

+ 2 - 2
thorlcr/activities/topn/thtopnslave.cpp

@@ -193,7 +193,7 @@ public:
 // IThorDataLink
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input = inputs.item(0);
         startInput(input);
         inputStopped = false;
@@ -224,7 +224,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (abortSoon || eos)
             return NULL;
         if (NULL == out)

+ 2 - 2
thorlcr/activities/when/thwhenslave.cpp

@@ -90,7 +90,7 @@ public:
     }
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         input.set(inputs.item(0));
         startInput(input);
         dataLinkStart();
@@ -105,7 +105,7 @@ public:
     virtual bool isGrouped() { return input->isGrouped(); }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         OwnedConstThorRow row(input->nextRow());
         if (!row)
             return NULL;

+ 2 - 2
thorlcr/activities/wuidread/thwuidreadslave.cpp

@@ -53,7 +53,7 @@ public:
     } 
     void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         dataLinkStart();
 
         eogPending = false;
@@ -75,7 +75,7 @@ public:
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (abortSoon || rowSource.eos())
             return NULL;
 

+ 2 - 2
thorlcr/activities/xmlparse/thxmlparseslave.cpp

@@ -66,7 +66,7 @@ public:
 // IThorDataLink methods
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         anyThisGroup = false;
         eogNext = false;
         input = inputs.item(0);
@@ -80,7 +80,7 @@ public:
     }
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         if (abortSoon)
             return NULL;
         if (eogNext)

+ 2 - 2
thorlcr/activities/xmlread/thxmlreadslave.cpp

@@ -211,7 +211,7 @@ public:
 // IThorDataLink
     virtual void start()
     {
-        ActivityTimer s(totalCycles, timeActivities, NULL);
+        ActivityTimer s(totalCycles, timeActivities);
         CDiskReadSlaveActivityBase::start();
         out = createSequentialPartHandler(partHandler, partDescs, false);
         dataLinkStart();
@@ -228,7 +228,7 @@ public:
 
     CATCH_NEXTROW()
     {
-        ActivityTimer t(totalCycles, timeActivities, NULL);
+        ActivityTimer t(totalCycles, timeActivities);
         OwnedConstThorRow row = out->nextRow();
         if (!row)
             return NULL;

+ 1 - 2
thorlcr/graph/thgraphslave.cpp

@@ -115,7 +115,6 @@ public:
 CSlaveActivity::CSlaveActivity(CGraphElementBase *_container) : CActivityBase(_container)
 {
     data = NULL;
-    totalCycles = 0;
 }
 
 CSlaveActivity::~CSlaveActivity()
@@ -289,7 +288,7 @@ unsigned __int64 CSlaveActivity::queryLocalCycles() const
 
 unsigned __int64 CSlaveActivity::queryTotalCycles() const
 {
-    return totalCycles;
+    return totalCycles.totalCycles;
 }
 
 void CSlaveActivity::serializeStats(MemoryBuffer &mb)

+ 3 - 2
thorlcr/graph/thgraphslave.hpp

@@ -31,6 +31,7 @@
 #include "platform.h"
 #include "slave.hpp"
 #include "thormisc.hpp"
+#include "thorcommon.hpp"
 #include "thgraph.hpp"
 #include "jdebug.hpp"
 
@@ -44,7 +45,7 @@ class graphslave_decl CSlaveActivity : public CActivityBase
 
 protected:
     IPointerArrayOf<IThorDataLink> inputs, outputs;
-    unsigned __int64 totalCycles;
+    ActivityTimeAccumulator totalCycles;
     MemoryBuffer startCtx;
 
 public:
@@ -68,7 +69,7 @@ public:
     void startInput(IThorDataLink *itdl, const char *extra=NULL);
     void stopInput(IRowStream *itdl, const char *extra=NULL);
 
-    unsigned __int64 &getTotalCyclesRef() { return totalCycles; }
+    ActivityTimeAccumulator &getTotalCyclesRef() { return totalCycles; }
     unsigned __int64 queryLocalCycles() const;
     virtual unsigned __int64 queryTotalCycles() const; // some acts. may calculate accumulated total from inputs (e.g. splitter)
     virtual void serializeStats(MemoryBuffer &mb);

+ 2 - 2
thorlcr/slave/slave.cpp

@@ -88,7 +88,7 @@ void ProcessSlaveActivity::main()
             process();
             {
                 SpinBlock b(cycleLock);
-                totalCycles += get_cycles_now()-lastCycles;
+                totalCycles.totalCycles += get_cycles_now()-lastCycles;
                 lastCycles = 0; // signal not processing
             }
         }
@@ -167,7 +167,7 @@ void ProcessSlaveActivity::serializeStats(MemoryBuffer &mb)
         if (lastCycles)
         {
             unsigned __int64 nowCycles = get_cycles_now();
-            totalCycles += nowCycles-lastCycles;
+            totalCycles.totalCycles += nowCycles-lastCycles;
             lastCycles = nowCycles; // time accounted for
         }
     }