jdebug.cpp 109 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833
  1. /*##############################################################################
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. ############################################################################## */
  12. #include "platform.h"
  13. #include "jdebug.hpp"
  14. #include "jstring.hpp"
  15. #include "jhash.hpp"
  16. #include "jmisc.hpp"
  17. #include "jexcept.hpp"
  18. #include "jmutex.hpp"
  19. #include "jtime.hpp"
  20. #include <stdio.h>
  21. #include <time.h>
  22. #include <atomic>
  23. #if defined(_DEBUG) && defined(_WIN32) && !defined(USING_MPATROL)
  24. #undef new
  25. #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
  26. #endif
  27. #ifdef _WIN32
  28. #define DPSAPI_VERSION 1
  29. #include <psapi.h>
  30. #endif
  31. #ifdef __linux__
  32. #include <sys/time.h>
  33. #include <sys/resource.h>
  34. #include <unistd.h>
  35. #include <sys/vfs.h>
  36. #include <sys/types.h>
  37. #include <sys/stat.h>
  38. #include <sys/klog.h>
  39. #include <dirent.h>
  40. #endif
  41. #ifdef __APPLE__
  42. #include <sys/param.h>
  43. #include <sys/mount.h>
  44. #include <sys/sysctl.h>
  45. #include <mach/task.h>
  46. #include <mach/mach_init.h>
  47. #include <mach/mach_host.h>
  48. #include <mach/vm_statistics.h>
  49. #endif
  50. #include "build-config.h"
  51. //===========================================================================
  52. #ifdef _DEBUG
  53. // #define _USE_MALLOC_HOOK // Only enable if you need it - slow!
  54. #else
  55. #undef _USE_MALLOC_HOOK // don't define for release - not threadsafe
  56. #endif
  57. #define _USE_RDTSC true
  58. #ifdef _USE_MALLOC_HOOK
  59. #define REPORT_LARGER_BLOCK_THAN (10*0x100000)
  60. static __int64 totalMem = 0;
  61. static __int64 hwmTotalMem = 0;
  62. #ifdef __linux__
  63. static unsigned memArea[32];
  64. #endif
  65. #endif
  66. // FIXME: Make sure this is still relevant, and if not, delete
  67. #ifndef _WIN32
  68. #ifndef __64BIT__
  69. #define USE_OLD_PU
  70. #endif
  71. #endif
  72. /* LINUX SYS: log KEY
  73. ========================
  74. PU (%) is the percentage CPU in use (unchanged from previously).
  75. MU (%) is what percentage of total (all processes) memory is in use
  76. (ram + swap) or in 32 bit is the percentage of 3GB (address space)
  77. used (whichever larger).
  78. MAL is total memory in use (i.e malloced and not freed ) by this
  79. process (= MMP+SBK)
  80. MMP is the sum of memory mapped (large) blocks in use by this process
  81. (which will be returned to OS when freed).
  82. SBK is the sbrk'ed memory i.e. smaller blocks allocated from the
  83. arena. (note this memory is unlikely to be returned to OS while the
  84. process is still running).
  85. TOT (K) is an indication of the memory footprint of the process.
  86. This is the 'arena' size (which is how much reserved by sbrk) plus the
  87. mmap memory size (MMP).
  88. RAM (K) is how much real memory is in use by all processes - it is
  89. the same as what would be reported by the 'free' command after the
  90. caches/buffers have been subtracted.
  91. SWP (K) is the swap size in use for all processes.
  92. Extended stats
  93. DSK: disk statistics for each disk (e.g. [sda] and [sdb])
  94. r/s read i/o operations per sec (over last period)
  95. kr/s K bytes read per sec
  96. w/s write i/o operations per sec
  97. kw/s K bytes written per sec
  98. busy indication how busy the disk was during period (%)
  99. NIC: network (i.e. eth0) statistics
  100. rxp/s packets received per sec
  101. rxk/s K bytes received per sec
  102. txp/s packets transmitted per sec
  103. txk/s K bytes transmitted per sec
  104. CPU:
  105. usr % at user level
  106. sys % in kernel
  107. iow % waiting for i/o
  108. */
  109. inline void skipSp(const char *&s)
  110. {
  111. while (isspace(*s))
  112. s++;
  113. }
  114. inline offset_t readHexNum(const char *&s)
  115. {
  116. offset_t ret = 0;
  117. for (;;) {
  118. switch (*s) {
  119. case '0':
  120. case '1':
  121. case '2':
  122. case '3':
  123. case '4':
  124. case '5':
  125. case '6':
  126. case '7':
  127. case '8':
  128. case '9': ret = ret*16+(*s-'0');
  129. break;
  130. case 'A':
  131. case 'B':
  132. case 'C':
  133. case 'D':
  134. case 'E':
  135. case 'F': ret = ret*16+(*s-'A'+10);
  136. break;
  137. case 'a':
  138. case 'b':
  139. case 'c':
  140. case 'd':
  141. case 'e':
  142. case 'f': ret = ret*16+(*s-'a'+10);
  143. break;
  144. default:
  145. return ret;
  146. }
  147. s++;
  148. }
  149. return 0;
  150. }
  151. inline offset_t readDecNum(const char *&s)
  152. {
  153. offset_t ret = 0;
  154. for (;;) {
  155. switch (*s) {
  156. case '0':
  157. case '1':
  158. case '2':
  159. case '3':
  160. case '4':
  161. case '5':
  162. case '6':
  163. case '7':
  164. case '8':
  165. case '9': ret = ret*10+(*s-'0');
  166. break;
  167. default:
  168. return ret;
  169. }
  170. s++;
  171. }
  172. return 0;
  173. }
  174. #if defined(_WIN32)
  175. static __int64 numCyclesNTicks;
  176. static __int64 ticksPerSec;
  177. static __int64 numScaleTicks;
  178. static bool useRDTSC = _USE_RDTSC;
  179. static double cycleToNanoScale;
  180. static void calibrate_timing()
  181. {
  182. #ifndef _AMD64_
  183. if (useRDTSC)
  184. {
  185. unsigned long r;
  186. __asm {
  187. mov eax, 1 ;
  188. cpuid ;
  189. mov r, edx
  190. }
  191. if ((r&0x10)==0)
  192. useRDTSC = false;
  193. }
  194. #endif
  195. if (useRDTSC) {
  196. unsigned startu = usTick();
  197. cycle_t start = getTSC();
  198. unsigned s1 = msTick();
  199. unsigned s2;
  200. while (s1==(s2=msTick()));
  201. unsigned s3;
  202. while (s2==(s3=msTick()));
  203. unsigned elapsedu = usTick()-startu;
  204. if (elapsedu) {
  205. double numPerUS=(double)(getTSC()-start)/(double)elapsedu; // this probably could be more accurate
  206. if (numPerUS>0)
  207. {
  208. cycleToNanoScale = 1000.0 / numPerUS;
  209. return;
  210. }
  211. }
  212. ERRLOG("calibrate_timing failed using RDTSC");
  213. useRDTSC = false;
  214. }
  215. static LARGE_INTEGER temp;
  216. QueryPerformanceFrequency(&temp);
  217. ticksPerSec = temp.QuadPart;
  218. numScaleTicks = ticksPerSec/100;
  219. LARGE_INTEGER t1;
  220. LARGE_INTEGER t2;
  221. QueryPerformanceCounter(&t1);
  222. t2.QuadPart=t1.QuadPart;
  223. while (t1.QuadPart==t2.QuadPart) QueryPerformanceCounter(&t1);
  224. cycle_t a1 = getTSC();
  225. t2.QuadPart = t1.QuadPart;
  226. while (t2.QuadPart-t1.QuadPart<numScaleTicks) QueryPerformanceCounter(&t2);
  227. cycle_t a2 = getTSC();
  228. numCyclesNTicks = (a2 - a1);
  229. cycleToNanoScale = ((double)numScaleTicks * 1000000000.0) / ((double)numCyclesNTicks * ticksPerSec);
  230. }
  231. __int64 cycle_to_nanosec(cycle_t cycles)
  232. {
  233. return (__int64)((double)cycles * cycleToNanoScale);
  234. }
  235. __int64 jlib_decl cycle_to_microsec(cycle_t cycles)
  236. {
  237. return (__int64)((double)cycles * cycleToNanoScale) / 1000;
  238. }
  239. __int64 jlib_decl cycle_to_millisec(cycle_t cycles)
  240. {
  241. return (__int64)((double)cycles * cycleToNanoScale) / 1000000;
  242. }
  243. cycle_t nanosec_to_cycle(__int64 ns)
  244. {
  245. return (__int64)((double)ns / cycleToNanoScale);
  246. }
  247. #if !(defined(INLINE_GET_CYCLES_NOW) && defined(HAS_GOOD_CYCLE_COUNTER))
  248. cycle_t jlib_decl get_cycles_now()
  249. {
  250. if (useRDTSC)
  251. return getTSC();
  252. LARGE_INTEGER temp;
  253. QueryPerformanceCounter(&temp);
  254. return temp.QuadPart;
  255. }
  256. #endif
  257. double getCycleToNanoScale()
  258. {
  259. return cycleToNanoScale;
  260. }
  261. #else
  262. #if defined(HAS_GOOD_CYCLE_COUNTER)
  263. static bool useRDTSC = _USE_RDTSC;
  264. #endif
  265. static double cycleToNanoScale;
  266. static double cycleToMicroScale;
  267. static double cycleToMilliScale;
  268. void calibrate_timing()
  269. {
  270. #if defined(_ARCH_X86_) || defined(_ARCH_X86_64_)
  271. if (useRDTSC) {
  272. unsigned long eax;
  273. unsigned long ebx;
  274. unsigned long ecx;
  275. unsigned long edx;
  276. #if defined(_ARCH_X86_64_)
  277. __asm__ ("cpuid\n\t" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "0" (1));
  278. #else
  279. // NB PIC code and ebx usage don't mix well
  280. asm volatile("pushl %%ebx \n\t"
  281. "cpuid \n\t"
  282. "movl %%ebx, %1 \n\t"
  283. "popl %%ebx \n\t"
  284. : "=a"(eax), "=r"(ebx), "=c"(ecx), "=d"(edx)
  285. : "a"(1)
  286. : "cc");
  287. #endif
  288. if ((edx&0x10)==0)
  289. useRDTSC = false;
  290. }
  291. #endif
  292. #if defined(HAS_GOOD_CYCLE_COUNTER)
  293. if (useRDTSC) {
  294. unsigned startu = usTick();
  295. cycle_t start = getTSC();
  296. unsigned s1 = msTick();
  297. unsigned s2;
  298. while (s1==(s2=msTick()));
  299. unsigned s3;
  300. while (s2==(s3=msTick()));
  301. unsigned elapsedu = usTick()-startu;
  302. if (elapsedu) {
  303. double numPerUS=(double)(getTSC()-start)/(double)elapsedu; // this probably could be more accurate
  304. if (numPerUS>0)
  305. {
  306. cycleToNanoScale = 1000.0 / numPerUS;
  307. cycleToMicroScale = 1.0 / numPerUS;
  308. cycleToMilliScale = 0.001 / numPerUS;
  309. return;
  310. }
  311. }
  312. ERRLOG("calibrate_timing failed using RDTSC");
  313. useRDTSC = false;
  314. }
  315. #endif
  316. cycleToNanoScale = 1.0;
  317. cycleToMicroScale = 1.0;
  318. cycleToMilliScale = 1.0;
  319. }
  320. #if !defined(INLINE_GET_CYCLES_NOW) || !defined(HAS_GOOD_CYCLE_COUNTER)
  321. #if defined(CLOCK_MONOTONIC) && !defined(__APPLE__)
  322. static bool use_gettimeofday=false;
  323. #endif
  324. cycle_t jlib_decl get_cycles_now()
  325. {
  326. #if defined(HAS_GOOD_CYCLE_COUNTER)
  327. if (useRDTSC)
  328. return getTSC();
  329. #endif
  330. #ifdef __APPLE__
  331. return mach_absolute_time();
  332. #elif defined(CLOCK_MONOTONIC)
  333. if (!use_gettimeofday) {
  334. timespec tm;
  335. if (clock_gettime(CLOCK_MONOTONIC, &tm)>=0)
  336. return ((cycle_t)tm.tv_sec)*1000000000L+(tm.tv_nsec);
  337. use_gettimeofday = true;
  338. fprintf(stderr,"clock_gettime CLOCK_MONOTONIC returns %d",errno); // don't use PROGLOG
  339. }
  340. #endif
  341. struct timeval tm;
  342. gettimeofday(&tm,NULL);
  343. return ((cycle_t)tm.tv_sec)*1000000000L+(cycle_t)tm.tv_usec*1000L;
  344. }
  345. #endif
  346. __int64 jlib_decl cycle_to_nanosec(cycle_t cycles)
  347. {
  348. #if defined(HAS_GOOD_CYCLE_COUNTER)
  349. if (useRDTSC)
  350. return (__int64)((double)cycles * cycleToNanoScale);
  351. #endif
  352. #ifdef __APPLE__
  353. return cycles * (uint64_t) timebase_info.numer / (uint64_t)timebase_info.denom;
  354. #endif
  355. return cycles;
  356. }
  357. __int64 jlib_decl cycle_to_microsec(cycle_t cycles)
  358. {
  359. #if defined(HAS_GOOD_CYCLE_COUNTER)
  360. if (useRDTSC)
  361. return (__int64)((double)cycles * cycleToMicroScale);
  362. #endif
  363. return cycles / 1000;
  364. }
  365. __int64 jlib_decl cycle_to_millisec(cycle_t cycles)
  366. {
  367. #if defined(HAS_GOOD_CYCLE_COUNTER)
  368. if (useRDTSC)
  369. return (__int64)((double)cycles * cycleToMilliScale);
  370. #endif
  371. return cycles / 1000000;
  372. }
  373. cycle_t nanosec_to_cycle(__int64 ns)
  374. {
  375. #if defined(HAS_GOOD_CYCLE_COUNTER)
  376. if (useRDTSC)
  377. return (__int64)((double)ns / cycleToNanoScale);
  378. #endif
  379. return ns;
  380. }
  381. double getCycleToNanoScale()
  382. {
  383. return cycleToNanoScale;
  384. }
  385. #endif
  386. void display_time(const char *title, cycle_t diff)
  387. {
  388. DBGLOG("Time taken for %s: %" I64F "d cycles (%" I64F "dM) = %" I64F "d msec", title, diff, diff/1000000, cycle_to_nanosec(diff)/1000000);
  389. }
  390. TimeSection::TimeSection(const char * _title) : title(_title)
  391. {
  392. start_time = get_cycles_now();
  393. }
  394. TimeSection::~TimeSection()
  395. {
  396. cycle_t end_time = get_cycles_now();
  397. if (title)
  398. display_time(title, end_time-start_time);
  399. }
  400. MTimeSection::MTimeSection(ITimeReporter *_master, const char * _scope) : scope(_scope), master(_master)
  401. {
  402. start_time = get_cycles_now();
  403. }
  404. MTimeSection::~MTimeSection()
  405. {
  406. cycle_t end_time = get_cycles_now();
  407. if (master)
  408. master->addTiming(scope, end_time-start_time);
  409. else
  410. display_time(title, end_time-start_time);
  411. }
  412. class TimeSectionInfo : public MappingBase
  413. {
  414. public:
  415. TimeSectionInfo(const char * _scope, const char *_description, __int64 _cycles) : scope(_scope), description(_description), totalcycles(_cycles), maxcycles(_cycles), count(1) {};
  416. TimeSectionInfo(const char * _scope, const char *_description, __int64 _cycles, __int64 _maxcycles, unsigned _count)
  417. : scope(_scope), description(_description), totalcycles(_cycles), maxcycles(_maxcycles), count(_count) {};
  418. TimeSectionInfo(MemoryBuffer &mb)
  419. {
  420. mb.read(scope).read(description).read(totalcycles).read(maxcycles).read(count);
  421. }
  422. void serialize(MemoryBuffer &mb)
  423. {
  424. mb.read(scope).read(description).append(totalcycles).append(maxcycles).append(count);
  425. }
  426. virtual const void * getKey() const { return scope.get(); }
  427. StringAttr scope;
  428. StringAttr description;
  429. __int64 totalcycles;
  430. __int64 maxcycles;
  431. unsigned count;
  432. };
  433. class DefaultTimeReporter : implements ITimeReporter, public CInterface
  434. {
  435. StringMapOf<TimeSectionInfo> *sections;
  436. CriticalSection c;
  437. TimeSectionInfo &findSection(unsigned idx)
  438. {
  439. CriticalBlock b(c);
  440. HashIterator iter(*sections);
  441. for(iter.first(); iter.isValid(); iter.next())
  442. {
  443. if (!idx--)
  444. return (TimeSectionInfo &) iter.query();
  445. }
  446. throw MakeStringException(2, "Invalid index to DefaultTimeReporter");
  447. }
  448. public:
  449. IMPLEMENT_IINTERFACE
  450. DefaultTimeReporter()
  451. {
  452. sections = new StringMapOf<TimeSectionInfo>(true);
  453. }
  454. DefaultTimeReporter(MemoryBuffer &mb)
  455. {
  456. sections = new StringMapOf<TimeSectionInfo>(true);
  457. unsigned ns;
  458. mb.read(ns);
  459. while (ns--)
  460. {
  461. TimeSectionInfo &newinfo = * new TimeSectionInfo(mb);
  462. sections->replaceOwn(newinfo);
  463. }
  464. }
  465. ~DefaultTimeReporter()
  466. {
  467. // printTimings(); // Must explicitly call printTimings - no automatic print (too late here!)
  468. delete sections;
  469. }
  470. virtual void report(ITimeReportInfo &cb)
  471. {
  472. CriticalBlock b(c);
  473. HashIterator iter(*sections);
  474. for(iter.first(); iter.isValid(); iter.next())
  475. {
  476. TimeSectionInfo &ts = (TimeSectionInfo &)iter.query();
  477. cb.report(ts.scope, ts.description, cycle_to_nanosec(ts.totalcycles), cycle_to_nanosec(ts.maxcycles), ts.count);
  478. }
  479. }
  480. virtual void addTiming(const char * scope, cycle_t cycles)
  481. {
  482. CriticalBlock b(c);
  483. TimeSectionInfo *info = sections->find(scope);
  484. if (info)
  485. {
  486. info->totalcycles += cycles;
  487. if (cycles > info->maxcycles) info->maxcycles = cycles;
  488. info->count++;
  489. }
  490. else
  491. {
  492. TimeSectionInfo &newinfo = * new TimeSectionInfo(scope, NULL, cycles);
  493. sections->replaceOwn(newinfo);
  494. }
  495. }
  496. virtual unsigned numSections()
  497. {
  498. CriticalBlock b(c);
  499. return sections->count();
  500. }
  501. virtual StatisticKind getTimerType(unsigned idx __attribute__((unused)))
  502. {
  503. return StTimeElapsed;
  504. }
  505. virtual StatisticScopeType getScopeType(unsigned idx __attribute__((unused)))
  506. {
  507. return SSTsection;
  508. }
  509. virtual __int64 getTime(unsigned idx)
  510. {
  511. CriticalBlock b(c);
  512. return cycle_to_nanosec(findSection(idx).totalcycles);
  513. }
  514. virtual __int64 getMaxTime(unsigned idx)
  515. {
  516. CriticalBlock b(c);
  517. return cycle_to_nanosec(findSection(idx).maxcycles);
  518. }
  519. virtual unsigned getCount(unsigned idx)
  520. {
  521. CriticalBlock b(c);
  522. return findSection(idx).count;
  523. }
  524. virtual StringBuffer &getScope(unsigned idx, StringBuffer &s)
  525. {
  526. CriticalBlock b(c);
  527. return s.append(findSection(idx).scope);
  528. }
  529. virtual void reset()
  530. {
  531. CriticalBlock b(c);
  532. delete sections;
  533. sections = new StringMapOf<TimeSectionInfo>(true);
  534. }
  535. virtual StringBuffer &getTimings(StringBuffer &str)
  536. {
  537. CriticalBlock b(c);
  538. if (numSections())
  539. {
  540. for (unsigned i = 0; i < numSections(); i++)
  541. {
  542. getScope(i, str.append("Timing: ")).append(" total=")
  543. .append(getTime(i)/1000000)
  544. .append("ms max=")
  545. .append(getMaxTime(i)/1000)
  546. .append("us count=")
  547. .append(getCount(i))
  548. .append(" ave=")
  549. .append((getTime(i)/1000)/getCount(i))
  550. .append("us\n");
  551. }
  552. }
  553. return str;
  554. }
  555. virtual void printTimings()
  556. {
  557. CriticalBlock b(c);
  558. if (numSections())
  559. {
  560. StringBuffer str;
  561. PrintLog(getTimings(str).str());
  562. }
  563. }
  564. virtual void mergeTiming(const char * scope, cycle_t totalcycles, cycle_t maxcycles, const unsigned count)
  565. {
  566. CriticalBlock b(c);
  567. TimeSectionInfo *info = sections->find(scope);
  568. if (!info)
  569. {
  570. info = new TimeSectionInfo(scope, NULL, totalcycles, maxcycles, count);
  571. sections->replaceOwn(*info);
  572. }
  573. else
  574. {
  575. info->totalcycles += totalcycles;
  576. if (maxcycles > info->maxcycles) info->maxcycles = maxcycles;
  577. info->count += count;
  578. }
  579. }
  580. virtual void mergeInto(ITimeReporter &other)
  581. {
  582. CriticalBlock b(c);
  583. HashIterator iter(*sections);
  584. for(iter.first(); iter.isValid(); iter.next())
  585. {
  586. TimeSectionInfo &ts = (TimeSectionInfo &) iter.query();
  587. other.mergeTiming(ts.scope, ts.totalcycles, ts.maxcycles, ts.count);
  588. }
  589. }
  590. virtual void merge(ITimeReporter &other)
  591. {
  592. CriticalBlock b(c);
  593. other.mergeInto(*this);
  594. }
  595. virtual void serialize(MemoryBuffer &mb)
  596. {
  597. CriticalBlock b(c);
  598. mb.append(numSections());
  599. HashIterator iter(*sections);
  600. for(iter.first(); iter.isValid(); iter.next())
  601. {
  602. TimeSectionInfo &ts = (TimeSectionInfo &) iter.query();
  603. ts.serialize(mb);
  604. }
  605. }
  606. };
  607. static ITimeReporter * activeTimer = NULL;
  608. ITimeReporter * queryActiveTimer()
  609. {
  610. return activeTimer;
  611. }
  612. ITimeReporter *createStdTimeReporter() { return new DefaultTimeReporter(); }
  613. ITimeReporter *createStdTimeReporter(MemoryBuffer &mb) { return new DefaultTimeReporter(mb); }
  614. cycle_t oneSecInCycles;
  615. MODULE_INIT(INIT_PRIORITY_JDEBUG1)
  616. {
  617. // perform v. early in process startup, ideally this would grab process exclusively for the 2 100ths of a sec it performs calc.
  618. calibrate_timing();
  619. oneSecInCycles = nanosec_to_cycle(1000000000);
  620. return 1;
  621. }
  622. MODULE_INIT(INIT_PRIORITY_JDEBUG2)
  623. {
  624. activeTimer = new DefaultTimeReporter();
  625. return true;
  626. }
  627. MODULE_EXIT()
  628. {
  629. ::Release(activeTimer);
  630. activeTimer = NULL;
  631. }
  632. //===========================================================================
  633. // Performance Monitor
  634. #ifdef _WIN32
  635. #define SystemBasicInformation 0
  636. #define SystemPerformanceInformation 2
  637. #define SystemTimeInformation 3
  638. #define SystemProcessList 5
  639. typedef enum _PROCESSINFOCLASS {
  640. ProcessBasicInformation,
  641. ProcessQuotaLimits,
  642. ProcessIoCounters,
  643. ProcessVmCounters,
  644. ProcessTimes,
  645. ProcessBasePriority,
  646. ProcessRaisePriority,
  647. ProcessDebugPort,
  648. ProcessExceptionPort,
  649. ProcessAccessToken,
  650. ProcessLdtInformation,
  651. ProcessLdtSize,
  652. ProcessDefaultHardErrorMode,
  653. ProcessIoPortHandlers, // Note: this is kernel mode only
  654. ProcessPooledUsageAndLimits,
  655. ProcessWorkingSetWatch,
  656. ProcessUserModeIOPL,
  657. ProcessEnableAlignmentFaultFixup,
  658. ProcessPriorityClass,
  659. ProcessWx86Information,
  660. ProcessHandleCount,
  661. ProcessAffinityMask,
  662. ProcessPriorityBoost,
  663. ProcessDeviceMap,
  664. ProcessSessionInformation,
  665. ProcessForegroundInformation,
  666. ProcessWow64Information,
  667. MaxProcessInfoClass
  668. } PROCESSINFOCLASS;
  669. typedef LONG NTSTATUS;
  670. #define Li2Double(x) ((double)((x).HighPart) * 4.294967296E9 + (double)((x).LowPart))
  671. typedef struct
  672. {
  673. DWORD dwUnknown1;
  674. ULONG uKeMaximumIncrement;
  675. ULONG uPageSize;
  676. ULONG uMmNumberOfPhysicalPages;
  677. ULONG uMmLowestPhysicalPage;
  678. ULONG uMmHighestPhysicalPage;
  679. ULONG uAllocationGranularity;
  680. PVOID pLowestUserAddress;
  681. PVOID pMmHighestUserAddress;
  682. ULONG uKeActiveProcessors;
  683. BYTE bKeNumberProcessors;
  684. BYTE bUnknown2;
  685. WORD wUnknown3;
  686. } SYSTEM_BASIC_INFORMATION;
  687. typedef struct
  688. {
  689. LARGE_INTEGER liIdleTime;
  690. DWORD dwSpare[76];
  691. } SYSTEM_PERFORMANCE_INFORMATION;
  692. typedef struct
  693. {
  694. LARGE_INTEGER liKeBootTime;
  695. LARGE_INTEGER liKeSystemTime;
  696. LARGE_INTEGER liExpTimeZoneBias;
  697. ULONG uCurrentTimeZoneId;
  698. DWORD dwReserved;
  699. } SYSTEM_TIME_INFORMATION;
  700. struct PROCESS_BASIC_INFORMATION {
  701. long ExitStatus;
  702. void * PebBaseAddress;
  703. unsigned long AffinityMask;
  704. long BasePriority;
  705. unsigned long UniqueProcessId;
  706. unsigned long InheritedFromUniqueProcessId;
  707. };
  708. // QUOTA_LIMITS
  709. struct __IO_COUNTERS { // defined in SDK
  710. ULONGLONG ReadOperationCount;
  711. ULONGLONG WriteOperationCount;
  712. ULONGLONG OtherOperationCount;
  713. ULONGLONG ReadTransferCount;
  714. ULONGLONG WriteTransferCount;
  715. ULONGLONG OtherTransferCount;
  716. };
  717. struct VM_COUNTERS {
  718. unsigned long PeakVirtualSize;
  719. unsigned long VirtualSize;
  720. unsigned long PageFaultCount;
  721. unsigned long PeakWorkingSetSize;
  722. unsigned long WorkingSetSize;
  723. unsigned long QuotaPeakPagedPoolUsage;
  724. unsigned long QuotaPagedPoolUsage;
  725. unsigned long QuotaPeakNonPagedPoolUsage;
  726. unsigned long QuotaNonPagedPoolUsage;
  727. unsigned long PagefileUsage;
  728. unsigned long PeakPagefileUsage;
  729. };
  730. struct POOLED_USAGE_AND_LIMITS {
  731. unsigned long PeakPagedPoolUsage;
  732. unsigned long PagedPoolUsage;
  733. unsigned long PagedPoolLimit;
  734. unsigned long PeakNonPagedPoolUsage;
  735. unsigned long NonPagedPoolUsage;
  736. unsigned long NonPagedPoolLimit;
  737. unsigned long PeakPagefileUsage;
  738. unsigned long PagefileUsage;
  739. unsigned long PagefileLimit;
  740. };
  741. struct KERNEL_USER_TIMES {
  742. __int64 CreateTime;
  743. __int64 ExitTime;
  744. __int64 KernelTime;
  745. __int64 UserTime;
  746. //__int64 EllapsedTime;
  747. };
  748. // ntdll!NtQuerySystemInformation (NT specific!)
  749. //
  750. // The function copies the system information of the
  751. // specified type into a buffer
  752. //
  753. // NTSYSAPI
  754. // NTSTATUS
  755. // NTAPI
  756. // NtQuerySystemInformation(
  757. // IN UINT SystemInformationClass, // information type
  758. // OUT PVOID SystemInformation, // pointer to buffer
  759. // IN ULONG SystemInformationLength, // buffer size in bytes
  760. // OUT PULONG ReturnLength OPTIONAL // pointer to a 32-bit
  761. // // variable that receives
  762. // // the number of bytes
  763. // // written to the buffer
  764. // );
  765. //
  766. //NTSYSCALLAPI
  767. //NTSTATUS
  768. //NTAPI
  769. //NtQueryInformationProcess(
  770. // IN HANDLE ProcessHandle,
  771. // IN PROCESSINFOCLASS ProcessInformationClass,
  772. // OUT PVOID ProcessInformation,
  773. // IN ULONG ProcessInformationLength,
  774. // OUT PULONG ReturnLength OPTIONAL
  775. // );
  776. typedef LONG (WINAPI *PROCNTQSI)(UINT,PVOID,ULONG,PULONG);
  777. typedef LONG (WINAPI *PROCNTQIP)(HANDLE,UINT,PVOID,ULONG,PULONG);
  778. typedef LONG (WINAPI *PROCNTGST)(LARGE_INTEGER*, LARGE_INTEGER*, LARGE_INTEGER*);
  779. memsize_t getMapInfo(const char *type)
  780. {
  781. return 0; // TODO/UNKNOWN
  782. }
  783. memsize_t getVMInfo(const char *type)
  784. {
  785. return 0; // TODO/UNKNOWN
  786. }
  787. void getCpuInfo(unsigned &numCPUs, unsigned &CPUSpeed)
  788. {
  789. // MORE: Might be a better way to get CPU speed (actual) than the one stored in Registry
  790. LONG lRet;
  791. HKEY hKey;
  792. DWORD keyValue;
  793. DWORD valueLen = sizeof(keyValue);
  794. if ((lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0L, KEY_READ , &hKey)) != ERROR_SUCCESS)
  795. {
  796. DBGLOG("RegOpenKeyEx(HKEY_LOCAL_MACHINE, ...) failed to open CentralProcessor\\0 - SysErrorCode=%d", lRet);
  797. }
  798. else if ((lRet = RegQueryValueEx(hKey, TEXT("~MHz"), NULL, NULL, (LPBYTE) &keyValue, &valueLen)) != ERROR_SUCCESS)
  799. {
  800. DBGLOG("RegQueryValueEx() failed to get CPU speed - errorCode=%d", lRet);
  801. RegCloseKey(hKey);
  802. }
  803. else
  804. {
  805. CPUSpeed = keyValue;
  806. RegCloseKey(hKey);
  807. }
  808. SYSTEM_INFO sysInfo;
  809. GetSystemInfo(&sysInfo);
  810. numCPUs = sysInfo.dwNumberOfProcessors;
  811. }
  812. static unsigned evalAffinityCpus()
  813. {
  814. unsigned numCpus = 0;
  815. DWORD ProcessAffinityMask, SystemAffinityMask;
  816. if (GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&ProcessAffinityMask, (PDWORD_PTR)&SystemAffinityMask))
  817. {
  818. unsigned i = 0;
  819. while (ProcessAffinityMask)
  820. {
  821. if (ProcessAffinityMask & 1)
  822. ++numCpus;
  823. ProcessAffinityMask >>=1;
  824. }
  825. }
  826. else // fall back to legacy num system cpus
  827. {
  828. Owned<IException> e = makeOsException(GetLastError(), "Failed to get affinity");
  829. EXCLOG(e, NULL);
  830. unsigned cpuSpeed;
  831. getCpuInfo(numCpus, cpuSpeed);
  832. return numCpus;
  833. }
  834. return numCpus;
  835. }
  836. #else // linux
  837. memsize_t getMapInfo(const char *type)
  838. {
  839. // NOTE: 'total' heap value includes Roxiemem allocation, if present
  840. enum mapList { HEAP, STACK, SBRK, ANON };
  841. enum mapList mapType;
  842. if ( streq(type, "heap") )
  843. mapType = HEAP;
  844. else if ( streq(type, "stack") )
  845. mapType = STACK;
  846. else if ( streq(type, "sbrk") )
  847. mapType = SBRK;
  848. else if ( streq(type, "anon") )
  849. mapType = ANON;
  850. else
  851. return 0;
  852. memsize_t ret = 0;
  853. VStringBuffer procMaps("/proc/%d/maps", GetCurrentProcessId());
  854. FILE *diskfp = fopen(procMaps.str(), "r");
  855. if (!diskfp)
  856. return false;
  857. char ln[256];
  858. /*
  859. * exmaple /proc/<pid>/maps format:
  860. * addr_start -addr_end perms offset dev inode pathname
  861. * 01c3a000-01c5b000 rw-p 00000000 00:00 0 [heap]
  862. * 7f3f25217000-7f3f25a40000 rw-p 00000000 00:00 0 [stack:2362]
  863. * 7f4020a40000-7f4020a59000 rw-p 00000000 00:00 0
  864. * 7f4020a59000-7f4020a5a000 ---p 00000000 00:00 0
  865. * 7f4029bd4000-7f4029bf6000 r-xp 00000000 08:01 17576135 /lib/x86_64-linux-gnu/ld-2.15.so
  866. */
  867. while (fgets(ln, sizeof(ln), diskfp))
  868. {
  869. bool skipline = true;
  870. if ( mapType == HEAP || mapType == ANON ) // 'general' heap includes anon mmapped + sbrk
  871. {
  872. // skip file maps (beginning with /) and all other regions (except [heap if selected)
  873. if ( (mapType == HEAP && strstr(ln, "[heap")) || (!strstr(ln, " /") && !strstr(ln, " [")) )
  874. {
  875. // include only (r)ead + (w)rite and (p)rivate (not shared), skipping e(x)ecutable
  876. // and ---p guard regions
  877. if ( strstr(ln, " rw-p") )
  878. skipline = false;
  879. }
  880. }
  881. else if ( mapType == STACK )
  882. {
  883. if ( strstr(ln, "[stack") )
  884. skipline = false;
  885. }
  886. else if ( mapType == SBRK )
  887. {
  888. if ( strstr(ln, "[heap") )
  889. skipline = false;
  890. }
  891. if ( !skipline )
  892. {
  893. unsigned __int64 addrLow, addrHigh;
  894. if (2 == sscanf(ln, "%16" I64F "x-%16" I64F "x", &addrLow, &addrHigh))
  895. ret += (memsize_t)(addrHigh-addrLow);
  896. }
  897. }
  898. fclose(diskfp);
  899. return ret;
  900. }
  901. static bool matchExtract(const char * prefix, const char * line, memsize_t & value)
  902. {
  903. size32_t len = strlen(prefix);
  904. if (strncmp(prefix, line, len)==0)
  905. {
  906. char * tail = NULL;
  907. value = strtol(line+len, &tail, 10);
  908. while (isspace(*tail))
  909. tail++;
  910. if (strncmp(tail, "kB", 2) == 0)
  911. value *= 0x400;
  912. else if (strncmp(tail, "mB", 2) == 0)
  913. value *= 0x100000;
  914. else if (strncmp(tail, "gB", 2) == 0)
  915. value *= 0x40000000;
  916. return true;
  917. }
  918. return false;
  919. }
  920. memsize_t getVMInfo(const char *type)
  921. {
  922. memsize_t ret = 0;
  923. VStringBuffer name("%s:", type);
  924. VStringBuffer procMaps("/proc/self/status");
  925. FILE *diskfp = fopen(procMaps.str(), "r");
  926. if (!diskfp)
  927. return 0;
  928. char ln[256];
  929. while (fgets(ln, sizeof(ln), diskfp))
  930. {
  931. if (matchExtract(name.str(), ln, ret))
  932. break;
  933. }
  934. fclose(diskfp);
  935. return ret;
  936. }
  937. void getCpuInfo(unsigned &numCPUs, unsigned &CPUSpeed)
  938. {
  939. numCPUs = 1;
  940. CPUSpeed = 0;
  941. #ifdef __APPLE__
  942. # if defined(_SC_NPROCESSORS_CONF)
  943. int ncpus = sysconf(_SC_NPROCESSORS_CONF);
  944. if (ncpus > 0)
  945. numCPUs = ncpus;
  946. # endif
  947. #else // linux
  948. // NOTE: Could have perhaps used sysconf(_SC_NPROCESSORS_CONF) for numCPUs
  949. FILE *cpufp = fopen("/proc/cpuinfo", "r");
  950. if (cpufp == NULL)
  951. return;
  952. char * tail;
  953. // MORE: It is a shame that the info in this file (/proc/cpuinfo) are formatted (ie tabs .. etc)
  954. const char *cpuNumTag = "processor\t:";
  955. const char *cpuSpeedTag = "cpu MHz\t\t:";
  956. // NOTE: This provides current cpu freq, not max
  957. numCPUs = 0;
  958. char line[1001];
  959. const char *bufptr;
  960. while ((bufptr = fgets(line, 1000, cpufp)) != NULL)
  961. {
  962. if (strncmp(cpuNumTag, bufptr, strlen(cpuNumTag))==0)
  963. numCPUs++;
  964. else if (strncmp(cpuSpeedTag, bufptr, strlen(cpuSpeedTag))==0)
  965. CPUSpeed = (unsigned)strtol(bufptr+strlen(cpuSpeedTag), &tail, 10);
  966. }
  967. fclose(cpufp);
  968. if (numCPUs < 1)
  969. numCPUs = 1;
  970. // max cpu freq (KHz) may be in:
  971. // /sys/devices/system/cpu/cpu[0-X]/cpufreq/cpuinfo_max_freq
  972. cpufp = fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r");
  973. if (cpufp != NULL)
  974. {
  975. unsigned CPUSpeedMax = 0;
  976. int srtn = fscanf(cpufp, "%u", &CPUSpeedMax);
  977. if (srtn == 1)
  978. {
  979. CPUSpeedMax /= 1000;
  980. if (CPUSpeedMax > CPUSpeed)
  981. CPUSpeed = CPUSpeedMax;
  982. }
  983. fclose(cpufp);
  984. }
  985. #endif
  986. }
  987. static unsigned evalAffinityCpus()
  988. {
  989. #ifdef __APPLE__
  990. // MORE - could do better
  991. #else
  992. cpu_set_t cpuset;
  993. int err = pthread_getaffinity_np(GetCurrentThreadId(), sizeof(cpu_set_t), &cpuset);
  994. if (0 == err)
  995. {
  996. #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 6)
  997. return CPU_COUNT(&cpuset);
  998. #else
  999. unsigned numCpus = 0;
  1000. unsigned setSize = CPU_SETSIZE;
  1001. while (setSize--)
  1002. {
  1003. if (CPU_ISSET(setSize, &cpuset))
  1004. ++numCpus;
  1005. }
  1006. return numCpus;
  1007. #endif /* GLIBC */
  1008. }
  1009. #endif
  1010. return 1;
  1011. }
  1012. // Note - values are returned in Kb
  1013. static void getMemUsage(unsigned &inuse,unsigned &active,unsigned &total,unsigned &swaptotal,unsigned &swapinuse)
  1014. {
  1015. #ifdef __APPLE__
  1016. active = 0;
  1017. inuse = 0;
  1018. total = 0;
  1019. swaptotal = 0;
  1020. swapinuse = 0;
  1021. vm_size_t pageSize;
  1022. if (KERN_SUCCESS != host_page_size(mach_host_self(), &pageSize))
  1023. return;
  1024. mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
  1025. vm_statistics64_data_t vmstat;
  1026. if (KERN_SUCCESS != host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&vmstat, &count))
  1027. return;
  1028. uint64_t totalBytes = (vmstat.wire_count + vmstat.active_count + vmstat.inactive_count + vmstat.free_count + vmstat.compressor_page_count) * pageSize;
  1029. uint64_t inuseBytes = (vmstat.wire_count + vmstat.active_count + vmstat.inactive_count + vmstat.compressor_page_count) * pageSize;
  1030. uint64_t activeBytes = (vmstat.wire_count + vmstat.active_count) * pageSize;
  1031. active = activeBytes / 1024;
  1032. inuse = inuseBytes / 1024;
  1033. total = totalBytes / 1024;
  1034. // swaptotal and swapinuse TBD
  1035. #else
  1036. unsigned free=0;
  1037. unsigned swapfree=0;
  1038. active = 0;
  1039. inuse = 0;
  1040. static int memfd = -1;
  1041. if (memfd==-1)
  1042. memfd = open("/proc/meminfo",O_RDONLY);
  1043. if (memfd==-1)
  1044. return;
  1045. char buf[2048];
  1046. size32_t l = pread(memfd, buf, sizeof(buf)-1, 0L);
  1047. if ((int)l<=0)
  1048. return;
  1049. buf[l] = 0;
  1050. const char *bufptr = buf;
  1051. char * tail;
  1052. unsigned i = 7; // supposed to match max number of items extract below
  1053. total = swaptotal = free = active = swapfree = 0;
  1054. unsigned swapcached = 0;
  1055. unsigned cached = 0;
  1056. while (bufptr&&i) {
  1057. if (*bufptr =='\n')
  1058. bufptr++;
  1059. i--;
  1060. if (strncmp("MemTotal:", bufptr, 9)==0)
  1061. total = (unsigned)strtol(bufptr+9, &tail, 10);
  1062. else if (strncmp("SwapTotal:", bufptr, 10)==0)
  1063. swaptotal = (unsigned)strtol(bufptr+10, &tail, 10);
  1064. else if (strncmp("MemFree:", bufptr, 8)==0)
  1065. free = (unsigned)strtol(bufptr+8, &tail, 10);
  1066. else if (strncmp("Active:", bufptr, 7)==0)
  1067. active = (unsigned)strtol(bufptr+7, &tail, 10);
  1068. else if (strncmp("SwapFree:", bufptr, 9)==0)
  1069. swapfree = (unsigned)strtol(bufptr+9, &tail, 10);
  1070. else if (strncmp("Cached:", bufptr, 7)==0)
  1071. cached = (unsigned)strtol(bufptr+7, &tail, 10);
  1072. else if (strncmp("SwapCached:", bufptr, 11)==0)
  1073. swapcached = (unsigned)strtol(bufptr+11, &tail, 10);
  1074. else
  1075. i++;
  1076. bufptr = strchr(bufptr, '\n');
  1077. }
  1078. inuse = total-free-cached;
  1079. swapinuse = swaptotal-swapfree-swapcached;
  1080. #endif
  1081. }
  1082. class CInt64fix
  1083. {
  1084. __int64 val;
  1085. public:
  1086. CInt64fix()
  1087. {
  1088. val = 0;
  1089. }
  1090. void set(int v)
  1091. {
  1092. __int64 ret = (unsigned)v;
  1093. while (val-ret>0x80000000LL)
  1094. ret += 0x100000000LL;
  1095. val = ret;
  1096. }
  1097. __int64 get()
  1098. {
  1099. return val;
  1100. }
  1101. };
  1102. void getMemStats(StringBuffer &out, unsigned &memused, unsigned &memtot)
  1103. {
  1104. #ifdef __linux__
  1105. __int64 total = getMapInfo("heap");
  1106. __int64 sbrkmem = getMapInfo("sbrk");
  1107. __int64 mmapmem = total - sbrkmem;
  1108. __int64 virttot = getVMInfo("VmData");
  1109. unsigned mu;
  1110. unsigned ma;
  1111. unsigned mt;
  1112. unsigned st;
  1113. unsigned su;
  1114. getMemUsage(mu,ma,mt,st,su);
  1115. unsigned muval = (unsigned)(((__int64)mu+(__int64)su)*100/((__int64)mt+(__int64)st));
  1116. if (sizeof(memsize_t)==4) {
  1117. unsigned muval2 = (virttot*100)/(3*(__int64)0x40000000);
  1118. if (muval2>muval)
  1119. muval = muval2;
  1120. }
  1121. if (muval>100)
  1122. muval = 100; // !
  1123. out.appendf("MU=%3u%% MAL=%" I64F "d MMP=%" I64F "d SBK=%" I64F "d TOT=%uK RAM=%uK SWP=%uK",
  1124. muval, total, mmapmem, sbrkmem, (unsigned)(virttot/1024), mu, su);
  1125. #ifdef _USE_MALLOC_HOOK
  1126. if (totalMem)
  1127. out.appendf(" TM=%" I64F "d",totalMem);
  1128. #endif
  1129. memused = mu+su;
  1130. memtot = mt+st;
  1131. #elif defined (__APPLE__)
  1132. __uint64 bytes;
  1133. size_t len = sizeof(bytes);
  1134. sysctlbyname("hw.memsize", &bytes, &len, NULL, 0);
  1135. // See http://miknight.blogspot.com/2005/11/resident-set-size-in-mac-os-x.html
  1136. struct task_basic_info t_info;
  1137. mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
  1138. task_info(current_task(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
  1139. out.appendf("RES=%" I64F "uMiB VIRT=%" I64F "uMiB TOT=%" I64F "uMiB",
  1140. (__uint64) t_info.resident_size/(1024*1024),
  1141. (__uint64) t_info.virtual_size/(1024*1024),
  1142. bytes/(1024*1024));
  1143. memused = t_info.resident_size;
  1144. memtot = t_info.virtual_size;
  1145. #elif defined (__FreeBSD___)
  1146. UNIMPLEMENTED;
  1147. #endif
  1148. }
  1149. void getDiskUsage(char const * path, unsigned __int64 & total, unsigned __int64 & inUse)
  1150. {
  1151. #if defined(__linux__) || defined(__APPLE__)
  1152. struct statfs stfs;
  1153. if(statfs(path, &stfs) < 0)
  1154. {
  1155. //PrintLog("statfs error for filesystem '%s'", path);
  1156. total = inUse = 0;
  1157. }
  1158. else
  1159. {
  1160. struct stat st;
  1161. if(stat(path, &st) < 0)
  1162. {
  1163. //PrintLog("stat error for filesystem '%s'", path);
  1164. total = inUse = 0;
  1165. }
  1166. else
  1167. {
  1168. total = (unsigned __int64)stfs.f_blocks * st.st_blksize;
  1169. inUse = total - (unsigned __int64)stfs.f_bfree * st.st_blksize;
  1170. }
  1171. }
  1172. #else
  1173. total = inUse = 0;
  1174. #endif
  1175. }
  1176. #endif
  1177. static std::atomic<unsigned> cachedNumCpus;
  1178. unsigned getAffinityCpus()
  1179. {
  1180. if (cachedNumCpus.load(std::memory_order_acquire) == 0)
  1181. cachedNumCpus.store(evalAffinityCpus(), std::memory_order_release);
  1182. return cachedNumCpus.load(std::memory_order_acquire);
  1183. }
  1184. void clearAffinityCache()
  1185. {
  1186. cachedNumCpus.store(0, std::memory_order_release);
  1187. }
  1188. void getPeakMemUsage(memsize_t &peakVm,memsize_t &peakResident)
  1189. {
  1190. peakVm = 0;
  1191. peakResident = 0;
  1192. #ifdef _WIN32
  1193. PROCESS_MEMORY_COUNTERS pmc;
  1194. if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
  1195. {
  1196. peakVm = pmc.PeakWorkingSetSize;
  1197. peakResident = pmc.PeakWorkingSetSize;
  1198. }
  1199. #else
  1200. static int memfd = -1;
  1201. if (memfd==-1)
  1202. memfd = open("/proc/self/status",O_RDONLY);
  1203. if (memfd==-1)
  1204. return;
  1205. char buf[2048];
  1206. size32_t l = pread(memfd, buf, sizeof(buf)-1, 0L);
  1207. if ((int)l<=0)
  1208. return;
  1209. buf[l] = 0;
  1210. const char *bufptr = buf;
  1211. while (bufptr) {
  1212. if (*bufptr =='\n')
  1213. bufptr++;
  1214. if (!matchExtract("VmPeak:", bufptr, peakVm) &&
  1215. !matchExtract("VmHWM:", bufptr, peakResident))
  1216. {
  1217. //ignore this line
  1218. }
  1219. bufptr = strchr(bufptr, '\n');
  1220. }
  1221. #endif
  1222. }
  1223. #define RXMAX 1000000 // can be 10x bigger but this produces reasonable amounts
  1224. unsigned packetsLasttime;
  1225. __int64 packetsLastrx = -1;
  1226. __int64 packetsLasttx;
  1227. bool getPacketStats(unsigned & tx, unsigned & rx)
  1228. {
  1229. unsigned thistime = msTick();
  1230. JSocketStatistics jstats;
  1231. getSocketStatistics(jstats);
  1232. bool ret = true;
  1233. if(packetsLastrx!=-1)
  1234. {
  1235. tx = (unsigned) ((jstats.writesize-packetsLasttx)*100000/(((__int64)(packetsLasttime-thistime))*RXMAX));
  1236. rx = (unsigned) ((jstats.readsize-packetsLastrx)*100000/(((__int64)(packetsLasttime-thistime))*RXMAX));
  1237. }
  1238. else
  1239. ret = false;
  1240. packetsLastrx = jstats.readsize;
  1241. packetsLasttx = jstats.writesize;
  1242. packetsLasttime = thistime;
  1243. return ret;
  1244. }
  1245. #ifndef _WIN32
  1246. struct UserStatusInfo
  1247. {
  1248. public:
  1249. UserStatusInfo(pid_t _pid)
  1250. {
  1251. pid = _pid;
  1252. }
  1253. bool update()
  1254. {
  1255. StringBuffer fn;
  1256. fn.appendf("/proc/%d/stat", pid);
  1257. char buf[800]; /* about 40 fields, 64-bit decimal is about 20 chars */
  1258. int fd = open(fn.str(), O_RDONLY, 0);
  1259. if (fd==-1)
  1260. return false;
  1261. int rd = read(fd, buf, sizeof(buf)-1);
  1262. close(fd);
  1263. if (rd<80)
  1264. return false;
  1265. buf[rd] = 0;
  1266. char *s = strchr(buf,'(');
  1267. if (!s)
  1268. return false;
  1269. s++;
  1270. unsigned i = 0;
  1271. while (*s&&(*s!=')')&&(i<15))
  1272. cmd[i++] = *(s++);
  1273. if (*s != ')')
  1274. return false;
  1275. cmd[i] = 0;
  1276. s+=3; // Skip ") X" where X is the state
  1277. //The PID of the parent process
  1278. const char *num;
  1279. s = skipnumfld(s,num);
  1280. //int ppid = atoi(num);
  1281. // skip pgrp, session, tty_num, tpgid, flags, min_flt, cmin_flt, maj_flt, cmaj_flt
  1282. for (i=0;i<9;i++)
  1283. s = skipnumfld(s,num);
  1284. //utime - user mode time in clock ticks.
  1285. s = skipnumfld(s,num);
  1286. //printf("**N'%s'\n",num);
  1287. time.user = (unsigned)atoi64_l(num,strlen(num));
  1288. //stime - amount of time scheduled in kernel mode in clock ticks
  1289. s = skipnumfld(s,num);
  1290. //printf("**N'%s'\n",num);
  1291. time.system = (unsigned)atoi64_l(num,strlen(num));
  1292. return true;
  1293. }
  1294. public:
  1295. pid_t pid;
  1296. char cmd[16];
  1297. UserSystemTime_t time;
  1298. private:
  1299. char *skipnumfld(char *s, const char *&num)
  1300. {
  1301. while (*s && isspace(*s))
  1302. s++;
  1303. num = s;
  1304. if ((*s=='-')||(*s=='+'))
  1305. s++;
  1306. while (*s && isdigit(*s))
  1307. s++;
  1308. if (*s==' ')
  1309. *(s++) = 0; // terminate num
  1310. while (*s && isspace(*s))
  1311. s++;
  1312. return s;
  1313. }
  1314. };
  1315. struct CProcInfo: extends CInterface
  1316. {
  1317. UserStatusInfo info;
  1318. UserSystemTime_t delta;
  1319. bool active;
  1320. bool first;
  1321. CProcInfo(int _pid) : info(_pid)
  1322. {
  1323. active = false;
  1324. first = true;
  1325. }
  1326. inline pid_t pid() const { return info.pid; }
  1327. bool load()
  1328. {
  1329. UserSystemTime_t prev = info.time;
  1330. if (!info.update())
  1331. return false;
  1332. active = true;
  1333. if (first)
  1334. first = false;
  1335. else {
  1336. delta.system = info.time.system-prev.system;
  1337. delta.user = info.time.user-prev.user;
  1338. }
  1339. return true;
  1340. }
  1341. };
  1342. class CProcessMonitor
  1343. {
  1344. CIArrayOf<CProcInfo> processes;
  1345. unsigned tot_time;
  1346. bool busy;
  1347. CriticalSection sect;
  1348. static int compare(CInterface * const *i1, CInterface * const *i2)
  1349. {
  1350. CProcInfo *pi1 = QUERYINTERFACE(*i1,CProcInfo);
  1351. CProcInfo *pi2 = QUERYINTERFACE(*i2,CProcInfo);
  1352. return pi2->delta.system+pi2->delta.user-pi1->delta.system-pi1->delta.user;
  1353. }
  1354. public:
  1355. CProcessMonitor()
  1356. {
  1357. busy = false;
  1358. }
  1359. void scan()
  1360. {
  1361. #ifdef __linux__
  1362. ForEachItemIn(i1,processes)
  1363. processes.item(i1).active = false;
  1364. DIR *dir = opendir("/proc");
  1365. for (;;) {
  1366. CriticalBlock b(sect);
  1367. struct dirent *ent = readdir(dir);
  1368. if (!ent)
  1369. break;
  1370. if ((ent->d_name[0]>='0')&&(ent->d_name[0]<='9')) {
  1371. int pid = atoi(ent->d_name);
  1372. if (pid) {
  1373. CProcInfo *pi = NULL;
  1374. ForEachItemIn(i2,processes) {
  1375. if (processes.item(i2).pid() == pid) {
  1376. pi = &processes.item(i2);
  1377. break;
  1378. }
  1379. }
  1380. if (!pi) {
  1381. pi = new CProcInfo(pid);
  1382. processes.append(*pi);
  1383. }
  1384. pi->load();
  1385. }
  1386. }
  1387. }
  1388. closedir(dir);
  1389. tot_time = 0;
  1390. ForEachItemInRev(i3,processes) {
  1391. CProcInfo &pi = processes.item(i3);
  1392. if (pi.active)
  1393. tot_time += pi.delta.system+pi.delta.user;
  1394. else
  1395. processes.remove(i3);
  1396. }
  1397. #endif
  1398. #if defined (__FreeBSD__) || defined (__APPLE__)
  1399. UNIMPLEMENTED;
  1400. #endif
  1401. }
  1402. void print(unsigned n,StringBuffer &str)
  1403. {
  1404. if (!tot_time)
  1405. return;
  1406. assertex(n);
  1407. processes.sort(compare);
  1408. StringBuffer name;
  1409. ForEachItemIn(i1,processes) {
  1410. CProcInfo &pi = processes.item(i1);
  1411. if ((pi.delta.system==0)&&(pi.delta.user==0))
  1412. break;
  1413. getThreadName(pi.pid(),0,name.clear());
  1414. str.appendf("\n TT: PI=%d PN=%s PC=%d ST=%d UT=%d%s%s",
  1415. pi.pid(),pi.info.cmd,(pi.delta.system+pi.delta.user)*100/tot_time,pi.delta.system,pi.delta.user,name.length()?" TN=":"",name.str());
  1416. if (--n==0)
  1417. break;
  1418. }
  1419. }
  1420. void printBusy(unsigned pc,StringBuffer &str)
  1421. {
  1422. if (pc>90) {
  1423. scan();
  1424. if (busy)
  1425. print(3,str); // print top 3
  1426. else
  1427. busy = true;
  1428. }
  1429. else {
  1430. busy = false;
  1431. processes.kill();
  1432. }
  1433. }
  1434. };
  1435. #ifndef HZ
  1436. #define HZ 100
  1437. #endif
  1438. #define IDE0_MAJOR 3
  1439. #define SCSI_DISK0_MAJOR 8
  1440. #define SCSI_DISK1_MAJOR 65
  1441. #define SCSI_DISK7_MAJOR 71
  1442. #define SCSI_DISK10_MAJOR 128
  1443. #define SCSI_DISK17_MAJOR 135
  1444. #define IDE1_MAJOR 22
  1445. #define IDE2_MAJOR 33
  1446. #define IDE3_MAJOR 34
  1447. #define IDE4_MAJOR 56
  1448. #define IDE5_MAJOR 57
  1449. #define IDE6_MAJOR 88
  1450. #define IDE7_MAJOR 89
  1451. #define IDE8_MAJOR 90
  1452. #define IDE9_MAJOR 91
  1453. #define COMPAQ_SMART2_MAJOR 72
  1454. #define IDE_DISK_MAJOR(M) ((M) == IDE0_MAJOR || (M) == IDE1_MAJOR || \
  1455. (M) == IDE2_MAJOR || (M) == IDE3_MAJOR || \
  1456. (M) == IDE4_MAJOR || (M) == IDE5_MAJOR || \
  1457. (M) == IDE6_MAJOR || (M) == IDE7_MAJOR || \
  1458. (M) == IDE8_MAJOR || (M) == IDE9_MAJOR)
  1459. #define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
  1460. ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) || \
  1461. ((M) >= SCSI_DISK10_MAJOR && (M) <= SCSI_DISK17_MAJOR))
  1462. #define OTHER_DISK_MAJOR(M) ((M) == COMPAQ_SMART2_MAJOR) // by investigation!
  1463. class CExtendedStats // Disk network and cpu stats
  1464. {
  1465. struct blkio_info
  1466. {
  1467. unsigned rd_ios; // Read I/O operations
  1468. unsigned rd_merges; // Reads merged
  1469. __uint64 rd_sectors; // Sectors read
  1470. unsigned rd_ticks; // Time in queue + service for read
  1471. unsigned wr_ios; // Write I/O operations
  1472. unsigned wr_merges; // Writes merged
  1473. __uint64 wr_sectors; // Sectors written
  1474. unsigned wr_ticks; // Time in queue + service for write
  1475. unsigned ticks; // Time of requests in queue
  1476. unsigned aveq; // Average queue length
  1477. };
  1478. struct cpu_info
  1479. {
  1480. __uint64 user;
  1481. __uint64 system;
  1482. __uint64 idle;
  1483. __uint64 iowait;
  1484. };
  1485. struct net_info
  1486. {
  1487. __uint64 rxbytes;
  1488. __uint64 rxpackets;
  1489. __uint64 rxerrors;
  1490. __uint64 rxdrops;
  1491. __uint64 txbytes;
  1492. __uint64 txpackets;
  1493. __uint64 txerrors;
  1494. __uint64 txdrops;
  1495. };
  1496. struct part_info
  1497. {
  1498. unsigned int major;
  1499. unsigned int minor;
  1500. char name[32];
  1501. };
  1502. part_info *partition;
  1503. unsigned nparts;
  1504. blkio_info *newblkio;
  1505. blkio_info *oldblkio;
  1506. cpu_info newcpu;
  1507. unsigned numcpu;
  1508. cpu_info oldcpu;
  1509. cpu_info cpu;
  1510. net_info oldnet;
  1511. net_info newnet;
  1512. unsigned ncpu;
  1513. bool first;
  1514. char *kbuf;
  1515. size32_t kbufmax;
  1516. int kbadcnt;
  1517. unsigned short kbufcrc;
  1518. __uint64 totalcpu;
  1519. unsigned ndisks;
  1520. int isdisk(unsigned int major, unsigned int minor)
  1521. {
  1522. if (IDE_DISK_MAJOR(major))
  1523. return ((minor&0x3F)==0);
  1524. if (SCSI_DISK_MAJOR(major))
  1525. return ((minor&0x0F)==0);
  1526. if (OTHER_DISK_MAJOR(major))
  1527. return ((minor&0x0F)==0);
  1528. return 0;
  1529. }
  1530. bool getNextCPU()
  1531. {
  1532. oldcpu = newcpu;
  1533. if (!ncpu) {
  1534. unsigned speed;
  1535. getCpuInfo(ncpu, speed);
  1536. if (!ncpu)
  1537. ncpu = 1;
  1538. }
  1539. FILE* cpufp = fopen("/proc/stat", "r");
  1540. if (!cpufp) {
  1541. memset(&cpu,0,sizeof(cpu));
  1542. totalcpu = 0;
  1543. return false;
  1544. }
  1545. char ln[256];
  1546. while (fgets(ln, sizeof(ln), cpufp)) {
  1547. if (strncmp(ln, "cpu ", 4)==0) {
  1548. int items;
  1549. __uint64 nice, irq, softirq;
  1550. items = sscanf(ln,
  1551. "cpu %llu %llu %llu %llu %llu %llu %llu",
  1552. &newcpu.user, &nice,
  1553. &newcpu.system,
  1554. &newcpu.idle,
  1555. &newcpu.iowait,
  1556. &irq, &softirq);
  1557. newcpu.user += nice;
  1558. if (items == 4)
  1559. newcpu.iowait = 0;
  1560. if (items == 7)
  1561. newcpu.system += irq + softirq;
  1562. break;
  1563. }
  1564. }
  1565. fclose(cpufp);
  1566. cpu.user = newcpu.user - oldcpu.user;
  1567. cpu.system = newcpu.system - oldcpu.system;
  1568. cpu.idle = newcpu.idle - oldcpu.idle;
  1569. cpu.iowait = newcpu.iowait - oldcpu.iowait;
  1570. totalcpu = (cpu.user + cpu.system + cpu.idle + cpu.iowait);
  1571. return true;
  1572. }
  1573. bool getDiskInfo()
  1574. {
  1575. char ln[256];
  1576. part_info pi;
  1577. FILE* diskfp = fopen("/proc/diskstats", "r");
  1578. if (!diskfp)
  1579. return false;
  1580. if (!newblkio) {
  1581. nparts = 0;
  1582. while (fgets(ln, sizeof(ln), diskfp)) {
  1583. unsigned reads = 0;
  1584. if (sscanf(ln, "%4d %4d %31s %u", &pi.major, &pi.minor, pi.name, &reads) == 4) {
  1585. unsigned p = 0;
  1586. while ((p<nparts) && (partition[p].major != pi.major || partition[p].minor != pi.minor))
  1587. p++;
  1588. if ((p==nparts) && reads && isdisk(pi.major,pi.minor)) {
  1589. nparts++;
  1590. partition = (part_info *)realloc(partition,nparts*sizeof(part_info));
  1591. partition[p] = pi;
  1592. }
  1593. }
  1594. }
  1595. free(newblkio);
  1596. free(oldblkio);
  1597. newblkio = (blkio_info *)calloc(sizeof(blkio_info),nparts);
  1598. oldblkio = (blkio_info* )calloc(sizeof(blkio_info),nparts);
  1599. }
  1600. rewind(diskfp);
  1601. // could skip lines we know aren't significant here
  1602. while (fgets(ln, sizeof(ln), diskfp)) {
  1603. blkio_info blkio;
  1604. unsigned items = sscanf(ln, "%4d %4d %*s %u %u %llu %u %u %u %llu %u %*u %u %u",
  1605. &pi.major, &pi.minor,
  1606. &blkio.rd_ios, &blkio.rd_merges,
  1607. &blkio.rd_sectors, &blkio.rd_ticks,
  1608. &blkio.wr_ios, &blkio.wr_merges,
  1609. &blkio.wr_sectors, &blkio.wr_ticks,
  1610. &blkio.ticks, &blkio.aveq);
  1611. if (items == 6) {
  1612. // hopefully not this branch!
  1613. blkio.rd_sectors = blkio.rd_merges;
  1614. blkio.wr_sectors = blkio.rd_ticks;
  1615. blkio.rd_ios = 0;
  1616. blkio.rd_merges = 0;
  1617. blkio.rd_ticks = 0;
  1618. blkio.wr_ios = 0;
  1619. blkio.wr_merges = 0;
  1620. blkio.wr_ticks = 0;
  1621. blkio.ticks = 0;
  1622. blkio.aveq = 0;
  1623. items = 12;
  1624. }
  1625. if (items == 12) {
  1626. for (unsigned p = 0; p < nparts; p++) {
  1627. if (partition[p].major == pi.major && partition[p].minor == pi.minor) {
  1628. newblkio[p] = blkio;
  1629. break;
  1630. }
  1631. }
  1632. }
  1633. }
  1634. fclose(diskfp);
  1635. return true;
  1636. }
  1637. bool getNetInfo()
  1638. {
  1639. FILE *netfp = fopen("/proc/net/dev", "r");
  1640. if (!netfp)
  1641. return false;
  1642. char ln[512];
  1643. // Read two lines
  1644. if (!fgets(ln, sizeof(ln), netfp) || !fgets(ln, sizeof(ln), netfp)) {
  1645. fclose(netfp);
  1646. return false;
  1647. }
  1648. unsigned txskip = 2;
  1649. bool hasbyt = false;
  1650. if (strstr(ln,"compressed")) {
  1651. txskip = 4;
  1652. hasbyt = true;
  1653. }
  1654. else if (strstr(ln,"bytes"))
  1655. hasbyt = true;
  1656. while (fgets(ln, sizeof(ln), netfp)) {
  1657. const char *s = ln;
  1658. skipSp(s);
  1659. if (strncmp(s, "eth0:", 5)==0) { // may want eth1 at some point!
  1660. s+=5;
  1661. if (hasbyt) {
  1662. newnet.rxbytes = readDecNum(s);
  1663. skipSp(s);
  1664. }
  1665. else
  1666. newnet.rxbytes = 0;
  1667. newnet.rxpackets = readDecNum(s);
  1668. skipSp(s);
  1669. newnet.rxerrors = readDecNum(s);
  1670. skipSp(s);
  1671. newnet.rxdrops = readDecNum(s);
  1672. skipSp(s);
  1673. while (txskip--) {
  1674. readDecNum(s);
  1675. skipSp(s);
  1676. }
  1677. if (hasbyt) {
  1678. newnet.txbytes = readDecNum(s);
  1679. skipSp(s);
  1680. }
  1681. else
  1682. newnet.txbytes = 0;
  1683. newnet.txpackets = readDecNum(s);
  1684. skipSp(s);
  1685. newnet.txerrors = readDecNum(s);
  1686. skipSp(s);
  1687. newnet.txdrops = readDecNum(s);
  1688. break;
  1689. }
  1690. }
  1691. fclose(netfp);
  1692. return true;
  1693. }
  1694. size32_t getKLog(const char *&data)
  1695. {
  1696. #ifdef __linux__
  1697. if (kbufmax)
  1698. {
  1699. data = nullptr;
  1700. size32_t ksz = 0;
  1701. unsigned short lastCRC = 0;
  1702. // NOTE: allocated 2*kbufmax to work around kernel bug
  1703. // where klogctl() could sometimes return more than requested
  1704. size32_t sz = klogctl(3, kbuf, kbufmax);
  1705. if ((int)sz < 0)
  1706. {
  1707. if (kbadcnt < 5)
  1708. {
  1709. ERRLOG("klogctl SYSLOG_ACTION_READ_ALL error %d", errno);
  1710. kbadcnt++;
  1711. }
  1712. else
  1713. kbufmax = 0;
  1714. return 0;
  1715. }
  1716. #if 0
  1717. kbuf[sz] = '\0';
  1718. #endif
  1719. if (kbufcrc)
  1720. {
  1721. data = kbuf;
  1722. ksz = sz;
  1723. }
  1724. // determine where new info starts ...
  1725. StringBuffer ln;
  1726. const char *p = kbuf;
  1727. const char *e = p+sz;
  1728. while (p && p!=e)
  1729. {
  1730. if (*p=='<')
  1731. {
  1732. ln.clear();
  1733. while ((p && p!=e)&&(*p!='\n'))
  1734. {
  1735. ln.append(*p);
  1736. p++;
  1737. sz--;
  1738. }
  1739. lastCRC = chksum16(ln.str(), ln.length());
  1740. if (kbufcrc && kbufcrc == lastCRC)
  1741. {
  1742. ksz = sz - 1;
  1743. if (ksz && sz)
  1744. data = p + 1;
  1745. else
  1746. data = nullptr;
  1747. }
  1748. }
  1749. while ((p && p!=e)&&(*p!='\n'))
  1750. {
  1751. p++;
  1752. sz--;
  1753. }
  1754. if (p && p!=e)
  1755. {
  1756. p++;
  1757. sz--;
  1758. }
  1759. }
  1760. if (lastCRC)
  1761. kbufcrc = lastCRC;
  1762. if (!ksz)
  1763. data = nullptr;
  1764. return ksz;
  1765. }
  1766. #endif
  1767. data = nullptr;
  1768. return 0;
  1769. }
  1770. inline double perSec(double v,double deltams)
  1771. {
  1772. return 1000.0*v/deltams;
  1773. }
  1774. public:
  1775. unsigned getCPU()
  1776. {
  1777. if (!getNextCPU())
  1778. return (unsigned)-1;
  1779. if (totalcpu==0)
  1780. return 0;
  1781. unsigned ret = (unsigned)((totalcpu-cpu.idle)*100/totalcpu);
  1782. if (ret>100)
  1783. ret = 100;
  1784. return ret;
  1785. }
  1786. CExtendedStats(bool printklog)
  1787. {
  1788. partition = (part_info *)malloc(sizeof(part_info));
  1789. nparts = 0;
  1790. newblkio = NULL;
  1791. oldblkio = NULL;
  1792. first = true;
  1793. ncpu = 0;
  1794. kbuf = nullptr;
  1795. kbufcrc = 0;
  1796. memset(&oldcpu, 0, sizeof(oldcpu));
  1797. memset(&newcpu, 0, sizeof(newcpu));
  1798. memset(&cpu, 0, sizeof(cpu));
  1799. totalcpu = 0;
  1800. numcpu = 0;
  1801. memset(&oldnet, 0, sizeof(oldnet));
  1802. memset(&newnet, 0, sizeof(newnet));
  1803. ndisks = 0;
  1804. kbadcnt = 0;
  1805. if (printklog)
  1806. {
  1807. kbufmax = 0x1000;
  1808. kbuf = (char *)malloc(kbufmax*2);
  1809. if (!kbuf)
  1810. kbufmax = 0;
  1811. }
  1812. else
  1813. kbufmax = 0;
  1814. }
  1815. ~CExtendedStats()
  1816. {
  1817. free(partition);
  1818. free(newblkio);
  1819. free(oldblkio);
  1820. if (kbuf != nullptr)
  1821. free(kbuf);
  1822. }
  1823. bool getLine(StringBuffer &out)
  1824. {
  1825. blkio_info *t = oldblkio;
  1826. oldblkio = newblkio;
  1827. newblkio = t;
  1828. oldnet = newnet;
  1829. #ifdef USE_OLD_PU
  1830. if (!getNextCPU())
  1831. return false; // required
  1832. #endif
  1833. bool gotdisk = getDiskInfo()&&nparts;
  1834. bool gotnet = getNetInfo();
  1835. if (first) {
  1836. first = false;
  1837. return false;
  1838. }
  1839. double deltams = ((double)totalcpu*1000) / ncpu / HZ;
  1840. if (deltams<10)
  1841. return false;
  1842. if (gotdisk) {
  1843. if (out.length()&&(out.charAt(out.length()-1)!=' '))
  1844. out.append(' ');
  1845. out.append("DSK: ");
  1846. for (unsigned p = 0; p < nparts; p++) {
  1847. unsigned rd_ios = newblkio[p].rd_ios - oldblkio[p].rd_ios;
  1848. __uint64 rd_sectors = newblkio[p].rd_sectors - oldblkio[p].rd_sectors;
  1849. unsigned wr_ios = newblkio[p].wr_ios - oldblkio[p].wr_ios;
  1850. __uint64 wr_sectors = newblkio[p].wr_sectors - oldblkio[p].wr_sectors;
  1851. unsigned ticks = newblkio[p].ticks - oldblkio[p].ticks;
  1852. unsigned busy = (unsigned)(100*ticks/deltams);
  1853. if (busy>100)
  1854. busy = 100;
  1855. out.appendf("[%s] r/s=%0.1f kr/s=%0.1f w/s=%0.1f kw/s=%0.1f bsy=%d",
  1856. partition[p].name,
  1857. perSec(rd_ios,deltams),
  1858. perSec(rd_sectors,deltams)/2.0,
  1859. perSec(wr_ios,deltams),
  1860. perSec(wr_sectors,deltams)/2.0,
  1861. busy);
  1862. out.append(' ');
  1863. }
  1864. }
  1865. if (gotnet) {
  1866. out.append("NIC: ");
  1867. __uint64 rxbytes = newnet.rxbytes-oldnet.rxbytes;
  1868. __uint64 rxpackets = newnet.rxpackets-oldnet.rxpackets;
  1869. __uint64 txbytes = newnet.txbytes-oldnet.txbytes;
  1870. __uint64 txpackets = newnet.txpackets-oldnet.txpackets;
  1871. out.appendf("rxp/s=%0.1f rxk/s=%0.1f txp/s=%0.1f txk/s=%0.1f",
  1872. perSec(rxpackets,deltams),
  1873. perSec(rxbytes/1024.0,deltams),
  1874. perSec(txpackets,deltams),
  1875. perSec(txbytes/1024.0,deltams));
  1876. out.append(' ');
  1877. }
  1878. if (totalcpu)
  1879. out.appendf("CPU: usr=%d sys=%d iow=%d idle=%d", (unsigned)(cpu.user*100/totalcpu), (unsigned)(cpu.system*100/totalcpu), (unsigned)(cpu.iowait*100/totalcpu), (unsigned)(cpu.idle*100/totalcpu));
  1880. return true;
  1881. }
  1882. #define KERN_EMERG "<0>" // system is unusable
  1883. #define KERN_ALERT "<1>" // action must be taken immediately
  1884. #define KERN_CRIT "<2>" // critical conditions
  1885. #define KERN_ERR "<3>" // error conditions
  1886. #define KERN_WARNING "<4>" // warning conditions
  1887. #define KERN_NOTICE "<5>" // normal but significant condition
  1888. #define KERN_INFO "<6>" // informational
  1889. #define KERN_DEBUG "<7>" // debug-level messages
  1890. #define KMSGTEST(S) if (memcmp(p,S,3)==0) { ln.append(#S); level = p[1]-'0'; }
  1891. void printKLog(IPerfMonHook *hook)
  1892. {
  1893. const char *p = nullptr;
  1894. size32_t sz = getKLog(p);
  1895. #if 0
  1896. DBGLOG("getKLog() returns: %u <%s>", sz, p);
  1897. #endif
  1898. StringBuffer ln;
  1899. const char *e = p+sz;
  1900. while (p && (p!=e)) {
  1901. if (*p=='<') {
  1902. ln.clear();
  1903. int level = -1;
  1904. KMSGTEST(KERN_EMERG)
  1905. else KMSGTEST(KERN_ALERT)
  1906. else KMSGTEST(KERN_CRIT)
  1907. else KMSGTEST(KERN_ERR)
  1908. else KMSGTEST(KERN_WARNING)
  1909. else KMSGTEST(KERN_NOTICE)
  1910. else KMSGTEST(KERN_INFO)
  1911. else KMSGTEST(KERN_DEBUG)
  1912. else {
  1913. ln.append("KERN_UNKNOWN");
  1914. p -= 3;
  1915. }
  1916. p += 3;
  1917. ln.append(": ");
  1918. while ((p && p!=e)&&(*p!='\n'))
  1919. ln.append(*(p++));
  1920. if (hook)
  1921. hook->log(level, ln.str());
  1922. else
  1923. PROGLOG("%s",ln.str());
  1924. }
  1925. while ((p && p!=e)&&(*p!='\n'))
  1926. p++;
  1927. if (p && p!=e)
  1928. p++;
  1929. }
  1930. }
  1931. };
  1932. #endif
  1933. #ifdef _WIN32
  1934. static struct CNtKernelInformation
  1935. {
  1936. CNtKernelInformation()
  1937. {
  1938. NtQuerySystemInformation = (PROCNTQSI)GetProcAddress(
  1939. GetModuleHandle("ntdll"),
  1940. "NtQuerySystemInformation"
  1941. );
  1942. NtQueryInformationProcess = (PROCNTQIP)GetProcAddress(
  1943. GetModuleHandle("ntdll"),
  1944. "NtQueryInformationProcess"
  1945. );
  1946. // GetSystemTimes not available on earlier versions of Windows - NtQuerySystemInformation not consistent on later ones. So use GetSystemTimes if available
  1947. pGetSystemTimes = (PROCNTGST)GetProcAddress(
  1948. GetModuleHandle("kernel32"),
  1949. "GetSystemTimes"
  1950. );
  1951. NtQuerySystemInformation(SystemBasicInformation,&SysBaseInfo,sizeof(SysBaseInfo),NULL);
  1952. }
  1953. PROCNTQSI NtQuerySystemInformation;
  1954. PROCNTQIP NtQueryInformationProcess;
  1955. PROCNTGST pGetSystemTimes;
  1956. SYSTEM_BASIC_INFORMATION SysBaseInfo;
  1957. } NtKernelFunctions;
  1958. #endif
  1959. struct PortStats
  1960. {
  1961. unsigned port;
  1962. unsigned drops;
  1963. unsigned rx_queue;
  1964. };
  1965. typedef MapBetween<unsigned, unsigned, PortStats, PortStats> MapPortToPortStats;
  1966. class CUdpStatsReporter
  1967. {
  1968. public:
  1969. CUdpStatsReporter()
  1970. {
  1971. dropsCol = -1;
  1972. portCol = -1;
  1973. uidCol = -1;
  1974. queueCol = -1;
  1975. }
  1976. bool reportUdpInfo(unsigned traceLevel)
  1977. {
  1978. #ifdef _WIN32
  1979. return false;
  1980. #else
  1981. if (uidCol==-1 && columnNames.length())
  1982. return false;
  1983. FILE *netfp = fopen("/proc/net/udp", "r");
  1984. if (!netfp)
  1985. return false;
  1986. char ln[512];
  1987. // Read header
  1988. if (!fgets(ln, sizeof(ln), netfp)) {
  1989. fclose(netfp);
  1990. return false;
  1991. }
  1992. if (!columnNames.length())
  1993. {
  1994. columnNames.appendList(ln, " ");
  1995. ForEachItemInRev(idx, columnNames)
  1996. {
  1997. if (streq(columnNames.item(idx), "rem_address"))
  1998. columnNames.add("rem_port", idx+1);
  1999. else if (streq(columnNames.item(idx), "local_address"))
  2000. columnNames.add("local_port", idx+1);
  2001. }
  2002. ForEachItemIn(idx2, columnNames)
  2003. {
  2004. if (streq(columnNames.item(idx2), "drops"))
  2005. dropsCol = idx2;
  2006. else if (streq(columnNames.item(idx2), "local_port"))
  2007. portCol = idx2;
  2008. else if (streq(columnNames.item(idx2), "rx_queue"))
  2009. queueCol = idx2;
  2010. else if (streq(columnNames.item(idx2), "uid"))
  2011. uidCol = idx2;
  2012. }
  2013. if (portCol == -1 || queueCol == -1 || uidCol == -1)
  2014. {
  2015. uidCol = -1;
  2016. fclose(netfp);
  2017. return false;
  2018. }
  2019. }
  2020. int myUid = geteuid();
  2021. while (fgets(ln, sizeof(ln), netfp))
  2022. {
  2023. StringArray cols;
  2024. cols.appendList(ln, " :");
  2025. if (cols.length() >= columnNames.length() && atoi(cols.item(uidCol))==myUid)
  2026. {
  2027. unsigned queue = strtoul(cols.item(queueCol), NULL, 16);
  2028. unsigned drops = 0;
  2029. if (dropsCol >= 0)
  2030. drops = strtoul(cols.item(dropsCol), NULL, 10);
  2031. if (queue || drops)
  2032. {
  2033. unsigned port = strtoul(cols.item(portCol), NULL, 16);
  2034. if (traceLevel > 0)
  2035. DBGLOG("From /proc/net/udp: port %d rx_queue=%u drops=%u", port, queue, drops);
  2036. PortStats *ret = map.getValue(port);
  2037. if (!ret)
  2038. {
  2039. PortStats e = {port, 0, 0};
  2040. map.setValue(port, e);
  2041. ret = map.getValue(port);
  2042. assertex(ret);
  2043. }
  2044. if (queue > ret->rx_queue)
  2045. {
  2046. DBGLOG("UDP queue: new max rx_queue: port %d rx_queue=%u drops=%u", port, queue, drops);
  2047. ret->rx_queue = queue;
  2048. }
  2049. if (drops > ret->drops)
  2050. {
  2051. LOG(MCoperatorError, unknownJob, "DROPPED UDP PACKETS: port %d rx_queue=%u (peak %u) drops=%u (total %i)", port, queue, ret->rx_queue, drops-ret->drops, drops);
  2052. ret->drops = drops;
  2053. }
  2054. }
  2055. }
  2056. }
  2057. fclose(netfp);
  2058. return true;
  2059. #endif
  2060. }
  2061. private:
  2062. MapPortToPortStats map;
  2063. StringArray columnNames;
  2064. int dropsCol;
  2065. int portCol;
  2066. int uidCol;
  2067. int queueCol;
  2068. };
  2069. class CSnmpStatsReporter
  2070. {
  2071. public:
  2072. CSnmpStatsReporter()
  2073. {
  2074. inErrorsCol = -1;
  2075. prevErrors = 0;
  2076. firstCall = true;
  2077. }
  2078. bool reportSnmpInfo()
  2079. {
  2080. #ifdef _WIN32
  2081. return false;
  2082. #else
  2083. if (inErrorsCol==-1 && columnNames.length())
  2084. return false;
  2085. FILE *netfp = fopen("/proc/net/snmp", "r");
  2086. if (!netfp)
  2087. return false;
  2088. char ln[512];
  2089. bool ok = false;
  2090. while (fgets(ln, sizeof(ln), netfp))
  2091. {
  2092. if (strncmp(ln, "Udp:", 4)==0)
  2093. {
  2094. if (!columnNames.length())
  2095. {
  2096. columnNames.appendList(ln, " ");
  2097. ForEachItemIn(idx, columnNames)
  2098. {
  2099. if (streq(columnNames.item(idx), "InErrors"))
  2100. inErrorsCol = idx;
  2101. }
  2102. if (inErrorsCol == -1)
  2103. break;
  2104. }
  2105. if (fgets(ln, sizeof(ln), netfp))
  2106. {
  2107. StringArray cols;
  2108. cols.appendList(ln, " ");
  2109. if (cols.length() >= columnNames.length())
  2110. {
  2111. ok = true;
  2112. unsigned errors = strtoul(cols.item(inErrorsCol), NULL, 10);
  2113. if (firstCall)
  2114. {
  2115. firstCall = false;
  2116. if (errors)
  2117. LOG(MCoperatorWarning, unknownJob, "UDP Initial InError total: %u", errors);
  2118. }
  2119. else if (errors > prevErrors)
  2120. LOG(MCoperatorError, unknownJob, "UDP InErrors: %u (total %u)", errors-prevErrors, errors);
  2121. prevErrors = errors;
  2122. }
  2123. }
  2124. break;
  2125. }
  2126. }
  2127. fclose(netfp);
  2128. return ok;
  2129. #endif
  2130. }
  2131. private:
  2132. StringArray columnNames;
  2133. int inErrorsCol;
  2134. unsigned prevErrors;
  2135. bool firstCall;
  2136. };
  2137. static class CMemoryUsageReporter: public Thread
  2138. {
  2139. bool term;
  2140. unsigned interval;
  2141. Semaphore sem;
  2142. PerfMonMode traceMode;
  2143. Linked<IPerfMonHook> hook;
  2144. unsigned latestCPU;
  2145. #if defined(USE_OLD_PU) || defined(_WIN32)
  2146. double dbIdleTime;
  2147. double dbSystemTime;
  2148. #endif
  2149. #ifdef _WIN32
  2150. LONG status;
  2151. LARGE_INTEGER liOldIdleTime;
  2152. LARGE_INTEGER liOldSystemTime;
  2153. #else
  2154. double OldIdleTime;
  2155. double OldSystemTime;
  2156. CProcessMonitor procmon;
  2157. CExtendedStats extstats;
  2158. #endif
  2159. StringBuffer primaryfs;
  2160. StringBuffer secondaryfs;
  2161. CriticalSection sect; // for getSystemTraceInfo
  2162. CSnmpStatsReporter snmpStats;
  2163. CUdpStatsReporter udpStats;
  2164. public:
  2165. CMemoryUsageReporter(unsigned _interval, PerfMonMode _traceMode, IPerfMonHook * _hook, bool printklog)
  2166. : Thread("CMemoryUsageReporter"), traceMode(_traceMode)
  2167. #ifndef _WIN32
  2168. , extstats(printklog)
  2169. #endif
  2170. {
  2171. interval = _interval;
  2172. hook.set(_hook);
  2173. term = false;
  2174. latestCPU = 0;
  2175. // UDP stats reported unless explicitly disabled
  2176. if (queryEnvironmentConf().getPropBool("udp_stats", true))
  2177. traceMode |= PerfMonUDP;
  2178. #ifdef _WIN32
  2179. memset(&liOldIdleTime,0,sizeof(liOldIdleTime));
  2180. memset(&liOldSystemTime,0,sizeof(liOldSystemTime));
  2181. dbIdleTime = 0;
  2182. primaryfs.append("C:");
  2183. #else
  2184. FILE* procfp;
  2185. procfp = fopen("/proc/uptime", "r");
  2186. int matched = 0;
  2187. if (procfp) {
  2188. matched = fscanf(procfp, "%lf %lf\n", &OldSystemTime, &OldIdleTime);
  2189. fclose(procfp);
  2190. }
  2191. if (!procfp || matched != 2)
  2192. {
  2193. OldSystemTime = 0;
  2194. OldIdleTime = 0;
  2195. }
  2196. primaryfs.append("/");
  2197. #endif
  2198. }
  2199. void setPrimaryFileSystem(char const * _primaryfs)
  2200. {
  2201. CriticalBlock block(sect);
  2202. primaryfs.clear();
  2203. if(_primaryfs)
  2204. primaryfs.append(_primaryfs);
  2205. }
  2206. void setSecondaryFileSystem(char const * _secondaryfs)
  2207. {
  2208. CriticalBlock block(sect);
  2209. secondaryfs.clear();
  2210. if(_secondaryfs)
  2211. secondaryfs.append(_secondaryfs);
  2212. }
  2213. void getSystemTraceInfo(StringBuffer &str, PerfMonMode mode)
  2214. {
  2215. CriticalBlock block(sect);
  2216. #ifdef _WIN32
  2217. if (NtKernelFunctions.pGetSystemTimes) {
  2218. LARGE_INTEGER idle, kernel, user;
  2219. NtKernelFunctions.pGetSystemTimes(&idle, &kernel, &user);
  2220. // note - kernel time seems to include idle time
  2221. if(liOldIdleTime.QuadPart != 0) {
  2222. // CurrentValue = NewValue - OldValue
  2223. dbIdleTime = Li2Double(idle) - Li2Double(liOldIdleTime);
  2224. dbSystemTime = (Li2Double(kernel) + Li2Double(user)) - Li2Double(liOldSystemTime);
  2225. // CurrentCpuIdle = IdleTime / SystemTime
  2226. dbIdleTime = dbIdleTime / dbSystemTime;
  2227. // CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors
  2228. latestCPU = (unsigned) (100.0 - dbIdleTime * 100.0 + 0.5);
  2229. }
  2230. liOldIdleTime = idle;
  2231. liOldSystemTime.QuadPart = user.QuadPart + kernel.QuadPart;
  2232. } else {
  2233. SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;
  2234. SYSTEM_TIME_INFORMATION SysTimeInfo;
  2235. NtKernelFunctions.NtQuerySystemInformation(SystemTimeInformation,&SysTimeInfo,sizeof(SysTimeInfo),0);
  2236. NtKernelFunctions.NtQuerySystemInformation(SystemPerformanceInformation,&SysPerfInfo,sizeof(SysPerfInfo),NULL);
  2237. if(liOldIdleTime.QuadPart != 0) {
  2238. // CurrentValue = NewValue - OldValue
  2239. dbIdleTime = Li2Double(SysPerfInfo.liIdleTime) - Li2Double(liOldIdleTime);
  2240. dbSystemTime = Li2Double(SysTimeInfo.liKeSystemTime) - Li2Double(liOldSystemTime);
  2241. // CurrentCpuIdle = IdleTime / SystemTime
  2242. dbIdleTime = dbIdleTime / dbSystemTime;
  2243. // CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors
  2244. latestCPU = (unsigned) (100.0 - dbIdleTime * 100.0 / (double)NtKernelFunctions.SysBaseInfo.bKeNumberProcessors + 0.5);
  2245. }
  2246. liOldIdleTime = SysPerfInfo.liIdleTime;
  2247. liOldSystemTime = SysTimeInfo.liKeSystemTime;
  2248. }
  2249. MEMORYSTATUSEX memstatus;
  2250. memstatus.dwLength = sizeof(memstatus);
  2251. GlobalMemoryStatusEx(&memstatus);
  2252. DWORDLONG vmTotal = memstatus.ullTotalVirtual;
  2253. DWORDLONG vmAvail = memstatus.ullAvailVirtual;
  2254. DWORDLONG vmInUse = vmTotal - vmAvail;
  2255. DWORDLONG physTotal = memstatus.ullAvailPhys;
  2256. DWORDLONG physAvail = memstatus.ullTotalPhys;
  2257. DWORDLONG physInUse = physTotal - physAvail;
  2258. ULARGE_INTEGER diskAvailStruct;
  2259. ULARGE_INTEGER diskTotalStruct;
  2260. unsigned __int64 firstDriveTotal = 0;
  2261. unsigned __int64 firstDriveInUse = 0;
  2262. unsigned __int64 secondDriveTotal = 0;
  2263. unsigned __int64 secondDriveInUse = 0;
  2264. if(primaryfs.length())
  2265. {
  2266. diskAvailStruct.QuadPart = 0;
  2267. diskTotalStruct.QuadPart = 0;
  2268. GetDiskFreeSpaceEx(primaryfs.str(), &diskAvailStruct, &diskTotalStruct, 0);
  2269. firstDriveTotal = diskTotalStruct.QuadPart;
  2270. firstDriveInUse = diskTotalStruct.QuadPart - diskAvailStruct.QuadPart;
  2271. }
  2272. if(secondaryfs.length())
  2273. {
  2274. diskAvailStruct.QuadPart = 0;
  2275. diskTotalStruct.QuadPart = 0;
  2276. GetDiskFreeSpaceEx(secondaryfs.str(), &diskAvailStruct, &diskTotalStruct, 0);
  2277. secondDriveTotal = diskTotalStruct.QuadPart;
  2278. secondDriveInUse = diskTotalStruct.QuadPart - diskAvailStruct.QuadPart;
  2279. }
  2280. if(hook)
  2281. hook->processPerfStats(latestCPU, (unsigned)(vmInUse/1024), (unsigned)(vmTotal/1024), firstDriveInUse, firstDriveTotal, secondDriveInUse, secondDriveTotal, getThreadCount());
  2282. if(!mode)
  2283. return;
  2284. if(mode & PerfMonProcMem)
  2285. {
  2286. str.appendf("PU=%3d%%",latestCPU);
  2287. #if 0
  2288. VM_COUNTERS vmc;
  2289. DWORD dwSize = 0;
  2290. NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &vmc, sizeof(vmc), &dwSize);
  2291. str.appendf(" MU=%3u%%",(unsigned)((__int64)vmc.WorkingSetSize*100/(__int64)vmTotal));
  2292. #else
  2293. str.appendf(" MU=%3u%%",(unsigned)((__int64)vmInUse*100/(__int64)vmTotal));
  2294. str.appendf(" PY=%3u%%",(unsigned)((__int64)physInUse*100/(__int64)physTotal));
  2295. if (hook)
  2296. hook->extraLogging(str);
  2297. #ifdef _USE_MALLOC_HOOK
  2298. if (totalMem)
  2299. str.appendf(" TM=%" I64F "d",totalMem);
  2300. #endif
  2301. #endif
  2302. }
  2303. if(mode & PerfMonPackets)
  2304. {
  2305. unsigned tx, rx;
  2306. if(getPacketStats(tx, rx))
  2307. str.appendf(" TX=%3u%% RX=%3u%%", tx, rx);
  2308. else
  2309. str.appendf(" ");
  2310. }
  2311. if(mode & PerfMonDiskUsage)
  2312. {
  2313. if(firstDriveTotal) str.appendf(" D1=%3u%%", (unsigned)(firstDriveInUse*100/firstDriveTotal));
  2314. if(secondDriveTotal) str.appendf(" D2=%3u%%", (unsigned)(secondDriveInUse*100/secondDriveTotal));
  2315. }
  2316. if(mode & PerfMonExtended)
  2317. {
  2318. __IO_COUNTERS ioc;
  2319. KERNEL_USER_TIMES kut;
  2320. POOLED_USAGE_AND_LIMITS put;
  2321. VM_COUNTERS vmc;
  2322. DWORD dwSize;
  2323. DWORD dwHandles;
  2324. dwSize = 0;
  2325. NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &vmc, sizeof(vmc), &dwSize);
  2326. dwHandles = 0;
  2327. dwSize = 0;
  2328. NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessHandleCount, &dwHandles, sizeof(dwHandles), &dwSize);
  2329. dwSize = 0;
  2330. NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessIoCounters, &ioc, sizeof(ioc), &dwSize);
  2331. dwSize = 0;
  2332. NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessTimes, &kut, sizeof(kut), &dwSize);
  2333. dwSize = 0;
  2334. NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessPooledUsageAndLimits, &put, sizeof(put), &dwSize);
  2335. str.appendf(" WS=%10u ",vmc.WorkingSetSize);
  2336. str.appendf("PP=%10u ",put.PagedPoolUsage);
  2337. str.appendf("NP=%10u ",put.NonPagedPoolUsage);
  2338. str.appendf("HC=%5u ",dwHandles);
  2339. str.appendf("TC=%5u ",getThreadCount());
  2340. str.appendf("IR=%10u ",(unsigned)(ioc.ReadTransferCount/1024));
  2341. str.appendf("IW=%10u ",(unsigned)(ioc.WriteTransferCount/1024));
  2342. str.appendf("IO=%10u ",(unsigned)(ioc.OtherTransferCount/1024));
  2343. str.appendf("KT=%16" I64F "u ",kut.KernelTime);
  2344. str.appendf("UT=%16" I64F "u ",kut.UserTime);
  2345. }
  2346. #else
  2347. bool outofhandles = false;
  2348. #ifdef USE_OLD_PU
  2349. FILE* procfp = fopen("/proc/uptime", "r");
  2350. int matched = 0;
  2351. OldSystemTime = 0;
  2352. if (procfp) {
  2353. matched = fscanf(procfp, "%lf %lf\n", &dbSystemTime, &dbIdleTime);
  2354. fclose(procfp);
  2355. outofhandles = false;
  2356. }
  2357. latestCPU = unsigned(100.0 - (dbIdleTime - OldIdleTime)*100.0/(dbSystemTime - OldSystemTime) + 0.5);
  2358. if (procfp && matched == 2)
  2359. {
  2360. OldSystemTime = dbSystemTime;
  2361. OldIdleTime = dbIdleTime;
  2362. }
  2363. #else
  2364. latestCPU = extstats.getCPU();
  2365. if (latestCPU==(unsigned)-1) {
  2366. outofhandles = true;
  2367. latestCPU = 0;
  2368. }
  2369. #endif
  2370. unsigned __int64 primaryfsTotal = 0;
  2371. unsigned __int64 primaryfsInUse = 0;
  2372. unsigned __int64 secondaryfsTotal = 0;
  2373. unsigned __int64 secondaryfsInUse = 0;
  2374. if(primaryfs.length())
  2375. getDiskUsage(primaryfs.str(), primaryfsTotal, primaryfsInUse);
  2376. if(secondaryfs.length())
  2377. getDiskUsage(secondaryfs.str(), secondaryfsTotal, secondaryfsInUse);
  2378. if(!mode) return;
  2379. unsigned memused=0;
  2380. unsigned memtot=0;
  2381. str.appendf("LPT=%u ", queryNumLocalTrees());
  2382. str.appendf("APT=%u ", queryNumAtomTrees());
  2383. if(mode & PerfMonProcMem)
  2384. {
  2385. if (!outofhandles)
  2386. str.appendf("PU=%3d%% ", latestCPU);
  2387. else
  2388. str.appendf("PU=OOH ");
  2389. getMemStats(str,memused,memtot);
  2390. if (hook)
  2391. hook->extraLogging(str);
  2392. procmon.printBusy(latestCPU,str);
  2393. }
  2394. if (hook) {
  2395. if (!memtot) {
  2396. unsigned mu;
  2397. unsigned ma;
  2398. unsigned mt;
  2399. unsigned st;
  2400. unsigned su;
  2401. getMemUsage(mu,ma,mt,st,su);
  2402. memused = mu+su;
  2403. memtot = mt+st;
  2404. }
  2405. hook->processPerfStats(latestCPU, memused, memtot, primaryfsInUse, primaryfsTotal, secondaryfsInUse, secondaryfsTotal, getThreadCount());
  2406. }
  2407. if(mode & PerfMonPackets)
  2408. {
  2409. unsigned tx, rx;
  2410. if(getPacketStats(tx, rx))
  2411. str.appendf(" TX=%3u%% RX=%3u%%", tx, rx);
  2412. else
  2413. str.appendf(" ");
  2414. }
  2415. if(mode & PerfMonDiskUsage)
  2416. {
  2417. if(primaryfsTotal) str.appendf(" D1=%3u%%", (unsigned)(primaryfsInUse*100/primaryfsTotal));
  2418. if(secondaryfsTotal) str.appendf(" D2=%3u%%", (unsigned)(secondaryfsInUse*100/secondaryfsTotal));
  2419. }
  2420. if(mode & PerfMonExtended)
  2421. {
  2422. extstats.getLine(str);
  2423. }
  2424. #endif
  2425. }
  2426. #define NAMEDCOUNTPERIOD 60*30
  2427. int run()
  2428. {
  2429. StringBuffer str;
  2430. getSystemTraceInfo(str, traceMode&~PerfMonExtended); // initializes the values so that first one we print is meaningful rather than always saying PU=0%
  2431. if (traceMode&PerfMonUDP)
  2432. {
  2433. snmpStats.reportSnmpInfo();
  2434. udpStats.reportUdpInfo(0);
  2435. }
  2436. CTimeMon tm(NAMEDCOUNTPERIOD*1000);
  2437. while (!term) {
  2438. if (sem.wait(interval))
  2439. break;
  2440. str.clear();
  2441. getSystemTraceInfo(str, traceMode&~PerfMonExtended);
  2442. #ifdef NAMEDCOUNTS
  2443. if (tm.timedout())
  2444. {
  2445. dumpNamedCounts(str.newline());
  2446. tm.reset(NAMEDCOUNTPERIOD*1000);
  2447. }
  2448. #endif
  2449. if (traceMode&PerfMonUDP)
  2450. {
  2451. snmpStats.reportSnmpInfo();
  2452. udpStats.reportUdpInfo(0);
  2453. }
  2454. if(traceMode&&str.length()) {
  2455. LOG(MCdebugInfo, unknownJob, "SYS: %s", str.str());
  2456. #ifndef _WIN32
  2457. if (traceMode&PerfMonExtended) {
  2458. if (extstats.getLine(str.clear()))
  2459. LOG(MCdebugInfo, unknownJob, "%s", str.str());
  2460. {
  2461. CriticalBlock block(sect);
  2462. extstats.printKLog(hook);
  2463. }
  2464. }
  2465. #endif
  2466. }
  2467. }
  2468. return 0;
  2469. }
  2470. void stop()
  2471. {
  2472. term = true;
  2473. sem.signal();
  2474. join();
  2475. }
  2476. unsigned queryLatestCPU() const
  2477. {
  2478. return latestCPU;
  2479. }
  2480. void setHook(IPerfMonHook *_hook)
  2481. {
  2482. CriticalBlock block(sect);
  2483. hook.set(_hook);
  2484. }
  2485. } *MemoryUsageReporter=NULL;
  2486. #ifdef _WIN32
  2487. static inline unsigned scaleFileTimeToMilli(unsigned __int64 nano100)
  2488. {
  2489. return (unsigned)(nano100 / 10000);
  2490. }
  2491. void getProcessTime(UserSystemTime_t & result)
  2492. {
  2493. LARGE_INTEGER startTime, exitTime, kernelTime, userTime;
  2494. if (GetProcessTimes(GetCurrentProcess(), (FILETIME *)&startTime, (FILETIME *)&exitTime, (FILETIME *)&kernelTime, (FILETIME *)&userTime))
  2495. {
  2496. result.user = scaleFileTimeToMilli(userTime.QuadPart);
  2497. result.system = scaleFileTimeToMilli(kernelTime.QuadPart);
  2498. }
  2499. }
  2500. #else
  2501. void getProcessTime(UserSystemTime_t & result)
  2502. {
  2503. UserStatusInfo info(GetCurrentProcessId());
  2504. if (info.update())
  2505. result = info.time;
  2506. }
  2507. #endif
  2508. void getSystemTraceInfo(StringBuffer &str, PerfMonMode mode)
  2509. {
  2510. if (!MemoryUsageReporter)
  2511. MemoryUsageReporter = new CMemoryUsageReporter(1000, mode, 0, false);
  2512. MemoryUsageReporter->getSystemTraceInfo(str, mode);
  2513. }
  2514. void startPerformanceMonitor(unsigned interval, PerfMonMode traceMode, IPerfMonHook * hook)
  2515. {
  2516. stopPerformanceMonitor();
  2517. if (!MemoryUsageReporter) {
  2518. MemoryUsageReporter = new CMemoryUsageReporter(interval, traceMode, hook, (traceMode&PerfMonExtended)!=0);
  2519. MemoryUsageReporter->start();
  2520. }
  2521. }
  2522. void stopPerformanceMonitor()
  2523. {
  2524. if (MemoryUsageReporter) {
  2525. MemoryUsageReporter->stop();
  2526. delete MemoryUsageReporter;
  2527. MemoryUsageReporter = NULL;
  2528. }
  2529. }
  2530. void setPerformanceMonitorHook(IPerfMonHook *hook)
  2531. {
  2532. if (MemoryUsageReporter)
  2533. MemoryUsageReporter->setHook(hook);
  2534. }
  2535. void setPerformanceMonitorPrimaryFileSystem(char const * fs)
  2536. {
  2537. if(MemoryUsageReporter)
  2538. MemoryUsageReporter->setPrimaryFileSystem(fs);
  2539. }
  2540. void setPerformanceMonitorSecondaryFileSystem(char const * fs)
  2541. {
  2542. if(MemoryUsageReporter)
  2543. MemoryUsageReporter->setSecondaryFileSystem(fs);
  2544. }
  2545. unsigned getLatestCPUUsage()
  2546. {
  2547. if (MemoryUsageReporter)
  2548. return MemoryUsageReporter->queryLatestCPU();
  2549. else
  2550. return 0;
  2551. }
  2552. void getHardwareInfo(HardwareInfo &hdwInfo, const char *primDiskPath, const char *secDiskPath)
  2553. {
  2554. memset(&hdwInfo, 0, sizeof(HardwareInfo));
  2555. getCpuInfo(hdwInfo.numCPUs, hdwInfo.CPUSpeed);
  2556. #ifdef _WIN32
  2557. MEMORYSTATUS memstatus;
  2558. GlobalMemoryStatus(&memstatus);
  2559. hdwInfo.totalMemory = (unsigned)(memstatus.dwTotalPhys / (1024*1024)); // in MB
  2560. ULARGE_INTEGER diskAvailStruct;
  2561. ULARGE_INTEGER diskTotalStruct;
  2562. if (primDiskPath)
  2563. {
  2564. diskTotalStruct.QuadPart = 0;
  2565. GetDiskFreeSpaceEx(primDiskPath, &diskAvailStruct, &diskTotalStruct, 0);
  2566. hdwInfo.primDiskSize = (unsigned)(diskTotalStruct.QuadPart / (1024*1024*1024)); // in GB
  2567. hdwInfo.primFreeSize = (unsigned)(diskAvailStruct.QuadPart / (1024*1024*1024)); // in GB
  2568. }
  2569. if (secDiskPath)
  2570. {
  2571. diskTotalStruct.QuadPart = 0;
  2572. GetDiskFreeSpaceEx(secDiskPath, &diskAvailStruct, &diskTotalStruct, 0);
  2573. hdwInfo.secDiskSize = (unsigned)(diskTotalStruct.QuadPart / (1024*1024*1024)); // in GB
  2574. hdwInfo.secFreeSize = (unsigned)(diskAvailStruct.QuadPart / (1024*1024*1024)); // in GB
  2575. }
  2576. // MORE: Find win32 call for NIC speed
  2577. #else // linux
  2578. unsigned memUsed, memActive, memSwap, memSwapUsed;
  2579. getMemUsage(memUsed, memActive, hdwInfo.totalMemory, memSwap, memSwapUsed);
  2580. hdwInfo.totalMemory /= 1024; // in MB
  2581. unsigned __int64 diskSize;
  2582. unsigned __int64 diskUsed;
  2583. if (primDiskPath)
  2584. {
  2585. getDiskUsage(primDiskPath, diskSize, diskUsed);
  2586. hdwInfo.primDiskSize = diskSize / (1024*1024*1024); // in GB
  2587. hdwInfo.primFreeSize = (diskSize - diskUsed) / (1024*1024*1024); // in GB
  2588. }
  2589. if (secDiskPath)
  2590. {
  2591. getDiskUsage(secDiskPath, diskSize, diskUsed);
  2592. hdwInfo.secDiskSize = diskSize / (1024*1024*1024); // in GB
  2593. hdwInfo.secFreeSize = (diskSize - diskUsed) / (1024*1024*1024); // in GB
  2594. }
  2595. // MORE: Find linux call for NIC speed -- mii-tool does not seem to work on our roxie clusters?
  2596. #endif
  2597. }
  2598. //===========================================================================
  2599. enum SegTypes {
  2600. segtype_free, //
  2601. segtype_heap, // rw-p named [heap]
  2602. segtype_data, // rw-p unnamed
  2603. segtype_guard, // ---p unnamed/named
  2604. segtype_stack, // rwxp
  2605. segtype_qlibcode, // r-xp named */lib200
  2606. segtype_qlibdata, // rw-p named */lib200
  2607. segtype_libcode, // r-xp named *
  2608. segtype_libdata, // rw-p named *
  2609. segtype_pstack, // rwxp named [stack]
  2610. segtype_const, // r--p
  2611. segtype_null // must be last
  2612. };
  2613. struct SegTypeRec
  2614. {
  2615. offset_t total;
  2616. unsigned n;
  2617. offset_t largest;
  2618. };
  2619. const char *PROCMAPHEADER =
  2620. "FREE,NFREE,MAXFREE,HEAP,STACK,NSTACKS,DATA,NDATA,MAXDATA,LIBDATA,QUERYDATA,MAXQUERYDATA,LIBCODE,QUERYCODE,MAXQLIBCODE";
  2621. class CProcReader
  2622. {
  2623. // Cant use JFile for /proc filesystem as seek doesn't work
  2624. public:
  2625. char ln [512];
  2626. FILE *file;
  2627. const char *buf;
  2628. size32_t bufsize;
  2629. CProcReader(const char *filename,const void *_buf,size32_t _buflen)
  2630. {
  2631. buf = (const char *)_buf;
  2632. bufsize = buf?_buflen:0;
  2633. file = buf?NULL:fopen(filename,"r");
  2634. }
  2635. ~CProcReader()
  2636. {
  2637. if (file)
  2638. fclose(file);
  2639. }
  2640. bool nextln()
  2641. {
  2642. if (buf) {
  2643. if (bufsize&&*buf) {
  2644. unsigned i = 0;
  2645. while (bufsize&&(i<sizeof(ln)-1)&&*buf&&(*buf!=10)&&(*buf!=13)) {
  2646. ln[i++] = *(buf++);
  2647. bufsize--;
  2648. }
  2649. ln[i] = 0;
  2650. while (bufsize&&*buf&&((*buf==10)||(*buf==13))) {
  2651. buf++;
  2652. bufsize--;
  2653. }
  2654. return true;
  2655. }
  2656. }
  2657. else if (file&&fgets (ln, sizeof(ln), file)) {
  2658. size_t i = strlen(ln);
  2659. while (i&&((ln[i-1]==10)||(ln[i-1]==13)))
  2660. i--;
  2661. ln[i] = 0;
  2662. return true;
  2663. }
  2664. if (file) {
  2665. fclose(file);
  2666. file = NULL;
  2667. }
  2668. return false;
  2669. }
  2670. void dump(bool useprintf)
  2671. {
  2672. while (nextln()) {
  2673. if (useprintf)
  2674. printf("%s\n",ln);
  2675. else
  2676. PROGLOG("%s",ln);
  2677. }
  2678. }
  2679. };
  2680. void printProcMap(const char *fn, bool printbody, bool printsummary, StringBuffer *lnout, MemoryBuffer *mb, bool useprintf)
  2681. {
  2682. CProcReader reader(fn,mb?mb->toByteArray():NULL,mb?mb->length():0);
  2683. unsigned i;
  2684. SegTypeRec recs[segtype_null];
  2685. memset(&recs,0,sizeof(recs));
  2686. offset_t last=0;
  2687. if (printbody) {
  2688. if (useprintf)
  2689. printf("START,END,SIZE,OFFSET,PERMS,PATH\n");
  2690. else
  2691. PROGLOG("START,END,SIZE,OFFSET,PERMS,PATH");
  2692. }
  2693. while (reader.nextln()) {
  2694. const char *ln = reader.ln;
  2695. unsigned n=0;
  2696. if (*ln) {
  2697. offset_t start = readHexNum(ln);
  2698. if (last&&(last!=start)) {
  2699. recs[segtype_free].n++;
  2700. offset_t ssz = start-last;
  2701. recs[segtype_free].total += ssz;
  2702. if (ssz>recs[segtype_free].largest)
  2703. recs[segtype_free].largest = ssz;
  2704. }
  2705. if (*ln=='-') {
  2706. ln++;
  2707. offset_t end = readHexNum(ln);
  2708. char perms[5];
  2709. skipSp(ln);
  2710. for (i=0;i<4;)
  2711. if (*ln)
  2712. perms[i++] = *(ln++);
  2713. perms[i] = 0;
  2714. skipSp(ln);
  2715. offset_t offset = readHexNum(ln);
  2716. skipSp(ln);
  2717. char dev[6];
  2718. for (i=0;i<5;)
  2719. if (*ln)
  2720. dev[i++] = *(ln++);
  2721. dev[i] = 0;
  2722. skipSp(ln);
  2723. unsigned inode __attribute__((unused)) = (unsigned) readDecNum(ln);
  2724. skipSp(ln);
  2725. const char *path = ln;
  2726. if (printbody) {
  2727. if (useprintf)
  2728. printf("%08" I64F "x,%08" I64F "x,%" I64F "d,%08" I64F "x,%s,%s,%s\n",start,end,(offset_t)(end-start),offset,perms,dev,path);
  2729. else
  2730. PROGLOG("%08" I64F "x,%08" I64F "x,%" I64F "d,%08" I64F "x,%s,%s,%s",start,end,(offset_t)(end-start),offset,perms,dev,path);
  2731. }
  2732. SegTypes t = segtype_data;
  2733. if (strcmp(perms,"---p")==0)
  2734. t = segtype_guard;
  2735. else if (strcmp(perms,"rwxp")==0) {
  2736. if (memicmp(ln,"[stack]",7)==0)
  2737. t = segtype_pstack;
  2738. else
  2739. t = segtype_stack;
  2740. }
  2741. else if (strcmp(perms,"rw-p")==0) {
  2742. if (memicmp(ln,"[heap]",6)==0)
  2743. t = segtype_heap;
  2744. else if (strstr(ln,"/libW200"))
  2745. t = segtype_qlibdata;
  2746. else if (*ln)
  2747. t = segtype_libdata;
  2748. else
  2749. t = segtype_data;
  2750. }
  2751. else if (strcmp(perms,"r-xp")==0) {
  2752. if (strstr(ln,"/libW200"))
  2753. t = segtype_qlibcode;
  2754. else if (*ln)
  2755. t = segtype_libcode;
  2756. }
  2757. else if (strcmp(perms,"r--p")==0)
  2758. t = segtype_const;
  2759. else {
  2760. ERRLOG("%s - unknown perms",perms);
  2761. continue;
  2762. }
  2763. recs[t].n++;
  2764. offset_t ssz = end-start;
  2765. recs[t].total += ssz;
  2766. if (ssz>recs[t].largest)
  2767. recs[t].largest = ssz;
  2768. n++;
  2769. last = end;
  2770. #ifndef __64BIT__
  2771. if ((end<0xffffffff)&&(end>=0xc0000000)) // rest is OS (32-bit only)
  2772. break;
  2773. #endif
  2774. }
  2775. }
  2776. }
  2777. if (printsummary||lnout) {
  2778. StringBuffer tln;
  2779. if (lnout==NULL)
  2780. lnout = &tln;
  2781. lnout->appendf("%" I64F "u," // total
  2782. "%u," // n
  2783. "%" I64F "u," // largest
  2784. "%" I64F "u," // total
  2785. "%" I64F "u," // total
  2786. "%u," // n
  2787. "%" I64F "u," // total
  2788. "%u," // n
  2789. "%" I64F "u," // largest
  2790. "%" I64F "u," // total
  2791. "%" I64F "u," // total
  2792. "%" I64F "u," // largest
  2793. "%" I64F "u," // total
  2794. "%" I64F "u," // total
  2795. "%" I64F "u" // largest
  2796. ,
  2797. recs[segtype_free].total,
  2798. recs[segtype_free].n,
  2799. recs[segtype_free].largest,
  2800. recs[segtype_heap].total,
  2801. recs[segtype_stack].total,
  2802. recs[segtype_stack].n,
  2803. recs[segtype_data].total,
  2804. recs[segtype_data].n,
  2805. recs[segtype_data].largest,
  2806. recs[segtype_libdata].total,
  2807. recs[segtype_qlibdata].total,
  2808. recs[segtype_qlibdata].largest,
  2809. recs[segtype_libcode].total,
  2810. recs[segtype_qlibcode].total,
  2811. recs[segtype_qlibcode].largest
  2812. );
  2813. if (printsummary) {
  2814. if (useprintf)
  2815. printf("%s\n%s\n",PROCMAPHEADER,tln.str());
  2816. else {
  2817. PROGLOG("%s",PROCMAPHEADER);
  2818. PROGLOG("%s",tln.str());
  2819. }
  2820. }
  2821. }
  2822. }
  2823. #ifdef _WIN32
  2824. // stubs
  2825. void PrintMemoryReport(bool full)
  2826. {
  2827. StringBuffer s;
  2828. getSystemTraceInfo(s,PerfMonProcMem);
  2829. PROGLOG("%s",s.str());
  2830. }
  2831. #else
  2832. void PrintMemoryReport(bool full)
  2833. {
  2834. // may be very close to oom so protect against re-entry
  2835. static int recurse=0;
  2836. if (recurse++==0) {
  2837. try {
  2838. printProcMap("/proc/self/maps",full,true,NULL,NULL,false);
  2839. }
  2840. catch (IException *e) {
  2841. e->Release();
  2842. }
  2843. catch (...) {
  2844. }
  2845. try {
  2846. PROGLOG("/proc/meminfo:");
  2847. CProcReader reader("/proc/meminfo",NULL,0);
  2848. reader.dump(false);
  2849. }
  2850. catch (IException *e) {
  2851. e->Release();
  2852. }
  2853. catch (...) {
  2854. }
  2855. try {
  2856. PROGLOG("/proc/self/status:");
  2857. CProcReader reader("/proc/self/status",NULL,0);
  2858. reader.dump(false);
  2859. }
  2860. catch (IException *e) {
  2861. e->Release();
  2862. }
  2863. catch (...) {
  2864. }
  2865. try {
  2866. StringBuffer s;
  2867. getSystemTraceInfo(s,PerfMonProcMem);
  2868. PROGLOG("%s",s.str());
  2869. PROGLOG("===============================================================");
  2870. }
  2871. catch (IException *e) {
  2872. e->Release();
  2873. }
  2874. catch (...) {
  2875. }
  2876. }
  2877. recurse--;
  2878. }
  2879. #endif
  2880. bool areTransparentHugePagesEnabled()
  2881. {
  2882. #ifdef __linux__
  2883. StringBuffer contents;
  2884. try
  2885. {
  2886. contents.loadFile("/sys/kernel/mm/transparent_hugepage/enabled");
  2887. return !strstr(contents.str(), "[never]");
  2888. }
  2889. catch (IException * e)
  2890. {
  2891. e->Release();
  2892. }
  2893. #endif
  2894. return false;
  2895. }
  2896. memsize_t getHugePageSize()
  2897. {
  2898. #ifdef __linux__
  2899. StringBuffer contents;
  2900. try
  2901. {
  2902. //Search for an entry Hugepagesize: xxxx kB
  2903. const char * const tag = "Hugepagesize:";
  2904. contents.loadFile("/proc/meminfo");
  2905. const char * hugepage = strstr(contents.str(), tag);
  2906. if (hugepage)
  2907. {
  2908. const char * next = hugepage + strlen(tag);
  2909. char * end;
  2910. memsize_t size = strtoul(next, &end, 10);
  2911. if (strncmp(end, " kB", 3) == 0)
  2912. return size * 0x400;
  2913. }
  2914. }
  2915. catch (IException * e)
  2916. {
  2917. e->Release();
  2918. }
  2919. #endif
  2920. return 0x200000; // Default for an x86 system
  2921. }
  2922. //===========================================================================
  2923. #ifdef LEAK_CHECK
  2924. #ifdef _WIN32
  2925. LeakChecker::LeakChecker(const char * _title) : title(_title)
  2926. {
  2927. _CrtMemCheckpoint(&oldMemState);
  2928. }
  2929. LeakChecker::~LeakChecker()
  2930. {
  2931. _CrtMemState newMemState, diffMemState;
  2932. _CrtMemCheckpoint(&newMemState);
  2933. if(_CrtMemDifference(&diffMemState, &oldMemState, &newMemState))
  2934. {
  2935. _RPT1(_CRT_WARN, "----- Memory leaks in '%s' -----\n", title);
  2936. _CrtMemDumpStatistics(&diffMemState);
  2937. _CrtMemDumpAllObjectsSince(&oldMemState);
  2938. _RPT0(_CRT_WARN, "----- End of leaks -----\n");
  2939. }
  2940. }
  2941. static char _logFile[255]; // used to hold last file name of log file for memory leak logging
  2942. static FILE *_logHandle = NULL;
  2943. _CRT_REPORT_HOOK oldReport;
  2944. static int MemoryLeakReportHook(int nRptType,char *szMsg,int *retVal)
  2945. {
  2946. if (szMsg && *szMsg)
  2947. {
  2948. if (_logHandle)
  2949. fprintf(_logHandle, szMsg);
  2950. if (*_logFile)
  2951. {
  2952. #if 1
  2953. // this works better in VS 2008 libraries (which fault in fopen)
  2954. int handle = _open(_logFile, O_RDWR | O_CREAT, _S_IREAD | _S_IWRITE);
  2955. _lseek(handle,0,SEEK_END);
  2956. _write(handle,szMsg,(unsigned)strlen(szMsg));
  2957. _close(handle);
  2958. #else
  2959. FILE *handle = fopen(_logFile, "a");
  2960. fprintf(handle, szMsg);
  2961. fclose(handle);
  2962. #endif
  2963. }
  2964. }
  2965. if (oldReport)
  2966. return oldReport(nRptType,szMsg,retVal);
  2967. else
  2968. return false;
  2969. }
  2970. MODULE_INIT(INIT_PRIORITY_JDEBUG1)
  2971. {
  2972. oldReport = _CrtSetReportHook(MemoryLeakReportHook);
  2973. return 1;
  2974. }
  2975. void logLeaks (const char *logFile)
  2976. {
  2977. if (logFile)
  2978. strncpy(_logFile, logFile, sizeof(_logFile));
  2979. else
  2980. _logFile[0] = 0;
  2981. }
  2982. void logLeaks (FILE *logHandle)
  2983. {
  2984. _logHandle = logHandle;
  2985. }
  2986. #else
  2987. #endif
  2988. #endif
  2989. #if !defined(USING_MPATROL) && defined(WIN32) && defined(_DEBUG)
  2990. void jlib_decl enableMemLeakChecking(bool enable)
  2991. {
  2992. int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
  2993. if (enable)
  2994. tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
  2995. else
  2996. tmpFlag &= ~_CRTDBG_LEAK_CHECK_DF;
  2997. _CrtSetDbgFlag( tmpFlag );
  2998. }
  2999. #endif
  3000. #if defined(_WIN32) && defined(_DEBUG)
  3001. //#include <dbgint.h>
  3002. const unsigned maxUnique = 10000;
  3003. typedef struct _CrtMemBlockHeader
  3004. {
  3005. // Pointer to the block allocated just before this one:
  3006. struct _CrtMemBlockHeader *pBlockHeaderNext;
  3007. // Pointer to the block allocated just after this one:
  3008. struct _CrtMemBlockHeader *pBlockHeaderPrev;
  3009. char *szFileName; // File name
  3010. int nLine; // Line number
  3011. size_t nDataSize; // Size of user block
  3012. int nBlockUse; // Type of block
  3013. long lRequest; // Allocation number
  3014. } _CrtMemBlockHeader;
  3015. int compareFile(_CrtMemBlockHeader * left, _CrtMemBlockHeader * right)
  3016. {
  3017. int compare;
  3018. if (left->szFileName && right->szFileName)
  3019. compare = strcmp(left->szFileName, right->szFileName);
  3020. else if (left->szFileName)
  3021. compare = -1;
  3022. else if (right->szFileName)
  3023. compare = +1;
  3024. else
  3025. compare = 0;
  3026. return compare;
  3027. }
  3028. int compareLocation(_CrtMemBlockHeader * left, _CrtMemBlockHeader * right)
  3029. {
  3030. int compare = compareFile(left, right);
  3031. if (compare != 0)
  3032. return compare;
  3033. return left->nLine - right->nLine;
  3034. }
  3035. int compareBlocks(_CrtMemBlockHeader * left, _CrtMemBlockHeader * right)
  3036. {
  3037. int compare = compareLocation(left, right);
  3038. if (compare != 0)
  3039. return compare;
  3040. return (int)(right->nDataSize - left->nDataSize);
  3041. }
  3042. void addLocation(unsigned & numUnique, _CrtMemBlockHeader * * locations, unsigned * counts, _CrtMemBlockHeader * search)
  3043. {
  3044. int left = 0;
  3045. int right = numUnique;
  3046. while (left < right)
  3047. {
  3048. int mid = (left + right) >> 1;
  3049. int cmp = compareBlocks(search, locations[mid]);
  3050. if (cmp < 0)
  3051. right = mid;
  3052. else if (cmp > 0)
  3053. left = mid+1;
  3054. else
  3055. {
  3056. //Save the lowest allocation number (so quicker to set a subsequent breakpoint)
  3057. if (search->lRequest < locations[mid]->lRequest)
  3058. locations[mid] = search;
  3059. counts[mid]++;
  3060. return;
  3061. }
  3062. }
  3063. if (numUnique != maxUnique)
  3064. {
  3065. assertex(left == right);
  3066. memmove(locations + left+1, locations + left, (numUnique-left)*sizeof(*locations));
  3067. memmove(counts + left+1, counts + left, (numUnique-left)*sizeof(*counts));
  3068. locations[left] = search;
  3069. counts[left] = 1;
  3070. numUnique++;
  3071. }
  3072. else
  3073. counts[maxUnique]++;
  3074. }
  3075. unsigned dumpMemory(unsigned lenTarget, char * target, unsigned lenSrc, const void * ptr)
  3076. {
  3077. if (lenSrc > lenTarget)
  3078. lenSrc = lenTarget;
  3079. const char * src = (const char *)ptr;
  3080. for (unsigned i=0; i < lenSrc; i++)
  3081. {
  3082. byte next = src[i];
  3083. target[i] = (next >= 0x20 && next <= 0x7e) ? next : '.';
  3084. }
  3085. return lenSrc;
  3086. }
  3087. void printAllocationSummary()
  3088. {
  3089. _CrtMemState state;
  3090. _CrtMemCheckpoint(&state);
  3091. unsigned numUnique = 0;
  3092. _CrtMemBlockHeader * locations[maxUnique+1];
  3093. unsigned counts[maxUnique+1];
  3094. _clear(counts);
  3095. unsigned __int64 totalFree = 0;
  3096. unsigned __int64 totalAllocated = 0;
  3097. //Walk the heap, keeping a tally of (filename, line, size)->count
  3098. _CrtMemBlockHeader * cur;
  3099. for (cur = state.pBlockHeader; cur; cur=cur->pBlockHeaderNext)
  3100. {
  3101. switch (cur->nBlockUse)
  3102. {
  3103. case _NORMAL_BLOCK:
  3104. {
  3105. addLocation(numUnique, locations, counts, cur);
  3106. totalAllocated += cur->nDataSize;
  3107. break;
  3108. }
  3109. case _FREE_BLOCK:
  3110. totalFree += cur->nDataSize;
  3111. break;
  3112. }
  3113. }
  3114. PROGLOG("%d Unique allocations by <filename>(line)@size", numUnique);
  3115. for (unsigned i2 = 0; i2 < numUnique; i2++)
  3116. {
  3117. _CrtMemBlockHeader * display = locations[i2];
  3118. //char tempBuffer[16];
  3119. //unsigned len = dumpMemory(sizeof(tempBuffer), tempBuffer, display->nDataSize,
  3120. PROGLOG("%s(%d) %d:%d {%ld} = %d", display->szFileName ? display->szFileName : "<unknown>", display->nLine, display->nDataSize, counts[i2], display->lRequest, display->nDataSize * counts[i2]);
  3121. }
  3122. PROGLOG("Ungrouped: %d Total %" I64F "d", counts[maxUnique], totalAllocated);
  3123. PROGLOG("Summary by location");
  3124. for (unsigned iSummary2 = 0; iSummary2 < numUnique; )
  3125. {
  3126. _CrtMemBlockHeader * display = locations[iSummary2];
  3127. unsigned count = counts[iSummary2];
  3128. unsigned __int64 size = count * display->nDataSize;
  3129. for (iSummary2++; iSummary2 < numUnique; iSummary2++)
  3130. {
  3131. _CrtMemBlockHeader * next = locations[iSummary2];
  3132. if (compareLocation(display, next) != 0)
  3133. break;
  3134. count += counts[iSummary2];
  3135. size += (counts[iSummary2] * next->nDataSize);
  3136. }
  3137. PROGLOG("%s(%d) %d = %d", display->szFileName ? display->szFileName : "<unknown>", display->nLine, count, size);
  3138. }
  3139. PROGLOG("Summary by source");
  3140. for (unsigned iSummary2 = 0; iSummary2 < numUnique; )
  3141. {
  3142. _CrtMemBlockHeader * display = locations[iSummary2];
  3143. unsigned count = counts[iSummary2];
  3144. unsigned __int64 size = count * display->nDataSize;
  3145. for (iSummary2++; iSummary2 < numUnique; iSummary2++)
  3146. {
  3147. _CrtMemBlockHeader * next = locations[iSummary2];
  3148. if (compareFile(display, next) != 0)
  3149. break;
  3150. count += counts[iSummary2];
  3151. size += (counts[iSummary2] * next->nDataSize);
  3152. }
  3153. PROGLOG("%s %d = %d", display->szFileName ? display->szFileName : "<unknown>", count, size);
  3154. }
  3155. }
  3156. #else
  3157. void printAllocationSummary()
  3158. {
  3159. }
  3160. #endif
  3161. #ifdef _USE_MALLOC_HOOK
  3162. // Note memory hooks should not be enabled for release (as not re-entrant in linux)
  3163. static CriticalSection hookSect;
  3164. #ifdef __linux__
  3165. static void *(*old_malloc_hook)(size_t, const void *);
  3166. static void (*old_free_hook)(void *, const void *);
  3167. static void *(*old_realloc_hook)(void *, size_t, const void *);
  3168. static void * jlib_malloc_hook (size_t size, const void *caller) ;
  3169. static void jlib_free_hook (void *ptr, const void *caller);
  3170. static void *jlib_realloc_hook (void *ptr, size_t size, const void *caller);
  3171. static int jlib_hooknest = 0; // this *shouldn't* really be needed
  3172. inline void restore_malloc_hooks()
  3173. {
  3174. if (--jlib_hooknest==0) {
  3175. __malloc_hook = old_malloc_hook;
  3176. __realloc_hook = old_realloc_hook;
  3177. __free_hook = old_free_hook;
  3178. }
  3179. }
  3180. inline void set_malloc_hooks()
  3181. {
  3182. assertex(jlib_hooknest==0);
  3183. old_malloc_hook = __malloc_hook;
  3184. old_free_hook = __free_hook;
  3185. old_realloc_hook = __realloc_hook;
  3186. __malloc_hook = jlib_malloc_hook;
  3187. __free_hook = jlib_free_hook;
  3188. __realloc_hook = jlib_realloc_hook;
  3189. jlib_hooknest = 1;
  3190. }
  3191. inline void reset_malloc_hooks()
  3192. {
  3193. if (jlib_hooknest++==0) {
  3194. __malloc_hook = jlib_malloc_hook;
  3195. __free_hook = jlib_free_hook;
  3196. __realloc_hook = jlib_realloc_hook;
  3197. }
  3198. }
  3199. inline void incCount(unsigned sz,bool inc)
  3200. {
  3201. int i=0;
  3202. size32_t s=sz;
  3203. while (s) {
  3204. s /= 2;
  3205. i++;
  3206. }
  3207. if (inc)
  3208. memArea[i] += sz;
  3209. else
  3210. memArea[i] -= sz;
  3211. }
  3212. void * jlib_malloc_hook (size_t size, const void *caller)
  3213. {
  3214. CriticalBlock block(hookSect);
  3215. void *res;
  3216. restore_malloc_hooks();
  3217. res = malloc (size);
  3218. if (res) {
  3219. size = malloc_usable_size(res);
  3220. totalMem+=size;
  3221. if (totalMem>hwmTotalMem) {
  3222. if (hwmTotalMem/(100*0x100000)!=totalMem/(100*0x100000)) {
  3223. PrintStackReport();
  3224. PROGLOG("TOTALMEM(%" I64F "d): malloc %u",totalMem,(unsigned)size);
  3225. }
  3226. hwmTotalMem = totalMem;
  3227. }
  3228. }
  3229. else
  3230. size = 0;
  3231. incCount(size,true);
  3232. if (size>REPORT_LARGER_BLOCK_THAN) {
  3233. PrintStackReport();
  3234. PROGLOG("LARGEALLOC(%u): %p",(unsigned)size,res);
  3235. }
  3236. reset_malloc_hooks();
  3237. return res;
  3238. }
  3239. void jlib_free_hook (void *ptr, const void *caller)
  3240. {
  3241. if (!ptr)
  3242. return;
  3243. CriticalBlock block(hookSect);
  3244. restore_malloc_hooks();
  3245. size32_t sz = malloc_usable_size(ptr);
  3246. free (ptr);
  3247. totalMem -= sz;
  3248. incCount(sz,false);
  3249. if (sz>REPORT_LARGER_BLOCK_THAN) {
  3250. PROGLOG("LARGEFREE(%u): %p",(unsigned)sz,ptr);
  3251. }
  3252. reset_malloc_hooks();
  3253. }
  3254. void *jlib_realloc_hook (void *ptr, size_t size, const void *caller)
  3255. {
  3256. CriticalBlock block(hookSect);
  3257. restore_malloc_hooks();
  3258. size32_t oldsz = ptr?malloc_usable_size(ptr):0;
  3259. void *res = realloc (ptr,size);
  3260. if (res) {
  3261. size = malloc_usable_size(res);
  3262. totalMem += size;
  3263. }
  3264. else
  3265. size = 0;
  3266. totalMem -= oldsz;
  3267. if (totalMem>hwmTotalMem) {
  3268. if (hwmTotalMem/(100*0x100000)!=totalMem/(100*0x100000)) {
  3269. PrintStackReport();
  3270. PROGLOG("TOTALMEM(%" I64F "d): realloc %u %u",totalMem,(unsigned)oldsz,(unsigned)size);
  3271. }
  3272. hwmTotalMem = totalMem;
  3273. }
  3274. incCount(size,true);
  3275. incCount(oldsz,false);
  3276. if ((size>REPORT_LARGER_BLOCK_THAN)||(oldsz>REPORT_LARGER_BLOCK_THAN)) {
  3277. if (size>oldsz) {
  3278. PrintStackReport();
  3279. PROGLOG("LARGEREALLOC_UP(%u,%u): %p %p",(unsigned)oldsz,(unsigned)size,ptr,res);
  3280. }
  3281. else {
  3282. PROGLOG("LARGEREALLOC_DN(%u,%u): %p %p",(unsigned)oldsz,(unsigned)size,ptr,res);
  3283. }
  3284. }
  3285. reset_malloc_hooks();
  3286. return res;
  3287. }
  3288. void jlib_decl jlib_init_hook()
  3289. {
  3290. set_malloc_hooks();
  3291. }
  3292. __int64 jlib_decl setAllocHook(bool on,bool clear)
  3293. {
  3294. CriticalBlock block(hookSect);
  3295. __int64 ret = totalMem;
  3296. if (clear) {
  3297. totalMem = 0;
  3298. hwmTotalMem = 0;
  3299. }
  3300. if (on) {
  3301. if (jlib_hooknest==0)
  3302. set_malloc_hooks();
  3303. }
  3304. else {
  3305. while (jlib_hooknest) {
  3306. restore_malloc_hooks();
  3307. //printf("Total = %d bytes\n",totalMem);
  3308. }
  3309. }
  3310. return ret;
  3311. }
  3312. unsigned jlib_decl setAllocHook(bool on)
  3313. {
  3314. // bwd compatible - should use above version in preference
  3315. CriticalBlock block(hookSect);
  3316. if (on) {
  3317. if (jlib_hooknest==0) {
  3318. set_malloc_hooks();
  3319. totalMem = 0;
  3320. hwmTotalMem = 0;
  3321. }
  3322. }
  3323. else {
  3324. while (jlib_hooknest) {
  3325. restore_malloc_hooks();
  3326. //printf("Total = %d bytes\n",totalMem);
  3327. }
  3328. }
  3329. return (unsigned)totalMem;
  3330. }
  3331. #else // windows
  3332. static _CRT_ALLOC_HOOK oldHook = NULL;
  3333. static int allocHook( int allocType, void *userData, size_t size, int nBlockUse,
  3334. long requestNumber, const unsigned char *filename, int lineNumber)
  3335. {
  3336. CriticalBlock block(hookSect);
  3337. if ( nBlockUse == _CRT_BLOCK ) // Ignore internal C runtime library allocations
  3338. return TRUE;
  3339. static bool recurse = false;
  3340. if (recurse)
  3341. return TRUE;
  3342. recurse = true;
  3343. char *operation[] = { "", "allocating", "re-allocating", "freeing" };
  3344. char *blockType[] = { "Free", "Normal", "CRT", "Ignore", "Client" };
  3345. switch (allocType) {
  3346. case _HOOK_REALLOC:
  3347. if (userData==NULL)
  3348. printf("no data on realloc\n");
  3349. else
  3350. totalMem-=_msize(userData);
  3351. // fall through
  3352. case _HOOK_ALLOC:
  3353. totalMem+=size;
  3354. break;
  3355. case _HOOK_FREE:
  3356. if (userData)
  3357. totalMem-=_msize(userData);
  3358. break;
  3359. }
  3360. // printf( "Memory operation in %s, line %d: %s a %d-byte '%s' block (#%ld)\n",
  3361. // filename, lineNumber, operation[allocType], size,
  3362. // blockType[nBlockUse], requestNumber );
  3363. recurse = false;
  3364. return TRUE; // Allow the memory operation to proceed
  3365. }
  3366. unsigned jlib_decl setAllocHook(bool on)
  3367. {
  3368. CriticalBlock block(hookSect);
  3369. if (on) {
  3370. if (oldHook==NULL) {
  3371. oldHook = _CrtSetAllocHook( allocHook );
  3372. totalMem = 0;
  3373. }
  3374. }
  3375. else {
  3376. if (oldHook!=NULL)
  3377. _CrtSetAllocHook( oldHook );
  3378. oldHook = NULL;
  3379. //printf("Total = %d bytes\n",totalMem);
  3380. }
  3381. return (unsigned)totalMem; // return unsigned for bwd compat
  3382. }
  3383. #endif
  3384. __int64 getTotalMem()
  3385. {
  3386. return totalMem;
  3387. }
  3388. #else // release
  3389. unsigned jlib_decl setAllocHook(bool on __attribute__((unused)))
  3390. {
  3391. return 0;
  3392. }
  3393. __int64 jlib_decl setAllocHook(bool on __attribute__((unused)), bool clear __attribute__((unused)))
  3394. {
  3395. return 0;
  3396. }
  3397. __int64 jlib_decl getTotalMem()
  3398. {
  3399. return 0;
  3400. }
  3401. void jlib_decl jlib_init_hook()
  3402. {
  3403. }
  3404. #endif
  3405. class UserMetricMsgHandler : public CInterface, implements ILogMsgHandler, implements IUserMetric
  3406. {
  3407. mutable unsigned __int64 counter;
  3408. StringAttr metricName;
  3409. StringAttr regex;
  3410. Owned<ILogMsgFilter> regexFilter;
  3411. public:
  3412. virtual void Link(void) const { CInterface::Link(); }
  3413. virtual bool Release(void) const
  3414. {
  3415. if (CInterface::Release())
  3416. return true;
  3417. if (!IsShared())
  3418. {
  3419. queryLogMsgManager()->removeMonitor(const_cast<UserMetricMsgHandler *>(this)); // removeMonitor should take a const param really
  3420. }
  3421. return false;
  3422. }
  3423. UserMetricMsgHandler(const char *_name, const char *_regex) : metricName(_name), regex(_regex)
  3424. {
  3425. counter = 0;
  3426. regexFilter.setown(getRegexLogMsgFilter(regex, true));
  3427. queryLogMsgManager()->addMonitor(this, regexFilter);
  3428. }
  3429. // interface ILogMsgHandler
  3430. virtual void handleMessage(const LogMsg & msg __attribute__((unused))) const { counter++; }
  3431. virtual bool needsPrep() const { return false; }
  3432. virtual void prep() {}
  3433. virtual unsigned queryMessageFields() const { return MSGFIELD_detail; }
  3434. virtual void setMessageFields(unsigned _fields __attribute__((unused)) = MSGFIELD_all) {}
  3435. virtual void addToPTree(IPropertyTree * parent __attribute__((unused))) const {}
  3436. virtual int flush() { return 0; }
  3437. virtual char const *disable() { return 0; }
  3438. virtual void enable() {}
  3439. virtual bool getLogName(StringBuffer &name __attribute__((unused))) const { return false; }
  3440. virtual offset_t getLogPosition(StringBuffer &logFileName __attribute__((unused))) const { return 0; };
  3441. // interface IUserMetric
  3442. virtual unsigned __int64 queryCount() const { return counter; }
  3443. virtual const char *queryName() const { return metricName; }
  3444. virtual const char *queryMatchString() const { return regex; }
  3445. virtual void inc() { counter++; }
  3446. virtual void reset() { counter = 0; }
  3447. };
  3448. jlib_decl IUserMetric *createUserMetric(const char *name, const char *matchString)
  3449. {
  3450. return new UserMetricMsgHandler(name, matchString);
  3451. }