12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166 |
- /*##############################################################################
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ############################################################################## */
- #include "platform.h"
- #include "jdebug.hpp"
- #include "jstring.hpp"
- #include "jhash.hpp"
- #include "jmisc.hpp"
- #include "jexcept.hpp"
- #include "jfile.hpp"
- #include "jmutex.hpp"
- #include "jtime.hpp"
- #include <stdio.h>
- #include <time.h>
- #include <atomic>
- #ifdef _WIN32
- #define DPSAPI_VERSION 1
- #include <psapi.h>
- #include <processthreadsapi.h>
- #include <sysinfoapi.h>
- #endif
- #ifdef __linux__
- #include <sys/time.h>
- #include <sys/resource.h>
- #include <unistd.h>
- #include <sys/vfs.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/klog.h>
- #include <dirent.h>
- #endif
- #ifdef __APPLE__
- #include <sys/param.h>
- #include <sys/mount.h>
- #include <sys/sysctl.h>
- #include <mach/task.h>
- #include <mach/mach_init.h>
- #include <mach/mach_host.h>
- #include <mach/vm_statistics.h>
- #endif
- //===========================================================================
- #ifdef _DEBUG
- // #define _USE_MALLOC_HOOK // Only enable if you need it - slow!
- #else
- #undef _USE_MALLOC_HOOK // don't define for release - not threadsafe
- #endif
- #define _USE_RDTSC true
- #ifdef _USE_MALLOC_HOOK
- #define REPORT_LARGER_BLOCK_THAN (10*0x100000)
- static __int64 totalMem = 0;
- static __int64 hwmTotalMem = 0;
- #ifdef __linux__
- static unsigned memArea[32];
- #endif
- #endif
- /* LINUX SYS: log KEY
- ========================
- PU (%) is the percentage CPU in use (unchanged from previously).
- MU (%) is what percentage of total (all processes) memory is in use
- (ram + swap) or in 32 bit is the percentage of 3GB (address space)
- used (whichever larger).
- MAL is total memory in use (i.e malloced and not freed ) by this
- process (= MMP+SBK)
- MMP is the sum of memory mapped (large) blocks in use by this process
- (which will be returned to OS when freed).
- SBK is the sbrk'ed memory i.e. smaller blocks allocated from the
- arena. (note this memory is unlikely to be returned to OS while the
- process is still running).
- TOT (K) is an indication of the memory footprint of the process.
- This is the 'arena' size (which is how much reserved by sbrk) plus the
- mmap memory size (MMP).
- RAM (K) is how much real memory is in use by all processes - it is
- the same as what would be reported by the 'free' command after the
- caches/buffers have been subtracted.
- SWP (K) is the swap size in use for all processes.
- Extended stats
- DSK: disk statistics for each disk (e.g. [sda] and [sdb])
- r/s read i/o operations per sec (over last period)
- kr/s K bytes read per sec
- w/s write i/o operations per sec
- kw/s K bytes written per sec
- busy indication how busy the disk was during period (%)
- NIC: network (i.e. eth0) statistics
- rxp/s packets received per sec
- rxk/s K bytes received per sec
- txp/s packets transmitted per sec
- txk/s K bytes transmitted per sec
- CPU:
- usr % at user level
- sys % in kernel
- iow % waiting for i/o
- */
- inline void skipSp(const char *&s)
- {
- while (isspace(*s))
- s++;
- }
- inline offset_t readHexNum(const char *&s)
- {
- offset_t ret = 0;
- for (;;) {
- switch (*s) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9': ret = ret*16+(*s-'0');
- break;
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F': ret = ret*16+(*s-'A'+10);
- break;
- case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f': ret = ret*16+(*s-'a'+10);
- break;
- default:
- return ret;
- }
- s++;
- }
- return 0;
- }
- inline offset_t readDecNum(const char *&s)
- {
- offset_t ret = 0;
- for (;;) {
- switch (*s) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9': ret = ret*10+(*s-'0');
- break;
- default:
- return ret;
- }
- s++;
- }
- return 0;
- }
- #if defined(_WIN32)
- static __int64 numCyclesNTicks;
- static __int64 ticksPerSec;
- static __int64 numScaleTicks;
- static bool useRDTSC = _USE_RDTSC;
- static double cycleToNanoScale;
- static void calibrate_timing()
- {
- #ifndef _AMD64_
- if (useRDTSC)
- {
- unsigned long r;
- __asm {
- mov eax, 1 ;
- cpuid ;
- mov r, edx
- }
- if ((r&0x10)==0)
- useRDTSC = false;
- }
- #endif
- if (useRDTSC) {
- unsigned startu = usTick();
- cycle_t start = getTSC();
- unsigned s1 = msTick();
- unsigned s2;
- while (s1==(s2=msTick()));
- unsigned s3;
- while (s2==(s3=msTick()));
- unsigned elapsedu = usTick()-startu;
- if (elapsedu) {
- double numPerUS=(double)(getTSC()-start)/(double)elapsedu; // this probably could be more accurate
- if (numPerUS>0)
- {
- cycleToNanoScale = 1000.0 / numPerUS;
- return;
- }
- }
- DBGLOG("calibrate_timing failed using RDTSC");
- useRDTSC = false;
- }
- static LARGE_INTEGER temp;
- QueryPerformanceFrequency(&temp);
- ticksPerSec = temp.QuadPart;
- numScaleTicks = ticksPerSec/100;
- LARGE_INTEGER t1;
- LARGE_INTEGER t2;
- QueryPerformanceCounter(&t1);
- t2.QuadPart=t1.QuadPart;
- while (t1.QuadPart==t2.QuadPart) QueryPerformanceCounter(&t1);
- cycle_t a1 = getTSC();
- t2.QuadPart = t1.QuadPart;
- while (t2.QuadPart-t1.QuadPart<numScaleTicks) QueryPerformanceCounter(&t2);
- cycle_t a2 = getTSC();
- numCyclesNTicks = (a2 - a1);
- cycleToNanoScale = ((double)numScaleTicks * 1000000000.0) / ((double)numCyclesNTicks * ticksPerSec);
- }
- __int64 cycle_to_nanosec(cycle_t cycles)
- {
- return (__int64)((double)cycles * cycleToNanoScale);
- }
- __int64 jlib_decl cycle_to_microsec(cycle_t cycles)
- {
- return (__int64)((double)cycles * cycleToNanoScale) / 1000;
- }
- __int64 jlib_decl cycle_to_millisec(cycle_t cycles)
- {
- return (__int64)((double)cycles * cycleToNanoScale) / 1000000;
- }
- cycle_t nanosec_to_cycle(__int64 ns)
- {
- return (__int64)((double)ns / cycleToNanoScale);
- }
- #if !(defined(INLINE_GET_CYCLES_NOW) && defined(HAS_GOOD_CYCLE_COUNTER))
- cycle_t jlib_decl get_cycles_now()
- {
- if (useRDTSC)
- return getTSC();
- LARGE_INTEGER temp;
- QueryPerformanceCounter(&temp);
- return temp.QuadPart;
- }
- #endif
- double getCycleToNanoScale()
- {
- return cycleToNanoScale;
- }
- #else
- #if defined(HAS_GOOD_CYCLE_COUNTER)
- static bool useRDTSC = _USE_RDTSC;
- #endif
- static double cycleToNanoScale;
- static double cycleToMicroScale;
- static double cycleToMilliScale;
- void calibrate_timing()
- {
- #if defined(_ARCH_X86_) || defined(_ARCH_X86_64_)
- if (useRDTSC) {
- unsigned long eax;
- unsigned long ebx;
- unsigned long ecx;
- unsigned long edx;
- #if defined(_ARCH_X86_64_)
- __asm__ ("cpuid\n\t" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "0" (1));
- #else
- // NB PIC code and ebx usage don't mix well
- asm volatile("pushl %%ebx \n\t"
- "cpuid \n\t"
- "movl %%ebx, %1 \n\t"
- "popl %%ebx \n\t"
- : "=a"(eax), "=r"(ebx), "=c"(ecx), "=d"(edx)
- : "a"(1)
- : "cc");
- #endif
- if ((edx&0x10)==0)
- useRDTSC = false;
- }
- #endif
- #if defined(HAS_GOOD_CYCLE_COUNTER)
- if (useRDTSC) {
- unsigned startu = usTick();
- cycle_t start = getTSC();
- unsigned s1 = msTick();
- unsigned s2;
- while (s1==(s2=msTick()));
- unsigned s3;
- while (s2==(s3=msTick()));
- unsigned elapsedu = usTick()-startu;
- if (elapsedu) {
- double numPerUS=(double)(getTSC()-start)/(double)elapsedu; // this probably could be more accurate
- if (numPerUS>0)
- {
- cycleToNanoScale = 1000.0 / numPerUS;
- cycleToMicroScale = 1.0 / numPerUS;
- cycleToMilliScale = 0.001 / numPerUS;
- return;
- }
- }
- IERRLOG("calibrate_timing failed using RDTSC");
- useRDTSC = false;
- }
- #endif
- cycleToNanoScale = 1.0;
- cycleToMicroScale = 1.0;
- cycleToMilliScale = 1.0;
- }
- #if !defined(INLINE_GET_CYCLES_NOW) || !defined(HAS_GOOD_CYCLE_COUNTER)
- #if defined(CLOCK_MONOTONIC) && !defined(__APPLE__)
- static bool use_gettimeofday=false;
- #endif
- cycle_t jlib_decl get_cycles_now()
- {
- #if defined(HAS_GOOD_CYCLE_COUNTER)
- if (useRDTSC)
- return getTSC();
- #endif
- #ifdef __APPLE__
- return mach_absolute_time();
- #elif defined(CLOCK_MONOTONIC)
- if (!use_gettimeofday) {
- timespec tm;
- if (clock_gettime(CLOCK_MONOTONIC, &tm)>=0)
- return ((cycle_t)tm.tv_sec)*1000000000L+(tm.tv_nsec);
- use_gettimeofday = true;
- fprintf(stderr,"clock_gettime CLOCK_MONOTONIC returns %d",errno); // don't use PROGLOG
- }
- #endif
- struct timeval tm;
- gettimeofday(&tm,NULL);
- return ((cycle_t)tm.tv_sec)*1000000000L+(cycle_t)tm.tv_usec*1000L;
- }
- #endif
- __int64 jlib_decl cycle_to_nanosec(cycle_t cycles)
- {
- #if defined(HAS_GOOD_CYCLE_COUNTER)
- if (useRDTSC)
- return (__int64)((double)cycles * cycleToNanoScale);
- #endif
- #ifdef __APPLE__
- return cycles * (uint64_t) timebase_info.numer / (uint64_t)timebase_info.denom;
- #endif
- return cycles;
- }
- __int64 jlib_decl cycle_to_microsec(cycle_t cycles)
- {
- #if defined(HAS_GOOD_CYCLE_COUNTER)
- if (useRDTSC)
- return (__int64)((double)cycles * cycleToMicroScale);
- #endif
- return cycles / 1000;
- }
- __int64 jlib_decl cycle_to_millisec(cycle_t cycles)
- {
- #if defined(HAS_GOOD_CYCLE_COUNTER)
- if (useRDTSC)
- return (__int64)((double)cycles * cycleToMilliScale);
- #endif
- return cycles / 1000000;
- }
- cycle_t nanosec_to_cycle(__int64 ns)
- {
- #if defined(HAS_GOOD_CYCLE_COUNTER)
- if (useRDTSC)
- return (__int64)((double)ns / cycleToNanoScale);
- #endif
- return ns;
- }
- double getCycleToNanoScale()
- {
- return cycleToNanoScale;
- }
- #endif
- void display_time(const char *title, cycle_t diff)
- {
- DBGLOG("Time taken for %s: %" I64F "d cycles (%" I64F "dM) = %" I64F "d msec", title, diff, diff/1000000, cycle_to_nanosec(diff)/1000000);
- }
- TimeSection::TimeSection(const char * _title) : title(_title)
- {
- start_time = get_cycles_now();
- }
- TimeSection::~TimeSection()
- {
- cycle_t end_time = get_cycles_now();
- if (title)
- display_time(title, end_time-start_time);
- }
- MTimeSection::MTimeSection(ITimeReporter *_master, const char * _scope) : scope(_scope), master(_master)
- {
- start_time = get_cycles_now();
- }
- MTimeSection::~MTimeSection()
- {
- cycle_t end_time = get_cycles_now();
- if (master)
- master->addTiming(scope, end_time-start_time);
- else if (scope)
- display_time(scope, end_time-start_time);
- }
- class TimeSectionInfo : public MappingBase
- {
- public:
- TimeSectionInfo(const char * _scope, __int64 _cycles) : scope(_scope), totalcycles(_cycles), maxcycles(_cycles), count(1) {};
- TimeSectionInfo(const char * _scope, __int64 _cycles, __int64 _maxcycles, unsigned _count)
- : scope(_scope), totalcycles(_cycles), maxcycles(_maxcycles), count(_count) {};
- virtual const void * getKey() const { return scope.get(); }
- __int64 getTime() const { return cycle_to_nanosec(totalcycles); }
- __int64 getMaxTime() const { return cycle_to_nanosec(maxcycles); }
- unsigned getCount() const { return count; }
- StringAttr scope;
- __int64 totalcycles;
- __int64 maxcycles;
- unsigned count;
- };
- class DefaultTimeReporter : implements ITimeReporter, public CInterface
- {
- StringMapOf<TimeSectionInfo> *sections;
- CriticalSection c;
- TimeSectionInfo &findSection(unsigned idx)
- {
- CriticalBlock b(c);
- HashIterator iter(*sections);
- for(iter.first(); iter.isValid(); iter.next())
- {
- if (!idx--)
- return (TimeSectionInfo &) iter.query();
- }
- throw MakeStringException(2, "Invalid index to DefaultTimeReporter");
- }
- public:
- IMPLEMENT_IINTERFACE
- DefaultTimeReporter()
- {
- sections = new StringMapOf<TimeSectionInfo>(true);
- }
- ~DefaultTimeReporter()
- {
- // printTimings(); // Must explicitly call printTimings - no automatic print (too late here!)
- delete sections;
- }
- virtual void report(ITimeReportInfo &cb)
- {
- CriticalBlock b(c);
- HashIterator iter(*sections);
- for(iter.first(); iter.isValid(); iter.next())
- {
- TimeSectionInfo &ts = (TimeSectionInfo &)iter.query();
- cb.report(ts.scope, ts.getTime(), ts.getMaxTime(), ts.count);
- }
- }
- virtual void addTiming(const char * scope, cycle_t cycles)
- {
- CriticalBlock b(c);
- TimeSectionInfo *info = sections->find(scope);
- if (info)
- {
- info->totalcycles += cycles;
- if (cycles > info->maxcycles) info->maxcycles = cycles;
- info->count++;
- }
- else
- {
- TimeSectionInfo &newinfo = * new TimeSectionInfo(scope, cycles);
- sections->replaceOwn(newinfo);
- }
- }
- virtual void reset()
- {
- CriticalBlock b(c);
- delete sections;
- sections = new StringMapOf<TimeSectionInfo>(true);
- }
- virtual StringBuffer &getTimings(StringBuffer &str)
- {
- CriticalBlock b(c);
- HashIterator iter(*sections);
- for(iter.first(); iter.isValid(); iter.next())
- {
- TimeSectionInfo &ts = (TimeSectionInfo &)iter.query();
- str.append("Timing: ").append(ts.scope)
- .append(" total=")
- .append(ts.getTime()/1000000)
- .append("ms max=")
- .append(ts.getMaxTime()/1000)
- .append("us count=")
- .append(ts.getCount())
- .append(" ave=")
- .append((ts.getTime()/1000)/ts.getCount())
- .append("us\n");
- }
- if (numSections())
- {
- for (unsigned i = 0; i < numSections(); i++)
- {
- }
- }
- return str;
- }
- virtual void printTimings()
- {
- CriticalBlock b(c);
- if (numSections())
- {
- StringBuffer str;
- LOG(MCuserInfo, "%s", getTimings(str).str());
- }
- }
- virtual void mergeTiming(const char * scope, cycle_t totalcycles, cycle_t maxcycles, const unsigned count)
- {
- CriticalBlock b(c);
- TimeSectionInfo *info = sections->find(scope);
- if (!info)
- {
- info = new TimeSectionInfo(scope, totalcycles, maxcycles, count);
- sections->replaceOwn(*info);
- }
- else
- {
- info->totalcycles += totalcycles;
- if (maxcycles > info->maxcycles) info->maxcycles = maxcycles;
- info->count += count;
- }
- }
- virtual void mergeInto(ITimeReporter &other)
- {
- CriticalBlock b(c);
- HashIterator iter(*sections);
- for(iter.first(); iter.isValid(); iter.next())
- {
- TimeSectionInfo &ts = (TimeSectionInfo &) iter.query();
- other.mergeTiming(ts.scope, ts.totalcycles, ts.maxcycles, ts.count);
- }
- }
- virtual void merge(ITimeReporter &other)
- {
- CriticalBlock b(c);
- other.mergeInto(*this);
- }
- protected:
- unsigned numSections()
- {
- return sections->count();
- }
- };
- static ITimeReporter * activeTimer = NULL;
- ITimeReporter * queryActiveTimer()
- {
- return activeTimer;
- }
- ITimeReporter *createStdTimeReporter() { return new DefaultTimeReporter(); }
- cycle_t oneSecInCycles;
- MODULE_INIT(INIT_PRIORITY_JDEBUG1)
- {
- // perform v. early in process startup, ideally this would grab process exclusively for the 2 100ths of a sec it performs calc.
- calibrate_timing();
- oneSecInCycles = nanosec_to_cycle(1000000000);
- return 1;
- }
- MODULE_INIT(INIT_PRIORITY_JDEBUG2)
- {
- activeTimer = new DefaultTimeReporter();
- return true;
- }
- MODULE_EXIT()
- {
- ::Release(activeTimer);
- activeTimer = NULL;
- }
- //===========================================================================
- void BlockedTimeTracker::noteWaiting()
- {
- CriticalBlock block(cs);
- numWaiting++;
- timeStampTally -= get_cycles_now();
- }
- void BlockedTimeTracker::noteComplete()
- {
- CriticalBlock block(cs);
- numWaiting--;
- timeStampTally += get_cycles_now();
- }
- __uint64 BlockedTimeTracker::getWaitingNs() const
- {
- unsigned active;
- cycle_t tally;
- {
- CriticalBlock block(cs);
- active = numWaiting;
- tally = timeStampTally;
- }
- if (active != 0)
- {
- cycle_t now = get_cycles_now();
- tally += active * now;
- }
- return cycle_to_nanosec(tally);
- }
- __uint64 LightweightBlockedTimeTracker::getWaitingNs() const
- {
- __uint64 tally = timeStampTally.load(std::memory_order_acquire); // read the value once atomically
- unsigned active = tally % MAX_ACTIVE;
- if (active != 0)
- {
- cycle_t now = get_cycles_now();
- tally += active * now * MAX_ACTIVE;
- }
- return cycle_to_nanosec(tally / MAX_ACTIVE);
- }
- //===========================================================================
- #ifdef _WIN32
- typedef enum _PROCESSINFOCLASS {
- ProcessBasicInformation,
- ProcessQuotaLimits,
- ProcessIoCounters,
- ProcessVmCounters,
- ProcessTimes,
- ProcessBasePriority,
- ProcessRaisePriority,
- ProcessDebugPort,
- ProcessExceptionPort,
- ProcessAccessToken,
- ProcessLdtInformation,
- ProcessLdtSize,
- ProcessDefaultHardErrorMode,
- ProcessIoPortHandlers, // Note: this is kernel mode only
- ProcessPooledUsageAndLimits,
- ProcessWorkingSetWatch,
- ProcessUserModeIOPL,
- ProcessEnableAlignmentFaultFixup,
- ProcessPriorityClass,
- ProcessWx86Information,
- ProcessHandleCount,
- ProcessAffinityMask,
- ProcessPriorityBoost,
- ProcessDeviceMap,
- ProcessSessionInformation,
- ProcessForegroundInformation,
- ProcessWow64Information,
- MaxProcessInfoClass
- } PROCESSINFOCLASS;
- typedef LONG NTSTATUS;
- struct __IO_COUNTERS { // defined in SDK
- ULONGLONG ReadOperationCount;
- ULONGLONG WriteOperationCount;
- ULONGLONG OtherOperationCount;
- ULONGLONG ReadTransferCount;
- ULONGLONG WriteTransferCount;
- ULONGLONG OtherTransferCount;
- };
- struct VM_COUNTERS {
- unsigned long PeakVirtualSize;
- unsigned long VirtualSize;
- unsigned long PageFaultCount;
- unsigned long PeakWorkingSetSize;
- unsigned long WorkingSetSize;
- unsigned long QuotaPeakPagedPoolUsage;
- unsigned long QuotaPagedPoolUsage;
- unsigned long QuotaPeakNonPagedPoolUsage;
- unsigned long QuotaNonPagedPoolUsage;
- unsigned long PagefileUsage;
- unsigned long PeakPagefileUsage;
- };
- struct POOLED_USAGE_AND_LIMITS {
- unsigned long PeakPagedPoolUsage;
- unsigned long PagedPoolUsage;
- unsigned long PagedPoolLimit;
- unsigned long PeakNonPagedPoolUsage;
- unsigned long NonPagedPoolUsage;
- unsigned long NonPagedPoolLimit;
- unsigned long PeakPagefileUsage;
- unsigned long PagefileUsage;
- unsigned long PagefileLimit;
- };
- struct KERNEL_USER_TIMES {
- __int64 CreateTime;
- __int64 ExitTime;
- __int64 KernelTime;
- __int64 UserTime;
- //__int64 EllapsedTime;
- };
- //
- //NTSYSCALLAPI
- //NTSTATUS
- //NTAPI
- //NtQueryInformationProcess(
- // IN HANDLE ProcessHandle,
- // IN PROCESSINFOCLASS ProcessInformationClass,
- // OUT PVOID ProcessInformation,
- // IN ULONG ProcessInformationLength,
- // OUT PULONG ReturnLength OPTIONAL
- // );
- typedef LONG(WINAPI *PROCNTQIP)(HANDLE, UINT, PVOID, ULONG, PULONG);
- static struct CNtKernelInformation
- {
- CNtKernelInformation()
- {
- NtQueryInformationProcess = (PROCNTQIP)GetProcAddress(
- GetModuleHandle("ntdll"),
- "NtQueryInformationProcess"
- );
- GetSystemInfo(&SysBaseInfo);
- }
- PROCNTQIP NtQueryInformationProcess;
- SYSTEM_INFO SysBaseInfo;
- } NtKernelFunctions;
- #endif
- //===========================================================================
- #ifdef _WIN32
- static __uint64 ticksToNs = I64C(100); // FILETIME is in 100ns increments
- #else
- static __uint64 ticksToNs = I64C(1000000000) / sysconf(_SC_CLK_TCK);
- #endif
- #ifdef _WIN32
- inline unsigned __int64 extractFILETIME(const FILETIME & value)
- {
- return ((__uint64)value.dwHighDateTime << (sizeof(value.dwLowDateTime) * 8) | value.dwLowDateTime);
- }
- #endif
- CpuInfo::CpuInfo(bool processTime, bool systemTime) : CpuInfo()
- {
- if (processTime)
- getProcessTimes();
- else if (systemTime)
- getSystemTimes();
- }
- void CpuInfo::clear()
- {
- user = 0;
- system = 0;
- idle = 0;
- iowait = 0;
- }
- CpuInfo CpuInfo::operator - (const CpuInfo & rhs) const
- {
- CpuInfo result;
- result.user = user - rhs.user;
- result.system = system - rhs.system;
- result.idle = idle - rhs.idle;
- result.iowait = iowait - rhs.iowait;
- result.ctx = ctx - rhs.ctx;
- return result;
- }
- bool CpuInfo::getProcessTimes()
- {
- #ifdef _WIN32
- FILETIME creationTime, exitTime;
- FILETIME kernelTime, userTime;
- GetProcessTimes(GetCurrentProcess(), &creationTime, &exitTime, &kernelTime, &userTime);
- user = extractFILETIME(userTime);
- system = extractFILETIME(kernelTime);
- return true;
- #else
- VStringBuffer fname("/proc/%u/stat", getpid());
- //NOTE: This file needs to be reopened each time - seeking to the start and rereading does not refresh it
- clear();
- FILE* cpufp = fopen(fname.str(), "r");
- if (!cpufp) {
- return false;
- }
- char ln[2560];
- if (fgets(ln, sizeof(ln), cpufp))
- {
- long int majorFaults = 0;
- long unsigned userTime = 0;
- long unsigned systemTime = 0;
- long unsigned childUserTime = 0;
- long unsigned childSystemTime = 0;
- 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);
- if (matched >= 3)
- {
- user = userTime + childUserTime;
- system = systemTime + childSystemTime;
- }
- }
- fclose(cpufp);
- return true;
- #endif
- }
- bool CpuInfo::getSystemTimes()
- {
- #ifdef _WIN32
- FILETIME idleTime, kernelTime, userTime;
- GetSystemTimes(&idleTime, &kernelTime, &userTime);
- // note - kernel time seems to include idle time
- idle = extractFILETIME(idleTime);
- user = extractFILETIME(userTime);
- system = extractFILETIME(kernelTime) - idle;
- return true;
- #else
- //NOTE: This file needs to be reopened each time - seeking to the start and rereading does not refresh it
- FILE* cpufp = fopen("/proc/stat", "r");
- if (!cpufp) {
- clear();
- return false;
- }
- char ln[256];
- while (fgets(ln, sizeof(ln), cpufp))
- {
- if (strncmp(ln, "cpu ", 4) == 0)
- {
- int items;
- __uint64 nice, irq, softirq;
- items = sscanf(ln,
- "cpu %llu %llu %llu %llu %llu %llu %llu",
- &user, &nice,
- &system,
- &idle,
- &iowait,
- &irq, &softirq);
- user += nice;
- if (items == 4)
- iowait = 0;
- if (items == 7)
- system += irq + softirq;
- }
- else if (strncmp(ln, "ctxt ", 5) == 0)
- {
- (void)sscanf(ln, "ctxt %llu", &ctx);
- }
- }
- fclose(cpufp);
- return true;
- #endif
- }
- unsigned CpuInfo::getPercentCpu() const
- {
- __uint64 total = getTotal();
- if (total == 0)
- return 0;
- unsigned percent = (unsigned)(((total - idle) * 100) / total);
- if (percent > 100)
- percent = 100;
- return percent;
- }
- __uint64 CpuInfo::getSystemNs() const
- {
- return system * ticksToNs;
- }
- __uint64 CpuInfo::getUserNs() const
- {
- return user * ticksToNs;
- }
- __uint64 CpuInfo::getTotalNs() const
- {
- return getTotal() * ticksToNs;
- }
- unsigned CpuInfo::getIdlePercent() const
- {
- __uint64 total = getTotal();
- if (total == 0)
- return 0;
- return (unsigned)((idle * 100) / total);
- }
- unsigned CpuInfo::getIoWaitPercent() const
- {
- __uint64 total = getTotal();
- if (total == 0)
- return 0;
- return (unsigned)((iowait * 100) / total);
- }
- unsigned CpuInfo::getSystemPercent() const
- {
- __uint64 total = getTotal();
- if (total == 0)
- return 0;
- return (unsigned)((system * 100) / total);
- }
- unsigned CpuInfo::getUserPercent() const
- {
- __uint64 total = getTotal();
- if (total == 0)
- return 0;
- return (unsigned)((user * 100) / total);
- }
- //===========================================================================
- void BlockIoStats::clear()
- {
- rd_ios = 0;
- rd_merges = 0;
- rd_sectors = 0;
- rd_ticks = 0;
- wr_ios = 0;
- wr_merges = 0;
- wr_sectors = 0;
- wr_ticks = 0;
- ticks = 0;
- aveq = 0;
- }
- BlockIoStats & BlockIoStats::operator += (const BlockIoStats & other)
- {
- rd_ios += other.rd_ios;
- rd_merges += other.rd_merges;
- rd_sectors += other.rd_sectors;
- rd_ticks += other.rd_ticks;
- wr_ios += other.wr_ios;
- wr_merges += other.wr_merges;
- wr_sectors += other.wr_sectors;
- wr_ticks += other.wr_ticks;
- ticks += other.ticks;
- aveq += other.aveq;
- return *this;
- }
- BlockIoStats BlockIoStats::operator - (const BlockIoStats & other) const
- {
- BlockIoStats result;
- result.rd_ios = rd_ios - other.rd_ios;
- result.rd_merges = rd_merges - other.rd_merges;
- result.rd_sectors = rd_sectors - other.rd_sectors;
- result.rd_ticks = rd_ticks - other.rd_ticks;
- result.wr_ios = wr_ios - other.wr_ios;
- result.wr_merges = wr_merges - other.wr_merges;
- result.wr_sectors = wr_sectors - other.wr_sectors;
- result.wr_ticks = wr_ticks - other.wr_ticks;
- result.ticks = ticks - other.ticks;
- result.aveq = aveq - other.aveq;
- return result;
- }
- //===========================================================================
- // Performance Monitor
- #ifdef _WIN32
- memsize_t getMapInfo(const char *type)
- {
- return 0; // TODO/UNKNOWN
- }
- memsize_t getVMInfo(const char *type)
- {
- return 0; // TODO/UNKNOWN
- }
- void getCpuInfo(unsigned &numCPUs, unsigned &CPUSpeed)
- {
- // MORE: Might be a better way to get CPU speed (actual) than the one stored in Registry
- LONG lRet;
- HKEY hKey;
- DWORD keyValue;
- DWORD valueLen = sizeof(keyValue);
- if ((lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0L, KEY_READ , &hKey)) != ERROR_SUCCESS)
- {
- DBGLOG("RegOpenKeyEx(HKEY_LOCAL_MACHINE, ...) failed to open CentralProcessor\\0 - SysErrorCode=%d", lRet);
- }
- else if ((lRet = RegQueryValueEx(hKey, TEXT("~MHz"), NULL, NULL, (LPBYTE) &keyValue, &valueLen)) != ERROR_SUCCESS)
- {
- DBGLOG("RegQueryValueEx() failed to get CPU speed - errorCode=%d", lRet);
- RegCloseKey(hKey);
- }
- else
- {
- CPUSpeed = keyValue;
- RegCloseKey(hKey);
- }
-
- SYSTEM_INFO sysInfo;
- GetSystemInfo(&sysInfo);
- numCPUs = sysInfo.dwNumberOfProcessors;
- }
- static unsigned evalAffinityCpus()
- {
- unsigned numCpus = 0;
- #ifdef __64BIT__
- DWORD64 ProcessAffinityMask, SystemAffinityMask;
- #else
- DWORD ProcessAffinityMask, SystemAffinityMask;
- #endif
- if (GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&ProcessAffinityMask, (PDWORD_PTR)&SystemAffinityMask))
- {
- unsigned i = 0;
- while (ProcessAffinityMask)
- {
- if (ProcessAffinityMask & 1)
- ++numCpus;
- ProcessAffinityMask >>=1;
- }
- }
- else // fall back to legacy num system cpus
- {
- Owned<IException> e = makeOsException(GetLastError(), "Failed to get affinity");
- EXCLOG(e, NULL);
- unsigned cpuSpeed;
- getCpuInfo(numCpus, cpuSpeed);
- return numCpus;
- }
- return numCpus;
- }
- #else // linux
- memsize_t getMapInfo(const char *type)
- {
- // NOTE: 'total' heap value includes Roxiemem allocation, if present
- enum mapList { HEAP, STACK, SBRK, ANON };
- enum mapList mapType;
- if ( streq(type, "heap") )
- mapType = HEAP;
- else if ( streq(type, "stack") )
- mapType = STACK;
- else if ( streq(type, "sbrk") )
- mapType = SBRK;
- else if ( streq(type, "anon") )
- mapType = ANON;
- else
- return 0;
- memsize_t ret = 0;
- VStringBuffer procMaps("/proc/%d/maps", GetCurrentProcessId());
- FILE *diskfp = fopen(procMaps.str(), "r");
- if (!diskfp)
- return false;
- char ln[256];
- /*
- * exmaple /proc/<pid>/maps format:
- * addr_start -addr_end perms offset dev inode pathname
- * 01c3a000-01c5b000 rw-p 00000000 00:00 0 [heap]
- * 7f3f25217000-7f3f25a40000 rw-p 00000000 00:00 0 [stack:2362]
- * 7f4020a40000-7f4020a59000 rw-p 00000000 00:00 0
- * 7f4020a59000-7f4020a5a000 ---p 00000000 00:00 0
- * 7f4029bd4000-7f4029bf6000 r-xp 00000000 08:01 17576135 /lib/x86_64-linux-gnu/ld-2.15.so
- */
- while (fgets(ln, sizeof(ln), diskfp))
- {
- bool skipline = true;
- if ( mapType == HEAP || mapType == ANON ) // 'general' heap includes anon mmapped + sbrk
- {
- // skip file maps (beginning with /) and all other regions (except [heap if selected)
- if ( (mapType == HEAP && strstr(ln, "[heap")) || (!strstr(ln, " /") && !strstr(ln, " [")) )
- {
- // include only (r)ead + (w)rite and (p)rivate (not shared), skipping e(x)ecutable
- // and ---p guard regions
- if ( strstr(ln, " rw-p") )
- skipline = false;
- }
- }
- else if ( mapType == STACK )
- {
- if ( strstr(ln, "[stack") )
- skipline = false;
- }
- else if ( mapType == SBRK )
- {
- if ( strstr(ln, "[heap") )
- skipline = false;
- }
- if ( !skipline )
- {
- unsigned __int64 addrLow, addrHigh;
- if (2 == sscanf(ln, "%16" I64F "x-%16" I64F "x", &addrLow, &addrHigh))
- ret += (memsize_t)(addrHigh-addrLow);
- }
- }
- fclose(diskfp);
- return ret;
- }
- static bool matchExtract(const char * prefix, const char * line, memsize_t & value)
- {
- size32_t len = strlen(prefix);
- if (strncmp(prefix, line, len)==0)
- {
- char * tail = NULL;
- value = strtol(line+len, &tail, 10);
- while (isspace(*tail))
- tail++;
- if (strncmp(tail, "kB", 2) == 0)
- value *= 0x400;
- else if (strncmp(tail, "mB", 2) == 0)
- value *= 0x100000;
- else if (strncmp(tail, "gB", 2) == 0)
- value *= 0x40000000;
- return true;
- }
- return false;
- }
- memsize_t getVMInfo(const char *type)
- {
- memsize_t ret = 0;
- VStringBuffer name("%s:", type);
- VStringBuffer procMaps("/proc/self/status");
- FILE *diskfp = fopen(procMaps.str(), "r");
- if (!diskfp)
- return 0;
- char ln[256];
- while (fgets(ln, sizeof(ln), diskfp))
- {
- if (matchExtract(name.str(), ln, ret))
- break;
- }
- fclose(diskfp);
- return ret;
- }
- void getCpuInfo(unsigned &numCPUs, unsigned &CPUSpeed)
- {
- numCPUs = 1;
- CPUSpeed = 0;
- #ifdef __APPLE__
- # if defined(_SC_NPROCESSORS_CONF)
- int ncpus = sysconf(_SC_NPROCESSORS_CONF);
- if (ncpus > 0)
- numCPUs = ncpus;
- # endif
- #else // linux
- // NOTE: Could have perhaps used sysconf(_SC_NPROCESSORS_CONF) for numCPUs
- FILE *cpufp = fopen("/proc/cpuinfo", "r");
- if (cpufp == NULL)
- return;
- char * tail;
- // MORE: It is a shame that the info in this file (/proc/cpuinfo) are formatted (ie tabs .. etc)
- const char *cpuNumTag = "processor\t:";
- const char *cpuSpeedTag = "cpu MHz\t\t:";
- // NOTE: This provides current cpu freq, not max
- numCPUs = 0;
- char line[1001];
- const char *bufptr;
- while ((bufptr = fgets(line, 1000, cpufp)) != NULL)
- {
- if (strncmp(cpuNumTag, bufptr, strlen(cpuNumTag))==0)
- numCPUs++;
- else if (strncmp(cpuSpeedTag, bufptr, strlen(cpuSpeedTag))==0)
- CPUSpeed = (unsigned)strtol(bufptr+strlen(cpuSpeedTag), &tail, 10);
- }
- fclose(cpufp);
- if (numCPUs < 1)
- numCPUs = 1;
- // max cpu freq (KHz) may be in:
- // /sys/devices/system/cpu/cpu[0-X]/cpufreq/cpuinfo_max_freq
- cpufp = fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r");
- if (cpufp != NULL)
- {
- unsigned CPUSpeedMax = 0;
- int srtn = fscanf(cpufp, "%u", &CPUSpeedMax);
- if (srtn == 1)
- {
- CPUSpeedMax /= 1000;
- if (CPUSpeedMax > CPUSpeed)
- CPUSpeed = CPUSpeedMax;
- }
- fclose(cpufp);
- }
- #endif
- }
- static unsigned evalAffinityCpus()
- {
- #ifdef __APPLE__
- // MORE - could do better
- #else
- cpu_set_t cpuset;
- int err = pthread_getaffinity_np(GetCurrentThreadId(), sizeof(cpu_set_t), &cpuset);
- if (0 == err)
- {
- #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 6)
- return CPU_COUNT(&cpuset);
- #else
- unsigned numCpus = 0;
- unsigned setSize = CPU_SETSIZE;
- while (setSize--)
- {
- if (CPU_ISSET(setSize, &cpuset))
- ++numCpus;
- }
- return numCpus;
- #endif /* GLIBC */
- }
- #endif
- return 1;
- }
- // Note - values are returned in Kb
- static void getMemUsage(unsigned &inuse,unsigned &active,unsigned &total,unsigned &swaptotal,unsigned &swapinuse)
- {
- #ifdef __APPLE__
- active = 0;
- inuse = 0;
- total = 0;
- swaptotal = 0;
- swapinuse = 0;
- vm_size_t pageSize;
- if (KERN_SUCCESS != host_page_size(mach_host_self(), &pageSize))
- return;
- mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
- vm_statistics64_data_t vmstat;
- if (KERN_SUCCESS != host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&vmstat, &count))
- return;
- uint64_t totalBytes = (vmstat.wire_count + vmstat.active_count + vmstat.inactive_count + vmstat.free_count + vmstat.compressor_page_count) * pageSize;
- uint64_t inuseBytes = (vmstat.wire_count + vmstat.active_count + vmstat.inactive_count + vmstat.compressor_page_count) * pageSize;
- uint64_t activeBytes = (vmstat.wire_count + vmstat.active_count) * pageSize;
- active = activeBytes / 1024;
- inuse = inuseBytes / 1024;
- total = totalBytes / 1024;
- // swaptotal and swapinuse TBD
- #else
- unsigned free=0;
- unsigned swapfree=0;
- active = 0;
- inuse = 0;
- static int memfd = -1;
- if (memfd==-1)
- memfd = open("/proc/meminfo",O_RDONLY);
- if (memfd==-1)
- return;
- char buf[2048];
- size32_t l = pread(memfd, buf, sizeof(buf)-1, 0L);
- if ((int)l<=0)
- return;
- buf[l] = 0;
- const char *bufptr = buf;
- char * tail;
- unsigned i = 7; // supposed to match max number of items extract below
- total = swaptotal = free = active = swapfree = 0;
- unsigned swapcached = 0;
- unsigned cached = 0;
- while (bufptr&&i) {
- if (*bufptr =='\n')
- bufptr++;
- i--;
- if (strncmp("MemTotal:", bufptr, 9)==0)
- total = (unsigned)strtol(bufptr+9, &tail, 10);
- else if (strncmp("SwapTotal:", bufptr, 10)==0)
- swaptotal = (unsigned)strtol(bufptr+10, &tail, 10);
- else if (strncmp("MemFree:", bufptr, 8)==0)
- free = (unsigned)strtol(bufptr+8, &tail, 10);
- else if (strncmp("Active:", bufptr, 7)==0)
- active = (unsigned)strtol(bufptr+7, &tail, 10);
- else if (strncmp("SwapFree:", bufptr, 9)==0)
- swapfree = (unsigned)strtol(bufptr+9, &tail, 10);
- else if (strncmp("Cached:", bufptr, 7)==0)
- cached = (unsigned)strtol(bufptr+7, &tail, 10);
- else if (strncmp("SwapCached:", bufptr, 11)==0)
- swapcached = (unsigned)strtol(bufptr+11, &tail, 10);
- else
- i++;
- bufptr = strchr(bufptr, '\n');
- }
- inuse = total-free-cached;
- swapinuse = swaptotal-swapfree-swapcached;
- #endif
- }
- class CInt64fix
- {
- __int64 val;
- public:
- CInt64fix()
- {
- val = 0;
- }
- void set(int v)
- {
- __int64 ret = (unsigned)v;
- while (val-ret>0x80000000LL)
- ret += 0x100000000LL;
- val = ret;
- }
- __int64 get()
- {
- return val;
- }
- };
-
- void getMemStats(StringBuffer &out, unsigned &memused, unsigned &memtot)
- {
- #ifdef __linux__
- __int64 total = getMapInfo("heap");
- __int64 sbrkmem = getMapInfo("sbrk");
- __int64 mmapmem = total - sbrkmem;
- __int64 virttot = getVMInfo("VmData");
- unsigned mu;
- unsigned ma;
- unsigned mt;
- unsigned st;
- unsigned su;
- getMemUsage(mu,ma,mt,st,su);
- unsigned muval = (unsigned)(((__int64)mu+(__int64)su)*100/((__int64)mt+(__int64)st));
- if (sizeof(memsize_t)==4) {
- unsigned muval2 = (virttot*100)/(3*(__int64)0x40000000);
- if (muval2>muval)
- muval = muval2;
- }
- if (muval>100)
- muval = 100; // !
- out.appendf("MU=%3u%% MAL=%" I64F "d MMP=%" I64F "d SBK=%" I64F "d TOT=%uK RAM=%uK SWP=%uK",
- muval, total, mmapmem, sbrkmem, (unsigned)(virttot/1024), mu, su);
- #ifdef _USE_MALLOC_HOOK
- if (totalMem)
- out.appendf(" TM=%" I64F "d",totalMem);
- #endif
- memused = mu+su;
- memtot = mt+st;
- #elif defined (__APPLE__)
- __uint64 bytes;
- size_t len = sizeof(bytes);
- sysctlbyname("hw.memsize", &bytes, &len, NULL, 0);
- // See http://miknight.blogspot.com/2005/11/resident-set-size-in-mac-os-x.html
- struct task_basic_info t_info;
- mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
- task_info(current_task(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
- out.appendf("RES=%" I64F "uMiB VIRT=%" I64F "uMiB TOT=%" I64F "uMiB",
- (__uint64) t_info.resident_size/(1024*1024),
- (__uint64) t_info.virtual_size/(1024*1024),
- bytes/(1024*1024));
- memused = t_info.resident_size;
- memtot = t_info.virtual_size;
- #elif defined (__FreeBSD___)
- UNIMPLEMENTED;
- #endif
- }
- void getDiskUsage(char const * path, unsigned __int64 & total, unsigned __int64 & inUse)
- {
- #if defined(__linux__) || defined(__APPLE__)
- struct statfs stfs;
- if(statfs(path, &stfs) < 0)
- {
- //IERRLOG("statfs error for filesystem '%s'", path);
- total = inUse = 0;
- }
- else
- {
- struct stat st;
- if(stat(path, &st) < 0)
- {
- //IERRLOG("stat error for filesystem '%s'", path);
- total = inUse = 0;
- }
- else
- {
- total = (unsigned __int64)stfs.f_blocks * st.st_blksize;
- inUse = total - (unsigned __int64)stfs.f_bfree * st.st_blksize;
- }
- }
- #else
- total = inUse = 0;
- #endif
- }
- #endif
- static std::atomic<unsigned> cachedNumCpus;
- unsigned getAffinityCpus()
- {
- if (cachedNumCpus.load(std::memory_order_acquire) == 0)
- cachedNumCpus.store(evalAffinityCpus(), std::memory_order_release);
- return cachedNumCpus.load(std::memory_order_acquire);
- }
- void clearAffinityCache()
- {
- cachedNumCpus.store(0, std::memory_order_release);
- }
- void getPeakMemUsage(memsize_t &peakVm,memsize_t &peakResident)
- {
- peakVm = 0;
- peakResident = 0;
- #ifdef _WIN32
- PROCESS_MEMORY_COUNTERS pmc;
- if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
- {
- peakVm = pmc.PeakWorkingSetSize;
- peakResident = pmc.PeakWorkingSetSize;
- }
- #else
- static int memfd = -1;
- if (memfd==-1)
- memfd = open("/proc/self/status",O_RDONLY);
- if (memfd==-1)
- return;
- char buf[2048];
- size32_t l = pread(memfd, buf, sizeof(buf)-1, 0L);
- if ((int)l<=0)
- return;
- buf[l] = 0;
- const char *bufptr = buf;
- while (bufptr) {
- if (*bufptr =='\n')
- bufptr++;
- if (!matchExtract("VmPeak:", bufptr, peakVm) &&
- !matchExtract("VmHWM:", bufptr, peakResident))
- {
- //ignore this line
- }
- bufptr = strchr(bufptr, '\n');
- }
- #endif
- }
- #define RXMAX 1000000 // can be 10x bigger but this produces reasonable amounts
- unsigned packetsLasttime;
- __int64 packetsLastrx = -1;
- __int64 packetsLasttx;
- bool getPacketStats(unsigned & tx, unsigned & rx)
- {
- unsigned thistime = msTick();
- JSocketStatistics jstats;
- getSocketStatistics(jstats);
- bool ret = true;
- if(packetsLastrx!=-1)
- {
- tx = (unsigned) ((jstats.writesize-packetsLasttx)*100000/(((__int64)(packetsLasttime-thistime))*RXMAX));
- rx = (unsigned) ((jstats.readsize-packetsLastrx)*100000/(((__int64)(packetsLasttime-thistime))*RXMAX));
- }
- else
- ret = false;
- packetsLastrx = jstats.readsize;
- packetsLasttx = jstats.writesize;
- packetsLasttime = thistime;
- return ret;
- }
- #ifndef _WIN32
- struct UserStatusInfo
- {
- public:
- UserStatusInfo(pid_t _pid)
- {
- pid = _pid;
- }
- bool update()
- {
- StringBuffer fn;
- fn.appendf("/proc/%d/stat", pid);
- char buf[800]; /* about 40 fields, 64-bit decimal is about 20 chars */
- int fd = open(fn.str(), O_RDONLY, 0);
- if (fd==-1)
- return false;
- int rd = read(fd, buf, sizeof(buf)-1);
- close(fd);
- if (rd<80)
- return false;
- buf[rd] = 0;
- char *s = strchr(buf,'(');
- if (!s)
- return false;
- s++;
- unsigned i = 0;
- while (*s&&(*s!=')')&&(i<15))
- cmd[i++] = *(s++);
- if (*s != ')')
- return false;
- cmd[i] = 0;
- s+=3; // Skip ") X" where X is the state
- //The PID of the parent process
- const char *num;
- s = skipnumfld(s,num);
- //int ppid = atoi(num);
- // skip pgrp, session, tty_num, tpgid, flags, min_flt, cmin_flt, maj_flt, cmaj_flt
- for (i=0;i<9;i++)
- s = skipnumfld(s,num);
- //utime - user mode time in clock ticks.
- s = skipnumfld(s,num);
- //printf("**N'%s'\n",num);
- time.user = (unsigned)atoi64_l(num,strlen(num));
- //stime - amount of time scheduled in kernel mode in clock ticks
- s = skipnumfld(s,num);
- //printf("**N'%s'\n",num);
- time.system = (unsigned)atoi64_l(num,strlen(num));
- return true;
- }
- public:
- pid_t pid;
- char cmd[16];
- UserSystemTime_t time;
- private:
- char *skipnumfld(char *s, const char *&num)
- {
- while (*s && isspace(*s))
- s++;
- num = s;
- if ((*s=='-')||(*s=='+'))
- s++;
- while (*s && isdigit(*s))
- s++;
- if (*s==' ')
- *(s++) = 0; // terminate num
- while (*s && isspace(*s))
- s++;
- return s;
- }
- };
- struct CProcInfo: extends CInterface
- {
- UserStatusInfo info;
- UserSystemTime_t delta;
- bool active;
- bool first;
- CProcInfo(int _pid) : info(_pid)
- {
- active = false;
- first = true;
- }
- inline pid_t pid() const { return info.pid; }
- bool load()
- {
- UserSystemTime_t prev = info.time;
- if (!info.update())
- return false;
- active = true;
- if (first)
- first = false;
- else {
- delta.system = info.time.system-prev.system;
- delta.user = info.time.user-prev.user;
- }
- return true;
- }
- };
- class CProcessMonitor
- {
- CIArrayOf<CProcInfo> processes;
- unsigned tot_time;
- bool busy;
- CriticalSection sect;
- static int compare(CInterface * const *i1, CInterface * const *i2)
- {
- CProcInfo *pi1 = QUERYINTERFACE(*i1,CProcInfo);
- CProcInfo *pi2 = QUERYINTERFACE(*i2,CProcInfo);
- return pi2->delta.system+pi2->delta.user-pi1->delta.system-pi1->delta.user;
- }
- public:
- CProcessMonitor()
- {
- busy = false;
- }
- void scan()
- {
- #ifdef __linux__
- ForEachItemIn(i1,processes)
- processes.item(i1).active = false;
- DIR *dir = opendir("/proc");
- for (;;) {
- CriticalBlock b(sect);
- struct dirent *ent = readdir(dir);
- if (!ent)
- break;
- if ((ent->d_name[0]>='0')&&(ent->d_name[0]<='9')) {
- int pid = atoi(ent->d_name);
- if (pid) {
- CProcInfo *pi = NULL;
- ForEachItemIn(i2,processes) {
- if (processes.item(i2).pid() == pid) {
- pi = &processes.item(i2);
- break;
- }
- }
- if (!pi) {
- pi = new CProcInfo(pid);
- processes.append(*pi);
- }
- pi->load();
- }
- }
- }
- closedir(dir);
- tot_time = 0;
- ForEachItemInRev(i3,processes) {
- CProcInfo &pi = processes.item(i3);
- if (pi.active)
- tot_time += pi.delta.system+pi.delta.user;
- else
- processes.remove(i3);
- }
- #endif
- #if defined (__FreeBSD__) || defined (__APPLE__)
- UNIMPLEMENTED;
- #endif
- }
- void print(unsigned n,StringBuffer &str)
- {
- if (!tot_time)
- return;
- assertex(n);
- processes.sort(compare);
- StringBuffer name;
- ForEachItemIn(i1,processes) {
- CProcInfo &pi = processes.item(i1);
- if ((pi.delta.system==0)&&(pi.delta.user==0))
- break;
- getThreadName(pi.pid(),0,name.clear());
- str.appendf("\n TT: PI=%d PN=%s PC=%d ST=%d UT=%d%s%s",
- 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());
- if (--n==0)
- break;
- }
- }
- void printBusy(unsigned pc,StringBuffer &str)
- {
- if (pc>90) {
- scan();
- if (busy)
- print(3,str); // print top 3
- else
- busy = true;
- }
- else {
- busy = false;
- processes.kill();
- }
- }
- };
- #ifndef HZ
- #define HZ 100
- #endif
- #define IDE0_MAJOR 3
- #define SCSI_DISK0_MAJOR 8
- #define SCSI_DISK1_MAJOR 65
- #define SCSI_DISK7_MAJOR 71
- #define SCSI_DISK10_MAJOR 128
- #define SCSI_DISK17_MAJOR 135
- #define IDE1_MAJOR 22
- #define IDE2_MAJOR 33
- #define IDE3_MAJOR 34
- #define IDE4_MAJOR 56
- #define IDE5_MAJOR 57
- #define IDE6_MAJOR 88
- #define IDE7_MAJOR 89
- #define IDE8_MAJOR 90
- #define IDE9_MAJOR 91
- #define COMPAQ_SMART2_MAJOR 72
- #define IDE_DISK_MAJOR(M) ((M) == IDE0_MAJOR || (M) == IDE1_MAJOR || \
- (M) == IDE2_MAJOR || (M) == IDE3_MAJOR || \
- (M) == IDE4_MAJOR || (M) == IDE5_MAJOR || \
- (M) == IDE6_MAJOR || (M) == IDE7_MAJOR || \
- (M) == IDE8_MAJOR || (M) == IDE9_MAJOR)
- #define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
- ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) || \
- ((M) >= SCSI_DISK10_MAJOR && (M) <= SCSI_DISK17_MAJOR))
- #define OTHER_DISK_MAJOR(M) ((M) == COMPAQ_SMART2_MAJOR) // by investigation!
- // nvme disk major is often 259 (blkext) but others are also
- //---------------------------------------------------------------------------
- class OsDiskInfo
- {
- public:
- OsDiskInfo();
- ~OsDiskInfo();
- unsigned getNumPartitions() const { return nparts; }
- unsigned mapPartition(unsigned major, unsigned minor) const;
- const char * queryPartitionName(unsigned p) const { return partition[p].name; }
- protected:
- void gatherPartitions();
- void initMajorMinor();
- bool isDisk(unsigned int major, unsigned int minor) const
- {
- unsigned mm = (major<<16)+minor;
- bool found = diskMajorMinor.contains(mm);
- if (found)
- return true;
- if (IDE_DISK_MAJOR(major))
- return ((minor&0x3F)==0);
- if (SCSI_DISK_MAJOR(major))
- return ((minor&0x0F)==0);
- if (OTHER_DISK_MAJOR(major))
- return ((minor&0x0F)==0);
- return 0;
- }
- private:
- struct part_info
- {
- unsigned int major;
- unsigned int minor;
- char name[32];
- };
- unsigned nparts = 0;
- part_info *partition = nullptr;
- UnsignedArray diskMajorMinor;
- };
- OsDiskInfo::OsDiskInfo()
- {
- initMajorMinor();
- gatherPartitions();
- }
- OsDiskInfo::~OsDiskInfo()
- {
- free(partition);
- }
- void OsDiskInfo::gatherPartitions()
- {
- char ln[256];
- part_info pi;
- FILE* diskfp = fopen("/proc/diskstats", "r");
- if (!diskfp)
- return;
- nparts = 0;
- while (fgets(ln, sizeof(ln), diskfp))
- {
- unsigned reads = 0;
- if (sscanf(ln, "%4d %4d %31s %u", &pi.major, &pi.minor, pi.name, &reads) == 4)
- {
- unsigned p = 0;
- while ((p<nparts) && (partition[p].major != pi.major || partition[p].minor != pi.minor))
- p++;
- if ((p==nparts) && reads && isDisk(pi.major,pi.minor))
- {
- nparts++;
- partition = (part_info *)realloc(partition,nparts*sizeof(part_info));
- partition[p] = pi;
- }
- }
- }
- fclose(diskfp);
- }
- void OsDiskInfo::initMajorMinor()
- {
- #ifdef __linux__
- // MCK - wish libblkid could do this ...
- // Another way might also be to look for:
- // /sys/block/sd*
- // /sys/block/nvme*
- // and match those with entries in /proc/diskstats
- StringBuffer cmd("lsblk -o TYPE,MAJ:MIN --pairs");
- Owned<IPipeProcess> pipe = createPipeProcess();
- if (pipe->run(nullptr, cmd, nullptr, false, true, true, 8192))
- {
- StringBuffer output;
- Owned<ISimpleReadStream> pipeReader = pipe->getOutputStream();
- readSimpleStream(output, *pipeReader);
- unsigned exitcode = pipe->wait();
- if ( (exitcode == 0) && (output.length() > 0) )
- {
- StringArray lines;
- lines.appendList(output, "\n");
- ForEachItemIn(idx, lines)
- {
- // line: TYPE="disk" MAJ:MIN="259:0"
- unsigned majnum, minnum;
- if (2 == sscanf(lines.item(idx), "TYPE=\"disk\" MAJ:MIN=\"%u:%u\"", &majnum, &minnum))
- {
- unsigned mm = (majnum<<16)+minnum;
- diskMajorMinor.appendUniq(mm);
- }
- }
- }
- else
- {
- StringBuffer outputErr;
- Owned<ISimpleReadStream> pipeReaderErr = pipe->getErrorStream();
- readSimpleStream(outputErr, *pipeReaderErr);
- if (outputErr.length() > 0)
- WARNLOG("WARNING: Pipe: output: %s", outputErr.str());
- }
- }
- #endif // __linux__
- }
- unsigned OsDiskInfo::mapPartition(unsigned major, unsigned minor) const
- {
- for (unsigned p = 0; p < nparts; p++)
- {
- if (partition[p].major == major && partition[p].minor == minor)
- return p;
- }
- return (unsigned)-1;
- }
- static Singleton<OsDiskInfo> globalOsDiskInfo;
- MODULE_INIT(INIT_PRIORITY_JDEBUG2)
- {
- return true;
- }
- MODULE_EXIT()
- {
- globalOsDiskInfo.destroy();
- }
- const OsDiskInfo & queryGlobalOsDiskInfo()
- {
- return *globalOsDiskInfo.query([] { return new OsDiskInfo; });
- }
- #endif
- //---------------------------------------------------------------------------------------------------------------------
- OsDiskStats::OsDiskStats()
- {
- stats = new BlockIoStats[getNumPartitions()];
- }
- OsDiskStats::OsDiskStats(bool updateNow) : OsDiskStats()
- {
- if (updateNow)
- updateCurrent();
- }
- OsDiskStats::~OsDiskStats()
- {
- delete [] stats;
- }
- unsigned OsDiskStats::getNumPartitions() const
- {
- #ifdef _WIN32
- return 0;
- #else
- return queryGlobalOsDiskInfo().getNumPartitions();
- #endif
- }
- bool OsDiskStats::updateCurrent()
- {
- #ifdef _WIN32
- //MORE: This should be updated (probably using the performance counters api in windows).
- //Revisit if windows ever becomes a supported server platform
- return false;
- #else
- FILE* diskfp = fopen("/proc/diskstats", "r");
- if (!diskfp)
- return false;
- total.clear();
- char ln[256];
- while (fgets(ln, sizeof(ln), diskfp))
- {
- unsigned major, minor;
- BlockIoStats blkio;
- unsigned items = sscanf(ln, "%4d %4d %*s %u %u %llu %u %u %u %llu %u %*u %u %u",
- &major, &minor,
- &blkio.rd_ios, &blkio.rd_merges,
- &blkio.rd_sectors, &blkio.rd_ticks,
- &blkio.wr_ios, &blkio.wr_merges,
- &blkio.wr_sectors, &blkio.wr_ticks,
- &blkio.ticks, &blkio.aveq);
- if (items == 6)
- {
- // hopefully not this branch!
- blkio.rd_sectors = blkio.rd_merges;
- blkio.wr_sectors = blkio.rd_ticks;
- blkio.rd_ios = 0;
- blkio.rd_merges = 0;
- blkio.rd_ticks = 0;
- blkio.wr_ios = 0;
- blkio.wr_merges = 0;
- blkio.wr_ticks = 0;
- blkio.ticks = 0;
- blkio.aveq = 0;
- items = 12;
- }
- if (items == 12)
- {
- unsigned match = queryGlobalOsDiskInfo().mapPartition(major, minor);
- if (match != NotFound)
- {
- stats[match] = blkio;
- total += blkio;
- }
- }
- }
- fclose(diskfp);
- return true;
- #endif
- }
- //---------------------------------------------------------------------------------------------------------------------
- OsNetworkStats::OsNetworkStats(const char * ifname)
- {
- updateCurrent(ifname);
- }
- OsNetworkStats OsNetworkStats::operator - (const OsNetworkStats & other) const
- {
- OsNetworkStats result;
- result.rxbytes = rxbytes - other.rxbytes;
- result.rxpackets = rxpackets - other.rxpackets;
- result.rxerrors = rxerrors - other.rxerrors;
- result.rxdrops = rxdrops - other.rxdrops;
- result.txbytes = txbytes - other.txbytes;
- result.txpackets = txpackets - other.txpackets;
- result.txerrors = txerrors - other.txerrors;
- result.txdrops = txdrops - other.txdrops;
- return result;
- }
- bool OsNetworkStats::updateCurrent(const char * ifname)
- {
- #ifdef _WIN32
- //MORE: Implement on windows when we have a requirement
- return false;
- #else
- FILE *netfp = fopen("/proc/net/dev", "r");
- if (!netfp)
- return false;
- char ln[512];
- // Read two lines
- if (!fgets(ln, sizeof(ln), netfp) || !fgets(ln, sizeof(ln), netfp)) {
- fclose(netfp);
- return false;
- }
- unsigned txskip = 2;
- bool hasbyt = false;
- if (strstr(ln,"compressed")) {
- txskip = 4;
- hasbyt = true;
- }
- else if (strstr(ln,"bytes"))
- hasbyt = true;
- size_t ilen = ifname ? strlen(ifname) : 0;
- while (fgets(ln, sizeof(ln), netfp)) {
- const char *s = ln;
- skipSp(s);
- const char * next = nullptr;
- if (!ifname)
- {
- const char * colon = strchr(s, ':');
- if (colon)
- next = colon + 1;
- }
- else
- {
- if ((strncmp(s, ifname, ilen)==0) && (s[ilen]==':'))
- next = s + ilen + 1;
- }
- if (next)
- {
- s = next;
- skipSp(s);
- if (hasbyt) {
- rxbytes = readDecNum(s);
- skipSp(s);
- }
- else
- rxbytes = 0;
- rxpackets = readDecNum(s);
- skipSp(s);
- rxerrors = readDecNum(s);
- skipSp(s);
- rxdrops = readDecNum(s);
- skipSp(s);
- while (txskip--) {
- readDecNum(s);
- skipSp(s);
- }
- if (hasbyt) {
- txbytes = readDecNum(s);
- skipSp(s);
- }
- else
- txbytes = 0;
- txpackets = readDecNum(s);
- skipSp(s);
- txerrors = readDecNum(s);
- skipSp(s);
- txdrops = readDecNum(s);
- if (ifname)
- break;
- }
- }
- fclose(netfp);
- return true;
- #endif
- }
- //---------------------------------------------------------------------------------------------------------------------
- #ifndef _WIN32
- //---------------------------------------------------------------------------
- class CExtendedStats // Disk network and cpu stats
- {
- unsigned nparts;
- OsDiskStats *newDiskStats;
- OsDiskStats *oldDiskStats;
- CpuInfo newcpu;
- unsigned numcpu;
- CpuInfo oldcpu;
- CpuInfo cpu;
- OsNetworkStats oldnet;
- OsNetworkStats newnet;
- unsigned ncpu;
- bool first;
- char *kbuf;
- size32_t kbufmax;
- int kbadcnt;
- unsigned short kbufcrc;
- __uint64 totalcpu;
- unsigned ndisks;
- StringBuffer ifname;
- bool getNextCPU()
- {
- if (!ncpu) {
- unsigned speed;
- getCpuInfo(ncpu, speed);
- if (!ncpu)
- ncpu = 1;
- }
- oldcpu = newcpu;
- if (newcpu.getSystemTimes())
- {
- cpu = newcpu - oldcpu;
- totalcpu = cpu.getTotal();
- return true;
- }
- else
- {
- cpu.clear();
- totalcpu = 0;
- return false;
- }
- }
- bool getDiskInfo()
- {
- if (!newDiskStats)
- {
- newDiskStats = new OsDiskStats;
- oldDiskStats = new OsDiskStats;
- }
- return newDiskStats->updateCurrent();
- }
- bool getNetInfo()
- {
- return newnet.updateCurrent(ifname);
- }
- size32_t getKLog(const char *&data)
- {
- #if defined(__linux__) && !defined(_CONTAINERIZED)
- if (kbufmax)
- {
- data = nullptr;
- size32_t ksz = 0;
- unsigned short lastCRC = 0;
- // NOTE: allocated 2*kbufmax to work around kernel bug
- // where klogctl() could sometimes return more than requested
- size32_t sz = klogctl(3, kbuf, kbufmax);
- if ((int)sz < 0)
- {
- if (kbadcnt < 5)
- {
- IERRLOG("klogctl SYSLOG_ACTION_READ_ALL error %d", errno);
- kbadcnt++;
- }
- else
- kbufmax = 0;
- return 0;
- }
- #if 0
- kbuf[sz] = '\0';
- #endif
- if (kbufcrc)
- {
- data = kbuf;
- ksz = sz;
- }
- // determine where new info starts ...
- StringBuffer ln;
- const char *p = kbuf;
- const char *e = p+sz;
- while (p && p!=e)
- {
- if (*p=='<')
- {
- ln.clear();
- while ((p && p!=e)&&(*p!='\n'))
- {
- ln.append(*p);
- p++;
- sz--;
- }
- lastCRC = chksum16(ln.str(), ln.length());
- if (kbufcrc && kbufcrc == lastCRC)
- {
- ksz = sz - 1;
- if (ksz && sz)
- data = p + 1;
- else
- data = nullptr;
- }
- }
- while ((p && p!=e)&&(*p!='\n'))
- {
- p++;
- sz--;
- }
- if (p && p!=e)
- {
- p++;
- sz--;
- }
- }
- if (lastCRC)
- kbufcrc = lastCRC;
- if (!ksz)
- data = nullptr;
- return ksz;
- }
- #endif
- data = nullptr;
- return 0;
- }
- inline double perSec(double v,double deltams)
- {
- return 1000.0*v/deltams;
- }
- public:
- unsigned getCPU()
- {
- if (!getNextCPU())
- return (unsigned)-1;
- return cpu.getPercentCpu();
- }
- CExtendedStats(bool printklog)
- {
- nparts = queryGlobalOsDiskInfo().getNumPartitions();
- newDiskStats = NULL;
- oldDiskStats = NULL;
- first = true;
- ncpu = 0;
- kbuf = nullptr;
- kbufcrc = 0;
- totalcpu = 0;
- numcpu = 0;
- ndisks = 0;
- kbadcnt = 0;
- if (printklog)
- {
- kbufmax = 0x1000;
- kbuf = (char *)malloc(kbufmax*2);
- if (!kbuf)
- kbufmax = 0;
- }
- else
- kbufmax = 0;
- if (!getInterfaceName(ifname))
- ifname.set("eth0");
- }
- ~CExtendedStats()
- {
- delete newDiskStats;
- delete oldDiskStats;
- if (kbuf != nullptr)
- free(kbuf);
- }
- bool getLine(StringBuffer &out)
- {
- std::swap(oldDiskStats, newDiskStats);
- oldnet = newnet;
- bool gotdisk = getDiskInfo()&&nparts;
- bool gotnet = getNetInfo();
- if (first)
- {
- first = false;
- return false;
- }
- double deltams = ((double)totalcpu*1000) / ncpu / HZ;
- if (deltams<10)
- return false;
- if (gotdisk)
- {
- if (out.length()&&(out.charAt(out.length()-1)!=' '))
- out.append(' ');
- out.append("DSK: ");
- for (unsigned p = 0; p < nparts; p++)
- {
- const BlockIoStats & oldStats = oldDiskStats->queryStats(p);
- const BlockIoStats & newStats = newDiskStats->queryStats(p);
- BlockIoStats diff = newStats - oldStats;
- unsigned busy = (unsigned)(100*diff.ticks/deltams);
- if (busy>100)
- busy = 100;
- out.appendf("[%s] r/s=%0.1f kr/s=%0.1f w/s=%0.1f kw/s=%0.1f bsy=%d",
- queryGlobalOsDiskInfo().queryPartitionName(p),
- perSec(diff.rd_ios,deltams),
- perSec(diff.rd_sectors,deltams)/2.0,
- perSec(diff.wr_ios,deltams),
- perSec(diff.wr_sectors,deltams)/2.0,
- busy);
- out.append(' ');
- }
- }
- if (gotnet)
- {
- if (out.length()&&(out.charAt(out.length()-1)!=' '))
- out.append(' ');
- out.appendf("NIC: [%s] ", ifname.str());
- OsNetworkStats diff = newnet - oldnet;
- 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",
- perSec(diff.rxpackets,deltams),
- perSec(diff.rxbytes/1024.0,deltams),
- perSec(diff.txpackets,deltams),
- perSec(diff.txbytes/1024.0,deltams),
- diff.rxerrors, diff.rxdrops, diff.txerrors, diff.txdrops);
- out.append(' ');
- }
- if (totalcpu)
- {
- if (out.length()&&(out.charAt(out.length()-1)!=' '))
- out.append(' ');
- out.appendf("CPU: usr=%d sys=%d iow=%d idle=%d", cpu.getUserPercent(), cpu.getSystemPercent(), cpu.getIoWaitPercent(), cpu.getIdlePercent());
- }
- return true;
- }
- void printKLog(IPerfMonHook *hook)
- {
- constexpr const char *kernLevelMsgs[] = {
- "KERN_EMERG", // 0: system is unusable
- "KERN_ALERT", // 1: action must be taken immediately
- "KERN_CRIT", // 2: critical conditions
- "KERN_ERR", // 3: error conditions
- "KERN_WARNING", // 4: warning conditions
- "KERN_NOTICE", // 5: normal but significant condition
- "KERN_INFO", // 6: informational
- "KERN_DEBUG", // 7: debug-level messages
- };
- constexpr unsigned unknownLevel = 8;
- const char *p = nullptr;
- size32_t sz = getKLog(p);
- #if 0
- DBGLOG("getKLog() returns: %u <%s>", sz, p);
- #endif
- StringBuffer ln;
- const char *e = p+sz;
- while (p && (p!=e))
- {
- if (*p=='<')
- {
- ln.clear();
- unsigned level = 0;
- const char *pstart = p;
- ++p;
- while (true)
- {
- if (!isdigit(*p))
- {
- if ((p != (pstart+1)) && (*p == '>'))
- {
- ++p;
- if (level>=unknownLevel)
- ln.appendf("KERN_UNKNOWN[%u]", level);
- else
- ln.append(kernLevelMsgs[level]);
- }
- else
- {
- ln.append("KERN_UNKNOWN");
- p = pstart;
- }
- break;
- }
- level = 10 * level + ((*p) - '0');
- p++;
- }
- ln.append(": ");
- while ((p && p!=e)&&(*p!='\n'))
- ln.append(*(p++));
- if (hook)
- hook->log(level, ln.str());
- else
- PROGLOG("%s",ln.str());
- }
- while ((p && p!=e)&&(*p!='\n'))
- p++;
- if (p && p!=e)
- p++;
- }
- }
- };
- #endif
- struct PortStats
- {
- unsigned port;
- unsigned drops;
- unsigned rx_queue;
- };
- typedef MapBetween<unsigned, unsigned, PortStats, PortStats> MapPortToPortStats;
- class CUdpStatsReporter
- {
- public:
- CUdpStatsReporter()
- {
- dropsCol = -1;
- portCol = -1;
- uidCol = -1;
- queueCol = -1;
- }
- bool reportUdpInfo(unsigned traceLevel)
- {
- #ifdef _WIN32
- return false;
- #else
- if (uidCol==-1 && columnNames.length())
- return false;
- FILE *netfp = fopen("/proc/net/udp", "r");
- if (!netfp)
- return false;
- char ln[512];
- // Read header
- if (!fgets(ln, sizeof(ln), netfp)) {
- fclose(netfp);
- return false;
- }
- bool firstTime = false;
- if (!columnNames.length())
- {
- firstTime = true;
- columnNames.appendList(ln, " ");
- ForEachItemInRev(idx, columnNames)
- {
- if (streq(columnNames.item(idx), "rem_address"))
- columnNames.add("rem_port", idx+1);
- else if (streq(columnNames.item(idx), "local_address"))
- columnNames.add("local_port", idx+1);
- }
- ForEachItemIn(idx2, columnNames)
- {
- if (streq(columnNames.item(idx2), "drops"))
- dropsCol = idx2;
- else if (streq(columnNames.item(idx2), "local_port"))
- portCol = idx2;
- else if (streq(columnNames.item(idx2), "rx_queue"))
- queueCol = idx2;
- else if (streq(columnNames.item(idx2), "uid"))
- uidCol = idx2;
- }
- if (portCol == -1 || queueCol == -1 || uidCol == -1)
- {
- uidCol = -1;
- fclose(netfp);
- return false;
- }
- }
- int myUid = geteuid();
- while (fgets(ln, sizeof(ln), netfp))
- {
- StringArray cols;
- cols.appendList(ln, " :");
- if (cols.length() >= columnNames.length() && atoi(cols.item(uidCol))==myUid)
- {
- unsigned queue = strtoul(cols.item(queueCol), NULL, 16);
- unsigned drops = 0;
- if (dropsCol >= 0)
- drops = strtoul(cols.item(dropsCol), NULL, 10);
- if (queue || drops)
- {
- unsigned port = strtoul(cols.item(portCol), NULL, 16);
- if (traceLevel > 0)
- DBGLOG("From /proc/net/udp: port %d rx_queue=%u drops=%u", port, queue, drops);
- PortStats *ret = map.getValue(port);
- if (!ret)
- {
- PortStats e = {port, 0, 0};
- map.setValue(port, e);
- ret = map.getValue(port);
- assertex(ret);
- }
- if (queue > ret->rx_queue)
- {
- if (!firstTime)
- DBGLOG("UDP queue: new max rx_queue: port %d rx_queue=%u drops=%u", port, queue, drops);
- ret->rx_queue = queue;
- }
- if (drops > ret->drops)
- {
- if (!firstTime)
- 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);
- ret->drops = drops;
- }
- }
- }
- }
- fclose(netfp);
- return true;
- #endif
- }
- private:
- MapPortToPortStats map;
- StringArray columnNames;
- int dropsCol;
- int portCol;
- int uidCol;
- int queueCol;
- };
- class CSnmpStatsReporter
- {
- public:
- CSnmpStatsReporter()
- {
- inErrorsCol = -1;
- prevErrors = 0;
- firstCall = true;
- }
- bool reportSnmpInfo()
- {
- #ifdef _WIN32
- return false;
- #else
- if (inErrorsCol==-1 && columnNames.length())
- return false;
- FILE *netfp = fopen("/proc/net/snmp", "r");
- if (!netfp)
- return false;
- char ln[512];
- bool ok = false;
- while (fgets(ln, sizeof(ln), netfp))
- {
- if (strncmp(ln, "Udp:", 4)==0)
- {
- if (!columnNames.length())
- {
- columnNames.appendList(ln, " ");
- ForEachItemIn(idx, columnNames)
- {
- if (streq(columnNames.item(idx), "InErrors"))
- inErrorsCol = idx;
- }
- if (inErrorsCol == -1)
- break;
- }
- if (fgets(ln, sizeof(ln), netfp))
- {
- StringArray cols;
- cols.appendList(ln, " ");
- if (cols.length() >= columnNames.length())
- {
- ok = true;
- unsigned errors = strtoul(cols.item(inErrorsCol), NULL, 10);
- if (firstCall)
- {
- firstCall = false;
- if (errors)
- LOG(MCoperatorWarning, unknownJob, "UDP Initial InError total: %u", errors);
- }
- else if (errors > prevErrors)
- LOG(MCoperatorError, unknownJob, "UDP InErrors: %u (total %u)", errors-prevErrors, errors);
- prevErrors = errors;
- }
- }
- break;
- }
- }
- fclose(netfp);
- return ok;
- #endif
- }
- private:
- StringArray columnNames;
- int inErrorsCol;
- unsigned prevErrors;
- bool firstCall;
- };
- static class CMemoryUsageReporter: public Thread
- {
- bool term;
- unsigned interval;
- Semaphore sem;
- PerfMonMode traceMode;
- Linked<IPerfMonHook> hook;
- unsigned latestCPU;
- #ifdef _WIN32
- LONG status;
- CpuInfo prevTime;
- CpuInfo deltaTime;
- #else
- CProcessMonitor procmon;
- CExtendedStats extstats;
- #endif
- StringBuffer primaryfs;
- StringBuffer secondaryfs;
- CriticalSection sect; // for getSystemTraceInfo
- CSnmpStatsReporter snmpStats;
- CUdpStatsReporter udpStats;
- public:
- CMemoryUsageReporter(unsigned _interval, PerfMonMode _traceMode, IPerfMonHook * _hook, bool printklog)
- : Thread("CMemoryUsageReporter"), traceMode(_traceMode)
- #ifndef _WIN32
- , extstats(printklog)
- #endif
- {
- interval = _interval;
- hook.set(_hook);
- term = false;
- latestCPU = 0;
- // UDP stats reported unless explicitly disabled
- if (queryEnvironmentConf().getPropBool("udp_stats", true))
- traceMode |= PerfMonUDP;
- #ifdef _WIN32
- primaryfs.append("C:");
- #else
- primaryfs.append("/");
- #endif
- }
- void setPrimaryFileSystem(char const * _primaryfs)
- {
- CriticalBlock block(sect);
- primaryfs.clear();
- if(_primaryfs)
- primaryfs.append(_primaryfs);
- }
- void setSecondaryFileSystem(char const * _secondaryfs)
- {
- CriticalBlock block(sect);
- secondaryfs.clear();
- if(_secondaryfs)
- secondaryfs.append(_secondaryfs);
- }
- void getSystemTraceInfo(StringBuffer &str, PerfMonMode mode)
- {
- CriticalBlock block(sect);
- #ifdef _WIN32
- CpuInfo current;
- current.getSystemTimes();
- if (prevTime.getTotal())
- {
- deltaTime = current - prevTime;
- latestCPU = 100 - deltaTime.getIdlePercent();
- }
- prevTime = current;
- MEMORYSTATUSEX memstatus;
- memstatus.dwLength = sizeof(memstatus);
- GlobalMemoryStatusEx(&memstatus);
- DWORDLONG vmTotal = memstatus.ullTotalVirtual;
- DWORDLONG vmAvail = memstatus.ullAvailVirtual;
- DWORDLONG vmInUse = vmTotal - vmAvail;
- DWORDLONG physTotal = memstatus.ullAvailPhys;
- DWORDLONG physAvail = memstatus.ullTotalPhys;
- DWORDLONG physInUse = physTotal - physAvail;
- ULARGE_INTEGER diskAvailStruct;
- ULARGE_INTEGER diskTotalStruct;
- unsigned __int64 firstDriveTotal = 0;
- unsigned __int64 firstDriveInUse = 0;
- unsigned __int64 secondDriveTotal = 0;
- unsigned __int64 secondDriveInUse = 0;
- if(primaryfs.length())
- {
- diskAvailStruct.QuadPart = 0;
- diskTotalStruct.QuadPart = 0;
- GetDiskFreeSpaceEx(primaryfs.str(), &diskAvailStruct, &diskTotalStruct, 0);
- firstDriveTotal = diskTotalStruct.QuadPart;
- firstDriveInUse = diskTotalStruct.QuadPart - diskAvailStruct.QuadPart;
- }
- if(secondaryfs.length())
- {
- diskAvailStruct.QuadPart = 0;
- diskTotalStruct.QuadPart = 0;
- GetDiskFreeSpaceEx(secondaryfs.str(), &diskAvailStruct, &diskTotalStruct, 0);
- secondDriveTotal = diskTotalStruct.QuadPart;
- secondDriveInUse = diskTotalStruct.QuadPart - diskAvailStruct.QuadPart;
- }
- if(hook)
- hook->processPerfStats(latestCPU, (unsigned)(vmInUse/1024), (unsigned)(vmTotal/1024), firstDriveInUse, firstDriveTotal, secondDriveInUse, secondDriveTotal, getThreadCount());
- if(!mode)
- return;
- if(mode & PerfMonProcMem)
- {
- str.appendf("PU=%3d%%",latestCPU);
- str.appendf(" MU=%3u%%",(unsigned)((__int64)vmInUse*100/(__int64)vmTotal));
- str.appendf(" PY=%3u%%",(unsigned)((__int64)physInUse*100/(__int64)physTotal));
- if (hook)
- hook->extraLogging(str);
- #ifdef _USE_MALLOC_HOOK
- if (totalMem)
- str.appendf(" TM=%" I64F "d",totalMem);
- #endif
- }
- if(mode & PerfMonPackets)
- {
- unsigned tx, rx;
- if(getPacketStats(tx, rx))
- str.appendf(" TX=%3u%% RX=%3u%%", tx, rx);
- else
- str.appendf(" ");
- }
- if(mode & PerfMonDiskUsage)
- {
- if(firstDriveTotal) str.appendf(" D1=%3u%%", (unsigned)(firstDriveInUse*100/firstDriveTotal));
- if(secondDriveTotal) str.appendf(" D2=%3u%%", (unsigned)(secondDriveInUse*100/secondDriveTotal));
- }
- if(mode & PerfMonExtended)
- {
- __IO_COUNTERS ioc;
- KERNEL_USER_TIMES kut;
- POOLED_USAGE_AND_LIMITS put;
- VM_COUNTERS vmc;
- DWORD dwSize;
- DWORD dwHandles;
- dwSize = 0;
- NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &vmc, sizeof(vmc), &dwSize);
- dwHandles = 0;
- dwSize = 0;
- NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessHandleCount, &dwHandles, sizeof(dwHandles), &dwSize);
- dwSize = 0;
- NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessIoCounters, &ioc, sizeof(ioc), &dwSize);
- dwSize = 0;
- NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessTimes, &kut, sizeof(kut), &dwSize);
- dwSize = 0;
- NtKernelFunctions.NtQueryInformationProcess(GetCurrentProcess(), ProcessPooledUsageAndLimits, &put, sizeof(put), &dwSize);
- str.appendf(" WS=%10u ",vmc.WorkingSetSize);
- str.appendf("PP=%10u ",put.PagedPoolUsage);
- str.appendf("NP=%10u ",put.NonPagedPoolUsage);
- str.appendf("HC=%5u ",dwHandles);
- str.appendf("TC=%5u ",getThreadCount());
- str.appendf("IR=%10u ",(unsigned)(ioc.ReadTransferCount/1024));
- str.appendf("IW=%10u ",(unsigned)(ioc.WriteTransferCount/1024));
- str.appendf("IO=%10u ",(unsigned)(ioc.OtherTransferCount/1024));
- str.appendf("KT=%16" I64F "u ",kut.KernelTime);
- str.appendf("UT=%16" I64F "u ",kut.UserTime);
- }
- #else
- bool outofhandles = false;
- latestCPU = extstats.getCPU();
- if (latestCPU==(unsigned)-1) {
- outofhandles = true;
- latestCPU = 0;
- }
- unsigned __int64 primaryfsTotal = 0;
- unsigned __int64 primaryfsInUse = 0;
- unsigned __int64 secondaryfsTotal = 0;
- unsigned __int64 secondaryfsInUse = 0;
- if(primaryfs.length())
- getDiskUsage(primaryfs.str(), primaryfsTotal, primaryfsInUse);
- if(secondaryfs.length())
- getDiskUsage(secondaryfs.str(), secondaryfsTotal, secondaryfsInUse);
- if(!mode) return;
- unsigned memused=0;
- unsigned memtot=0;
- str.appendf("LPT=%u ", queryNumLocalTrees());
- str.appendf("APT=%u ", queryNumAtomTrees());
- if(mode & PerfMonProcMem)
- {
- if (!outofhandles)
- str.appendf("PU=%3d%% ", latestCPU);
- else
- str.appendf("PU=OOH ");
- getMemStats(str,memused,memtot);
- if (hook)
- hook->extraLogging(str);
- procmon.printBusy(latestCPU,str);
- }
- if (hook) {
- if (!memtot) {
- unsigned mu;
- unsigned ma;
- unsigned mt;
- unsigned st;
- unsigned su;
- getMemUsage(mu,ma,mt,st,su);
- memused = mu+su;
- memtot = mt+st;
- }
- hook->processPerfStats(latestCPU, memused, memtot, primaryfsInUse, primaryfsTotal, secondaryfsInUse, secondaryfsTotal, getThreadCount());
- }
- if(mode & PerfMonPackets)
- {
- unsigned tx, rx;
- if(getPacketStats(tx, rx))
- str.appendf(" TX=%3u%% RX=%3u%%", tx, rx);
- else
- str.appendf(" ");
- }
- if(mode & PerfMonDiskUsage)
- {
- if(primaryfsTotal) str.appendf(" D1=%3u%%", (unsigned)(primaryfsInUse*100/primaryfsTotal));
- if(secondaryfsTotal) str.appendf(" D2=%3u%%", (unsigned)(secondaryfsInUse*100/secondaryfsTotal));
- }
- if(mode & PerfMonExtended)
- {
- extstats.getLine(str);
- }
- #endif
- }
- #define NAMEDCOUNTPERIOD 60*30
- int run()
- {
- StringBuffer str;
- getSystemTraceInfo(str, traceMode&~PerfMonExtended); // initializes the values so that first one we print is meaningful rather than always saying PU=0%
- if (traceMode&PerfMonUDP)
- {
- snmpStats.reportSnmpInfo();
- udpStats.reportUdpInfo(0);
- }
- CTimeMon tm(NAMEDCOUNTPERIOD*1000);
- while (!term) {
- if (sem.wait(interval))
- break;
- str.clear();
- getSystemTraceInfo(str, traceMode&~PerfMonExtended);
- #ifdef NAMEDCOUNTS
- if (tm.timedout())
- {
- dumpNamedCounts(str.newline());
- tm.reset(NAMEDCOUNTPERIOD*1000);
- }
- #endif
- if (traceMode&PerfMonUDP)
- {
- snmpStats.reportSnmpInfo();
- udpStats.reportUdpInfo(0);
- }
- if(traceMode&&str.length()) {
- MLOG(MCdebugInfo, unknownJob, "SYS: %s", str.str());
- #ifndef _WIN32
- if (traceMode&PerfMonExtended)
- {
- if (extstats.getLine(str.clear()))
- MLOG(MCdebugInfo, "%s", str.str());
- {
- CriticalBlock block(sect);
- extstats.printKLog(hook);
- }
- }
- #endif
- }
- }
- return 0;
- }
- void stop()
- {
- term = true;
- sem.signal();
- join();
- }
- unsigned queryLatestCPU() const
- {
- return latestCPU;
- }
- void setHook(IPerfMonHook *_hook)
- {
- CriticalBlock block(sect);
- hook.set(_hook);
- }
- } *MemoryUsageReporter=NULL;
- #ifdef _WIN32
- static inline unsigned scaleFileTimeToMilli(unsigned __int64 nano100)
- {
- return (unsigned)(nano100 / 10000);
- }
- void getProcessTime(UserSystemTime_t & result)
- {
- LARGE_INTEGER startTime, exitTime, kernelTime, userTime;
- if (GetProcessTimes(GetCurrentProcess(), (FILETIME *)&startTime, (FILETIME *)&exitTime, (FILETIME *)&kernelTime, (FILETIME *)&userTime))
- {
- result.user = scaleFileTimeToMilli(userTime.QuadPart);
- result.system = scaleFileTimeToMilli(kernelTime.QuadPart);
- }
- }
- #else
- void getProcessTime(UserSystemTime_t & result)
- {
- UserStatusInfo info(GetCurrentProcessId());
- if (info.update())
- result = info.time;
- }
- #endif
- void getSystemTraceInfo(StringBuffer &str, PerfMonMode mode)
- {
- if (!MemoryUsageReporter)
- MemoryUsageReporter = new CMemoryUsageReporter(1000, mode, 0, false);
- MemoryUsageReporter->getSystemTraceInfo(str, mode);
- }
- void startPerformanceMonitor(unsigned interval, PerfMonMode traceMode, IPerfMonHook * hook)
- {
- stopPerformanceMonitor();
- if (!MemoryUsageReporter) {
- MemoryUsageReporter = new CMemoryUsageReporter(interval, traceMode, hook, (traceMode&PerfMonExtended)!=0);
- MemoryUsageReporter->start();
- }
- }
- void stopPerformanceMonitor()
- {
- if (MemoryUsageReporter) {
- MemoryUsageReporter->stop();
- delete MemoryUsageReporter;
- MemoryUsageReporter = NULL;
- }
- }
- void setPerformanceMonitorHook(IPerfMonHook *hook)
- {
- if (MemoryUsageReporter)
- MemoryUsageReporter->setHook(hook);
- }
- void setPerformanceMonitorPrimaryFileSystem(char const * fs)
- {
- if(MemoryUsageReporter)
- MemoryUsageReporter->setPrimaryFileSystem(fs);
- }
- void setPerformanceMonitorSecondaryFileSystem(char const * fs)
- {
- if(MemoryUsageReporter)
- MemoryUsageReporter->setSecondaryFileSystem(fs);
- }
- unsigned getLatestCPUUsage()
- {
- if (MemoryUsageReporter)
- return MemoryUsageReporter->queryLatestCPU();
- else
- return 0;
- }
- void getHardwareInfo(HardwareInfo &hdwInfo, const char *primDiskPath, const char *secDiskPath)
- {
- memset(&hdwInfo, 0, sizeof(HardwareInfo));
- getCpuInfo(hdwInfo.numCPUs, hdwInfo.CPUSpeed);
- #ifdef _WIN32
- MEMORYSTATUS memstatus;
- GlobalMemoryStatus(&memstatus);
- hdwInfo.totalMemory = (unsigned)(memstatus.dwTotalPhys / (1024*1024)); // in MB
- ULARGE_INTEGER diskAvailStruct;
- ULARGE_INTEGER diskTotalStruct;
- if (primDiskPath)
- {
- diskTotalStruct.QuadPart = 0;
- GetDiskFreeSpaceEx(primDiskPath, &diskAvailStruct, &diskTotalStruct, 0);
- hdwInfo.primDiskSize = (unsigned)(diskTotalStruct.QuadPart / (1024*1024*1024)); // in GB
- hdwInfo.primFreeSize = (unsigned)(diskAvailStruct.QuadPart / (1024*1024*1024)); // in GB
- }
- if (secDiskPath)
- {
- diskTotalStruct.QuadPart = 0;
- GetDiskFreeSpaceEx(secDiskPath, &diskAvailStruct, &diskTotalStruct, 0);
- hdwInfo.secDiskSize = (unsigned)(diskTotalStruct.QuadPart / (1024*1024*1024)); // in GB
- hdwInfo.secFreeSize = (unsigned)(diskAvailStruct.QuadPart / (1024*1024*1024)); // in GB
- }
- // MORE: Find win32 call for NIC speed
- #else // linux
- unsigned memUsed, memActive, memSwap, memSwapUsed;
- getMemUsage(memUsed, memActive, hdwInfo.totalMemory, memSwap, memSwapUsed);
- hdwInfo.totalMemory /= 1024; // in MB
- unsigned __int64 diskSize;
- unsigned __int64 diskUsed;
- if (primDiskPath)
- {
- getDiskUsage(primDiskPath, diskSize, diskUsed);
- hdwInfo.primDiskSize = diskSize / (1024*1024*1024); // in GB
- hdwInfo.primFreeSize = (diskSize - diskUsed) / (1024*1024*1024); // in GB
- }
- if (secDiskPath)
- {
- getDiskUsage(secDiskPath, diskSize, diskUsed);
- hdwInfo.secDiskSize = diskSize / (1024*1024*1024); // in GB
- hdwInfo.secFreeSize = (diskSize - diskUsed) / (1024*1024*1024); // in GB
- }
- // MORE: Find linux call for NIC speed -- mii-tool does not seem to work on our roxie clusters?
- #endif
- }
- //===========================================================================
- enum SegTypes {
- segtype_free, //
- segtype_heap, // rw-p named [heap]
- segtype_data, // rw-p unnamed
- segtype_guard, // ---p unnamed/named
- segtype_stack, // rwxp
- segtype_qlibcode, // r-xp named */lib200
- segtype_qlibdata, // rw-p named */lib200
- segtype_libcode, // r-xp named *
- segtype_libdata, // rw-p named *
- segtype_pstack, // rwxp named [stack]
- segtype_const, // r--p
- segtype_null // must be last
- };
- struct SegTypeRec
- {
- offset_t total;
- unsigned n;
- offset_t largest;
- };
- const char *PROCMAPHEADER =
- "FREE,NFREE,MAXFREE,HEAP,STACK,NSTACKS,DATA,NDATA,MAXDATA,LIBDATA,QUERYDATA,MAXQUERYDATA,LIBCODE,QUERYCODE,MAXQLIBCODE";
- class CProcReader
- {
- // Cant use JFile for /proc filesystem as seek doesn't work
- public:
- char ln [512];
- FILE *file;
- const char *buf;
- size32_t bufsize;
- CProcReader(const char *filename,const void *_buf,size32_t _buflen)
- {
- buf = (const char *)_buf;
- bufsize = buf?_buflen:0;
- file = buf?NULL:fopen(filename,"r");
- }
- ~CProcReader()
- {
- if (file)
- fclose(file);
- }
- bool nextln()
- {
- if (buf) {
- if (bufsize&&*buf) {
- unsigned i = 0;
- while (bufsize&&(i<sizeof(ln)-1)&&*buf&&(*buf!=10)&&(*buf!=13)) {
- ln[i++] = *(buf++);
- bufsize--;
- }
- ln[i] = 0;
- while (bufsize&&*buf&&((*buf==10)||(*buf==13))) {
- buf++;
- bufsize--;
- }
- return true;
- }
- }
- else if (file&&fgets (ln, sizeof(ln), file)) {
- size_t i = strlen(ln);
- while (i&&((ln[i-1]==10)||(ln[i-1]==13)))
- i--;
- ln[i] = 0;
- return true;
- }
- if (file) {
- fclose(file);
- file = NULL;
- }
- return false;
- }
- void dump(bool useprintf)
- {
- while (nextln()) {
- if (useprintf)
- printf("%s\n",ln);
- else
- PROGLOG("%s",ln);
- }
- }
- };
- void printProcMap(const char *fn, bool printbody, bool printsummary, StringBuffer *lnout, MemoryBuffer *mb, bool useprintf)
- {
- CProcReader reader(fn,mb?mb->toByteArray():NULL,mb?mb->length():0);
- unsigned i;
- SegTypeRec recs[segtype_null];
- memset(&recs,0,sizeof(recs));
- offset_t last=0;
- if (printbody) {
- if (useprintf)
- printf("START,END,SIZE,OFFSET,PERMS,PATH\n");
- else
- PROGLOG("START,END,SIZE,OFFSET,PERMS,PATH");
- }
- while (reader.nextln()) {
- const char *ln = reader.ln;
- unsigned n=0;
- if (*ln) {
- offset_t start = readHexNum(ln);
- if (last&&(last!=start)) {
- recs[segtype_free].n++;
- offset_t ssz = start-last;
- recs[segtype_free].total += ssz;
- if (ssz>recs[segtype_free].largest)
- recs[segtype_free].largest = ssz;
- }
- if (*ln=='-') {
- ln++;
- offset_t end = readHexNum(ln);
- char perms[5];
- skipSp(ln);
- for (i=0;i<4;)
- if (*ln)
- perms[i++] = *(ln++);
- perms[i] = 0;
- skipSp(ln);
- offset_t offset = readHexNum(ln);
- skipSp(ln);
- char dev[6];
- for (i=0;i<5;)
- if (*ln)
- dev[i++] = *(ln++);
- dev[i] = 0;
- skipSp(ln);
- unsigned inode __attribute__((unused)) = (unsigned) readDecNum(ln);
- skipSp(ln);
- const char *path = ln;
- if (printbody) {
- if (useprintf)
- 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);
- else
- 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);
- }
- SegTypes t = segtype_data;
- if (strcmp(perms,"---p")==0)
- t = segtype_guard;
- else if (strcmp(perms,"rwxp")==0) {
- if (memicmp(ln,"[stack]",7)==0)
- t = segtype_pstack;
- else
- t = segtype_stack;
- }
- else if (strcmp(perms,"rw-p")==0) {
- if (memicmp(ln,"[heap]",6)==0)
- t = segtype_heap;
- else if (strstr(ln,"/libW200"))
- t = segtype_qlibdata;
- else if (*ln)
- t = segtype_libdata;
- else
- t = segtype_data;
- }
- else if (strcmp(perms,"r-xp")==0) {
- if (strstr(ln,"/libW200"))
- t = segtype_qlibcode;
- else if (*ln)
- t = segtype_libcode;
- }
- else if (strcmp(perms,"r--p")==0)
- t = segtype_const;
- else {
- IERRLOG("%s - unknown perms",perms);
- continue;
- }
- recs[t].n++;
- offset_t ssz = end-start;
- recs[t].total += ssz;
- if (ssz>recs[t].largest)
- recs[t].largest = ssz;
- n++;
- last = end;
- #ifndef __64BIT__
- if ((end<0xffffffff)&&(end>=0xc0000000)) // rest is OS (32-bit only)
- break;
- #endif
- }
- }
- }
- if (printsummary||lnout) {
- StringBuffer tln;
- if (lnout==NULL)
- lnout = &tln;
- lnout->appendf("%" I64F "u," // total
- "%u," // n
- "%" I64F "u," // largest
- "%" I64F "u," // total
- "%" I64F "u," // total
- "%u," // n
- "%" I64F "u," // total
- "%u," // n
- "%" I64F "u," // largest
- "%" I64F "u," // total
- "%" I64F "u," // total
- "%" I64F "u," // largest
- "%" I64F "u," // total
- "%" I64F "u," // total
- "%" I64F "u" // largest
- ,
- recs[segtype_free].total,
- recs[segtype_free].n,
- recs[segtype_free].largest,
- recs[segtype_heap].total,
- recs[segtype_stack].total,
- recs[segtype_stack].n,
- recs[segtype_data].total,
- recs[segtype_data].n,
- recs[segtype_data].largest,
- recs[segtype_libdata].total,
- recs[segtype_qlibdata].total,
- recs[segtype_qlibdata].largest,
- recs[segtype_libcode].total,
- recs[segtype_qlibcode].total,
- recs[segtype_qlibcode].largest
- );
- if (printsummary) {
- if (useprintf)
- printf("%s\n%s\n",PROCMAPHEADER,tln.str());
- else {
- PROGLOG("%s",PROCMAPHEADER);
- PROGLOG("%s",tln.str());
- }
- }
- }
- }
- #ifdef _WIN32
- // stubs
- void PrintMemoryReport(bool full)
- {
- StringBuffer s;
- getSystemTraceInfo(s,PerfMonProcMem);
- MLOG("%s",s.str());
- }
- #else
- void PrintMemoryReport(bool full)
- {
- // may be very close to oom so protect against re-entry
- static int recurse=0;
- if (recurse++==0) {
- try {
- printProcMap("/proc/self/maps",full,true,NULL,NULL,false);
- }
- catch (IException *e) {
- e->Release();
- }
- catch (...) {
- }
- try {
- PROGLOG("/proc/meminfo:");
- CProcReader reader("/proc/meminfo",NULL,0);
- reader.dump(false);
- }
- catch (IException *e) {
- e->Release();
- }
- catch (...) {
- }
- try {
- PROGLOG("/proc/self/status:");
- CProcReader reader("/proc/self/status",NULL,0);
- reader.dump(false);
- }
- catch (IException *e) {
- e->Release();
- }
- catch (...) {
- }
- try {
- StringBuffer s;
- getSystemTraceInfo(s,PerfMonProcMem);
- MLOG("%s",s.str());
- PROGLOG("===============================================================");
- }
- catch (IException *e) {
- e->Release();
- }
- catch (...) {
- }
- }
- recurse--;
- }
- #endif
- bool areTransparentHugePagesEnabled(HugePageMode mode)
- {
- return (mode != HugePageMode::Never) && (mode != HugePageMode::Unknown);
- }
- HugePageMode queryTransparentHugePagesMode()
- {
- #ifdef __linux__
- StringBuffer contents;
- try
- {
- contents.loadFile("/sys/kernel/mm/transparent_hugepage/enabled");
- if (strstr(contents.str(), "[never]"))
- return HugePageMode::Never;
- if (strstr(contents.str(), "[madvise]"))
- return HugePageMode::Madvise;
- if (strstr(contents.str(), "[always]"))
- return HugePageMode::Always;
- }
- catch (IException * e)
- {
- e->Release();
- }
- return HugePageMode::Unknown;
- #endif
- return HugePageMode::Never;
- }
- memsize_t getHugePageSize()
- {
- #ifdef __linux__
- StringBuffer contents;
- try
- {
- //Search for an entry Hugepagesize: xxxx kB
- const char * const tag = "Hugepagesize:";
- contents.loadFile("/proc/meminfo");
- const char * hugepage = strstr(contents.str(), tag);
- if (hugepage)
- {
- const char * next = hugepage + strlen(tag);
- char * end;
- memsize_t size = strtoul(next, &end, 10);
- if (strncmp(end, " kB", 3) == 0)
- return size * 0x400;
- }
- }
- catch (IException * e)
- {
- e->Release();
- }
- #endif
- return 0x200000; // Default for an x86 system
- }
- //===========================================================================
- #ifdef LEAK_CHECK
- #ifdef _WIN32
- LeakChecker::LeakChecker(const char * _title) : title(_title)
- {
- _CrtMemCheckpoint(&oldMemState);
- }
- LeakChecker::~LeakChecker()
- {
- _CrtMemState newMemState, diffMemState;
- _CrtMemCheckpoint(&newMemState);
- if(_CrtMemDifference(&diffMemState, &oldMemState, &newMemState))
- {
- _RPT1(_CRT_WARN, "----- Memory leaks in '%s' -----\n", title);
- _CrtMemDumpStatistics(&diffMemState);
- _CrtMemDumpAllObjectsSince(&oldMemState);
- _RPT0(_CRT_WARN, "----- End of leaks -----\n");
- }
- }
- static char _logFile[255]; // used to hold last file name of log file for memory leak logging
- static FILE *_logHandle = NULL;
- _CRT_REPORT_HOOK oldReport;
- static int MemoryLeakReportHook(int nRptType,char *szMsg,int *retVal)
- {
- if (szMsg && *szMsg)
- {
- if (_logHandle)
- fprintf(_logHandle, szMsg);
- if (*_logFile)
- {
- #if 1
- // this works better in VS 2008 libraries (which fault in fopen)
- int handle = _open(_logFile, O_RDWR | O_CREAT, _S_IREAD | _S_IWRITE);
- _lseek(handle,0,SEEK_END);
- _write(handle,szMsg,(unsigned)strlen(szMsg));
- _close(handle);
- #else
- FILE *handle = fopen(_logFile, "a");
- fprintf(handle, szMsg);
- fclose(handle);
- #endif
- }
- }
- if (oldReport)
- return oldReport(nRptType,szMsg,retVal);
- else
- return false;
- }
- MODULE_INIT(INIT_PRIORITY_JDEBUG1)
- {
- oldReport = _CrtSetReportHook(MemoryLeakReportHook);
- return 1;
- }
- void logLeaks (const char *logFile)
- {
- if (logFile)
- strncpy(_logFile, logFile, sizeof(_logFile));
- else
- _logFile[0] = 0;
- }
- void logLeaks (FILE *logHandle)
- {
- _logHandle = logHandle;
- }
- #else
- #endif
- #endif
- #if !defined(USING_MPATROL) && defined(WIN32) && defined(_DEBUG)
- void jlib_decl enableMemLeakChecking(bool enable)
- {
- int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
- if (enable)
- tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
- else
- tmpFlag &= ~_CRTDBG_LEAK_CHECK_DF;
- _CrtSetDbgFlag( tmpFlag );
- }
- #endif
- #if defined(_WIN32) && defined(_DEBUG)
- //#include <dbgint.h>
- const unsigned maxUnique = 10000;
- typedef struct _CrtMemBlockHeader
- {
- // Pointer to the block allocated just before this one:
- struct _CrtMemBlockHeader *pBlockHeaderNext;
- // Pointer to the block allocated just after this one:
- struct _CrtMemBlockHeader *pBlockHeaderPrev;
- char *szFileName; // File name
- int nLine; // Line number
- size_t nDataSize; // Size of user block
- int nBlockUse; // Type of block
- long lRequest; // Allocation number
- } _CrtMemBlockHeader;
- int compareFile(_CrtMemBlockHeader * left, _CrtMemBlockHeader * right)
- {
- int compare;
- if (left->szFileName && right->szFileName)
- compare = strcmp(left->szFileName, right->szFileName);
- else if (left->szFileName)
- compare = -1;
- else if (right->szFileName)
- compare = +1;
- else
- compare = 0;
- return compare;
- }
- int compareLocation(_CrtMemBlockHeader * left, _CrtMemBlockHeader * right)
- {
- int compare = compareFile(left, right);
- if (compare != 0)
- return compare;
- return left->nLine - right->nLine;
- }
- int compareBlocks(_CrtMemBlockHeader * left, _CrtMemBlockHeader * right)
- {
- int compare = compareLocation(left, right);
- if (compare != 0)
- return compare;
- return (int)(right->nDataSize - left->nDataSize);
- }
- void addLocation(unsigned & numUnique, _CrtMemBlockHeader * * locations, unsigned * counts, _CrtMemBlockHeader * search)
- {
- int left = 0;
- int right = numUnique;
- while (left < right)
- {
- int mid = (left + right) >> 1;
- int cmp = compareBlocks(search, locations[mid]);
- if (cmp < 0)
- right = mid;
- else if (cmp > 0)
- left = mid+1;
- else
- {
- //Save the lowest allocation number (so quicker to set a subsequent breakpoint)
- if (search->lRequest < locations[mid]->lRequest)
- locations[mid] = search;
- counts[mid]++;
- return;
- }
- }
- if (numUnique != maxUnique)
- {
- assertex(left == right);
- memmove(locations + left+1, locations + left, (numUnique-left)*sizeof(*locations));
- memmove(counts + left+1, counts + left, (numUnique-left)*sizeof(*counts));
- locations[left] = search;
- counts[left] = 1;
- numUnique++;
- }
- else
- counts[maxUnique]++;
- }
- unsigned dumpMemory(unsigned lenTarget, char * target, unsigned lenSrc, const void * ptr)
- {
- if (lenSrc > lenTarget)
- lenSrc = lenTarget;
- const char * src = (const char *)ptr;
- for (unsigned i=0; i < lenSrc; i++)
- {
- byte next = src[i];
- target[i] = (next >= 0x20 && next <= 0x7e) ? next : '.';
- }
- return lenSrc;
- }
- void printAllocationSummary()
- {
- _CrtMemState state;
- _CrtMemCheckpoint(&state);
- unsigned numUnique = 0;
- _CrtMemBlockHeader * locations[maxUnique+1];
- unsigned counts[maxUnique+1];
- _clear(counts);
- unsigned __int64 totalFree = 0;
- unsigned __int64 totalAllocated = 0;
- //Walk the heap, keeping a tally of (filename, line, size)->count
- _CrtMemBlockHeader * cur;
- for (cur = state.pBlockHeader; cur; cur=cur->pBlockHeaderNext)
- {
- switch (cur->nBlockUse)
- {
- case _NORMAL_BLOCK:
- {
- addLocation(numUnique, locations, counts, cur);
- totalAllocated += cur->nDataSize;
- break;
- }
- case _FREE_BLOCK:
- totalFree += cur->nDataSize;
- break;
- }
- }
- PROGLOG("%d Unique allocations by <filename>(line)@size", numUnique);
- for (unsigned i2 = 0; i2 < numUnique; i2++)
- {
- _CrtMemBlockHeader * display = locations[i2];
- //char tempBuffer[16];
- //unsigned len = dumpMemory(sizeof(tempBuffer), tempBuffer, display->nDataSize,
- PROGLOG("%s(%d) %d:%d {%ld} = %d", display->szFileName ? display->szFileName : "<unknown>", display->nLine, display->nDataSize, counts[i2], display->lRequest, display->nDataSize * counts[i2]);
- }
- PROGLOG("Ungrouped: %d Total %" I64F "d", counts[maxUnique], totalAllocated);
- PROGLOG("Summary by location");
- for (unsigned iSummary2 = 0; iSummary2 < numUnique; )
- {
- _CrtMemBlockHeader * display = locations[iSummary2];
- unsigned count = counts[iSummary2];
- unsigned __int64 size = count * display->nDataSize;
- for (iSummary2++; iSummary2 < numUnique; iSummary2++)
- {
- _CrtMemBlockHeader * next = locations[iSummary2];
- if (compareLocation(display, next) != 0)
- break;
- count += counts[iSummary2];
- size += (counts[iSummary2] * next->nDataSize);
- }
- PROGLOG("%s(%d) %d = %d", display->szFileName ? display->szFileName : "<unknown>", display->nLine, count, size);
- }
- PROGLOG("Summary by source");
- for (unsigned iSummary2 = 0; iSummary2 < numUnique; )
- {
- _CrtMemBlockHeader * display = locations[iSummary2];
- unsigned count = counts[iSummary2];
- unsigned __int64 size = count * display->nDataSize;
- for (iSummary2++; iSummary2 < numUnique; iSummary2++)
- {
- _CrtMemBlockHeader * next = locations[iSummary2];
- if (compareFile(display, next) != 0)
- break;
- count += counts[iSummary2];
- size += (counts[iSummary2] * next->nDataSize);
- }
- PROGLOG("%s %d = %d", display->szFileName ? display->szFileName : "<unknown>", count, size);
- }
- }
- #else
- void printAllocationSummary()
- {
- }
- #endif
- #ifdef _USE_MALLOC_HOOK
- // Note memory hooks should not be enabled for release (as not re-entrant in linux)
- static CriticalSection hookSect;
- #ifdef __linux__
- static void *(*old_malloc_hook)(size_t, const void *);
- static void (*old_free_hook)(void *, const void *);
- static void *(*old_realloc_hook)(void *, size_t, const void *);
- static void * jlib_malloc_hook (size_t size, const void *caller) ;
- static void jlib_free_hook (void *ptr, const void *caller);
- static void *jlib_realloc_hook (void *ptr, size_t size, const void *caller);
- static int jlib_hooknest = 0; // this *shouldn't* really be needed
- inline void restore_malloc_hooks()
- {
- if (--jlib_hooknest==0) {
- __malloc_hook = old_malloc_hook;
- __realloc_hook = old_realloc_hook;
- __free_hook = old_free_hook;
- }
- }
- inline void set_malloc_hooks()
- {
- assertex(jlib_hooknest==0);
- old_malloc_hook = __malloc_hook;
- old_free_hook = __free_hook;
- old_realloc_hook = __realloc_hook;
- __malloc_hook = jlib_malloc_hook;
- __free_hook = jlib_free_hook;
- __realloc_hook = jlib_realloc_hook;
- jlib_hooknest = 1;
- }
- inline void reset_malloc_hooks()
- {
- if (jlib_hooknest++==0) {
- __malloc_hook = jlib_malloc_hook;
- __free_hook = jlib_free_hook;
- __realloc_hook = jlib_realloc_hook;
- }
- }
- inline void incCount(unsigned sz,bool inc)
- {
- int i=0;
- size32_t s=sz;
- while (s) {
- s /= 2;
- i++;
- }
- if (inc)
- memArea[i] += sz;
- else
- memArea[i] -= sz;
- }
- void * jlib_malloc_hook (size_t size, const void *caller)
- {
- CriticalBlock block(hookSect);
- void *res;
- restore_malloc_hooks();
- res = malloc (size);
- if (res) {
- size = malloc_usable_size(res);
- totalMem+=size;
- if (totalMem>hwmTotalMem) {
- if (hwmTotalMem/(100*0x100000)!=totalMem/(100*0x100000)) {
- PrintStackReport();
- PROGLOG("TOTALMEM(%" I64F "d): malloc %u",totalMem,(unsigned)size);
- }
- hwmTotalMem = totalMem;
- }
- }
- else
- size = 0;
- incCount(size,true);
- if (size>REPORT_LARGER_BLOCK_THAN) {
- PrintStackReport();
- PROGLOG("LARGEALLOC(%u): %p",(unsigned)size,res);
- }
- reset_malloc_hooks();
- return res;
- }
- void jlib_free_hook (void *ptr, const void *caller)
- {
- if (!ptr)
- return;
- CriticalBlock block(hookSect);
- restore_malloc_hooks();
- size32_t sz = malloc_usable_size(ptr);
- free (ptr);
- totalMem -= sz;
- incCount(sz,false);
- if (sz>REPORT_LARGER_BLOCK_THAN) {
- PROGLOG("LARGEFREE(%u): %p",(unsigned)sz,ptr);
- }
- reset_malloc_hooks();
- }
- void *jlib_realloc_hook (void *ptr, size_t size, const void *caller)
- {
- CriticalBlock block(hookSect);
- restore_malloc_hooks();
- size32_t oldsz = ptr?malloc_usable_size(ptr):0;
- void *res = realloc (ptr,size);
- if (res) {
- size = malloc_usable_size(res);
- totalMem += size;
- }
- else
- size = 0;
- totalMem -= oldsz;
- if (totalMem>hwmTotalMem) {
- if (hwmTotalMem/(100*0x100000)!=totalMem/(100*0x100000)) {
- PrintStackReport();
- PROGLOG("TOTALMEM(%" I64F "d): realloc %u %u",totalMem,(unsigned)oldsz,(unsigned)size);
- }
- hwmTotalMem = totalMem;
- }
- incCount(size,true);
- incCount(oldsz,false);
- if ((size>REPORT_LARGER_BLOCK_THAN)||(oldsz>REPORT_LARGER_BLOCK_THAN)) {
- if (size>oldsz) {
- PrintStackReport();
- PROGLOG("LARGEREALLOC_UP(%u,%u): %p %p",(unsigned)oldsz,(unsigned)size,ptr,res);
- }
- else {
- PROGLOG("LARGEREALLOC_DN(%u,%u): %p %p",(unsigned)oldsz,(unsigned)size,ptr,res);
- }
- }
- reset_malloc_hooks();
- return res;
- }
- void jlib_decl jlib_init_hook()
- {
- set_malloc_hooks();
- }
- __int64 jlib_decl setAllocHook(bool on,bool clear)
- {
- CriticalBlock block(hookSect);
- __int64 ret = totalMem;
- if (clear) {
- totalMem = 0;
- hwmTotalMem = 0;
- }
- if (on) {
- if (jlib_hooknest==0)
- set_malloc_hooks();
- }
- else {
- while (jlib_hooknest) {
- restore_malloc_hooks();
- //printf("Total = %d bytes\n",totalMem);
- }
- }
- return ret;
- }
- unsigned jlib_decl setAllocHook(bool on)
- {
- // bwd compatible - should use above version in preference
- CriticalBlock block(hookSect);
- if (on) {
- if (jlib_hooknest==0) {
- set_malloc_hooks();
- totalMem = 0;
- hwmTotalMem = 0;
- }
- }
- else {
- while (jlib_hooknest) {
- restore_malloc_hooks();
- //printf("Total = %d bytes\n",totalMem);
- }
- }
- return (unsigned)totalMem;
- }
- #else // windows
- static _CRT_ALLOC_HOOK oldHook = NULL;
- static int allocHook( int allocType, void *userData, size_t size, int nBlockUse,
- long requestNumber, const unsigned char *filename, int lineNumber)
- {
- CriticalBlock block(hookSect);
- if ( nBlockUse == _CRT_BLOCK ) // Ignore internal C runtime library allocations
- return TRUE;
- static bool recurse = false;
- if (recurse)
- return TRUE;
- recurse = true;
- char *operation[] = { "", "allocating", "re-allocating", "freeing" };
- char *blockType[] = { "Free", "Normal", "CRT", "Ignore", "Client" };
- switch (allocType) {
- case _HOOK_REALLOC:
- if (userData==NULL)
- printf("no data on realloc\n");
- else
- totalMem-=_msize(userData);
- // fall through
- case _HOOK_ALLOC:
- totalMem+=size;
- break;
- case _HOOK_FREE:
- if (userData)
- totalMem-=_msize(userData);
- break;
- }
- // printf( "Memory operation in %s, line %d: %s a %d-byte '%s' block (#%ld)\n",
- // filename, lineNumber, operation[allocType], size,
- // blockType[nBlockUse], requestNumber );
- recurse = false;
- return TRUE; // Allow the memory operation to proceed
- }
- unsigned jlib_decl setAllocHook(bool on)
- {
- CriticalBlock block(hookSect);
- if (on) {
- if (oldHook==NULL) {
- oldHook = _CrtSetAllocHook( allocHook );
- totalMem = 0;
- }
- }
- else {
- if (oldHook!=NULL)
- _CrtSetAllocHook( oldHook );
- oldHook = NULL;
- //printf("Total = %d bytes\n",totalMem);
- }
- return (unsigned)totalMem; // return unsigned for bwd compat
- }
- #endif
- __int64 getTotalMem()
- {
- return totalMem;
- }
- #else // release
- unsigned jlib_decl setAllocHook(bool on __attribute__((unused)))
- {
- return 0;
- }
- __int64 jlib_decl setAllocHook(bool on __attribute__((unused)), bool clear __attribute__((unused)))
- {
- return 0;
- }
- __int64 jlib_decl getTotalMem()
- {
- return 0;
- }
- void jlib_decl jlib_init_hook()
- {
- }
- #endif
- class UserMetricMsgHandler : public CInterface, implements ILogMsgHandler, implements IUserMetric
- {
- mutable unsigned __int64 counter;
- StringAttr metricName;
- StringAttr regex;
- Owned<ILogMsgFilter> regexFilter;
- public:
- virtual void Link(void) const { CInterface::Link(); }
- virtual bool Release(void) const
- {
- if (CInterface::Release())
- return true;
- if (!IsShared())
- {
- queryLogMsgManager()->removeMonitor(const_cast<UserMetricMsgHandler *>(this)); // removeMonitor should take a const param really
- }
- return false;
- }
- UserMetricMsgHandler(const char *_name, const char *_regex) : metricName(_name), regex(_regex)
- {
- counter = 0;
- regexFilter.setown(getRegexLogMsgFilter(regex, true));
- queryLogMsgManager()->addMonitor(this, regexFilter);
- }
- // interface ILogMsgHandler
- virtual void handleMessage(const LogMsg & msg __attribute__((unused))) { counter++; }
- virtual bool needsPrep() const { return false; }
- virtual void prep() {}
- virtual unsigned queryMessageFields() const { return MSGFIELD_detail; }
- virtual void setMessageFields(unsigned _fields __attribute__((unused)) = MSGFIELD_all) {}
- virtual void addToPTree(IPropertyTree * parent __attribute__((unused))) const {}
- virtual int flush() { return 0; }
- virtual bool getLogName(StringBuffer &name __attribute__((unused))) const { return false; }
- virtual offset_t getLogPosition(StringBuffer &logFileName __attribute__((unused))) const { return 0; };
- // interface IUserMetric
- virtual unsigned __int64 queryCount() const { return counter; }
- virtual const char *queryName() const { return metricName; }
- virtual const char *queryMatchString() const { return regex; }
- virtual void inc() { counter++; }
- virtual void reset() { counter = 0; }
- };
- jlib_decl IUserMetric *createUserMetric(const char *name, const char *matchString)
- {
- return new UserMetricMsgHandler(name, matchString);
- }
- jlib_decl bool printProcessHandles(unsigned pid)
- {
- #if defined(__linux__)
- StringBuffer curFilePathSB("/proc/");
- if (pid)
- curFilePathSB.append(pid);
- else
- curFilePathSB.append("self");
- curFilePathSB.append("/fd/");
- size32_t tailPos = curFilePathSB.length();
- Owned<IFile> fdDir = createIFile(curFilePathSB);
- if (!fdDir)
- {
- WARNLOG("Failed to create IFile for %s", curFilePathSB.str());
- return false;
- }
- Owned<IDirectoryIterator> dirIter = fdDir->directoryFiles();
- StringBuffer linkedFileNameSB, curFileNameSB;
- char *linkedFileName = linkedFileNameSB.reserveTruncate(PATH_MAX);
- ForEach(*dirIter)
- {
- dirIter->getName(curFileNameSB.clear());
- curFilePathSB.setLength(tailPos);
- curFilePathSB.append(curFileNameSB);
- struct stat st;
- int err = lstat(curFilePathSB, &st);
- if (0 == err)
- {
- ssize_t sz = readlink(curFilePathSB, linkedFileName, PATH_MAX-1);
- if (-1 != sz)
- {
- linkedFileNameSB.setLength(sz);
- DBGLOG("%s -> %s", curFileNameSB.str(), linkedFileNameSB.str());
- }
- }
- else
- {
- Owned<IException> e = makeErrnoExceptionV(errno, "Failed: err=%d", err);
- EXCLOG(e, nullptr);
- }
- }
- #else
- // JCSMORE - other OS implementations
- #endif
- return true;
- }
- jlib_decl bool printLsOf(unsigned pid)
- {
- #if defined(__linux__)
- if (!pid)
- pid = getpid();
- // Use lsof to output handles of files and sockets
- VStringBuffer cmd("lsof -n -P -d '^mem,^rtd,^txt,^cwd' -f -a -p %u", pid);
- Owned<IPipeProcess> pipe = createPipeProcess();
- if (!pipe->run("lsof", cmd, nullptr, false, true, false, 0, true))
- return false;
- Owned<ISimpleReadStream> stream = pipe->getOutputStream();
- Owned<IStreamLineReader> lineReader = createLineReader(stream, false);
- StringBuffer line;
- while (!lineReader->readLine(line.clear()))
- DBGLOG("%s", line.str());
- #else
- // JCSMORE - other OS implementations
- #endif
- return true;
- }
|