jdebug.cpp 114 KB

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