selfping_actor.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. #include "selfping_actor.h"
  2. #include <library/cpp/actors/core/actor_bootstrapped.h>
  3. #include <library/cpp/actors/core/hfunc.h>
  4. #include <library/cpp/containers/stack_vector/stack_vec.h>
  5. #include <library/cpp/sliding_window/sliding_window.h>
  6. namespace NActors {
  7. ui64 MeasureTaskDurationNs() {
  8. // Prepare worm test data
  9. // 11 * 11 * 3 * 8 = 2904 bytes, fits in L1 cache
  10. constexpr ui64 Size = 11;
  11. // Align the data to reduce random alignment effects
  12. alignas(64) TStackVec<ui64, Size * Size * 3> data;
  13. ui64 s = 0;
  14. NHPTimer::STime beginTime;
  15. NHPTimer::STime endTime;
  16. // Prepare the data
  17. data.resize(Size * Size * 3);
  18. for (ui64 matrixIdx = 0; matrixIdx < 3; ++matrixIdx) {
  19. for (ui64 y = 0; y < Size; ++y) {
  20. for (ui64 x = 0; x < Size; ++x) {
  21. data[matrixIdx * (Size * Size) + y * Size + x] = y * Size + x;
  22. }
  23. }
  24. }
  25. // Warm-up the cache
  26. NHPTimer::GetTime(&beginTime);
  27. for (ui64 idx = 0; idx < data.size(); ++idx) {
  28. s += data[idx];
  29. }
  30. NHPTimer::GetTime(&endTime);
  31. s += (ui64)(1000000.0 * NHPTimer::GetSeconds(endTime - beginTime));
  32. // Measure the CPU performance
  33. // C = A * B with injected dependency to s
  34. NHPTimer::GetTime(&beginTime);
  35. for (ui64 y = 0; y < Size; ++y) {
  36. for (ui64 x = 0; x < Size; ++x) {
  37. for (ui64 i = 0; i < Size; ++i) {
  38. s += data[y * Size + i] * data[Size * Size + i * Size + x];
  39. }
  40. data[2 * Size * Size + y * Size + x] = s;
  41. s = 0;
  42. }
  43. }
  44. for (ui64 idx = 0; idx < data.size(); ++idx) {
  45. s += data[idx];
  46. }
  47. NHPTimer::GetTime(&endTime);
  48. // Prepare the result
  49. double d = 1000000000.0 * (NHPTimer::GetSeconds(endTime - beginTime) + 0.000000001 * (s & 1));
  50. return (ui64)d;
  51. }
  52. namespace {
  53. struct TEvPing: public TEventLocal<TEvPing, TEvents::THelloWorld::Ping> {
  54. TEvPing(double timeStart)
  55. : TimeStart(timeStart)
  56. {}
  57. const double TimeStart;
  58. };
  59. template <class TValueType_>
  60. struct TAvgOperation {
  61. struct TValueType {
  62. ui64 Count = 0;
  63. TValueType_ Sum = TValueType_();
  64. };
  65. using TValueVector = TVector<TValueType>;
  66. static constexpr TValueType InitialValue() {
  67. return TValueType(); // zero
  68. }
  69. // Updates value in current bucket and returns window value
  70. static TValueType UpdateBucket(TValueType windowValue, TValueVector& buckets, size_t index, TValueType newVal) {
  71. Y_ASSERT(index < buckets.size());
  72. buckets[index].Sum += newVal.Sum;
  73. buckets[index].Count += newVal.Count;
  74. windowValue.Sum += newVal.Sum;
  75. windowValue.Count += newVal.Count;
  76. return windowValue;
  77. }
  78. static TValueType ClearBuckets(TValueType windowValue, TValueVector& buckets, size_t firstElemIndex, size_t bucketsToClear) {
  79. Y_ASSERT(!buckets.empty());
  80. Y_ASSERT(firstElemIndex < buckets.size());
  81. Y_ASSERT(bucketsToClear <= buckets.size());
  82. const size_t arraySize = buckets.size();
  83. for (size_t i = 0; i < bucketsToClear; ++i) {
  84. TValueType& curVal = buckets[firstElemIndex];
  85. windowValue.Sum -= curVal.Sum;
  86. windowValue.Count -= curVal.Count;
  87. curVal = InitialValue();
  88. firstElemIndex = (firstElemIndex + 1) % arraySize;
  89. }
  90. return windowValue;
  91. }
  92. };
  93. class TSelfPingActor : public TActorBootstrapped<TSelfPingActor> {
  94. private:
  95. const TDuration SendInterval;
  96. const NMonitoring::TDynamicCounters::TCounterPtr MaxPingCounter;
  97. const NMonitoring::TDynamicCounters::TCounterPtr AvgPingCounter;
  98. const NMonitoring::TDynamicCounters::TCounterPtr AvgPingCounterWithSmallWindow;
  99. const NMonitoring::TDynamicCounters::TCounterPtr CalculationTimeCounter;
  100. NSlidingWindow::TSlidingWindow<NSlidingWindow::TMaxOperation<ui64>> MaxPingSlidingWindow;
  101. NSlidingWindow::TSlidingWindow<TAvgOperation<ui64>> AvgPingSlidingWindow;
  102. NSlidingWindow::TSlidingWindow<TAvgOperation<ui64>> AvgPingSmallSlidingWindow;
  103. NSlidingWindow::TSlidingWindow<TAvgOperation<ui64>> CalculationSlidingWindow;
  104. THPTimer Timer;
  105. public:
  106. static constexpr auto ActorActivityType() {
  107. return EActivityType::SELF_PING_ACTOR;
  108. }
  109. TSelfPingActor(TDuration sendInterval,
  110. const NMonitoring::TDynamicCounters::TCounterPtr& maxPingCounter,
  111. const NMonitoring::TDynamicCounters::TCounterPtr& avgPingCounter,
  112. const NMonitoring::TDynamicCounters::TCounterPtr& avgPingSmallWindowCounter,
  113. const NMonitoring::TDynamicCounters::TCounterPtr& calculationTimeCounter)
  114. : SendInterval(sendInterval)
  115. , MaxPingCounter(maxPingCounter)
  116. , AvgPingCounter(avgPingCounter)
  117. , AvgPingCounterWithSmallWindow(avgPingSmallWindowCounter)
  118. , CalculationTimeCounter(calculationTimeCounter)
  119. , MaxPingSlidingWindow(TDuration::Seconds(15), 100)
  120. , AvgPingSlidingWindow(TDuration::Seconds(15), 100)
  121. , AvgPingSmallSlidingWindow(TDuration::Seconds(1), 100)
  122. , CalculationSlidingWindow(TDuration::Seconds(15), 100)
  123. {
  124. }
  125. void Bootstrap(const TActorContext& ctx)
  126. {
  127. Become(&TSelfPingActor::RunningState);
  128. SchedulePing(ctx, Timer.Passed());
  129. }
  130. STFUNC(RunningState)
  131. {
  132. switch (ev->GetTypeRewrite()) {
  133. HFunc(TEvPing, HandlePing);
  134. default:
  135. Y_FAIL("TSelfPingActor::RunningState: unexpected event 0x%08" PRIx32, ev->GetTypeRewrite());
  136. }
  137. }
  138. void HandlePing(TEvPing::TPtr &ev, const TActorContext &ctx)
  139. {
  140. const auto now = ctx.Now();
  141. const double hpNow = Timer.Passed();
  142. const auto& e = *ev->Get();
  143. const double passedTime = hpNow - e.TimeStart;
  144. const ui64 delayUs = passedTime > 0.0 ? static_cast<ui64>(passedTime * 1e6) : 0;
  145. if (MaxPingCounter) {
  146. *MaxPingCounter = MaxPingSlidingWindow.Update(delayUs, now);
  147. }
  148. if (AvgPingCounter) {
  149. auto res = AvgPingSlidingWindow.Update({1, delayUs}, now);
  150. *AvgPingCounter = double(res.Sum) / double(res.Count + 1);
  151. }
  152. if (AvgPingCounterWithSmallWindow) {
  153. auto res = AvgPingSmallSlidingWindow.Update({1, delayUs}, now);
  154. *AvgPingCounterWithSmallWindow = double(res.Sum) / double(res.Count + 1);
  155. }
  156. if (CalculationTimeCounter) {
  157. ui64 d = MeasureTaskDurationNs();
  158. auto res = CalculationSlidingWindow.Update({1, d}, now);
  159. *CalculationTimeCounter = double(res.Sum) / double(res.Count + 1);
  160. }
  161. SchedulePing(ctx, hpNow);
  162. }
  163. private:
  164. void SchedulePing(const TActorContext &ctx, double hpNow) const
  165. {
  166. ctx.Schedule(SendInterval, new TEvPing(hpNow));
  167. }
  168. };
  169. } // namespace
  170. IActor* CreateSelfPingActor(
  171. TDuration sendInterval,
  172. const NMonitoring::TDynamicCounters::TCounterPtr& maxPingCounter,
  173. const NMonitoring::TDynamicCounters::TCounterPtr& avgPingCounter,
  174. const NMonitoring::TDynamicCounters::TCounterPtr& avgPingSmallWindowCounter,
  175. const NMonitoring::TDynamicCounters::TCounterPtr& calculationTimeCounter)
  176. {
  177. return new TSelfPingActor(sendInterval, maxPingCounter, avgPingCounter, avgPingSmallWindowCounter, calculationTimeCounter);
  178. }
  179. } // NActors