jdebug.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  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 JDEBUG_HPP
  14. #define JDEBUG_HPP
  15. #include "jiface.hpp"
  16. #include "jstats.h"
  17. #include <atomic>
  18. #define TIMING
  19. __int64 jlib_decl cycle_to_nanosec(cycle_t cycles);
  20. __int64 jlib_decl cycle_to_microsec(cycle_t cycles);
  21. __int64 jlib_decl cycle_to_millisec(cycle_t cycles);
  22. cycle_t jlib_decl nanosec_to_cycle(__int64 cycles);
  23. double jlib_decl getCycleToNanoScale();
  24. void jlib_decl display_time(const char * title, cycle_t diff);
  25. // X86 / X86_64
  26. #if defined(_ARCH_X86_64_) || defined(_ARCH_X86_)
  27. #define HAS_GOOD_CYCLE_COUNTER
  28. #if defined(_WIN32) && defined (_ARCH_X86_)
  29. #pragma warning(push)
  30. #pragma warning(disable:4035)
  31. inline cycle_t getTSC() { __asm { __asm _emit 0x0f __asm _emit 0x31 } }
  32. #pragma warning(pop)
  33. #elif !defined(_WIN32)
  34. inline __int64 getTSC()
  35. {
  36. unsigned a, d;
  37. __asm__ volatile("rdtsc" : "=a" (a), "=d" (d));
  38. return ((cycle_t)a)|(((cycle_t)d) << 32);
  39. }
  40. #else
  41. #include <intrin.h>
  42. inline cycle_t getTSC() { return __rdtsc(); }
  43. #endif // WIN32
  44. #elif defined(_ARCH_PPC)
  45. #define HAS_GOOD_CYCLE_COUNTER
  46. static inline cycle_t getTSC()
  47. {
  48. int64_t result;
  49. #ifdef _ARCH_PPC64
  50. /*
  51. This reads timebase in one 64bit go. Does *not* include a workaround for the cell (see
  52. http://ozlabs.org/pipermail/linuxppc-dev/2006-October/027052.html)
  53. */
  54. __asm__ volatile(
  55. "mftb %0"
  56. : "=r" (result));
  57. #else
  58. /*
  59. Read the high 32bits of the timer, then the lower, and repeat if high order has changed in the meantime. See
  60. http://ozlabs.org/pipermail/linuxppc-dev/1999-October/003889.html
  61. */
  62. unsigned long dummy;
  63. __asm__ volatile(
  64. "mfspr %1,269\n\t" /* mftbu */
  65. "mfspr %L0,268\n\t" /* mftb */
  66. "mfspr %0,269\n\t" /* mftbu */
  67. "cmpw %0,%1\n\t" /* check if the high order word has chanegd */
  68. "bne $-16"
  69. : "=r" (result), "=r" (dummy));
  70. #endif
  71. return result;
  72. }
  73. #else
  74. // ARMFIX: cycle-count is not always available in user mode
  75. // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0338g/Bihbeabc.html
  76. // http://neocontra.blogspot.co.uk/2013/05/user-mode-performance-counters-for.html
  77. inline cycle_t getTSC() { return 0; }
  78. #endif // X86
  79. #if defined(INLINE_GET_CYCLES_NOW) && defined(HAS_GOOD_CYCLE_COUNTER)
  80. inline cycle_t get_cycles_now() { return getTSC(); }
  81. #else
  82. cycle_t jlib_decl get_cycles_now(); // equivalent to getTSC when available
  83. #endif
  84. struct HardwareInfo
  85. {
  86. unsigned numCPUs;
  87. unsigned CPUSpeed; // In MHz
  88. unsigned totalMemory; // In MB
  89. unsigned primDiskSize; // In GB
  90. unsigned primFreeSize; // In GB
  91. unsigned secDiskSize; // In GB
  92. unsigned secFreeSize; // In GB
  93. unsigned NICSpeed; //
  94. };
  95. struct UserSystemTime_t
  96. {
  97. public:
  98. UserSystemTime_t() : user(0), system(0) {}
  99. unsigned user;
  100. unsigned system;
  101. };
  102. interface ITimeReportInfo
  103. {
  104. virtual void report(const char * scope, const __int64 totaltime, const __int64 maxtime, const unsigned count) = 0;
  105. };
  106. class StringBuffer;
  107. class MemoryBuffer;
  108. struct ITimeReporter : public IInterface
  109. {
  110. virtual void addTiming(const char * scope, cycle_t cycles) = 0;
  111. virtual void mergeTiming(const char * scope, cycle_t totalcycles, cycle_t maxcycles, const unsigned count) = 0;
  112. virtual StringBuffer &getTimings(StringBuffer &s) = 0;
  113. virtual void printTimings() = 0;
  114. virtual void reset() = 0;
  115. virtual void mergeInto(ITimeReporter &other) = 0; // Used internally
  116. virtual void merge(ITimeReporter &other)= 0;
  117. virtual void report(ITimeReportInfo &cb) = 0;
  118. };
  119. extern jlib_decl cycle_t oneSecInCycles;
  120. class CCycleTimer
  121. {
  122. cycle_t start_time;
  123. public:
  124. inline CCycleTimer()
  125. {
  126. reset();
  127. }
  128. inline void reset()
  129. {
  130. start_time = get_cycles_now();
  131. }
  132. inline cycle_t elapsedCycles() const
  133. {
  134. return get_cycles_now() - start_time;
  135. }
  136. inline unsigned __int64 elapsedNs() const
  137. {
  138. return cycle_to_nanosec(elapsedCycles());
  139. }
  140. inline unsigned elapsedMs() const
  141. {
  142. return static_cast<unsigned>(cycle_to_millisec(elapsedCycles()));
  143. }
  144. };
  145. inline cycle_t queryOneSecCycles() { return oneSecInCycles; }
  146. class jlib_decl TimeSection
  147. {
  148. public:
  149. TimeSection(const char * _title);
  150. ~TimeSection();
  151. protected:
  152. const char * title;
  153. cycle_t start_time;
  154. };
  155. class jlib_decl MTimeSection
  156. {
  157. public:
  158. MTimeSection(ITimeReporter *_master, const char * scope);
  159. ~MTimeSection();
  160. protected:
  161. const char * scope;
  162. cycle_t start_time;
  163. ITimeReporter *master;
  164. };
  165. #if defined(TIMING)
  166. extern jlib_decl ITimeReporter * queryActiveTimer();
  167. extern jlib_decl ITimeReporter *createStdTimeReporter();
  168. #define TIME_SECTION(title) TimeSection glue(_timer,__LINE__)(title);
  169. #define MTIME_SECTION(master,title) MTimeSection glue(mtimer,__LINE__)(master, title);
  170. #else
  171. #define TIME_SECTION(title)
  172. #define MTIME_SECTION(master,title)
  173. #endif
  174. extern jlib_decl unsigned usTick();
  175. class jlib_decl HiresTimer
  176. {
  177. public:
  178. inline HiresTimer()
  179. {
  180. start=usTick();
  181. }
  182. inline void reset()
  183. {
  184. start=usTick();
  185. }
  186. inline double get()
  187. {
  188. return (double)(usTick()-start)/1000000;
  189. }
  190. private:
  191. unsigned start;
  192. };
  193. //---------------------------------------------------------------------------------------------------------------------
  194. /*
  195. There are several situations where we want to record the time spent waiting for items to be processed - time an item
  196. is queued before processing, time spent calling LDAP from within esp etc.. Gathering the metric has a few complications:
  197. * The metric gathering needs to have minimal impact
  198. * The waiting time needs to include items that are currently waiting as well completed
  199. * Multiple items can be being waited for at the same time, and complete at different times.
  200. waitingTime = sum(itemTime)
  201. = sum(completedItemTime) + sum(inflightItemTime)
  202. = sum(endCompletedTime-startCompletedTime) + sum(currentTime-startInflightTime))
  203. = sumEndCompletedTime - sumStartCompletedTime + sum(currentTime) - sumStartInflightTime
  204. = sumEndCompletedTime + num*current - sumStartTime
  205. The following pattern efficiently solves the problem:
  206. * When an item is queued/started atomically increment a counter, and add the current timestamp to the accumulated start time stamps.
  207. * When an items is dequeued/complete atomically decrement a counter and add the current timestamp to the accumulated end time stamps.
  208. * To calculate the waiting time use (sumEndTimestamps + numWaiting * currentTimeStamp) - sumStartTimestamps.
  209. At first glance this appears to have a problem because sumEndTimestamps will quickly overflow, but because of the
  210. properties of modulo arithmetic, the final result will be correct even if it has overflowed!
  211. Also since you are only ever interested in (sumEndTimestamps - sumStartTimestamps) the same field can be used for both.
  212. There are two versions, one that uses a critical section, and a second that uses atomics, but is limited to the number
  213. of active blocked items.
  214. */
  215. class jlib_decl BlockedTimeTracker
  216. {
  217. public:
  218. BlockedTimeTracker() = default;
  219. BlockedTimeTracker(const BlockedTimeTracker &) = delete;
  220. void noteWaiting();
  221. void noteComplete();
  222. __uint64 getWaitingNs() const;
  223. private:
  224. mutable CriticalSection cs;
  225. unsigned numWaiting = 0;
  226. cycle_t timeStampTally = 0;
  227. };
  228. class jlib_decl BlockedSection
  229. {
  230. public:
  231. BlockedSection(BlockedTimeTracker & _tracker) : tracker(_tracker) { tracker.noteWaiting(); }
  232. ~BlockedSection() { tracker.noteComplete(); }
  233. private:
  234. BlockedTimeTracker & tracker;
  235. };
  236. //Lightweight version that uses a single atomic, but has a limit on the number of active blocked items
  237. //Easier to understand by looking at the code for the BlockedTimeTracker class
  238. //Could be a template class (for MAX_ACTIVE), but I doubt it is worth it.
  239. class jlib_decl LightweightBlockedTimeTracker
  240. {
  241. //MAX_ACTIVE should be a power of 2 for efficiency, 256 gives a max blocked time of about half a year before wrapping.
  242. static constexpr unsigned MAX_ACTIVE = 256;
  243. public:
  244. LightweightBlockedTimeTracker() = default;
  245. LightweightBlockedTimeTracker(const LightweightBlockedTimeTracker &) = delete;
  246. void noteWaiting() { timeStampTally.fetch_sub((get_cycles_now() * MAX_ACTIVE) - 1); } // i.e. add 1 and subtract the time
  247. void noteComplete() { timeStampTally.fetch_add((get_cycles_now() * MAX_ACTIVE) - 1); }
  248. __uint64 getWaitingNs() const;
  249. private:
  250. std::atomic<__uint64> timeStampTally{0}; // timestamp * MAX_ACTIVE + active
  251. };
  252. class jlib_decl LightweightBlockedSection
  253. {
  254. public:
  255. LightweightBlockedSection(LightweightBlockedTimeTracker & _tracker) : tracker(_tracker) { tracker.noteWaiting(); }
  256. ~LightweightBlockedSection() { tracker.noteComplete(); }
  257. private:
  258. LightweightBlockedTimeTracker & tracker;
  259. };
  260. //===========================================================================
  261. #ifndef USING_MPATROL
  262. #ifdef _DEBUG
  263. #define LEAK_CHECK
  264. #endif
  265. #endif
  266. #ifdef LEAK_CHECK
  267. #ifdef _WIN32
  268. #include <stdio.h>
  269. #define _CRTDBG_MAP_ALLOC
  270. #include <crtdbg.h>
  271. #define CHECK_FOR_LEAKS(title) LeakChecker checker##__LINE__(title)
  272. class jlib_decl LeakChecker
  273. {
  274. public:
  275. LeakChecker(const char * _title);
  276. ~LeakChecker();
  277. protected:
  278. const char * title;
  279. _CrtMemState oldMemState;
  280. };
  281. extern jlib_decl void logLeaks (const char *logFile); // logFile may be NULL, leaks are logged to only stderr in this case
  282. extern jlib_decl void logLeaks (FILE *logHandle); // only use predefined file handles like stderr and stdout
  283. #else
  284. #define CHECK_FOR_LEAKS(title)
  285. #define logLeaks(name)
  286. #endif
  287. #else
  288. #define CHECK_FOR_LEAKS(title)
  289. #define logLeaks(name)
  290. #endif
  291. #if !defined(USING_MPATROL) && defined(_DEBUG) && (defined(_WIN32) || defined(WIN32))
  292. void jlib_decl enableMemLeakChecking(bool enable);
  293. #else
  294. #define enableMemLeakChecking(enable)
  295. #endif
  296. // Hook to be called by the performance monitor, takes stats for processor, virtual memory, disk, and thread usage
  297. class jlib_decl CpuInfo
  298. {
  299. public:
  300. CpuInfo() = default;
  301. CpuInfo(bool processTime, bool systemTime);
  302. void clear();
  303. bool getProcessTimes();
  304. bool getSystemTimes();
  305. CpuInfo operator - (const CpuInfo & rhs) const;
  306. __uint64 getNumContextSwitches() const { return ctx; }
  307. unsigned getPercentCpu() const;
  308. __uint64 getSystemNs() const;
  309. __uint64 getUserNs() const;
  310. __uint64 getTotalNs() const;
  311. unsigned getIdlePercent() const;
  312. unsigned getIoWaitPercent() const;
  313. unsigned getSystemPercent() const;
  314. unsigned getUserPercent() const;
  315. __uint64 getTotal() const { return user + system + idle + iowait; }
  316. protected:
  317. __uint64 user = 0; // user time in jiffies (~`1/100s)
  318. __uint64 system = 0;
  319. __uint64 idle = 0;
  320. __uint64 iowait =0;
  321. __uint64 ctx =0;
  322. };
  323. //Information about a single IO device
  324. class jlib_decl BlockIoStats
  325. {
  326. public:
  327. void clear();
  328. BlockIoStats & operator += (const BlockIoStats & other);
  329. BlockIoStats operator - (const BlockIoStats & other) const;
  330. unsigned getSectorSize() const { return 512; }
  331. public:
  332. unsigned rd_ios = 0; // Read I/O operations
  333. unsigned rd_merges = 0; // Reads merged
  334. __uint64 rd_sectors = 0; // Sectors read
  335. unsigned rd_ticks = 0; // Time in queue + service for read
  336. unsigned wr_ios = 0; // Write I/O operations
  337. unsigned wr_merges = 0; // Writes merged
  338. __uint64 wr_sectors = 0; // Sectors written
  339. unsigned wr_ticks = 0; // Time in queue + service for write
  340. unsigned ticks = 0; // Time of requests in queue
  341. unsigned aveq = 0; // Average queue length
  342. };
  343. //Information about all the block IO devices being tracked
  344. class jlib_decl OsDiskStats
  345. {
  346. public:
  347. OsDiskStats();
  348. OsDiskStats(bool updateNow);
  349. ~OsDiskStats();
  350. bool updateCurrent();
  351. unsigned getNumPartitions() const;
  352. const BlockIoStats & queryStats(unsigned i) const { return stats[i]; }
  353. const BlockIoStats & querySummaryStats() const { return total; }
  354. protected:
  355. BlockIoStats * stats;
  356. BlockIoStats total;
  357. };
  358. class jlib_decl OsNetworkStats
  359. {
  360. public:
  361. OsNetworkStats() = default;
  362. OsNetworkStats(const char * ifname);
  363. bool updateCurrent(const char * ifname); // ifname = null gathers all matches
  364. OsNetworkStats operator - (const OsNetworkStats & other) const;
  365. public:
  366. __uint64 rxbytes = 0;
  367. __uint64 rxpackets = 0;
  368. __uint64 rxerrors = 0;
  369. __uint64 rxdrops = 0;
  370. __uint64 txbytes = 0;
  371. __uint64 txpackets = 0;
  372. __uint64 txerrors = 0;
  373. __uint64 txdrops = 0;
  374. };
  375. interface IPerfMonHook : extends IInterface
  376. {
  377. public:
  378. virtual void processPerfStats(unsigned processorUsage, unsigned memoryUsage, unsigned memoryTotal, unsigned __int64 fistDiskUsage, unsigned __int64 firstDiskTotal, unsigned __int64 secondDiskUsage, unsigned __int64 secondDiskTotal, unsigned threadCount) = 0;
  379. virtual StringBuffer &extraLogging(StringBuffer &extra) = 0; // for extra periodic logging
  380. virtual void log(int level, const char *msg) = 0;
  381. };
  382. enum
  383. {
  384. //do nothing modes:
  385. PerfMonSilent = 0x00,
  386. //individual components:
  387. PerfMonProcMem = 0x01,
  388. PerfMonPackets = 0x02,
  389. PerfMonDiskUsage = 0x04,
  390. //default and full modes:
  391. PerfMonExtended = 0x08,
  392. // UDP packet loss tracing
  393. PerfMonUDP = 0x10,
  394. #ifdef _WIN32
  395. PerfMonStandard = PerfMonProcMem
  396. #else
  397. PerfMonStandard = PerfMonProcMem|PerfMonExtended
  398. #endif
  399. };
  400. interface IUserMetric : extends IInterface
  401. {
  402. virtual unsigned __int64 queryCount() const = 0;
  403. virtual const char *queryName() const = 0;
  404. virtual const char *queryMatchString() const = 0;
  405. virtual void inc() = 0;
  406. virtual void reset() = 0;
  407. };
  408. extern jlib_decl IUserMetric * createUserMetric(const char *name, const char *matchString);
  409. typedef unsigned PerfMonMode;
  410. void jlib_decl getSystemTraceInfo(StringBuffer &str, PerfMonMode mode = PerfMonProcMem);
  411. void jlib_decl startPerformanceMonitor(unsigned interval, PerfMonMode traceMode = PerfMonStandard, IPerfMonHook * hook = NULL);
  412. void jlib_decl stopPerformanceMonitor();
  413. void jlib_decl setPerformanceMonitorHook(IPerfMonHook *hook);
  414. void jlib_decl setPerformanceMonitorPrimaryFileSystem(char const * fs); // for monitoring disk1, defaults to C: (win) or / (linux)
  415. void jlib_decl setPerformanceMonitorSecondaryFileSystem(char const * fs); // for monitoring disk2, no default
  416. unsigned jlib_decl getLatestCPUUsage();
  417. __int64 jlib_decl getTotalMem();
  418. unsigned jlib_decl setAllocHook(bool on); // bwd compat returns unsigned
  419. #if defined(__GLIBC) && !defined(_DEBUG)
  420. #if __GLIBC_PREREQ(2, 14)
  421. #define USE_JLIB_ALLOC_HOOK extern void jlib_decl jlib_init_hook(); void (* volatile __malloc_initialize_hook) (void) = jlib_init_hook;
  422. #else
  423. #define USE_JLIB_ALLOC_HOOK extern void jlib_decl jlib_init_hook(); void (* __malloc_initialize_hook) (void) = jlib_init_hook;
  424. #endif
  425. #else
  426. #define USE_JLIB_ALLOC_HOOK
  427. #endif
  428. enum class HugePageMode { Always, Madvise, Never, Unknown };
  429. extern jlib_decl void getHardwareInfo(HardwareInfo &hdwInfo, const char *primDiskPath = NULL, const char *secDiskPath = NULL);
  430. extern jlib_decl void getProcessTime(UserSystemTime_t & time);
  431. extern jlib_decl memsize_t getMapInfo(const char *type);
  432. extern jlib_decl memsize_t getVMInfo(const char *type);
  433. extern jlib_decl void getCpuInfo(unsigned &numCPUs, unsigned &CPUSpeed);
  434. extern jlib_decl void getPeakMemUsage(memsize_t &peakVm,memsize_t &peakResident);
  435. extern jlib_decl unsigned getAffinityCpus();
  436. extern jlib_decl void clearAffinityCache(); // should be called whenever the process affinity is changed to reset the cache
  437. extern jlib_decl void printProcMap(const char *fn, bool printbody, bool printsummary, StringBuffer *lnout, MemoryBuffer *mb, bool useprintf);
  438. extern jlib_decl void PrintMemoryReport(bool full=true);
  439. extern jlib_decl void printAllocationSummary();
  440. extern jlib_decl bool printProcessHandles(unsigned pid=0); // returns false if fails
  441. extern jlib_decl bool printLsOf(unsigned pid=0); // returns false if fails
  442. extern jlib_decl bool areTransparentHugePagesEnabled(HugePageMode mode);
  443. extern jlib_decl HugePageMode queryTransparentHugePagesMode();
  444. extern jlib_decl memsize_t getHugePageSize();
  445. #endif