selfping_actor.cpp 5.9 KB

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