probe.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #pragma once
  2. #include "event.h"
  3. #include "preprocessor.h"
  4. #include "rwspinlock.h"
  5. #include "shuttle.h"
  6. #include <util/datetime/cputimer.h>
  7. #include <util/generic/hide_ptr.h>
  8. #include <util/generic/scope.h>
  9. #include <library/cpp/deprecated/atomic/atomic.h>
  10. namespace NLWTrace {
  11. // Represents a chain (linked list) of steps for execution of a trace query block
  12. // NOTE: different executor objects are used on different probes (even for the same query block)
  13. class IExecutor {
  14. private:
  15. IExecutor* Next;
  16. public:
  17. IExecutor()
  18. : Next(nullptr)
  19. {
  20. }
  21. virtual ~IExecutor() {
  22. if (Next != nullptr) {
  23. delete Next;
  24. }
  25. }
  26. void Execute(TOrbit& orbit, const TParams& params) {
  27. if (DoExecute(orbit, params) && Next != nullptr) {
  28. Next->Execute(orbit, params);
  29. }
  30. }
  31. void SetNext(IExecutor* next) {
  32. Next = next;
  33. }
  34. IExecutor* GetNext() {
  35. return Next;
  36. }
  37. const IExecutor* GetNext() const {
  38. return Next;
  39. }
  40. protected:
  41. virtual bool DoExecute(TOrbit& orbit, const TParams& params) = 0;
  42. };
  43. // Common class for all probes
  44. struct TProbe {
  45. // Const configuration
  46. TEvent Event;
  47. // State that don't need any locking
  48. TAtomic ExecutorsCount;
  49. // State that must be accessed under lock
  50. TRWSpinLock Lock;
  51. IExecutor* Executors[LWTRACE_MAX_ACTIONS];
  52. IExecutor** Front; // Invalid if ExecutorsCount == 0
  53. IExecutor** Back; // Invalid if ExecutorsCount == 0
  54. void Init() {
  55. ExecutorsCount = 0;
  56. Lock.Init();
  57. Zero(Executors);
  58. Front = nullptr;
  59. Back = nullptr;
  60. }
  61. IExecutor** First() {
  62. return Executors;
  63. }
  64. IExecutor** Last() {
  65. return Executors + LWTRACE_MAX_ACTIONS;
  66. }
  67. void Inc(IExecutor**& it) {
  68. it++;
  69. if (it == Last()) {
  70. it = First();
  71. }
  72. }
  73. intptr_t GetExecutorsCount() const {
  74. return AtomicGet(ExecutorsCount);
  75. }
  76. bool Attach(IExecutor* exec) {
  77. TWriteSpinLockGuard g(Lock);
  78. if (ExecutorsCount > 0) {
  79. for (IExecutor** it = Front;; Inc(it)) {
  80. if (*it == nullptr) {
  81. *it = exec;
  82. AtomicIncrement(ExecutorsCount);
  83. return true; // Inserted into free slot in [First; Last]
  84. }
  85. if (it == Back) {
  86. break;
  87. }
  88. }
  89. IExecutor** newBack = Back;
  90. Inc(newBack);
  91. if (newBack == Front) {
  92. return false; // Buffer is full
  93. } else {
  94. Back = newBack;
  95. *Back = exec;
  96. AtomicIncrement(ExecutorsCount);
  97. return true; // Inserted after Last
  98. }
  99. } else {
  100. Front = Back = First();
  101. *Front = exec;
  102. AtomicIncrement(ExecutorsCount);
  103. return true; // Inserted as a first element
  104. }
  105. }
  106. bool Detach(IExecutor* exec) {
  107. TWriteSpinLockGuard g(Lock);
  108. for (IExecutor** it = First(); it != Last(); it++) {
  109. if ((*it) == exec) {
  110. *it = nullptr;
  111. AtomicDecrement(ExecutorsCount);
  112. if (ExecutorsCount > 0) {
  113. for (;; Inc(Front)) {
  114. if (*Front != nullptr) {
  115. break;
  116. }
  117. if (Front == Back) {
  118. break;
  119. }
  120. }
  121. }
  122. return true;
  123. }
  124. }
  125. return false;
  126. }
  127. void RunExecutors(TOrbit& orbit, const TParams& params) {
  128. // Read lock is implied
  129. if (ExecutorsCount > 0) {
  130. for (IExecutor** it = Front;; Inc(it)) {
  131. IExecutor* exec = *it;
  132. if (exec) {
  133. exec->Execute(orbit, params);
  134. }
  135. if (it == Back) {
  136. break;
  137. }
  138. }
  139. }
  140. }
  141. void RunShuttles(TOrbit& orbit, const TParams& params) {
  142. orbit.AddProbe(this, params);
  143. }
  144. };
  145. #ifndef LWTRACE_DISABLE
  146. template <class T>
  147. inline void PreparePtr(const T& ref, const T*& ptr) {
  148. ptr = &ref;
  149. }
  150. template <>
  151. inline void PreparePtr<TNil>(const TNil&, const TNil*&) {
  152. }
  153. #define LWTRACE_SCOPED_FUNCTION_PARAMS_I(i) (1) typename ::NLWTrace::TParamTraits<TP##i>::TFuncParam p##i = ERROR_not_enough_parameters() LWTRACE_COMMA
  154. #define LWTRACE_SCOPED_FUNCTION_PARAMS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_SCOPED_FUNCTION_PARAMS_I)(0))
  155. #define LWTRACE_SCOPED_FUNCTION_PARAMS_BY_REF_I(i) (1) typename ::NLWTrace::TParamTraits<TP##i>::TStoreType& p##i = *(ERROR_not_enough_parameters*)(HidePointerOrigin(nullptr))LWTRACE_COMMA
  156. #define LWTRACE_SCOPED_FUNCTION_PARAMS_BY_REF LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_SCOPED_FUNCTION_PARAMS_BY_REF_I)(0))
  157. #define LWTRACE_SCOPED_PREPARE_PTRS_I(i) PreparePtr(p##i, P##i);
  158. #define LWTRACE_SCOPED_PREPARE_PTRS() \
  159. do { \
  160. FOREACH_PARAMNUM(LWTRACE_SCOPED_PREPARE_PTRS_I) \
  161. } while (false)
  162. #define LWTRACE_SCOPED_PREPARE_PARAMS_I(i, params) params.Param[i].CopyConstruct<typename ::NLWTrace::TParamTraits<TP##i>::TStoreType>(*P##i);
  163. #define LWTRACE_SCOPED_PREPARE_PARAMS(params) \
  164. do { \
  165. FOREACH_PARAMNUM(LWTRACE_SCOPED_PREPARE_PARAMS_I, params) \
  166. } while (false)
  167. template <LWTRACE_TEMPLATE_PARAMS>
  168. struct TUserProbe;
  169. template <LWTRACE_TEMPLATE_PARAMS>
  170. class TScopedDurationImpl {
  171. private:
  172. TUserProbe<LWTRACE_TEMPLATE_ARGS>* Probe;
  173. ui64 Started;
  174. TParams Params;
  175. public:
  176. explicit TScopedDurationImpl(TUserProbe<LWTRACE_TEMPLATE_ARGS>& probe, LWTRACE_SCOPED_FUNCTION_PARAMS) {
  177. if (probe.Probe.GetExecutorsCount() > 0) {
  178. Probe = &probe;
  179. LWTRACE_PREPARE_PARAMS(Params);
  180. Started = GetCycleCount();
  181. } else {
  182. Probe = nullptr;
  183. }
  184. }
  185. ~TScopedDurationImpl() {
  186. if (Probe) {
  187. if (Probe->Probe.GetExecutorsCount() > 0) {
  188. TReadSpinLockGuard g(Probe->Probe.Lock);
  189. if (Probe->Probe.GetExecutorsCount() > 0) {
  190. ui64 duration = CyclesToDuration(GetCycleCount() - Started).MicroSeconds();
  191. Params.Param[0].template CopyConstruct<typename TParamTraits<TP0>::TStoreType>(duration);
  192. TOrbit orbit;
  193. Probe->Probe.RunExecutors(orbit, Params);
  194. }
  195. }
  196. TUserSignature<LWTRACE_TEMPLATE_ARGS>::DestroyParams(Params);
  197. }
  198. }
  199. };
  200. // Class representing a specific probe
  201. template <LWTRACE_TEMPLATE_PARAMS_NODEF>
  202. struct TUserProbe {
  203. TProbe Probe;
  204. inline void operator()(LWTRACE_FUNCTION_PARAMS) {
  205. TParams params;
  206. LWTRACE_PREPARE_PARAMS(params);
  207. Y_DEFER { TUserSignature<LWTRACE_TEMPLATE_ARGS>::DestroyParams(params); };
  208. TOrbit orbit;
  209. Probe.RunExecutors(orbit, params);
  210. }
  211. inline void Run(TOrbit& orbit, LWTRACE_FUNCTION_PARAMS) {
  212. TParams params;
  213. LWTRACE_PREPARE_PARAMS(params);
  214. Y_DEFER { TUserSignature<LWTRACE_TEMPLATE_ARGS>::DestroyParams(params); };
  215. Probe.RunExecutors(orbit, params);
  216. Probe.RunShuttles(orbit, params); // Executors can create shuttles
  217. }
  218. // Required to avoid running executors w/o lock
  219. inline void RunShuttles(TOrbit& orbit, LWTRACE_FUNCTION_PARAMS) {
  220. TParams params;
  221. LWTRACE_PREPARE_PARAMS(params);
  222. Probe.RunShuttles(orbit, params);
  223. TUserSignature<LWTRACE_TEMPLATE_ARGS>::DestroyParams(params);
  224. }
  225. typedef TScopedDurationImpl<LWTRACE_TEMPLATE_ARGS> TScopedDuration;
  226. };
  227. #endif
  228. }