jstats.h 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #ifndef JSTATS_H
  14. #define JSTATS_H
  15. #include "jlib.hpp"
  16. #include "jmutex.hpp"
  17. #include <vector>
  18. #include <initializer_list>
  19. #include "jstatcodes.h"
  20. typedef unsigned __int64 stat_type;
  21. typedef unsigned __int64 cost_type; // Decimal currency amount multiplied by 10^6
  22. const unsigned __int64 MaxStatisticValue = (unsigned __int64)0-1U;
  23. const unsigned __int64 AnyStatisticValue = MaxStatisticValue; // Use the maximum value to also represent unknown, since it is unlikely to ever occur.
  24. inline constexpr stat_type seconds2StatUnits(stat_type secs) { return secs * 1000000000; }
  25. inline constexpr stat_type msecs2StatUnits(stat_type ms) { return ms * 1000000; }
  26. inline constexpr stat_type statUnits2seconds(stat_type stat) {return stat / 1000000000; }
  27. inline constexpr stat_type statUnits2msecs(stat_type stat) {return stat / 1000000; }
  28. inline constexpr stat_type statPercent(int value) { return (stat_type)value * 100; } // Since 1 = 0.01% skew
  29. inline constexpr stat_type statPercent(double value) { return (stat_type)(value * 100); }
  30. inline constexpr stat_type statPercent(stat_type value) { return (stat_type)(value * 100); }
  31. inline constexpr stat_type statPercentageOf(stat_type value, stat_type per) { return value * per / 10000; }
  32. inline StatisticKind queryStatsVariant(StatisticKind kind) { return (StatisticKind)(kind & ~StKindMask); }
  33. inline cost_type money2cost_type(double money) { return money * 1E6; }
  34. inline double cost_type2money(cost_type cost) { return ((double) cost) / 1E6; }
  35. //---------------------------------------------------------------------------------------------------------------------
  36. //Represents a single level of a scope
  37. class jlib_decl StatsScopeId
  38. {
  39. public:
  40. StatsScopeId() {}
  41. StatsScopeId(StatisticScopeType _scopeType, unsigned _id, unsigned _extra = 0)
  42. : id(_id), extra(_extra), scopeType(_scopeType)
  43. {
  44. }
  45. StatsScopeId(StatisticScopeType _scopeType, const char * _name)
  46. : name(_name), scopeType(_scopeType)
  47. {
  48. }
  49. StatsScopeId(const char * _scope)
  50. {
  51. setScopeText(_scope);
  52. }
  53. StatisticScopeType queryScopeType() const { return scopeType; }
  54. StringBuffer & getScopeText(StringBuffer & out) const;
  55. bool isWildcard() const;
  56. unsigned getHash() const;
  57. bool matches(const StatsScopeId & other) const;
  58. unsigned queryActivity() const;
  59. void describe(StringBuffer & description) const;
  60. void deserialize(MemoryBuffer & in, unsigned version);
  61. void serialize(MemoryBuffer & out) const;
  62. bool extractScopeText(const char * text, const char * * next);
  63. bool setScopeText(const char * text, const char * * next = nullptr);
  64. void setId(StatisticScopeType _scopeType, unsigned _id, unsigned _extra = 0);
  65. void setActivityId(unsigned _id);
  66. void setEdgeId(unsigned _id, unsigned _output);
  67. void setFunctionId(const char * _name);
  68. void setFileId(const char * _name);
  69. void setChannelId(unsigned id);
  70. void setSubgraphId(unsigned _id);
  71. void setWorkflowId(unsigned _id);
  72. void setChildGraphId(unsigned _id);
  73. int compare(const StatsScopeId & other) const;
  74. bool operator == (const StatsScopeId & other) const { return matches(other); }
  75. protected:
  76. //If any more items are added then this could become a union...
  77. unsigned id = 0;
  78. unsigned extra = 0;
  79. StringAttr name;
  80. StatisticScopeType scopeType = SSTnone;
  81. };
  82. interface IStatisticCollectionIterator;
  83. interface IStatisticGatherer;
  84. interface IStatisticCollection : public IInterface
  85. {
  86. public:
  87. virtual StatisticScopeType queryScopeType() const = 0;
  88. virtual StringBuffer & getFullScope(StringBuffer & str) const = 0;
  89. virtual StringBuffer & getScope(StringBuffer & str) const = 0;
  90. virtual unsigned __int64 queryStatistic(StatisticKind kind) const = 0;
  91. virtual unsigned getNumStatistics() const = 0;
  92. virtual bool getStatistic(StatisticKind kind, unsigned __int64 & value) const = 0;
  93. virtual void getStatistic(StatisticKind & kind, unsigned __int64 & value, unsigned idx) const = 0;
  94. virtual IStatisticCollectionIterator & getScopes(const char * filter, bool sorted) = 0;
  95. virtual void getMinMaxScope(IStringVal & minValue, IStringVal & maxValue, StatisticScopeType searchScopeType) const = 0;
  96. virtual void getMinMaxActivity(unsigned & minValue, unsigned & maxValue) const = 0;
  97. virtual void serialize(MemoryBuffer & out) const = 0;
  98. virtual unsigned __int64 queryWhenCreated() const = 0;
  99. virtual void mergeInto(IStatisticGatherer & target) const = 0;
  100. virtual StringBuffer &toXML(StringBuffer &out) const = 0;
  101. };
  102. interface IStatisticCollectionIterator : public IIteratorOf<IStatisticCollection>
  103. {
  104. };
  105. enum StatsMergeAction
  106. {
  107. StatsMergeKeepNonZero,
  108. StatsMergeReplace,
  109. StatsMergeSum,
  110. StatsMergeMin,
  111. StatsMergeMax,
  112. StatsMergeAppend,
  113. };
  114. interface IStatisticGatherer : public IInterface
  115. {
  116. public:
  117. virtual void beginScope(const StatsScopeId & id) = 0;
  118. virtual void beginSubGraphScope(unsigned id) = 0;
  119. virtual void beginActivityScope(unsigned id) = 0;
  120. virtual void beginEdgeScope(unsigned id, unsigned oid) = 0;
  121. virtual void beginChildGraphScope(unsigned id) = 0;
  122. virtual void beginChannelScope(unsigned id) = 0;
  123. virtual void endScope() = 0;
  124. virtual void addStatistic(StatisticKind kind, unsigned __int64 value) = 0;
  125. virtual void updateStatistic(StatisticKind kind, unsigned __int64 value, StatsMergeAction mergeAction) = 0;
  126. virtual IStatisticCollection * getResult() = 0;
  127. };
  128. class StatsScopeBlock
  129. {
  130. public:
  131. inline StatsScopeBlock(IStatisticGatherer & _gatherer) : gatherer(_gatherer)
  132. {
  133. }
  134. inline ~StatsScopeBlock()
  135. {
  136. gatherer.endScope();
  137. }
  138. protected:
  139. IStatisticGatherer & gatherer;
  140. };
  141. class jlib_decl StatsAggregation
  142. {
  143. public:
  144. void noteValue(stat_type value);
  145. stat_type getCount() const { return count; }
  146. stat_type getMin() const { return minValue; }
  147. stat_type getMax() const { return maxValue; }
  148. stat_type getSum() const { return sumValue; }
  149. stat_type getAve() const;
  150. //MORE: StDev would require a sum of squares.
  151. protected:
  152. stat_type count = 0;
  153. stat_type sumValue = 0;
  154. stat_type minValue = 0;
  155. stat_type maxValue = 0;
  156. };
  157. //---------------------------------------------------------------------------------------------------------------------
  158. class StatsSubgraphScope : public StatsScopeBlock
  159. {
  160. public:
  161. inline StatsSubgraphScope(IStatisticGatherer & _gatherer, unsigned id) : StatsScopeBlock(_gatherer)
  162. {
  163. gatherer.beginSubGraphScope(id);
  164. }
  165. };
  166. class StatsChildGraphScope : public StatsScopeBlock
  167. {
  168. public:
  169. inline StatsChildGraphScope(IStatisticGatherer & _gatherer, unsigned id) : StatsScopeBlock(_gatherer)
  170. {
  171. gatherer.beginChildGraphScope(id);
  172. }
  173. };
  174. class StatsActivityScope : public StatsScopeBlock
  175. {
  176. public:
  177. inline StatsActivityScope(IStatisticGatherer & _gatherer, unsigned id) : StatsScopeBlock(_gatherer)
  178. {
  179. gatherer.beginActivityScope(id);
  180. }
  181. };
  182. class ChannelActivityScope : public StatsScopeBlock
  183. {
  184. public:
  185. inline ChannelActivityScope(IStatisticGatherer & _gatherer, unsigned id) : StatsScopeBlock(_gatherer)
  186. {
  187. gatherer.beginChannelScope(id);
  188. }
  189. };
  190. class StatsEdgeScope : public StatsScopeBlock
  191. {
  192. public:
  193. inline StatsEdgeScope(IStatisticGatherer & _gatherer, unsigned id, unsigned oid) : StatsScopeBlock(_gatherer)
  194. {
  195. gatherer.beginEdgeScope(id, oid);
  196. }
  197. };
  198. class StatsScope : public StatsScopeBlock
  199. {
  200. public:
  201. inline StatsScope(IStatisticGatherer & _gatherer, const StatsScopeId & id) : StatsScopeBlock(_gatherer)
  202. {
  203. gatherer.beginScope(id);
  204. }
  205. };
  206. class StatsOptScope
  207. {
  208. public:
  209. inline StatsOptScope(IStatisticGatherer & _gatherer, const StatsScopeId & _id) : gatherer(_gatherer), id(_id)
  210. {
  211. if (id.queryScopeType() != SSTnone)
  212. gatherer.beginScope(id);
  213. }
  214. inline ~StatsOptScope()
  215. {
  216. if (id.queryScopeType() != SSTnone)
  217. gatherer.endScope();
  218. }
  219. protected:
  220. IStatisticGatherer & gatherer;
  221. const StatsScopeId & id;
  222. };
  223. //---------------------------------------------------------------------------------------------------------------------
  224. class ScopedItemFilter
  225. {
  226. public:
  227. ScopedItemFilter() : minDepth(0), maxDepth(0), hasWildcard(false) {}
  228. bool match(const char * search) const;
  229. bool matchDepth(unsigned low, unsigned high) const;
  230. bool recurseChildScopes(const char * curScope) const;
  231. const char * queryValue() const { return value ? value.get() : "*"; }
  232. void set(const char * value);
  233. void setDepth(unsigned _depth);
  234. void setDepth(unsigned _minDepth, unsigned _maxDepth);
  235. protected:
  236. unsigned minDepth;
  237. unsigned maxDepth;
  238. StringAttr value;
  239. bool hasWildcard;
  240. };
  241. class jlib_decl StatisticValueFilter
  242. {
  243. public:
  244. StatisticValueFilter(StatisticKind _kind, stat_type _minValue, stat_type _maxValue) :
  245. kind(_kind), minValue(_minValue), maxValue(_maxValue)
  246. {
  247. }
  248. bool matches(stat_type value) const
  249. {
  250. return ((value >= minValue) && (value <= maxValue));
  251. }
  252. StatisticKind queryKind() const { return kind; }
  253. StringBuffer & describe(StringBuffer & out) const;
  254. protected:
  255. StatisticKind kind;
  256. stat_type minValue;
  257. stat_type maxValue;
  258. };
  259. enum ScopeCompare : unsigned
  260. {
  261. SCunknown = 0x0000, //
  262. SCparent = 0x0001, // is a parent of: w1, w1:g1
  263. SCchild = 0x0002, // is a child of: w1:g1, w1
  264. SCequal = 0x0004, // w1:g1, w1:g1 - may extend to wildcards later.
  265. SCrelated = 0x0008, // w1:g1, w1:g2 - some shared relationship
  266. SCunrelated = 0x0010, // no connection
  267. };
  268. BITMASK_ENUM(ScopeCompare);
  269. /*
  270. * compare two scopes, and return a value indicating their relationship
  271. */
  272. extern jlib_decl ScopeCompare compareScopes(const char * scope, const char * key);
  273. class jlib_decl ScopeFilter
  274. {
  275. public:
  276. ScopeFilter() = default;
  277. ScopeFilter(const char * scopeList);
  278. void addScope(const char * scope);
  279. void addScopes(const char * scope);
  280. void addScopeType(StatisticScopeType scopeType);
  281. void addId(const char * id);
  282. void setDepth(unsigned low, unsigned high);
  283. void setDepth(unsigned value) { setDepth(value, value); }
  284. /*
  285. * Return a mask containing information about whether the scope will match the filter
  286. * It errs on the side of false positives - e.g. SCparent is set if it might be the parent of a match
  287. */
  288. ScopeCompare compare(const char * scope) const;
  289. int compareDepth(unsigned depth) const; // -1 too shallow, 0 a match, +1 too deep
  290. bool hasSingleMatch() const;
  291. bool canAlwaysPreFilter() const;
  292. void finishedFilter();
  293. const StringArray & queryScopes() const { return scopes; }
  294. bool matchOnly(StatisticScopeType scopeType) const;
  295. StringBuffer & describe(StringBuffer & out) const;
  296. protected:
  297. void intersectDepth(unsigned _minDepth, unsigned _maxDepth);
  298. protected:
  299. UnsignedArray scopeTypes;
  300. StringArray scopes;
  301. StringArray ids;
  302. unsigned minDepth = 0;
  303. unsigned maxDepth = UINT_MAX;
  304. };
  305. class jlib_decl StatisticsFilter : public CInterface
  306. {
  307. public:
  308. StatisticsFilter();
  309. StatisticsFilter(const char * filter);
  310. StatisticsFilter(StatisticCreatorType _creatorType, StatisticScopeType _scopeType, StatisticMeasure _measure, StatisticKind _kind);
  311. StatisticsFilter(const char * _creatorType, const char * _scopeType, const char * _kind);
  312. StatisticsFilter(const char * _creatorTypeText, const char * _creator, const char * _scopeTypeText, const char * _scope, const char * _measureText, const char * _kindText);
  313. StatisticsFilter(StatisticCreatorType _creatorType, const char * _creator, StatisticScopeType _scopeType, const char * _scope, StatisticMeasure _measure, StatisticKind _kind);
  314. bool matches(StatisticCreatorType curCreatorType, const char * curCreator, StatisticScopeType curScopeType, const char * curScope, StatisticMeasure curMeasure, StatisticKind curKind, unsigned __int64 value) const;
  315. bool recurseChildScopes(StatisticScopeType curScopeType, const char * curScope) const;
  316. const char * queryScope() const { return scopeFilter.queryValue(); }
  317. void set(const char * _creatorTypeText, const char * _scopeTypeText, const char * _kindText);
  318. void set(const char * _creatorTypeText, const char * _creator, const char * _scopeTypeText, const char * _scope, const char * _measureText, const char * _kindText);
  319. void setCreatorDepth(unsigned _minCreatorDepth, unsigned _maxCreatorDepth);
  320. void setCreator(const char * _creator);
  321. void setCreatorType(StatisticCreatorType _creatorType);
  322. void setFilter(const char * filter);
  323. void setScopeDepth(unsigned _minScopeDepth);
  324. void setScopeDepth(unsigned _minScopeDepth, unsigned _maxScopeDepth);
  325. void setScope(const char * _scope);
  326. void setScopeType(StatisticScopeType _scopeType);
  327. void setValueRange(unsigned __int64 minValue, unsigned __int64 _maxValue);
  328. void setKind(StatisticKind _kind);
  329. void setKind(const char * _kind);
  330. void setMeasure(StatisticMeasure _measure);
  331. protected:
  332. void addFilter(const char * filter);
  333. void init();
  334. protected:
  335. StatisticCreatorType creatorType;
  336. StatisticScopeType scopeType;
  337. StatisticMeasure measure;
  338. StatisticKind kind;
  339. ScopedItemFilter creatorFilter;
  340. ScopedItemFilter scopeFilter;
  341. unsigned __int64 minValue = 0;
  342. unsigned __int64 maxValue = (unsigned __int64)(-1);
  343. };
  344. //---------------------------------------------------------------------------------------------------------------------
  345. class jlib_decl StatisticsMapping
  346. {
  347. public:
  348. //Takes a list of StatisticKind and a variable number of existing mappings and combines
  349. template <typename... Mappings>
  350. StatisticsMapping(const std::initializer_list<StatisticKind> &kinds, const Mappings &... mappings) : StatisticsMapping(&mappings...)
  351. {
  352. for (auto kind : kinds)
  353. {
  354. assert((kind != StKindNone) && (kind != StKindAll) && (kind < StMax));
  355. assert(!indexToKind.contains(kind));
  356. indexToKind.append(kind);
  357. }
  358. createMappings();
  359. }
  360. StatisticsMapping(StatisticKind kind)
  361. {
  362. if (StKindAll == kind)
  363. {
  364. for (int i = StKindAll+1; i < StMax; i++)
  365. indexToKind.append(i);
  366. }
  367. else
  368. {
  369. assert(kind != StKindNone && kind < StMax);
  370. indexToKind.append(kind);
  371. }
  372. createMappings();
  373. }
  374. inline unsigned getIndex(StatisticKind kind) const
  375. {
  376. dbgassertex(kind >= StKindNone && kind < StMax);
  377. return kindToIndex.item(kind);
  378. }
  379. inline StatisticKind getKind(unsigned index) const { return (StatisticKind)indexToKind.item(index); }
  380. inline unsigned numStatistics() const { return indexToKind.ordinality(); }
  381. protected:
  382. StatisticsMapping() { }
  383. template <typename Mapping>
  384. StatisticsMapping(const Mapping *mapping)
  385. {
  386. ForEachItemIn(idx, mapping->indexToKind)
  387. indexToKind.append(mapping->indexToKind.item(idx));
  388. }
  389. template <typename Mapping, typename... Mappings>
  390. StatisticsMapping(const Mapping *mapping, const Mappings * ... mappings) : StatisticsMapping(mappings...)
  391. {
  392. ForEachItemIn(idx, mapping->indexToKind)
  393. indexToKind.append(mapping->indexToKind.item(idx));
  394. }
  395. void createMappings();
  396. protected:
  397. UnsignedArray kindToIndex;
  398. UnsignedArray indexToKind;
  399. private:
  400. StatisticsMapping& operator=(const StatisticsMapping&) =delete;
  401. };
  402. extern const jlib_decl StatisticsMapping allStatistics;
  403. extern const jlib_decl StatisticsMapping heapStatistics;
  404. extern const jlib_decl StatisticsMapping diskLocalStatistics;
  405. extern const jlib_decl StatisticsMapping diskRemoteStatistics;
  406. extern const jlib_decl StatisticsMapping diskReadRemoteStatistics;
  407. extern const jlib_decl StatisticsMapping diskWriteRemoteStatistics;
  408. //---------------------------------------------------------------------------------------------------------------------
  409. class jlib_decl CRuntimeStatistic
  410. {
  411. public:
  412. CRuntimeStatistic() : value(0) {}
  413. inline void add(unsigned __int64 delta)
  414. {
  415. //load and store default to relaxed - so this has no atomic synchronization
  416. value.store(value.load() + delta);
  417. }
  418. inline void addAtomic(unsigned __int64 delta)
  419. {
  420. value.fetch_add(delta);
  421. }
  422. inline unsigned __int64 get() const { return value; }
  423. inline unsigned __int64 getClear()
  424. {
  425. unsigned __int64 ret = value;
  426. value.store(0);
  427. return ret;
  428. }
  429. inline unsigned __int64 getClearAtomic()
  430. {
  431. unsigned __int64 ret = value;
  432. value.fetch_sub(ret);
  433. return ret;
  434. }
  435. inline void clear() { set(0); }
  436. void merge(unsigned __int64 otherValue, StatsMergeAction mergeAction);
  437. void sum(unsigned __int64 otherValue) { if (otherValue) addAtomic(otherValue); }
  438. inline void set(unsigned __int64 _value) { value = _value; }
  439. protected:
  440. RelaxedAtomic<unsigned __int64> value;
  441. };
  442. //This class is used to gather statistics for an activity - it has no notion of scope.
  443. interface IContextLogger;
  444. class CNestedRuntimeStatisticMap;
  445. class jlib_decl CRuntimeStatisticCollection
  446. {
  447. public:
  448. CRuntimeStatisticCollection(const StatisticsMapping & _mapping, bool _ignoreUnknown = false) : mapping(_mapping)
  449. #ifdef _DEBUG
  450. ,ignoreUnknown(_ignoreUnknown)
  451. #endif
  452. {
  453. unsigned num = mapping.numStatistics();
  454. values = new CRuntimeStatistic[num+1]; // extra entry is to gather unexpected stats
  455. }
  456. CRuntimeStatisticCollection(const CRuntimeStatisticCollection & _other) : mapping(_other.mapping)
  457. #ifdef _DEBUG
  458. , ignoreUnknown(_other.ignoreUnknown)
  459. #endif
  460. {
  461. unsigned num = mapping.numStatistics();
  462. values = new CRuntimeStatistic[num+1];
  463. for (unsigned i=0; i <= num; i++)
  464. values[i].set(_other.values[i].get());
  465. }
  466. virtual ~CRuntimeStatisticCollection();
  467. inline CRuntimeStatistic & queryStatistic(StatisticKind kind)
  468. {
  469. unsigned index = queryMapping().getIndex(kind);
  470. #ifdef _DEBUG
  471. if (!ignoreUnknown)
  472. dbgassertex(index < mapping.numStatistics());
  473. #endif
  474. return values[index];
  475. }
  476. inline CRuntimeStatistic * queryOptStatistic(StatisticKind kind)
  477. {
  478. unsigned index = queryMapping().getIndex(kind);
  479. if (index == mapping.numStatistics())
  480. return nullptr;
  481. return &values[index];
  482. }
  483. inline const CRuntimeStatistic & queryStatistic(StatisticKind kind) const
  484. {
  485. unsigned index = queryMapping().getIndex(kind);
  486. #ifdef _DEBUG
  487. if (!ignoreUnknown)
  488. dbgassertex(index < mapping.numStatistics());
  489. #endif
  490. return values[index];
  491. }
  492. void addStatistic(StatisticKind kind, unsigned __int64 value)
  493. {
  494. queryStatistic(kind).add(value);
  495. }
  496. void addStatisticAtomic(StatisticKind kind, unsigned __int64 value)
  497. {
  498. queryStatistic(kind).addAtomic(value);
  499. }
  500. void mergeStatistic(StatisticKind kind, unsigned __int64 value);
  501. void sumStatistic(StatisticKind kind, unsigned __int64 value); // Special more efficient version of mergeStatistic useful in time critical sections
  502. void setStatistic(StatisticKind kind, unsigned __int64 value)
  503. {
  504. queryStatistic(kind).set(value);
  505. }
  506. unsigned __int64 getStatisticValue(StatisticKind kind) const
  507. {
  508. return queryStatistic(kind).get();
  509. }
  510. unsigned __int64 getSerialStatisticValue(StatisticKind kind) const;
  511. void reset();
  512. void reset(const StatisticsMapping & toClear);
  513. CRuntimeStatisticCollection & registerNested(const StatsScopeId & scope, const StatisticsMapping & mapping);
  514. inline const StatisticsMapping & queryMapping() const { return mapping; };
  515. inline unsigned ordinality() const { return mapping.numStatistics(); }
  516. inline StatisticKind getKind(unsigned i) const { return mapping.getKind(i); }
  517. inline unsigned __int64 getValue(unsigned i) const { return values[i].get(); }
  518. void set(const CRuntimeStatisticCollection & other, unsigned node = 0);
  519. void merge(const CRuntimeStatisticCollection & other, unsigned node = 0);
  520. void updateDelta(CRuntimeStatisticCollection & target, const CRuntimeStatisticCollection & source);
  521. void rollupStatistics(IContextLogger * target) { rollupStatistics(1, &target); }
  522. void rollupStatistics(unsigned num, IContextLogger * const * targets) const;
  523. virtual void recordStatistics(IStatisticGatherer & target, bool clear) const;
  524. // Print out collected stats to string
  525. StringBuffer &toStr(StringBuffer &str) const;
  526. // Print out collected stats to string as XML
  527. StringBuffer &toXML(StringBuffer &str) const;
  528. // Serialize/deserialize
  529. virtual void setStatistic(StatisticKind kind, unsigned __int64 value, unsigned node);
  530. virtual void mergeStatistic(StatisticKind kind, unsigned __int64 value, unsigned node);
  531. virtual bool serialize(MemoryBuffer & out) const; // Returns true if any non-zero
  532. virtual void deserialize(MemoryBuffer & in);
  533. virtual void deserializeMerge(MemoryBuffer& in);
  534. protected:
  535. virtual CNestedRuntimeStatisticMap *createNested() const;
  536. CNestedRuntimeStatisticMap & ensureNested();
  537. CNestedRuntimeStatisticMap *queryNested() const;
  538. void reportIgnoredStats() const;
  539. void mergeStatistic(StatisticKind kind, unsigned __int64 value, StatsMergeAction mergeAction)
  540. {
  541. queryStatistic(kind).merge(value, mergeAction);
  542. }
  543. const CRuntimeStatistic & queryUnknownStatistic() const { return values[mapping.numStatistics()]; }
  544. protected:
  545. const StatisticsMapping & mapping;
  546. CRuntimeStatistic * values;
  547. std::atomic<CNestedRuntimeStatisticMap *> nested {nullptr};
  548. static CriticalSection nestlock;
  549. #ifdef _DEBUG
  550. bool ignoreUnknown = false;
  551. #endif
  552. };
  553. //NB: Serialize and deserialize are not currently implemented.
  554. class jlib_decl CRuntimeSummaryStatisticCollection : public CRuntimeStatisticCollection
  555. {
  556. public:
  557. CRuntimeSummaryStatisticCollection(const StatisticsMapping & _mapping);
  558. ~CRuntimeSummaryStatisticCollection();
  559. virtual void recordStatistics(IStatisticGatherer & target, bool clear = false) const override;
  560. virtual bool serialize(MemoryBuffer & out) const override; // Returns true if any non-zero
  561. virtual void deserialize(MemoryBuffer & in) override;
  562. virtual void deserializeMerge(MemoryBuffer& in) override;
  563. void mergeStatistic(StatisticKind kind, unsigned __int64 value, unsigned node);
  564. void setStatistic(StatisticKind kind, unsigned __int64 value, unsigned node);
  565. protected:
  566. struct DerivedStats
  567. {
  568. public:
  569. void mergeStatistic(unsigned __int64 value, unsigned node);
  570. void setStatistic(unsigned __int64 value, unsigned node);
  571. public:
  572. unsigned __int64 max = 0;
  573. unsigned __int64 min = 0;
  574. unsigned __int64 count = 0;
  575. double sum = 0;
  576. double sumSquares = 0;
  577. unsigned minNode = 0;
  578. unsigned maxNode = 0;
  579. };
  580. protected:
  581. virtual CNestedRuntimeStatisticMap *createNested() const override;
  582. protected:
  583. DerivedStats * derived;
  584. };
  585. class CNestedRuntimeStatisticCollection : public CInterface
  586. {
  587. public:
  588. CNestedRuntimeStatisticCollection(const StatsScopeId & _scope, CRuntimeStatisticCollection * _stats)
  589. : scope(_scope), stats(_stats)
  590. {
  591. }
  592. CNestedRuntimeStatisticCollection(const CNestedRuntimeStatisticCollection & _other) = delete;
  593. ~CNestedRuntimeStatisticCollection() { delete stats; }
  594. bool matches(const StatsScopeId & otherScope) const;
  595. inline const StatisticsMapping & queryMapping() const { return stats->queryMapping(); };
  596. inline CRuntimeStatisticCollection & queryStats() { return *stats; }
  597. inline const CRuntimeStatisticCollection & queryStats() const { return *stats; }
  598. bool serialize(MemoryBuffer & out) const; // Returns true if any non-zero
  599. void deserialize(MemoryBuffer & in);
  600. void deserializeMerge(MemoryBuffer& in);
  601. void set(const CNestedRuntimeStatisticCollection & other, unsigned node);
  602. void merge(const CNestedRuntimeStatisticCollection & other, unsigned node);
  603. void recordStatistics(IStatisticGatherer & target, bool clear) const;
  604. StringBuffer & toStr(StringBuffer &str) const;
  605. StringBuffer & toXML(StringBuffer &str) const;
  606. void updateDelta(CNestedRuntimeStatisticCollection & target, const CNestedRuntimeStatisticCollection & source);
  607. public:
  608. StatsScopeId scope;
  609. CRuntimeStatisticCollection * stats;
  610. };
  611. class CNestedRuntimeStatisticMap
  612. {
  613. public:
  614. virtual ~CNestedRuntimeStatisticMap() = default;
  615. CNestedRuntimeStatisticCollection & addNested(const StatsScopeId & scope, const StatisticsMapping & mapping);
  616. bool serialize(MemoryBuffer & out) const; // Returns true if any non-zero
  617. void deserialize(MemoryBuffer & in);
  618. void deserializeMerge(MemoryBuffer& in);
  619. void merge(const CNestedRuntimeStatisticMap & other, unsigned node);
  620. void set(const CNestedRuntimeStatisticMap & other, unsigned node);
  621. void recordStatistics(IStatisticGatherer & target, bool clear) const;
  622. StringBuffer & toStr(StringBuffer &str) const;
  623. StringBuffer & toXML(StringBuffer &str) const;
  624. void updateDelta(CNestedRuntimeStatisticMap & target, const CNestedRuntimeStatisticMap & source);
  625. protected:
  626. virtual CRuntimeStatisticCollection * createStats(const StatisticsMapping & mapping);
  627. protected:
  628. CIArrayOf<CNestedRuntimeStatisticCollection> map;
  629. mutable ReadWriteLock lock;
  630. };
  631. class CNestedSummaryRuntimeStatisticMap : public CNestedRuntimeStatisticMap
  632. {
  633. protected:
  634. virtual CRuntimeStatisticCollection * createStats(const StatisticsMapping & mapping) override;
  635. };
  636. //---------------------------------------------------------------------------------------------------------------------
  637. //Some template helper classes for merging statistics from external sources.
  638. template <class INTERFACE>
  639. void mergeStats(CRuntimeStatisticCollection & stats, INTERFACE * source, const StatisticsMapping & mapping)
  640. {
  641. if (!source)
  642. return;
  643. unsigned max = mapping.numStatistics();
  644. for (unsigned i=0; i < max; i++)
  645. {
  646. StatisticKind kind = mapping.getKind(i);
  647. stats.mergeStatistic(kind, source->getStatistic(kind));
  648. }
  649. }
  650. template <class INTERFACE>
  651. void mergeStats(CRuntimeStatisticCollection & stats, Shared<INTERFACE> source, const StatisticsMapping & mapping) { mergeStats(stats, source.get(), mapping); }
  652. template <class INTERFACE>
  653. void mergeStats(CRuntimeStatisticCollection & stats, INTERFACE * source) { mergeStats(stats, source, stats.queryMapping()); }
  654. template <class INTERFACE>
  655. void mergeStats(CRuntimeStatisticCollection & stats, Shared<INTERFACE> source) { mergeStats(stats, source.get(), stats.queryMapping()); }
  656. template <class INTERFACE>
  657. void mergeStat(CRuntimeStatisticCollection & stats, INTERFACE * source, StatisticKind kind)
  658. {
  659. if (source)
  660. stats.mergeStatistic(kind, source->getStatistic(kind));
  661. }
  662. template <class INTERFACE>
  663. void mergeStat(CRuntimeStatisticCollection & stats, Shared<INTERFACE> source, StatisticKind kind) { mergeStat(stats, source.get(), kind); }
  664. //---------------------------------------------------------------------------------------------------------------------
  665. //A class for minimizing the overhead of collecting timestamps.
  666. class IpAddress;
  667. extern jlib_decl unsigned __int64 getTimeStampNowValue();
  668. extern jlib_decl unsigned __int64 getIPV4StatsValue(const IpAddress & ip);
  669. extern jlib_decl StringBuffer & formatStatistic(StringBuffer & out, unsigned __int64 value, StatisticMeasure measure);
  670. extern jlib_decl StringBuffer & formatStatistic(StringBuffer & out, unsigned __int64 value, StatisticKind kind);
  671. extern jlib_decl void formatTimeStampAsLocalTime(StringBuffer & out, unsigned __int64 value);
  672. extern jlib_decl stat_type readStatisticValue(const char * cur, const char * * end, StatisticMeasure measure);
  673. extern jlib_decl unsigned __int64 mergeStatistic(StatisticMeasure measure, unsigned __int64 value, unsigned __int64 otherValue);
  674. extern jlib_decl unsigned __int64 mergeStatisticValue(unsigned __int64 prevValue, unsigned __int64 newValue, StatsMergeAction mergeAction);
  675. extern jlib_decl StatisticMeasure queryMeasure(StatisticKind kind);
  676. extern jlib_decl const char * queryStatisticName(StatisticKind kind);
  677. extern jlib_decl void queryLongStatisticName(StringBuffer & out, StatisticKind kind);
  678. extern jlib_decl const char * queryTreeTag(StatisticKind kind);
  679. extern jlib_decl const char * queryCreatorTypeName(StatisticCreatorType sct);
  680. extern jlib_decl const char * queryScopeTypeName(StatisticScopeType sst);
  681. extern jlib_decl const char * queryMeasureName(StatisticMeasure measure);
  682. extern jlib_decl const char * queryMeasurePrefix(StatisticMeasure measure);
  683. extern jlib_decl StatsMergeAction queryMergeMode(StatisticMeasure measure);
  684. extern jlib_decl StatsMergeAction queryMergeMode(StatisticKind kind);
  685. extern jlib_decl StatisticMeasure queryMeasure(const char * measure, StatisticMeasure dft);
  686. extern jlib_decl StatisticKind queryStatisticKind(const char * kind, StatisticKind dft);
  687. extern jlib_decl StatisticCreatorType queryCreatorType(const char * sct, StatisticCreatorType dft);
  688. extern jlib_decl StatisticScopeType queryScopeType(const char * sst, StatisticScopeType dft);
  689. extern jlib_decl IStatisticGatherer * createStatisticsGatherer(StatisticCreatorType creatorType, const char * creator, const StatsScopeId & rootScope);
  690. extern jlib_decl void serializeStatisticCollection(MemoryBuffer & out, IStatisticCollection * collection);
  691. extern jlib_decl IStatisticCollection * createStatisticCollection(MemoryBuffer & in);
  692. inline unsigned __int64 milliToNano(unsigned __int64 value) { return value * 1000000; } // call avoids need to upcast values
  693. inline unsigned __int64 nanoToMilli(unsigned __int64 value) { return value / 1000000; }
  694. extern jlib_decl unsigned __int64 convertMeasure(StatisticMeasure from, StatisticMeasure to, unsigned __int64 value);
  695. extern jlib_decl unsigned __int64 convertMeasure(StatisticKind from, StatisticKind to, unsigned __int64 value);
  696. extern jlib_decl StatisticCreatorType queryStatisticsComponentType();
  697. extern jlib_decl const char * queryStatisticsComponentName();
  698. extern jlib_decl void setStatisticsComponentName(StatisticCreatorType processType, const char * processName, bool appendIP);
  699. extern jlib_decl void verifyStatisticFunctions();
  700. extern jlib_decl void formatTimeCollatable(StringBuffer & out, unsigned __int64 value, bool nano);
  701. extern jlib_decl unsigned __int64 extractTimeCollatable(const char *s, const char * * end);
  702. extern jlib_decl void validateScopeId(const char * idText);
  703. extern jlib_decl void validateScope(const char * scopeText);
  704. //Scopes need to be processed in a consistent order so they can be merged.
  705. //activities are in numeric order
  706. //edges must come before activities.
  707. extern jlib_decl int compareScopeName(const char * left, const char * right);
  708. extern jlib_decl unsigned queryScopeDepth(const char * text);
  709. extern jlib_decl const char * queryScopeTail(const char * scope);
  710. extern jlib_decl bool getParentScope(StringBuffer & parent, const char * scope);
  711. extern jlib_decl bool isParentScope(const char *parent, const char *scope);
  712. extern jlib_decl void describeScope(StringBuffer & description, const char * scope);
  713. //This interface is primarily here to reduce the dependency between the different components.
  714. interface IStatisticTarget
  715. {
  716. virtual void addStatistic(StatisticScopeType scopeType, const char * scope, StatisticKind kind, char * description, unsigned __int64 value, unsigned __int64 count, unsigned __int64 maxValue, StatsMergeAction mergeAction) = 0;
  717. };
  718. class jlib_decl NullStatisticTarget : implements IStatisticTarget
  719. {
  720. public:
  721. virtual void addStatistic(StatisticScopeType scopeType, const char * scope, StatisticKind kind, char * description, unsigned __int64 value, unsigned __int64 count, unsigned __int64 maxValue, StatsMergeAction mergeAction)
  722. {
  723. }
  724. };
  725. extern jlib_decl StringBuffer & formatMoney(StringBuffer &out, unsigned __int64 value);
  726. #endif