PNG  IHDRQgAMA a cHRMz&u0`:pQ<bKGDgmIDATxwUﹻ& ^CX(J I@ "% (** BX +*i"]j(IH{~R)[~>h{}gy)I$Ij .I$I$ʊy@}x.: $I$Ii}VZPC)I$IF ^0ʐJ$I$Q^}{"r=OzI$gRZeC.IOvH eKX $IMpxsk.쒷/&r[޳<v| .I~)@$updYRa$I |M.e JaֶpSYR6j>h%IRز if&uJ)M$I vLi=H;7UJ,],X$I1AҒJ$ XY XzI@GNҥRT)E@;]K*Mw;#5_wOn~\ DC&$(A5 RRFkvIR}l!RytRl;~^ǷJj اy뷦BZJr&ӥ8Pjw~vnv X^(I;4R=P[3]J,]ȏ~:3?[ a&e)`e*P[4]T=Cq6R[ ~ޤrXR Հg(t_HZ-Hg M$ãmL5R uk*`%C-E6/%[t X.{8P9Z.vkXŐKjgKZHg(aK9ڦmKjѺm_ \#$5,)-  61eJ,5m| r'= &ڡd%-]J on Xm|{ RҞe $eڧY XYrԮ-a7RK6h>n$5AVڴi*ֆK)mѦtmr1p| q:흺,)Oi*ֺK)ܬ֦K-5r3>0ԔHjJئEZj,%re~/z%jVMڸmrt)3]J,T K֦OvԒgii*bKiNO~%PW0=dii2tJ9Jݕ{7"I P9JKTbu,%r"6RKU}Ij2HKZXJ,妝 XYrP ެ24c%i^IK|.H,%rb:XRl1X4Pe/`x&P8Pj28Mzsx2r\zRPz4J}yP[g=L) .Q[6RjWgp FIH*-`IMRaK9TXcq*I y[jE>cw%gLRԕiFCj-ďa`#e~I j,%r,)?[gp FI˨mnWX#>mʔ XA DZf9,nKҲzIZXJ,L#kiPz4JZF,I,`61%2s $,VOϚ2/UFJfy7K> X+6 STXIeJILzMfKm LRaK9%|4p9LwJI!`NsiazĔ)%- XMq>pk$-$Q2x#N ؎-QR}ᶦHZډ)J,l#i@yn3LN`;nڔ XuX5pF)m|^0(>BHF9(cզEerJI rg7 4I@z0\JIi䵙RR0s;$s6eJ,`n 䂦0a)S)A 1eJ,堌#635RIgpNHuTH_SԕqVe ` &S)>p;S$魁eKIuX`I4춒o}`m$1":PI<[v9^\pTJjriRŭ P{#{R2,`)e-`mgj~1ϣLKam7&U\j/3mJ,`F;M'䱀 .KR#)yhTq;pcK9(q!w?uRR,n.yw*UXj#\]ɱ(qv2=RqfB#iJmmL<]Y͙#$5 uTU7ӦXR+q,`I}qL'`6Kͷ6r,]0S$- [RKR3oiRE|nӦXR.(i:LDLTJjY%o:)6rxzҒqTJjh㞦I.$YR.ʼnGZ\ֿf:%55 I˼!6dKxm4E"mG_ s? .e*?LRfK9%q#uh$)i3ULRfK9yxm܌bj84$i1U^@Wbm4uJ,ҪA>_Ij?1v32[gLRD96oTaR׿N7%L2 NT,`)7&ƝL*꽙yp_$M2#AS,`)7$rkTA29_Iye"|/0t)$n XT2`YJ;6Jx".e<`$) PI$5V4]29SRI>~=@j]lp2`K9Jaai^" Ԋ29ORI%:XV5]JmN9]H;1UC39NI%Xe78t)a;Oi Ҙ>Xt"~G>_mn:%|~ޅ_+]$o)@ǀ{hgN;IK6G&rp)T2i୦KJuv*T=TOSV>(~D>dm,I*Ɛ:R#ۙNI%D>G.n$o;+#RR!.eU˽TRI28t)1LWϚ>IJa3oFbu&:tJ*(F7y0ZR ^p'Ii L24x| XRI%ۄ>S1]Jy[zL$adB7.eh4%%누>WETf+3IR:I3Xה)3אOۦSRO'ٺ)S}"qOr[B7ϙ.edG)^ETR"RtRݜh0}LFVӦDB^k_JDj\=LS(Iv─aTeZ%eUAM-0;~˃@i|l @S4y72>sX-vA}ϛBI!ݎߨWl*)3{'Y|iSlEڻ(5KtSI$Uv02,~ԩ~x;P4ցCrO%tyn425:KMlD ^4JRxSهF_}شJTS6uj+ﷸk$eZO%G*^V2u3EMj3k%)okI]dT)URKDS 7~m@TJR~荪fT"֛L \sM -0T KfJz+nإKr L&j()[E&I ߴ>e FW_kJR|!O:5/2跌3T-'|zX ryp0JS ~^F>-2< `*%ZFP)bSn"L :)+pʷf(pO3TMW$~>@~ū:TAIsV1}S2<%ޟM?@iT ,Eūoz%i~g|`wS(]oȤ8)$ ntu`өe`6yPl IzMI{ʣzʨ )IZ2= ld:5+請M$-ї;U>_gsY$ÁN5WzWfIZ)-yuXIfp~S*IZdt;t>KūKR|$#LcԀ+2\;kJ`]YǔM1B)UbG"IRߊ<xܾӔJ0Z='Y嵤 Leveg)$znV-º^3Ւof#0Tfk^Zs[*I꯳3{)ˬW4Ւ4 OdpbZRS|*I 55#"&-IvT&/윚Ye:i$ 9{LkuRe[I~_\ؠ%>GL$iY8 9ܕ"S`kS.IlC;Ҏ4x&>u_0JLr<J2(^$5L s=MgV ~,Iju> 7r2)^=G$1:3G< `J3~&IR% 6Tx/rIj3O< ʔ&#f_yXJiގNSz; Tx(i8%#4 ~AS+IjerIUrIj362v885+IjAhK__5X%nV%Iͳ-y|7XV2v4fzo_68"S/I-qbf; LkF)KSM$ Ms>K WNV}^`-큧32ŒVؙGdu,^^m%6~Nn&͓3ŒVZMsRpfEW%IwdǀLm[7W&bIRL@Q|)* i ImsIMmKmyV`i$G+R 0tV'!V)֏28vU7͒vHꦼtxꗞT ;S}7Mf+fIRHNZUkUx5SAJㄌ9MqμAIRi|j5)o*^'<$TwI1hEU^c_j?Е$%d`z cyf,XO IJnTgA UXRD }{H}^S,P5V2\Xx`pZ|Yk:$e ~ @nWL.j+ϝYb퇪bZ BVu)u/IJ_ 1[p.p60bC >|X91P:N\!5qUB}5a5ja `ubcVxYt1N0Zzl4]7­gKj]?4ϻ *[bg$)+À*x쳀ogO$~,5 زUS9 lq3+5mgw@np1sso Ӻ=|N6 /g(Wv7U;zωM=wk,0uTg_`_P`uz?2yI!b`kĸSo+Qx%!\οe|އԁKS-s6pu_(ֿ$i++T8=eY; צP+phxWQv*|p1. ά. XRkIQYP,drZ | B%wP|S5`~́@i޾ E;Չaw{o'Q?%iL{u D?N1BD!owPHReFZ* k_-~{E9b-~P`fE{AܶBJAFO wx6Rox5 K5=WwehS8 (JClJ~ p+Fi;ŗo+:bD#g(C"wA^ r.F8L;dzdIHUX݆ϞXg )IFqem%I4dj&ppT{'{HOx( Rk6^C٫O.)3:s(۳(Z?~ٻ89zmT"PLtw䥈5&b<8GZ-Y&K?e8,`I6e(֍xb83 `rzXj)F=l($Ij 2*(F?h(/9ik:I`m#p3MgLaKjc/U#n5S# m(^)=y=đx8ŬI[U]~SцA4p$-F i(R,7Cx;X=cI>{Km\ o(Tv2vx2qiiDJN,Ҏ!1f 5quBj1!8 rDFd(!WQl,gSkL1Bxg''՞^ǘ;pQ P(c_ IRujg(Wz bs#P­rz> k c&nB=q+ؔXn#r5)co*Ũ+G?7< |PQӣ'G`uOd>%Mctz# Ԫڞ&7CaQ~N'-P.W`Oedp03C!IZcIAMPUۀ5J<\u~+{9(FbbyAeBhOSܳ1 bÈT#ŠyDžs,`5}DC-`̞%r&ڙa87QWWp6e7 Rϫ/oY ꇅ Nܶըtc!LA T7V4Jsū I-0Pxz7QNF_iZgúWkG83 0eWr9 X]㾮݁#Jˢ C}0=3ݱtBi]_ &{{[/o[~ \q鯜00٩|cD3=4B_b RYb$óBRsf&lLX#M*C_L܄:gx)WΘsGSbuL rF$9';\4Ɍq'n[%p.Q`u hNb`eCQyQ|l_C>Lb꟟3hSb #xNxSs^ 88|Mz)}:](vbۢamŖ࿥ 0)Q7@0=?^k(*J}3ibkFn HjB׻NO z x}7p 0tfDX.lwgȔhԾŲ }6g E |LkLZteu+=q\Iv0쮑)QٵpH8/2?Σo>Jvppho~f>%bMM}\//":PTc(v9v!gոQ )UfVG+! 35{=x\2+ki,y$~A1iC6#)vC5^>+gǵ@1Hy٪7u;p psϰu/S <aʸGu'tD1ԝI<pg|6j'p:tպhX{o(7v],*}6a_ wXRk,O]Lܳ~Vo45rp"N5k;m{rZbΦ${#)`(Ŵg,;j%6j.pyYT?}-kBDc3qA`NWQū20/^AZW%NQ MI.X#P#,^Ebc&?XR tAV|Y.1!؅⨉ccww>ivl(JT~ u`ٵDm q)+Ri x/x8cyFO!/*!/&,7<.N,YDŽ&ܑQF1Bz)FPʛ?5d 6`kQձ λc؎%582Y&nD_$Je4>a?! ͨ|ȎWZSsv8 j(I&yj Jb5m?HWp=g}G3#|I,5v珿] H~R3@B[☉9Ox~oMy=J;xUVoj bUsl_35t-(ՃɼRB7U!qc+x4H_Qo֮$[GO<4`&č\GOc[.[*Af%mG/ ňM/r W/Nw~B1U3J?P&Y )`ѓZ1p]^l“W#)lWZilUQu`-m|xĐ,_ƪ|9i:_{*(3Gѧ}UoD+>m_?VPۅ15&}2|/pIOʵ> GZ9cmíتmnz)yߐbD >e}:) r|@R5qVSA10C%E_'^8cR7O;6[eKePGϦX7jb}OTGO^jn*媓7nGMC t,k31Rb (vyܴʭ!iTh8~ZYZp(qsRL ?b}cŨʊGO^!rPJO15MJ[c&~Z`"ѓޔH1C&^|Ш|rʼ,AwĴ?b5)tLU)F| &g٣O]oqSUjy(x<Ϳ3 .FSkoYg2 \_#wj{u'rQ>o;%n|F*O_L"e9umDds?.fuuQbIWz |4\0 sb;OvxOSs; G%T4gFRurj(֍ڑb uԖKDu1MK{1^ q; C=6\8FR艇!%\YÔU| 88m)֓NcLve C6z;o&X x59:q61Z(T7>C?gcļxѐ Z oo-08jہ x,`' ҔOcRlf~`jj".Nv+sM_]Zk g( UOPyεx%pUh2(@il0ݽQXxppx-NS( WO+轾 nFߢ3M<;z)FBZjciu/QoF 7R¥ ZFLF~#ȣߨ^<쩡ݛкvџ))ME>ώx4m#!-m!L;vv#~Y[đKmx9.[,UFS CVkZ +ߟrY٧IZd/ioi$%͝ب_ֶX3ܫhNU ZZgk=]=bbJS[wjU()*I =ώ:}-蹞lUj:1}MWm=̛ _ ¾,8{__m{_PVK^n3esw5ӫh#$-q=A̟> ,^I}P^J$qY~Q[ Xq9{#&T.^GVj__RKpn,b=`żY@^՝;z{paVKkQXj/)y TIc&F;FBG7wg ZZDG!x r_tƢ!}i/V=M/#nB8 XxЫ ^@CR<{䤭YCN)eKOSƟa $&g[i3.C6xrOc8TI;o hH6P&L{@q6[ Gzp^71j(l`J}]e6X☉#͕ ׈$AB1Vjh㭦IRsqFBjwQ_7Xk>y"N=MB0 ,C #o6MRc0|$)ف"1!ixY<B9mx `,tA>)5ػQ?jQ?cn>YZe Tisvh# GMމȇp:ԴVuږ8ɼH]C.5C!UV;F`mbBk LTMvPʍϤj?ԯ/Qr1NB`9s"s TYsz &9S%U԰> {<ؿSMxB|H\3@!U| k']$U+> |HHMLޢ?V9iD!-@x TIî%6Z*9X@HMW#?nN ,oe6?tQwڱ.]-y':mW0#!J82qFjH -`ѓ&M0u Uγmxϵ^-_\])@0Rt.8/?ٰCY]x}=sD3ojަЫNuS%U}ԤwHH>ڗjܷ_3gN q7[q2la*ArǓԖ+p8/RGM ]jacd(JhWko6ڎbj]i5Bj3+3!\j1UZLsLTv8HHmup<>gKMJj0@H%,W΃7R) ">c, xixј^ aܖ>H[i.UIHc U1=yW\=S*GR~)AF=`&2h`DzT󑓶J+?W+}C%P:|0H܆}-<;OC[~o.$~i}~HQ TvXΈr=b}$vizL4:ȰT|4~*!oXQR6Lk+#t/g lԁߖ[Jڶ_N$k*". xsxX7jRVbAAʯKҎU3)zSNN _'s?f)6X!%ssAkʱ>qƷb hg %n ~p1REGMHH=BJiy[<5 ǁJҖgKR*倳e~HUy)Ag,K)`Vw6bRR:qL#\rclK/$sh*$ 6덤 KԖc 3Z9=Ɣ=o>X Ώ"1 )a`SJJ6k(<c e{%kϊP+SL'TcMJWRm ŏ"w)qc ef꒵i?b7b('"2r%~HUS1\<(`1Wx9=8HY9m:X18bgD1u ~|H;K-Uep,, C1 RV.MR5άh,tWO8WC$ XRVsQS]3GJ|12 [vM :k#~tH30Rf-HYݺ-`I9%lIDTm\ S{]9gOڒMNCV\G*2JRŨ;Rҏ^ڽ̱mq1Eu?To3I)y^#jJw^Ńj^vvlB_⋌P4x>0$c>K†Aļ9s_VjTt0l#m>E-,,x,-W)سo&96RE XR.6bXw+)GAEvL)͞K4$p=Ũi_ѱOjb HY/+@θH9޼]Nԥ%n{ &zjT? Ty) s^ULlb,PiTf^<À] 62R^V7)S!nllS6~͝V}-=%* ʻ>G DnK<y&>LPy7'r=Hj 9V`[c"*^8HpcO8bnU`4JȪAƋ#1_\ XϘHPRgik(~G~0DAA_2p|J묭a2\NCr]M_0 ^T%e#vD^%xy-n}-E\3aS%yN!r_{ )sAw ڼp1pEAk~v<:`'ӭ^5 ArXOI驻T (dk)_\ PuA*BY]yB"l\ey hH*tbK)3 IKZ򹞋XjN n *n>k]X_d!ryBH ]*R 0(#'7 %es9??ښFC,ՁQPjARJ\Ρw K#jahgw;2$l*) %Xq5!U᢯6Re] |0[__64ch&_}iL8KEgҎ7 M/\`|.p,~`a=BR?xܐrQ8K XR2M8f ?`sgWS%" Ԉ 7R%$ N}?QL1|-эټwIZ%pvL3Hk>,ImgW7{E xPHx73RA @RS CC !\ȟ5IXR^ZxHл$Q[ŝ40 (>+ _C >BRt<,TrT {O/H+˟Pl6 I B)/VC<6a2~(XwV4gnXR ϱ5ǀHٻ?tw똤Eyxp{#WK qG%5],(0ӈH HZ])ג=K1j&G(FbM@)%I` XRg ʔ KZG(vP,<`[ Kn^ SJRsAʠ5xՅF`0&RbV tx:EaUE/{fi2;.IAwW8/tTxAGOoN?G}l L(n`Zv?pB8K_gI+ܗ #i?ޙ.) p$utc ~DžfՈEo3l/)I-U?aԅ^jxArA ΧX}DmZ@QLےbTXGd.^|xKHR{|ΕW_h] IJ`[G9{).y) 0X YA1]qp?p_k+J*Y@HI>^?gt.06Rn ,` ?);p pSF9ZXLBJPWjgQ|&)7! HjQt<| ؅W5 x W HIzYoVMGP Hjn`+\(dNW)F+IrS[|/a`K|ͻ0Hj{R,Q=\ (F}\WR)AgSG`IsnAR=|8$}G(vC$)s FBJ?]_u XRvύ6z ŨG[36-T9HzpW̞ú Xg큽=7CufzI$)ki^qk-) 0H*N` QZkk]/tnnsI^Gu't=7$ Z;{8^jB% IItRQS7[ϭ3 $_OQJ`7!]W"W,)Iy W AJA;KWG`IY{8k$I$^%9.^(`N|LJ%@$I}ֽp=FB*xN=gI?Q{٥4B)mw $Igc~dZ@G9K X?7)aK%݅K$IZ-`IpC U6$I\0>!9k} Xa IIS0H$I H ?1R.Чj:4~Rw@p$IrA*u}WjWFPJ$I➓/6#! LӾ+ X36x8J |+L;v$Io4301R20M I$-E}@,pS^ޟR[/s¹'0H$IKyfŸfVOπFT*a$I>He~VY/3R/)>d$I>28`Cjw,n@FU*9ttf$I~<;=/4RD~@ X-ѕzἱI$: ԍR a@b X{+Qxuq$IЛzo /~3\8ڒ4BN7$IҀj V]n18H$IYFBj3̵̚ja pp $Is/3R Ӻ-Yj+L;.0ŔI$Av? #!5"aʄj}UKmɽH$IjCYs?h$IDl843.v}m7UiI=&=0Lg0$I4: embe` eQbm0u? $IT!Sƍ'-sv)s#C0:XB2a w I$zbww{."pPzO =Ɔ\[ o($Iaw]`E).Kvi:L*#gР7[$IyGPI=@R 4yR~̮´cg I$I/<tPͽ hDgo 94Z^k盇΄8I56^W$I^0̜N?4*H`237}g+hxoq)SJ@p|` $I%>-hO0eO>\ԣNߌZD6R=K ~n($I$y3D>o4b#px2$yڪtzW~a $I~?x'BwwpH$IZݑnC㧄Pc_9sO gwJ=l1:mKB>Ab<4Lp$Ib o1ZQ@85b̍ S'F,Fe,^I$IjEdù{l4 8Ys_s Z8.x m"+{~?q,Z D!I$ϻ'|XhB)=…']M>5 rgotԎ 獽PH$IjIPhh)n#cÔqA'ug5qwU&rF|1E%I$%]!'3AFD/;Ck_`9 v!ٴtPV;x`'*bQa w I$Ix5 FC3D_~A_#O݆DvV?<qw+I$I{=Z8".#RIYyjǪ=fDl9%M,a8$I$Ywi[7ݍFe$s1ՋBVA?`]#!oz4zjLJo8$I$%@3jAa4(o ;p,,dya=F9ً[LSPH$IJYЉ+3> 5"39aZ<ñh!{TpBGkj}Sp $IlvF.F$I z< '\K*qq.f<2Y!S"-\I$IYwčjF$ w9 \ߪB.1v!Ʊ?+r:^!I$BϹB H"B;L'G[ 4U#5>੐)|#o0aڱ$I>}k&1`U#V?YsV x>{t1[I~D&(I$I/{H0fw"q"y%4 IXyE~M3 8XψL}qE$I[> nD?~sf ]o΁ cT6"?'_Ἣ $I>~.f|'!N?⟩0G KkXZE]ޡ;/&?k OۘH$IRۀwXӨ<7@PnS04aӶp.:@\IWQJ6sS%I$e5ڑv`3:x';wq_vpgHyXZ 3gЂ7{{EuԹn±}$I$8t;b|591nءQ"P6O5i }iR̈́%Q̄p!I䮢]O{H$IRϻ9s֧ a=`- aB\X0"+5"C1Hb?߮3x3&gşggl_hZ^,`5?ߎvĸ%̀M!OZC2#0x LJ0 Gw$I$I}<{Eb+y;iI,`ܚF:5ܛA8-O-|8K7s|#Z8a&><a&/VtbtLʌI$I$I$I$I$I$IRjDD%tEXtdate:create2022-05-31T04:40:26+00:00!Î%tEXtdate:modify2022-05-31T04:40:26+00:00|{2IENDB`Mini Shell

HOME


Mini Shell 1.0
DIR:/bin/
Upload File :
Current File : //bin/niceload
#!/usr/bin/perl -w

# Copyright (C) 2004-2010 Ole Tange, http://ole.tange.dk
#
# Copyright (C) 2010-2024 Ole Tange, http://ole.tange.dk and
# Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>
# or write to the Free Software Foundation, Inc., 51 Franklin St,
# Fifth Floor, Boston, MA 02110-1301 USA
#
# SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
# SPDX-License-Identifier: GPL-3.0-or-later

use strict;
use Getopt::Long;
$Global::progname="niceload";
$Global::version = 20241222;
Getopt::Long::Configure("bundling","require_order");
get_options_from_array(\@ARGV) || die_usage();
if($opt::version) {
    version();
    exit 0;
}
if($opt::help) {
    help();
    exit 0;
}
if($opt::factor and $opt::suspend) {
    # You cannot have --suspend and --factor
    help();
    exit;
}

if(not (defined $opt::start_io or defined $opt::run_io
	or defined $opt::start_load or defined $opt::run_load
	or defined $opt::start_mem or defined $opt::run_mem
	or defined $opt::start_noswap or defined $opt::run_noswap
	or defined $opt::io or defined $opt::load
	or defined $opt::mem or defined $opt::noswap)) {
    # Default is --runload=1
    $opt::run_load = 1;
}

if(not defined $opt::start_io) { $opt::start_io = $opt::io; }
if(not defined $opt::run_io) { $opt::run_io = $opt::io; }
if(not defined $opt::start_load) { $opt::start_load = $opt::load; }
if(not defined $opt::run_load) { $opt::run_load = $opt::load; }
if(not defined $opt::start_mem) { $opt::start_mem = $opt::mem; }
if(not defined $opt::run_mem) { $opt::run_mem = $opt::mem; }
if(not defined $opt::start_noswap) { $opt::start_noswap = $opt::noswap; }
if(not defined $opt::run_noswap) { $opt::run_noswap = $opt::noswap; }

if(defined $opt::load) { multiply_binary_prefix($opt::load); }
if(defined $opt::baseline) { collect_net_baseline(); }

my $limit = Limit->new();
my $process = Process->new($opt::nice,@ARGV);
$::exitstatus = 0;
if(@opt::prg) {
    # Find all pids of prg
    my($children_of, $parent_of, $name_of) = pid_table();
    my @exact_name_pids;
    my @substr_name_pids;
    for my $name (@opt::prg) {
	push(@exact_name_pids,
	     grep { index($name_of->{$_},$name) == 0 and $_ } keys %$name_of);
	push(@substr_name_pids,
	     grep { index($name_of->{$_},$name) != -1 and $_ } keys %$name_of);
    }
    # Remove current pid
    @exact_name_pids = grep { $_ != $$ } @exact_name_pids;
    @substr_name_pids = grep { $_ != $$ } @substr_name_pids;
    my @pids;
    if(@exact_name_pids) {
	@pids = @exact_name_pids;
    } elsif(@substr_name_pids) {
	warning("@opt::prg no exact matches. Using substrings.");
	my %name_pids;
	for(sort @substr_name_pids) {
	    # If the process has run for long, then time column will
	    # enter the name, so remove leading digits
	    $name_of->{$_} =~ s/^\d+ //;
	    # Remove arguments
	    $name_of->{$_} =~ s/ .*//;
	    push @{$name_pids{$name_of->{$_}}},$_;
	}
	warning("Niceloading",
		map { "$_ (".(join" ",sort @{$name_pids{$_}}).")" } keys %name_pids
		);
	@pids = @substr_name_pids;
    } else {
	error("@opt::prg no matches.");
	exit(1);
    }
    $process->set_pid(@pids);
    $::resume_process = $process;
    $SIG{TERM} = $SIG{INT} = \&resume;
} elsif(@opt::pid) {
    # Support --pid 3567,25678
    @opt::pid = map { split /,/, $_ } @opt::pid;
    $process->set_pid(@opt::pid);
    $::resume_process = $process;
    $SIG{TERM} = $SIG{INT} = \&resume;
} elsif (@ARGV) {
    # Wait until limit is below start_limit and run_limit
    while($limit->over_start_limit()
	  or
	  ($limit->hard() and $limit->over_run_limit())) {
	$limit->sleep_for_recheck();
    }
    $process->start();
}

while($process->is_alive()) {
    if($limit->over_run_limit()) {
	$process->suspend();
	$limit->sleep_for_recheck();
	if(not $limit->hard()) {
	    $process->resume();
	    $limit->sleep_while_running();
	}
    } else {
	$process->resume();
	$limit->sleep_while_running();
    }
}

exit($::exitstatus);

{
    my %pid_parentpid_cmd;

    sub pid_table {
	# Returns:
	#   %children_of = { pid -> children of pid }
	#   %parent_of = { pid -> pid of parent }
	#   %name_of = { pid -> commandname }

       	if(not %pid_parentpid_cmd) {
	    # Filter for SysV-style `ps`
	    my $sysv = q( ps -ef | perl -ane '1..1 and /^(.*)CO?MM?A?N?D/ and $s=length $1;).
		q(s/^.{$s}//; print "@F[1,2] $_"' );
	    # Crazy msys: ' is not accepted on the cmd line, but " are treated as '
	    my $msys = q( ps -ef | perl -ane "1..1 and /^(.*)CO?MM?A?N?D/ and $s=length $1;).
		q(s/^.{$s}//; print qq{@F[1,2] $_}" );
	    # BSD-style `ps`
	    my $bsd = q(ps -o pid,ppid,command -ax);
	    %pid_parentpid_cmd =
	    (
	     'aix' => $sysv,
	     'cygwin' => $sysv,
	     'darwin' => $bsd,
	     'dec_osf' => $sysv,
	     'dragonfly' => $bsd,
	     'freebsd' => $bsd,
	     'gnu' => $sysv,
	     'hpux' => $sysv,
	     'linux' => $sysv,
	     'mirbsd' => $bsd,
	     'msys' => $msys,
	     'MSWin32' => $sysv,
	     'netbsd' => $bsd,
	     'nto' => $sysv,
	     'openbsd' => $bsd,
	     'solaris' => $sysv,
	     'svr5' => $sysv,
	     'syllable' => "echo ps not supported",
	    );
	}
	$pid_parentpid_cmd{$^O} or ::die_bug("pid_parentpid_cmd for $^O missing");

	my (@pidtable,%parent_of,%children_of,%name_of);
	# Table with pid -> children of pid
	@pidtable = `$pid_parentpid_cmd{$^O}`;
	my $p=$$;
	for (@pidtable) {
	    # must match: 24436 21224 busybox ash
	    # must match: 24436 21224 <<empty on MacOSX running cubase>>
	    #   or: perl -e 'while($0=" "){}'
	    if(/^\s*(\S+)\s+(\S+)\s+(\S+.*)/
	       or
	       $^O eq "darwin" and /^\s*(\S+)\s+(\S+)\s+()$/) {
		$parent_of{$1} = $2;
		push @{$children_of{$2}}, $1;
		$name_of{$1} = $3;
	    } else {
		::die_bug("pidtable format: $_");
	    }
	}
	return(\%children_of, \%parent_of, \%name_of);
    }
}

sub resume {
    $::resume_process->resume();
    exit(0);
}

sub status {
    my @w = @_;
    my $fh = *STDERR;
    print $fh @w;
    flush $fh;
}

sub warning {
    my @w = @_;
    my $prog = $Global::progname || "niceload";
    status(map { ($prog, ": Warning: ", $_, "\n"); } @w);
}

sub error {
    my @w = @_;
    my $prog = $Global::progname || "niceload";
    status(map { ($prog, ": Error: ", $_, "\n"); } @w);
}

sub uniq {
    # Remove duplicates and return unique values
    return keys %{{ map { $_ => 1 } @_ }};
}

sub multiply_binary_prefix {
    # Evalualte numbers with binary prefix
    # k=10^3, m=10^6, g=10^9, t=10^12, p=10^15, e=10^18, z=10^21, y=10^24
    # K=2^10, M=2^20, G=2^30, T=2^40, P=2^50, E=2^70, Z=2^80, Y=2^80
    # Ki=2^10, Mi=2^20, Gi=2^30, Ti=2^40, Pi=2^50, Ei=2^70, Zi=2^80, Yi=2^80
    # ki=2^10, mi=2^20, gi=2^30, ti=2^40, pi=2^50, ei=2^70, zi=2^80, yi=2^80
    # 13G = 13*1024*1024*1024 = 13958643712
    my $s = shift;
    $s =~ s/k/*1000/g;
    $s =~ s/M/*1000*1000/g;
    $s =~ s/G/*1000*1000*1000/g;
    $s =~ s/T/*1000*1000*1000*1000/g;
    $s =~ s/P/*1000*1000*1000*1000*1000/g;
    $s =~ s/E/*1000*1000*1000*1000*1000*1000/g;
    $s =~ s/Z/*1000*1000*1000*1000*1000*1000*1000/g;
    $s =~ s/Y/*1000*1000*1000*1000*1000*1000*1000*1000/g;
    $s =~ s/X/*1000*1000*1000*1000*1000*1000*1000*1000*1000/g;

    $s =~ s/Ki?/*1024/gi;
    $s =~ s/Mi?/*1024*1024/gi;
    $s =~ s/Gi?/*1024*1024*1024/gi;
    $s =~ s/Ti?/*1024*1024*1024*1024/gi;
    $s =~ s/Pi?/*1024*1024*1024*1024*1024/gi;
    $s =~ s/Ei?/*1024*1024*1024*1024*1024*1024/gi;
    $s =~ s/Zi?/*1024*1024*1024*1024*1024*1024*1024/gi;
    $s =~ s/Yi?/*1024*1024*1024*1024*1024*1024*1024*1024/gi;
    $s =~ s/Xi?/*1024*1024*1024*1024*1024*1024*1024*1024*1024/gi;
    $s = eval $s;
    return $s;
}

sub get_options_from_array {
    # Run GetOptions on @array
    # Returns:
    #   true if parsing worked
    #   false if parsing failed
    #   @array is changed
    my $array_ref = shift;
    # A bit of shuffling of @ARGV needed as GetOptionsFromArray is not
    # supported everywhere
    my @save_argv;
    my $this_is_ARGV = (\@::ARGV == $array_ref);
    if(not $this_is_ARGV) {
	@save_argv = @::ARGV;
	@::ARGV = @{$array_ref};
    }
    my @retval = GetOptions
	("debug|D" => \$opt::debug,
	 "factor|f=s" => \$opt::factor,
	 "hard|H" => \$opt::hard,
	 "soft|S" => \$opt::soft,
	 "sensor=s" => \$opt::sensor,

	 "si|sio|startio|start-io=s" => \$opt::start_io,
	 "ri|rio|runio|run-io=s" => \$opt::run_io,
	 "io|I=s" => \$opt::io,

	 "sl|startload|start-load=s" => \$opt::start_load,
	 "rl|runload|run-load=s" => \$opt::run_load,
	 "load|L|l=s" => \$opt::load,

	 "sm|startmem|start-mem=s" => \$opt::start_mem,
	 "rm|runmem|run-mem=s" => \$opt::run_mem,
	 "mem|M=s" => \$opt::mem,

	 "sn|startnoswap|start-noswap|start-no-swap" => \$opt::start_noswap,
	 "rn|runnoswap|run-noswap|run-no-swap" => \$opt::run_noswap,
	 "noswap|N" => \$opt::noswap,

	 "battery|B" => \$opt::battery,
	 "net" => \$opt::net,
	 "nethops=i" => \$opt::nethops,
	 "baseline" => \$opt::baseline,

	 "nice|n=i" => \$opt::nice,
	 "program|prg=s" => \@opt::prg,
	 "process|pid|p=s" => \@opt::pid,
	 "suspend|s=s" => \$opt::suspend,
	 "recheck|t=s" => \$opt::recheck,
	 "quote|q" => \$opt::quote,
	 "help|h" => \$opt::help,
	 "verbose|v" => \$opt::verbose,
	 "version|V" => \$opt::version,
	);
    if($opt::battery) {
	# niceload -l -1 --sensor \
	#   'cat /sys/class/power_supply/BAT0/status \
	#    /proc/acpi/battery/BAT0/state 2>/dev/null |
	#    grep -i -q discharging; echo $?'
	$opt::sensor = ('cat /sys/class/power_supply/BAT0/status '.
			'/proc/acpi/battery/BAT0/state 2>/dev/null | '.
			'grep -i -q discharging; echo $?');
	$opt::load = -1;
    }
    if($opt::net) {
	$opt::nethops ||= 3;
    }
    if($opt::nethops) {
	# niceload -l 0.01 --sensor 'netsensor_script'
	$opt::sensor = netsensor_script($opt::nethops);
	$opt::load ||= 0.01;
    }
    if(not $this_is_ARGV) {
	@{$array_ref} = @::ARGV;
	@::ARGV = @save_argv;
    }
    return @retval;
}

sub shell_quote_scalar {
    # Quote for other shells
    my $a = $_[0];
    if(defined $a) {
	# zsh wants '=' quoted
	# Solaris sh wants ^ quoted.
	# $a =~ s/([\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\>\<\~\|\; \"\!\$\&\'\202-\377])/\\$1/g;
	# This is 1% faster than the above
	if(($a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go)
	   +
	   # quote newline as '\n'
	   ($a =~ s/[\n]/'\n'/go)) {
	    # A string was replaced
	    # No need to test for "" or \0
	} elsif($a eq "") {
	    $a = "''";
	} elsif($a eq "\0") {
	    $a = "";
	}
    }
    return $a;
}

sub die_usage {
    help();
    exit 1;
}


sub help {
    print q{
Usage:
   niceload [-v] [-n niceness] [-L loadavg] [-I io] [-N] [-M mem]
            [-s suspend_sec|-f factor] [-H] [-S]
            command or -p pid
};
}


sub die_bug {
    my $bugid = shift;
    print STDERR
	("$Global::progname: This should not happen. You have found a bug.\n",
	 "Please contact <parallel\@gnu.org> and include:\n",
	 "* The version number: $Global::version\n",
	 "* The bugid: $bugid\n",
	 "* The command line being run\n",
	 "* The files being read (put the files on a webserver if they are big)\n",
	 "\n",
	 "If you get the error on smaller/fewer files, please include those instead.\n");
    exit(255);
}

sub now {
    # Returns time since epoch as in seconds with 3 decimals
    # Uses:
    #   @Global::use
    # Returns:
    #   $time = time now with millisecond accuracy
    if(not $Global::use{"Time::HiRes"}) {
	if(eval "use Time::HiRes qw ( time );") {
	    eval "sub TimeHiRestime { return Time::HiRes::time };";
	} else {
	    eval "sub TimeHiRestime { return time() };";
	}
	$Global::use{"Time::HiRes"} = 1;
    }

    return (int(TimeHiRestime()*1000))/1000;
}

sub usleep {
    # Sleep this many milliseconds.
    my $ms = shift;
    ::debug("Sleeping ",$ms," millisecs\n");
    my $start = now();
    my $now;
    do {
	# Something makes 'select' wake up too early
	# when using --sensor
	select(undef, undef, undef, $ms/1000);
	$now = now();
    } while($now < $start + $ms/1000);
}

sub debug {
    if($opt::debug) {
	print STDERR @_;
    }
}


sub my_dump {
    # Returns:
    #   ascii expression of object if Data::Dump(er) is installed
    #   error code otherwise
    my @dump_this = (@_);
    eval "use Data::Dump qw(dump);";
    if ($@) {
        # Data::Dump not installed
        eval "use Data::Dumper;";
        if ($@) {
            my $err =  "Neither Data::Dump nor Data::Dumper is installed\n".
                "Not dumping output\n";
            print STDERR $err;
            return $err;
        } else {
            return Dumper(@dump_this);
        }
    } else {
        eval "use Data::Dump qw(dump);";
        return (Data::Dump::dump(@dump_this));
    }
}


sub version {
    # Returns: N/A
    print join("\n",
	       "GNU $Global::progname $Global::version",
	       "Copyright (C) 2004,2005,2006,2007,2008,2009 Ole Tange",
	       "Copyright (C) 2010,2011 Ole Tange and Free Software Foundation, Inc.",
	       "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>",
	       "This is free software: you are free to change and redistribute it.",
	       "GNU $Global::progname comes with no warranty.",
	       "",
	       "Web site: http://www.gnu.org/software/parallel\n"
	);
}


sub max {
    # Returns:
    #   Maximum value of array
    my $max;
    for (@_) {
        # Skip undefs
        defined $_ or next;
        defined $max or do { $max = $_; next; }; # Set $_ to the first non-undef
        $max = ($max > $_) ? $max : $_;
    }
    return $max;
}

sub min {
    # Returns:
    #   Minimum value of array
    my $min;
    for (@_) {
        # Skip undefs
        defined $_ or next;
        defined $min or do { $min = $_; next; }; # Set $_ to the first non-undef
        $min = ($min < $_) ? $min : $_;
    }
    return $min;
}

sub collect_net_baseline {
    # Collect what a normal (unloaded) net connection looks line
}


sub netsensor_script {
    # Script for --sensor when using --net
    my $hops = shift;
    my $perlscript = q{
	use Net::Traceroute;
	use Net::Ping;

	my $medtrc = MedianTraceroute->new(shift);
	$medtrc->set_remedian($medtrc->ping());
	$medtrc->set_remedian($medtrc->ping());
	while(1) {
	    my $ms = $medtrc->ping();
	    my $m = $medtrc->remedian();
	    if($m*1.5 < $ms) {
		# Bad 1 = median*1.5 < current latency
	    } else {
		# OK 0 = median*1.5 > current latency
		$medtrc->set_remedian($ms);
	    }
	    printf("%d\n",$m*1.5 < $ms);
	    sleep(1);
	}

	package MedianTraceroute;

	sub new {
	    my $class = shift;
	    my $hop = shift;
	    # Find router
	    my $tr = Net::Traceroute->new(host => "8.8.8.8",
					  max_ttl => $hop);
	    if($tr->found) {
		$host = $tr->hop_query_host($hop, 0);
	    } else {
		# ns1.censurfridns.dk
		$tr = Net::Traceroute->new(host => "89.233.43.71",
					   max_ttl => $hop);
		if($tr->found) {
		    $host = $tr->hop_query_host($hop, 0);
		} else {
		    die("Cannot traceroute to 8.8.8.8 and 89.233.43.71");
		}
	    }
	    my $p = Net::Ping->new();
	    $p->hires();

	    return bless {
		'hop' => $hop,
		'host' => $host,
		'pinger' => $p,
		'remedian_idx' => 0,
		'remedian_arr' => [],
		'remedian' => undef,
	    }, ref($class) || $class;
	}

	sub ping {
	    my $self = shift;
	    for(1..3) {
		# Ping should never take longer than 5.5 sec
		my ($ret, $duration, $ip) =
		    $self->{'pinger'}->ping($self->{'host'}, 5.5);
		if($ret) {
		    return $duration;
		}
	    }
	    warn("Ping failed 3 times.");
	}

	sub remedian {
	    my $self = shift;
	    return $self->{'remedian'};
	}

	sub set_remedian {
	    # Set median of the last 999^3 (=997002999) values using Remedian
	    #
	    # Rousseeuw, Peter J., and Gilbert W. Bassett Jr. "The remedian: A
	    # robust averaging method for large data sets." Journal of the
	    # American Statistical Association 85.409 (1990): 97-104.
	    my $self = shift;
	    my $val = shift;
	    my $i = $self->{'remedian_idx'}++;
	    my $rref = $self->{'remedian_arr'};
	    $rref->[0][$i%999] = $val;
	    $rref->[1][$i/999%999] = (sort @{$rref->[0]})[$#{$rref->[0]}/2];
	    $rref->[2][$i/999/999%999] = (sort @{$rref->[1]})[$#{$rref->[1]}/2];
	    $self->{'remedian'} = (sort @{$rref->[2]})[$#{$rref->[2]}/2];
	}
    };
    return "perl -e ".shell_quote_scalar($perlscript)." $hops";
}


package Process;

sub new {
    my $class = shift;
    my $nice = shift;
    my @ARGV = @_;
    if($nice) {
	unshift(@ARGV, "nice", "-n", $nice);
    }
    return bless {
	'running' => 0, # Is the process running now?
	'command' => [@ARGV],
    }, ref($class) || $class;
}

sub pgrp {
    my $self = shift;
    my @pgrp;
    if(not $self->{'pgrp'}) {
	for(@{$self->{'pids'}}) {
	    push @pgrp,-getpgrp($_);
	}
	@pgrp = ::uniq(@pgrp);
	@{$self->{'pgrp'}} = @pgrp;
    }
    return @{$self->{'pgrp'}};
}

sub set_pid {
    my $self = shift;
    push(@{$self->{'pids'}},@_);
    $self->{'running'} = 1;
    $::exitstatus = 0;
}

sub start {
    # Start the program
    my $self = shift;
    ::debug("Starting @{$self->{'command'}}\n");
    $self->{'running'} = 1;
    if($self->{'pid'} = fork) {
	# set signal handler to kill children if parent is killed
	push @{$self->{'pids'}}, $self->{'pid'};
	$Global::process = $self;
	$SIG{CHLD} = \&REAPER;
	$SIG{INT}=\&kill_child_INT;
	$SIG{TSTP}=\&kill_child_TSTP;
	$SIG{CONT}=\&kill_child_CONT;
 	sleep 1; # Give child time to setpgrp(0,0);
    } else {
 	setpgrp(0,0);
 	::debug("Child pid: $$, pgrp: ",getpgrp $$,"\n");
 	::debug("@{$self->{'command'}}\n");
	if($opt::quote) {
	    system(@{$self->{'command'}});
	} else {
	    system("@{$self->{'command'}}");
	}
	$::exitstatus = $? >> 8;
	$::exitsignal = $? & 127;
	::debug("Child exit $::exitstatus\n");
	exit($::exitstatus);
    }
}

use POSIX ":sys_wait_h";
use POSIX qw(:sys_wait_h);

sub REAPER {
    my $stiff;
    while (($stiff = waitpid(-1, &WNOHANG)) > 0) {
        # do something with $stiff if you want
        $::exitstatus = $? >> 8;
        $::exitsignal = $? & 127;
    }
    $SIG{CHLD} = \&REAPER;                  # install *after* calling waitpid
}


sub kill_child_CONT {
    my $self = $Global::process;
    ::debug("SIGCONT received. Killing @{$self->{'pgrp'}}\n");
    kill CONT => $self->pgrp();
}


sub kill_child_TSTP {
    my $self = $Global::process;
    ::debug("SIGTSTP received. Killing $self->{'pid'} and self ($$)\n");
    kill TSTP => $self->pgrp();
    kill STOP => -$$;
    kill STOP => $$;
}


sub kill_child_INT {
    my $self = $Global::process;
    ::debug("SIGINT received.\n");
    if(not @opt::pid) {
	::debug("Killing $self->{'pid'} Exit\n");
	kill INT => $self->pgrp();
    } else {
	::debug("Continue pids $self->{'pid'} Exit\n");
	kill CONT => $self->pgrp();
    }
    exit;
}


sub resume {
    my $self = shift;
    ::debug("Resume @{$self->{'pids'}}\n");
    if(not $self->{'running'}) {
	# - = PID group
	map { kill "CONT", -$_ } @{$self->{'pids'}};
	# If using -p it is not in a group
	map { kill "CONT", $_ } @{$self->{'pids'}};
	$self->{'running'} = 1;
    }
}


sub suspend {
    my $self = shift;
    ::debug("Suspend @{$self->{'pids'}}\n");
    if($self->{'running'}) {
	# - = PID group
	map { kill "STOP", -$_ } @{$self->{'pids'}};
	# If using -p it is not in a group
	map { kill "STOP", $_ } @{$self->{'pids'}};
	$self->{'running'} = 0;
    }
}


sub is_alive {
    # The process is dead if none of the pids exist
    my $self = shift;
    my ($exists) = 0;
    for my $pid (@{$self->{'pids'}}) {
	if(kill 0 => $pid) { $exists++ }
    }
    ::debug("is_alive: $exists\n");
    return $exists;
}


package Limit;

sub new {
    my $class = shift;
    my %limits = @_;
    my $hard = $opt::soft ? 0 : $opt::hard;
    my $runio = $opt::run_io ? ::multiply_binary_prefix($opt::run_io) : 0;
    my $startio = $opt::start_io ? ::multiply_binary_prefix($opt::start_io) : 0;
    my $runload = $opt::run_load ? ::multiply_binary_prefix($opt::run_load) : 0;
    my $startload = $opt::start_load ? ::multiply_binary_prefix($opt::start_load) : 0;
    my $runmem = $opt::run_mem ? ::multiply_binary_prefix($opt::run_mem) : 0;
    my $startmem = $opt::start_mem ? ::multiply_binary_prefix($opt::start_mem) : 0;
    my $runnoswap = $opt::run_noswap ? ::multiply_binary_prefix($opt::run_noswap) : 0;
    my $startnoswap = $opt::start_noswap ? ::multiply_binary_prefix($opt::start_noswap) : 0;
    my $recheck = $opt::recheck ? ::multiply_binary_prefix($opt::recheck) : 1; # Default
    my $runtime = $opt::suspend ? ::multiply_binary_prefix($opt::suspend) : 1; # Default

    return bless {
	'hard' => $hard,
	'recheck' => $recheck,
	'runio' => $runio,
	'startio' => $startio,
	'runload' => $runload,
	'startload' => $startload,
	'runmem' => $runmem,
	'startmem' => $startmem,
	'runnoswap' => $runnoswap,
	'startnoswap' => $startnoswap,
	'factor' => $opt::factor || 1,
	'recheck' => $recheck,
	'runtime' => $runtime,
	'over_run_limit' => 1,
	'over_start_limit' => 1,
	'verbose' => $opt::verbose,
    }, ref($class) || $class;
}


sub over_run_limit {
    my $self = shift;
    my $status = 0;
    if($self->{'runmem'}) {
	# mem should be between 0-10ish
	# 100% available => 0 (1-1)
	# 50% available => 1 (2-1)
	# 10% available => 9 (10-1)
	my $mem = $self->mem_status();
	::debug("Run memory: $self->{'runmem'}/$mem\n");
	$status += (::max(1,$self->{'runmem'}/$mem)-1);
    }
    if($self->{'runload'}) {
	# If used with other limits load should be between 0-10ish
	no warnings 'numeric';
	my $load = $self->load_status();
	if($self->{'runload'} > 0) {
	    # Stop if the load is above the limit
	    $status += ::max(0,$load - $self->{'runload'});
	} else {
	    # Stop if the load is below the limit (for sensor)
	    $status += ::max(0,-$load - $self->{'runload'});
	}
    }
    if($self->{'runnoswap'}) {
	# swap should be between 0-10ish
	# swap in or swap out or no swap = 0
	# else log(swapin*swapout)
	my $swap = $self->swap_status();
	$status += log(::max(1, $swap - $self->{'runnoswap'}));
    }
    if($self->{'runio'}) {
	my $io = $self->io_status();
	$status += ::max(0,$io - $self->{'runio'});
    }
    $self->{'over_run_limit'} = $status;
    if(not $opt::recheck) {
	$self->{'recheck'} = $self->{'factor'} * $self->{'over_run_limit'};
    }
    ::debug("over_run_limit: $status\n");
    return $self->{'over_run_limit'};
}

sub over_start_limit {
    my $self = shift;
    my $status = 0;
    if($self->{'startmem'}) {
	# mem should be between 0-10ish
	# 100% available => 0 (1-1)
	# 50% available => 1 (2-1)
	# 10% available => 9 (10-1)
	my $mem = $self->mem_status();
	::debug("Start memory: $self->{'startmem'}/$mem\n");
	$status += (::max(1,$self->{'startmem'}/$mem)-1);
    }
    if($self->{'startload'}) {
	# load should be between 0-10ish
	# 0 load => 0
	no warnings 'numeric';
	my $load = $self->load_status();
	if($self->{'startload'} > 0) {
	    # Stop if the load is above the limit
	    $status += ::max(0,$load - $self->{'startload'});
	} else {
	    # Stop if the load is below the limit (for sensor)
	    $status += ::max(0,-$load - $self->{'startload'});
	}
    }
    if($self->{'startnoswap'}) {
	# swap should be between 0-10ish
	# swap in or swap out or no swap = 0
	# else log(swapin*swapout)
	my $swap = $self->swap_status();
	$status += log(::max(1, $swap - $self->{'startnoswap'}));
    }
    if($self->{'startio'}) {
	my $io = $self->io_status();
	$status += ::max(0,$io - $self->{'startio'});
    }
    $self->{'over_start_limit'} = $status;
    if(not $opt::recheck) {
	$self->{'recheck'} = $self->{'factor'} * $self->{'over_start_limit'};
    }
    ::debug("over_start_limit: $status\n");
    return $self->{'over_start_limit'};
}


sub hard {
    my $self = shift;
    return $self->{'hard'};
}


sub verbose {
    my $self = shift;
    return $self->{'verbose'};
}


sub sleep_for_recheck {
    my $self = shift;
    if($self->{'recheck'} < 0.01) {
	# Never sleep less than 0.01 sec
	$self->{'recheck'} = 0.01;
    }
    if($self->verbose()) {
	$self->{'recheck'} = int($self->{'recheck'}*100)/100;
	print STDERR "Sleeping $self->{'recheck'}s\n";
    }
    ::debug("recheck in $self->{'recheck'}s\n");
    ::usleep(1000*$self->{'recheck'});
}


sub sleep_while_running {
    my $self = shift;
    ::debug("check in $self->{'runtime'}s\n");
    if($self->verbose()) {
	$self->{'runtime'} = int($self->{'runtime'}*100)/100;
	print STDERR "Running $self->{'runtime'}s\n";
    }
    ::usleep(1000*$self->{'runtime'});
}


sub nonblockGetLines {
    # An non-blocking filehandle read that returns an array of lines read
    # Returns:  ($eof,@lines)
    # Example: --sensor 'vmstat 1 | perl -ane '\''$|=1; 4..0 and print $F[8],"\n"'\'
    my ($fh,$timeout) = @_;

    $timeout = 0 unless defined $timeout;
    my $rfd = '';
    $::nonblockGetLines_last{$fh} = ''
        unless defined $::nonblockGetLines_last{$fh};

    vec($rfd,fileno($fh),1) = 1;
    return unless select($rfd, undef, undef, $timeout)>=0;
    # I'm not sure the following is necessary?
    return unless vec($rfd,fileno($fh),1);
    my $buf = '';
    my $n = sysread($fh,$buf,1024*1024);

    my $eof = eof($fh);
    # If we're done, make sure to send the last unfinished line
    return ($eof,$::nonblockGetLines_last{$fh}) unless $n;
    # Prepend the last unfinished line
    $buf = $::nonblockGetLines_last{$fh}.$buf;
    # And save any newly unfinished lines
    $::nonblockGetLines_last{$fh} =
        (substr($buf,-1) !~ /[\r\n]/ && $buf =~ s/([^\r\n]*)$//)
	? $1 : '';
    $buf ? ($eof,split(/\n/,$buf)) : ($eof);
}

sub read_sensor {
    my $self = shift;
    ::debug("read_sensor: ");
    my $fh = $self->{'sensor_fh'};
    if(not $fh) {
	# Start the sensor
	$self->{'sensor_pid'} =
	    open($fh, "-|", $opt::sensor) ||
	    ::die_bug("Cannot open: $opt::sensor");
	$self->{'sensor_fh'} = $fh;
    }
    # Read as much as we can (non_block)
    my ($eof,@lines) = nonblockGetLines($fh);

    # new load = last full line
    foreach my $line (@lines) {
	if(defined $line) {
	    ::debug("Pipe saw: [$line] eof=$eof\n");
	    $Global::last_sensor_reading = $line;
	}
    }
    if($eof) {
	# End of file => Restart the sensor
	close $fh;
#	waitpid($self->{'sensor_pid'},0);
	$self->{'sensor_pid'} =
	    open($fh, "-|", $opt::sensor) ||
	    ::die_bug("Cannot open: $opt::sensor");
	$self->{'sensor_fh'} = $fh;
    }

    return $Global::last_sensor_reading;
}

sub load_status {
    # Returns:
    #   loadavg or sensor measurement
    my $self = shift;

    if($opt::sensor) {
	if(not defined $self->{'load_status'} or
	   $self->{'load_status_cache_time'} + $self->{'recheck'} < time) {
	    $self->{'load_status'} = $self->read_sensor();
	    while (not defined $self->{'load_status'}) {
		sleep 1;
		$self->{'load_status'} = $self->read_sensor();
	    }
	    $self->{'load_status_cache_time'} = time - 0.001;
	}
    } else {
	# Normal load avg
	# Cache for some seconds
	if(not defined $self->{'load_status'} or
	   $self->{'load_status_cache_time'} + $self->{'recheck'} < time) {
	    $self->{'load_status'} = load_status_linux() if $^O ne 'darwin';
	    $self->{'load_status'} = load_status_darwin() if $^O eq 'darwin';
	    $self->{'load_status_cache_time'} = time;
	}
    }
    ::debug("load_status: ".$self->{'load_status'}."\n");
    return $self->{'load_status'};
}

sub undef_as_zero {
    my $a = shift;
    return $a ? $a : 0;
}


sub load_status_linux {
    my ($loadavg);
    if(open(IN,"/proc/loadavg")) {
	# Linux specific (but fast)
	my $upString = <IN>;
	if($upString =~ m/^(\d+\.\d+)/) {
	    $loadavg = $1;
	} else {
	    ::die_bug("proc_loadavg");
	}
	close IN;
    } elsif (open(IN,"LANG=C uptime|")) {
	my $upString = <IN>;
	if($upString =~ m/averages?.\s*(\d+\.\d+)/) {
	    $loadavg = $1;
	} else {
	    ::die_bug("uptime");
	}	
	close IN;
    }
    return $loadavg;
}

sub load_status_darwin {
    my $loadavg = `sysctl vm.loadavg`;
    if($loadavg =~ /vm\.loadavg: \{ ([0-9.]+) ([0-9.]+) ([0-9.]+) \}/) {
	$loadavg = $1;
    } elsif (open(IN,"LANG=C uptime|")) {
	my $upString = <IN>;
	if($upString =~ m/averages?.\s*(\d+\.\d+)/) {
	    $loadavg = $1;
	} else {
	    ::die_bug("uptime");
	}
	close IN;
    }
    return $loadavg;
}


sub swap_status {
    # Returns:
    #   (swap in)*(swap out) kb
    my $self = shift;
    my $status;
    # Cache for some seconds
    if(not defined $self->{'swap_status'} or
       $self->{'swap_status_cache_time'}+$self->{'recheck'} < time) {
	$status = swap_status_linux() if $^O ne 'darwin';
	$status = swap_status_darwin() if $^O eq 'darwin';
	$self->{'swap_status'} = ::max($status,0);
	$self->{'swap_status_cache_time'} = time;
    }
    ::debug("swap_status: $self->{'swap_status'}\n");
    return $self->{'swap_status'};
}


sub swap_status_linux {
    my $swap_activity;
    $swap_activity = "vmstat 1 2 | tail -n1 | awk '{print \$7*\$8}'";
    # Run swap_activity measuring.
    return qx{ $swap_activity };
}

sub swap_status_darwin {
    # Mach Virtual Memory Statistics: (page size of 4096 bytes, cache hits 0%)
    #   free active   spec inactive   wire   faults     copy    0fill reactive  pageins  pageout
    # 298987 251463 162637    69437 265724 29730558   299022  2308237        1   110058        0
    # 298991 251479 162637    69437 265726       43        4       16        0        0        0
    my ($pagesize, $pageins, $pageouts);
    my @vm_stat = `vm_stat 1 | head -n4`;
    $pagesize = $1 if $vm_stat[0] =~ m/page size of (\d+) bytes/;
    $pageins = (split(/\s+/,$vm_stat[3]))[9];
    $pageouts = (split(/\s+/,$vm_stat[3]))[10];
    return ($pageins*$pageouts*$pagesize)/1024;
}


sub mem_status {
    # Returns:
    #   number of bytes (free+cache)
    my $self = shift;
    # Cache for one second
    if(not defined $self->{'mem_status'} or
       $self->{'mem_status_cache_time'}+$self->{'recheck'} < time) {
	$self->{'mem_status'} = mem_status_linux() if $^O ne 'darwin';
	$self->{'mem_status'} = mem_status_darwin() if $^O eq 'darwin';
	$self->{'mem_status_cache_time'} = time;
    }
    ::debug("mem_status: $self->{'mem_status'}\n");
    return $self->{'mem_status'};
}


sub mem_status_linux {
    #              total       used       free     shared    buffers     cached
    # Mem:       3366496    2901664     464832          0     179228    1850692
    # -/+ buffers/cache:     871744    2494752
    # Swap:      6445476    1396860    5048616
    my @free = `free`;
    my $free = (split(/\s+/,$free[2]))[3];
    return $free*1024;
}

sub mem_status_darwin {
    # Mach Virtual Memory Statistics: (page size of 4096 bytes, cache hits 0%)
    #   free active   spec inactive   wire   faults     copy    0fill reactive  pageins  pageout
    # 298987 251463 162637    69437 265724 29730558   299022  2308237        1   110058        0
    # 298991 251479 162637    69437 265726       43        4       16        0        0        0
    my ($pagesize, $pages_free, $pages_speculative);
    my @vm_stat = `vm_stat 1 | head -n4`;
    $pagesize = $1 if $vm_stat[0] =~ m/page size of (\d+) bytes/;
    $pages_free = (split(/\s+/,$vm_stat[3]))[0];
    $pages_speculative = (split(/\s+/,$vm_stat[3]))[2];
    return ($pages_free+$pages_speculative)*$pagesize;
}


sub io_status {
    # Returns:
    #   max percent for all devices
    my $self = shift;
    # Cache for one second
    if(not defined $self->{'io_status'} or
       $self->{'io_status_cache_time'}+$self->{'recheck'} < time) {
	$self->{'io_status'} = io_status_linux() if $^O ne 'darwin';
	$self->{'io_status'} = io_status_darwin() if $^O eq 'darwin';
	$self->{'io_status_cache_time'} = time;
    }
    ::debug("io_status: $self->{'io_status'}\n");
    return $self->{'io_status'};
}


sub io_status_linux {
    # Device rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
    # sda       0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
    my @iostat_out = `LANG=C iostat -x 1 2`;
    # throw away all execpt the last Device-section
    my @iostat;
    for(reverse @iostat_out) {
	/Device/ and last;
	my @col = (split(/\s+/,$_));
	# Util% is last column
	push @iostat, pop @col;
    }
    my $io = ::max(@iostat);
    return undef_as_zero($io)/10;
}

sub io_status_darwin {
    #           disk0           disk1           disk2
    #     KB/t tps  MB/s     KB/t tps  MB/s     KB/t tps  MB/s
    #    14.95  15  0.22    11.18  35  0.38     2.00   0  0.00
    #     0.00   0  0.00     0.00   0  0.00     0.00   0  0.00
    my @iostat_out = `LANG=C iostat -d -w 1 -c 2`;
    # return the MB/s of the last second (not the %util)
    my @iostat = split(/\s+/, $iostat_out[3]);
    my $io = $iostat[3] + $iostat[6] + $iostat[9];
    return ::min($io, 10);
}

$::exitsignal = $::exitstatus = 0; # Dummy