gperftools-0.2.0/.gitignore010064400007650000024000000000311343325711200140770ustar0000000000000000target Cargo.lock *.heap gperftools-0.2.0/build.rs010064400007650000024000000012771343324551500135750ustar0000000000000000extern crate pkg_config; /// Configures the crate to link against `lib_name`. /// /// The library is first searched via the pkg-config file provided in /// `pc_name`, which provides us accurate information on how to find the /// library to link to. But because old gperftools did not supply such /// files, this falls back to using the linker's path. fn find_library(pc_name: &str, lib_name: &str) { match pkg_config::Config::new().atleast_version("2.0").probe(pc_name) { Ok(_) => (), Err(_) => println!("cargo:rustc-link-lib={}", lib_name), }; } fn main () { find_library("libprofiler", "profiler"); #[cfg(feature = "heap")] find_library("libtcmalloc", "tcmalloc"); } gperftools-0.2.0/Cargo.toml.orig010064400007650000024000000010121343325731100147770ustar0000000000000000[package] name = "gperftools" version = "0.2.0" authors = ["dignifiedquire ", "james "] description = "Bindings to google's gperftools" repository = "https://github.com/dignifiedquire/rust-gperftools" keywords = ["profiler", "cpuprofiler", "heapprofiler", "memoryprofiler", "gperftools"] readme = "README.md" license = "BSD-2-Clause" [dependencies] lazy_static = "1.1.0" error-chain = "0.12.0" [features] default = [] heap = [] [build-dependencies] pkg-config = "0.3" gperftools-0.2.0/Cargo.toml0000644000000020730000000000000112560ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "gperftools" version = "0.2.0" authors = ["dignifiedquire ", "james "] description = "Bindings to google's gperftools" readme = "README.md" keywords = ["profiler", "cpuprofiler", "heapprofiler", "memoryprofiler", "gperftools"] license = "BSD-2-Clause" repository = "https://github.com/dignifiedquire/rust-gperftools" [dependencies.error-chain] version = "0.12.0" [dependencies.lazy_static] version = "1.1.0" [build-dependencies.pkg-config] version = "0.3" [features] default = [] heap = [] gperftools-0.2.0/images/pprof-gz.jpg010064400007650000024000003255211336134371000156400ustar0000000000000000JFIFHHC     C   5  yQ*=TTheP @ʏUu@)J*Uu RT9NS<9A 3ʠMhs|P)P*(=<4 h@uZƍT,go)j*=T8hbgu 79@ 9JPT9@G(b@8Prq9@8Pq#*DFTgxhv#$4gl5LCƏk2McuMSSLẉ&JO3RѠ |;GPh=9/5KS@S4=S x褩zb恪uR=Tl=@SO*6@#|;FeꤩT1LUPGg  -IO5%,@1@-O*<|&TGEԊ5M{<!PB:y}xQYG2OSSO8)O0;GEP횤璒RJ{GJOP Rdd@rbqF)JJP;`vgy'Ρ`e<2NcT'<E)hh%K)KRT,@]tUGqgh=(򢬟4 -MS (h恞m&#˲h<2N"ш@*Ρm4z*U'1s9* Rh-@T%Jy>uOe<恔mgy!l=(*e2cuNPMh|:@{P R*|zQF"N"<&l&UmP*2Q]<=<@Q*RG)vl4 d&b|:!TK@ EeP'`zP R*Ph;` ST%JT<o=j=xGy)JGQ*U%J |9OE<Կ<ԫ,ٔP'Q*U%JCRT%JT)GyygbQ角yQu B*R*UyzyjxxygQDQDTe@UP皝B#SO'@<'SK:*LQꤩTTlvR(!Uk9Mx4 >PCꝣ<)m%@6TgM@m@1LhDyJ4RQXbUT;`84"h@T~{PjvJRORbD)@gjtz*vGFjM*d2T%J`( R)T (%J h*%@4 S<|}hv&:Q@yvѠOP@;E*U'J>uJG7*vcQ P>[> (J@8/">%JJ@<;g 'J4}@R* s$%JM(T%Hl%OTTC <;G1=P>Bh. RT*l*P*U<$;EYJGl4 RTB6@T*%J'TTyRP%JF!*ZT6J@PTy>gr R4vR*UTe`x)U$9N#<5LPhh1tH lѠBybEQhp@1٠j(qyQu (UgShP5I8 RP%JJ!;GT1 4 T:*ju#<횤;g)sbGlGrG2]FIpT4c$vhx8M(TykC&8hE)4m'T v@&uN@ehl4 U RP)(r(9JP%Jr@T R^kTP%J%I|%JJ@)@PUTCRh휧l TP%J`v#1L4"P2<92J@<3SɢjZ RJ@*@T5('S(T@ꝠqEQ**UP%N@b@TTTPtr%%JI]B(P'RTgPLġVg@:UFP5MP ReF3<#Je@JDT5N"h'SU (T#R橔jFyjq@JD<du STE @!jTP`@FP5@%JC4PJ@%N@2`T*UJ@ jC@CP*2SMlTJ@J@c6)NP5@ mJ@b@`mG)NPq@)zPP4q(yP*P%W(P(T<@)&hC(J@J@%@l49*RTTTOP6 RMF1PkQu*='hTv j R Rbv%J@;eJB*>4 *UOv R RCTP4vrP'ʣ%J h9@*U"|%@<|(T*3TT%J4 056@P`#p%G7!"$&43M˥7#WPc؟/46}x+^@iR @J]TMKi֝i֝i֝i֝i֝I/1tNNNNN,?O`m@@k1x\R!W0ݯVJ\p  h#鑍jK޶Bab@.-s?jYEbc3o+Қs)I^)Hbu )B@t$@ > ?|䧻 #^2Ő! I9>v<&VIo1Ly!ϨH%j2y .` WYl*-e˂i.g(&"iϨHb_82Hl5$I9 ̠F]qG"Ug6 .ZeVZPd $VwDz>Byf L.ȟ`Y.ghG9Ί.`݉+v$ؒbJ %nQ+r[JD]]d%Y.uwZuwZuwZwuwJl*̓,LSNvVK1Kgb+2+֋F[BXTVKwT%Gcd \) vK2 tlPfD>'^'>̹2x%݉+v$ؒ0\kr[JܢWZ"%Y.uo-j֡jw=i֝iցы]tb뢑um+m [hJBVQum4VIB) -:zb22%"!W4s?b]%m+m [UEմVI[M%EE#L09 E# `@9`\QYVdcXa]15]jxkt,>VDrDZaY" 딿LV%Ad'1_&8XaTϨ%Ɣ/@Jz׵P >'."M & g!Gr^m`KqaշZ^ ,`4+Lu•9$ : &A_ǮTU[B@!n(>ŎlfHy˼O-"`a>Dy/:։RQ"OvV*Nவ<5YZoA$x7/2JfohZ*!Vt:~4ѥ2C)B@t]uʊ͏]X+t..dnĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕWF_7bJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉*)l/$yYأXkTzE_{[IlR<_o@k-%-Wdwx"-e[#Kg|RKd6-E-%_r5[Ζ+'kwu60 kv|yyEH\Y`al7Z[-#Ufc*6UǑ]jO̡dqdm,dh ܖ|zRy;^ f<49(6)l\ wDLXg9Q 8ځ5G Hp}{bu|1CƱ?k|CR.e.܂*kvتC?%}|Gw4}Y<, =3Rmg@EXcPkd 3ِ/oyI6'̋jX9cVp@/4ԯNqc1YqB!1 z\]5sGؙYݒnF$ّaX*rq?&>7ˁ ;VMɜixSTzac"0V@RydVGU+œQI[0peL^u[Wx0J//LDɇ?  l\%ay7 5Ƥlȱ;,G n0*Ty9! CdX*m}JFXKgyͱUß2 vwܗŻ!sXUK=ǕC~C<]a8#L|5&߫,A[EžgZc9wTs[ `o_ݼd,s6WpԩjqoЉ+n!x&$m}J4̛ifǏ5gw1kr؍ Gs\(gG9Q8%*A82b{L{2qQiWHc8DY[L#ɕB9E XnBt ħ%K%ؔ`ܷ Y~J%(Jr)1`S O;TVXN7HѪInf>b,8H] O+4ڢ6K= L^\oAmfCy-ŏˢڡu5.(&:b5Ze]>6KcWvU퀜qbw$(r4a"ώv;$9KMUkQ,@<%Z*B$2$dɣ-[,z|Ʌh$dɦOa6#F̱c.|rX&lZa8%*$i9%>`*KW8(rLSJ6~Blܪ+]0"G"FL2F*!@swl =!7SNtUZoЕ%Y%hJBVЕ&>6+>vЕ%m*\|"BW|+m [hO+,tPX)Pn~֬ӻ3D!b͢14G Xr[o{$ګ"xVt-O>3a|lp+`zQBV2HA|F+5/%^NYo9*R: rdJQp jGk07k3%h6] \A.B`*حvBv0`fqZ_N>x-|Euq,W{$ .zNYo/.7L qm ĘSXSy~f>S^b!", LhXp8<8-s5O >dk}PDj[sv7-}vϏ26nY&SٛMv06Šb2܏%$0-X p8O ɕ[&a7f}'j};eNS^唷̓3c6XHsVeN=xagw1@*UoCr,|2!lqښLPLR-jYVd٠@+5vKnVXs?kVK;,y"K24X,cܟ9*탗ؚwTŤ0wu8\C;*܅pWvgYb~֬ӾvYo #`>K + ?kVK;, hvTla'dvxt]]-XO,A90*\"?'0aK1-eq'j};e-^< p b8W!J #lal` Ɓhjw^)=.SNXF,U8<$+^"s?kS5]F.1uы]tb]F.1uы]tb]F.1~VYoXc 1aYV<ЂEYP+S;yÂA& j/PCPˌ\7 )Lv$G BeȆwOA{[󂅈% ,AAXQ[Y}udܵk5m%Z@ӻ;ӻ;ӻ;ӻ;ӻ;ӻ;ӻ;ӻ;ӻ;ӻ;ӻ;ӻ;ӻ;ӻX]^TMi֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝iԒi֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝i֝iRNKwZwuwZwuwZwuwZwto z*`tNN x_cG+2 +5VI[%nĔ `Zx vl%nĕVI[%nĕVI_ȮjbA$\_DWAK[4ӎ')dC&v#t5"Rˇ"/bmGr'$'rtYX\"UZτ[h`%(]dkVn"ʭ_#?i PtDY<]<KZ* 2dm4|Ÿ~%\xȳ&Nެ]$. !JCJ'ٔ ӯx@ZSv܋2IGȵbl OCNVq/ܢM]s+o5 $[{#,/ic"k*~0+{oqʄe]Qr-nNK±h< lܷ22?Y)j)l/#IBa/G$j501|$O`e 'r=rBE*#` 'YZ6WV,Z L%f |A&T"ߺ"A$a~츯ȥxe (*[M^+(Pr-n( K<Ÿ$WAK[}ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉+v$ؒbJ݉(kIvI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĕVI[%nĔ.BGyT)%X ːls+o5 $M?uj1TG .}FYHBdKd ;![/|۰OQEdxzK k']XO{GzsN~nI1e_]pRӅL'$2]d+u)\ĉsICHvb7[= "%glV:0p}O_%_^sN˂; wp.mqDpZ2)@F_^;%'Sq#/&N}GV2)QْwnB¿(t>xVp\Vv依G~M&H"g<jlhI\˜H.oj% Hq%C!cD=Ti1dMgxID XT&Ax0+] $CkGq{Gb !xzlX(B/\Q \4 C͎/ 8H$&,HL$]^&tACJY0v"ʹ0J~,_PBXЍN/\e#"e%r^.ʽ(WcBIPFX/TH6XЍN_c&v,Ĕ(^=̱~4$dĕMp &6\C*(  ,al])X.i x[za$tAA㠁,I- qL'n_-鄒)LwBJL9X1ЁX =h6 1SX"6:aNMG>A]/vYԸO EaaD@yBۏG]~0g};t0C. J3LOboQ۸P|X[Ϩ,%L<+Hc f};tq)ۚ5##OboQIˀZ[ 6װ3`) Ip*)2p;`E*rg c. W>c{2_N3 GnA/o542.6Lk^G Ϝֵ,I?(;|ӻOsAԭ6\-sdref|IaM?i𿊓ks,vYL!Ba11 b>.v0{Okylhi,;ڥG>ȿ~̗ӫ(4pC`E4B.zox(YnŃ:ʖN8}wa% @OҺ Yc~|뗈 &Hďt&V7 c-wm|_1̗ӼgtLTyYDƗ~K݄{k PPPPPPz!!Q+A0bQDJ|Ϩ%e|n_NPZϩXv. s}3HcK݌F.1uы_aʄe]$kF^boQ]cX ʡ;PvKVD-xI)N}GÌ]doJȨjO5--cB'2_NT#*%]At+O&XWJqiտ<+* D7z駱R=5ZZ#+d.}GȧrC;C;CƿPPP뭴ap< : ݹu@PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPlPPPPPPPPPPPPPPPPfj֡j֡j֡j֡j֡j֡j֡j֡j֡j֡j֡j֡j49gw"5)m衭;qk8-i{ #`UA p_ȳ]A<  K+V!Vt  ؒ8VJ%֩;-tbmum+k*Ji+iJi+i\+m ] i֡u60:ixOsed,H=-_PN8 i+m [v(]15wZwuwZwuwZwuwZwusutb[~km [Q7V 7j&[~ȫ@P䛂Ȩ'kK2diOB|=O7o-kA: aj~q6XB{XksE-YgWMoYK9^ v1t9c7/OlA@P{eǂ]+PpD-E-_i/o">8V2?HO*K,Nf *QO?8\,/&Iee  TO_N6Š$ ~Umt+;k^n.nhydtVPM6_PJ4%Q_T[]XkP[U)pض^+,iJi+iJi+iJi+i8r.24VI[M%m4VI[M%m4VI[M%m4xrC@]BU,bFt% ?uǕ>݊:U Bh&OFIfk  oTȷoǙ z*G_'1.\dgJ{n3l8ǡlj??{;Хt%:A;Ur_NOs)vJ>*.஦܂B*ΟHO!Lq=j[!0ǺN,'}ǽ;2>I,A&Y\$Sb/(9#l:/+ȴ#l:/xQ,TPYet9c;k^nN R uO. .)0w$]|$p[wnoG~XDe`ee?e?e_ !15A"2Qa#Rqt 3B$0@Pb`rCSTp%D4Ecues?T"@2mvL#h7ΙikH4ny8꺆B4=dQQp)0Ѹpm+T`DELW.ek0WN ]*TJR9Vrf =oGUp uQ2%Z4FԕK])?oM&#HD&ehyˎZH-Qa B8q.j߉f;NUR'qmw[h]~5mw[h]~5mw[h]jlMӌ"F4TD=?mw[h]~5mw[h]~5mw[h]ֻLrHRləֺE:ԍqZQjڽ߁JY2BVl$tDERc#xԳвTeR7fE&EH!E֋E\„1";u-:a-1c2ӜVᘴAE;-}kk'A0?I V6K墭w#5}LDҥ3B9p^IưԖ4񓋄QFQRzZ醗v(K)00]r%ֶv"CŜ aP-uYm$f=(%I{~5wԍqM@xҽyfFY}1u*&6&Ǥ-XMvG%)L(o2&̸f_qѸJ ֝ZBƴ'[,2蓣%BΊ͛HؕH+2o6=]dT#&^n;#q)hmڀ*WQzўnC%q+&7pi48ubU [l-&H(\_~yAilJTf7*]}/78a4O6@\y Emb#%"uۖ#J=tjחqz~#xzoϐ:I|GTKv.`cރw uK9.}67[FKrㆈ Q_MsZ&v {pjۋ[Npjt;{amM:BQU+uյt]l"GO&&KS]U7+,~R8#@-e:IMUժ\Gc@~zVd4ثTJa.UZ"%{F6ƹd%Ob{2yd$mQsi,|ِF:RwGCEE3%. 3A&yuGz*^Q]bj" Qj9 |N22"ST=Vt0 MOc@o`))0HdZk{-^9 z1c@{tVůuյt]l"GO&&KS]U7NJ^l$V0q΍uYeILrӼ:&,DVv.aZ):F[@mƀ\_e/\/ý;'vG㥄SmwAmwAmwAmwAo"GτÒ;1*W%xgHK|#-Wt^?n蟑] T-W׏a^^?mx}x-}ǟmwgy6~ }ǟmw[h]ּ[̾$Bem)Ekbht'7-EQBAUD^={GVRbϛnhүFJˤc8Dϯ+&qQ䐐+\mw}˛+C*ѓnTPpUu"YME牥m@TwW1#+ܧQp,q`MaʭZ,[ޓTZpcf2&,Dyfwmوl:S]3ӫ97R}!xrUz,QR!)!\|*- r.^^$ˬƽ8܍2!oDZ37rѕiH'P )ZЗI3<(,2+dDkJf߾% Tܽp扙,!6[ȴ!!>p^ c^25(:$5뭿|^6=4A6vs~{7[:!p^F창2],Bxzoƾ~d8 qVЫT)뮤Y.D-#ҘcuD\.KQ˜I~a"{4Pp2cT k%U%-Ya!'D0յhp/h(- 󨔢o6~Y^E'<<@އPTD-f@&H|ռ`ꪥUusV)ot ML) btUDU]B,PGY.Oj%X.4qכR2JD^zg&1PmB %T8S|kwhGJAh]4q`Z2tLB& m/\/ý=&!8DZ^O$]Tw}[tzC? J{=Mcf'=` Ioʮ-z>CM=47T| 2N¹k^40aeU:w^DmKGP]&MJU5n^i=!1sBKZpVvGÍ͕T\ ߯zP 14z&[efBL $jTNM8ߏJt+-PWiTEU)sLgT,uMKZ`ҜA!ƾ @6 %oi9$2@I=\^FjcV[Jqu*xwU @kRΒzgj<+8U&DDDNK\^_{Sm4@ITT귐z l^}ЏAp$ƩKb]hjv⫟E=!Me承b ZQ]e"Y\%MSdҽYMz;M*= TQ'pmwgy6~ }ǟmwgy6~ }ǟmwgy6#|r\aŇֻl?>ϻm<l?>ϻm<l?>rcCgVL”ѧZ9.YN"aCy5VvY!t4RI@;S[/}-uthmm΃@jI (اUxEGiSxGq= tT<& {1kf^ϮKb|8ꭨ ?Ak2^r?GuorqC譿&Yi FhVo.6a _oy=*t/tjɺ"&9nӶf.6iLV0mvGOTo*-촫̛k aW)U^kD)dۇU@ CUTMj7%ƅ%$1TBTBUK, a4Nzoo-z^_M=6t9:&~C/j4dӤ%GJڮ Ben$DĠkN3^, +DLz؀:CFWrBT.jaTM&RF Nc h, VzS?q_*-|Ďƅf,y3)3)/tG&m6̡W"*nBiUE_1)Z2Jֿq.$ +םNB2G ^bjᦡDߵA-Gwߤqن}5[cB=7Z{WzQ-\H_eR*D: = >㩆9% H.D#rSgBn>L$$J.rWE@һb丕i^v$]uROeGq[aj&^tzJC?J{}7S91=]ZƟml,Ƽx-/oB9m)T S^|/y7%Àaŋh2)!F+r.n!_eNB2G ^y`t[p;y?z$2:45ꭼB>kGh^ ўnC%q+pŶ1:n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;n(;ȹT?yN-/(Z}xymmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm٦!1Z_7l9IX%ؘx09cS\Rۣ6*SPJQdQ@4DOF<ߕ]ׄZ|%:{i`ho(.dAssEo}1 Ii>6bfj$\1!jE1) W5DWObp5%jD}15ZVE>9mb#%"uBm tJkE$b$kW؋{+"֋/8bT5Z"}?pŶ1:8:BE$ 樔+"֋/6bcU4Z*}>l a $*u[F=|6/NRabksum~Dն-%;vƧn*Sj=su}PZ="(ovTWYm=&bW"IfShT44V_}M︿r%ƾvdtehq`BUuH!& %Í(],[Rf˕*TL 0;#+FAr9{S*%iLu~SGӎ,W1 <ӯ;٦!1Z_9qmSF **"в뱸mb#%"u[>,1(2ӯ+#rŊ$ZunSo`is0^2#yC")2<Җ%QCETS_j}66^ Qw'n~e I8$ĪK2;D*rVL~xYyCt[i"_e} #sF%+RVKXt68!8ekO,D̦phi^LɼxzM'`$Hd_u'(H؈Zgt\h }bJRa .t\%͉>"#e &hJ"BjheR(찳!D%CxY\%MSdҽYXyCuOel r!IWha8UTELZnHu]O3;rnS3|4<M5+LZgWeLGN/Emyd~GMtk,Axp"r^S:\ҋg#32;[6[uƙ-RkO+kq##2bJYi:n4eʉ9оBF<4ĉ%mɤbf$PS%*z~W+&cݖmqdܹbyا9!ڸi>_^϶׍wȏ32ᢶxhZ{ G!}ӎ+Jѥ5eYd-#6^&MHփJ֖'u(%zKXGC3n4x G)Qz#Dx4:7Ǘ<iֺvH"v$ۓp/ëט˔I.5v$ۣ(CZ;ДӒΙJ:xAQ9uK\s$p1Py4oD.fBUAz-L2]Dĕ\UK +[2ɉq4Nifb!Q ^Ž=T@JU\Im}*Di<9Nu(gv nEk$K klhrA@ 4P}?mi\UdQ^TeKBqmIlǙgEo[2o(qn"I쭧͈A@RJҤ_׉/#`I8񽮪HCQw]79Ӝ={Sh!uY9iUENk^*tw?)p*5Zikdnf91&(S{jI#}rWp ׉/#`I8񽮪HCQdx:wP1z+f=2;2\\uʹ%&J hC7MKUiQÇۏMc.'[0E%Q)>_lJBrآq̪fWWUm2vA9Dq|!4֊ט˔I.5v$ۣ(CZ;Д5'tםU6$SבZRx^A# DNuT~7nKFv ^jK&!0ƘPRk[].NC&VHUyOJs1»TIOU+Yz*t.3r4nFjMi.|LqnBE4iGDJ#YR9jOxхZ(YkVLz]w6s <U2OG۪ҽpXDp*{~^F7` ʪ!P%EZ&:3n&)D)MV$8!Y&n%VYqku% bT0Q rMH!,ZNeEkG)]˜֋Z-WI?5/fM+֞љu)8kGs^I%@bu)EE^(NDdqM&Yb^DwBx 'PaDh)=HYtm֤$^anml:4UR[\b+ψZU}E(̐qxA9y%ĝU϶_)HONv4e!б)is,Y֙vO+(f0U2J'ߋnpdiW_9)ib8,~haNgL-s&f3ɥ8:6X 5%3Qe-wC\cȇHry`Jn9%:l-4_'[Ei\`2hX,Ltd&#z\* )bQ=y]Ork UJ&<^ZSTEV/̊8/#&*XFcWWZﷺVy`: 8ѭukr$[8#á%^OzCQ2q;[lDѺa-=OE~Dیay4F&u/쥽qz~E23MuDhGx4E|Ѫ*{dugthFu% )$DMּnD `Š-5؜1 Ii>5'ܱ<>괟&9\ծ^6-8!UG7+"֋/oq~y1{ތ-NZМB_JגgkLENR* *>]_/.=]iۂEb#~q 痧u8߼煲g *s/-D^$KB^r 4hsZ{iӜ91#hE (i>wFv?(3uA9^VO,u9T*eOڵܳt(-q#篚הsvcfDN p*uh<mAt'1+An8b`hv ^\z#,ӷ?yjgX[df7 <J5'ܱ<>괟&9\ծХLmjd&VV{w32$BuqW+GuNAtAAT*eҎ~sy="XQmRU@֨ 箮_>[]Jsmⴥt,MKioWQi"k57 o}Cfc3xcyFt.%UrOfaC9TF㭢:8I*)JՕm.Tim%0>8PF"CDOJ]lHW7Whse.+LhT.,Z[ۈ˴)3,)JjPnh2D,h:]ZLQ^%+UDBBEu62)0 07Fq"Mj[e-"ze$7q:)ҁ. FѣwRe&q0TADxS2^TPj;iQZ&*Q֨Y-w4,uV-[FVE ܕ_V]w ɶDB#I}2vKt#ZU+;m[] A5לڢůK'64CAZub]V$Óc+QμZ˻ל˾(^#9\$M[񺜘RnJjB5jS S$νt?w4t@zROgߏ--݊<VI52 ũ8-U>б.+[_y6cůI-.Y͟) GR9صSw]+˖mP3PhXM;+$4 Uؚi1!Mr)q8Kvt*S*Rht{r@&ݢgU] meiJ%5v3o/iZ8W1WkD[bU 8"Ii׮]Ejqu&IΪ%j߾ׅI-\ؕ *\^KmMc<ҕZ昳zҡ ]lɊa*S>viuo]O\8IT&=}Hd6ɦʊ(JϥmRsg '5wX.YSU\P,\]F=3)T] @G?秅Wx5*C Opֹ&}=c+#~G[:-=6(8S2S."f~F@H"aTsVV1%쌔lx]"HcRȗmzʘs#akL*\쑡{yRF( RRšX$o!ŏg]l)%{AWU=}F.6HU!\}}.JZ&. ]?s\󴘲9*Dt2%*dDުs~Vָ֥UUkLw\zLj 5LQSq"RZK D'sQkNl2'EDTgR5o&GH u(ss5[B$#* Q|Eju-+`GMsF&jnV9WbջK^KMT괻^pVO8fGT\Kש2,YnyA~80**UIq*k%i/\)A EzM~ڎ%S*dհ07FUUq,heDn򂭰ش*PNDJ~tQ)5Z OI \d֪t\Ǫ’\m׾q}_0#rcLuq$ujʶ80Iy9`ˆ :k^[\ܰfIayf)u\$4ů rSx]H\WݒTRWTS$ܙ%-DdmpGbeovjkӒ'g:8Ov.JgVV Ѩ-tBܽwF& : 23 ִD-~ yM})!%$mQR.~)Sx<+Z5Z]]2LH㥢1{+Rn! `.~ZR"ubd,m4㱢)%^抑"瞼5k{" Dʈ]ɾG[,aҿҨȇ$Ozmsr%Ep55On,QEI^TT%)L)K^LLő v4U$R"D\ב&vbm҄ueQ1˜hגͿq[| Sͭ1*U7"%m^w4QgVrS^}T}UmSU]*zW6mܥ0wtx9Sr""zw٘PU1A&:hJRe[LNfIJ"DZ˛  g4׉2Ϫe71*:*ROGά7ҒbRF)Zޒ7ljU._h0*^/&y+.Ιb#*gEպdp2#`52K?~e>7+T']vr#i,&*$K@^ #RKJTyh7tR ,|WZ.%ekɉ!ӎƊ{*DHz$ծt y(*֖BrM؉Jm-. ޒ AB^Ce3q'5QQiL0Nnl@9>u\߮yBQdhѓi2&%JQkR_%z;bJiTPʪRמ/z6~{"n7LfԚ5<z+xh{|#籈ɜD /9եhO+xh{|#2?؜85+BfDN]Vё&L r*2?+xh{|#籸Ͷ 9};|#-BE$UQ)Uo?d=Vё[FGj719C"zDj9曽+fDhXaߥYCB¹QzSUY6$qև*tuvF.oSg'׮DC~+eAGGk6TBWwvZt^ i9Q>ۍƜU^z%ikx iLu8SdJK__8hߒ:92U@EL;rMf|HSꋩSEULҿe}c14T qpTRU̳)k\)f)ITa\kUhׄmrqt89W6ڮK\9Sxږv"Mkh*R9jL}QK45Ztu51L*> +A)Ҋ5,S/OdRJm>e3s 0I&% JX]U5ZjnMƌ=';c,Β3kG2X/2hM|Q5)Bʨb^.yi]M[qˤL,AN&hJ"H-zq9#'88zKfJiO%jj]Tkf4G" U3K-)~"8UZfu202ǔ%WG{ZsHڶODLh*Vx80NBu:Zٗ6.(yL+^ Qr IMTe?q_jo+cZHrJj':C毟S{/w|R4$apH+睝xnH/:4SVID܉^nD(MsIJdrea">0XQ3UJl³  \Y.I+9HkŒtq|m 6hUwYIt1zEO!U_q/E.(hl@>jzzSUk)#խsQcbXQ1tEeT-kKK{䮒i# EO\<2iΨo7 D55ު[Kq]ml 7m}+גZpw8_I*X㌆*r2 lIT(}sz?q=r'>7 ܌KUIS3d9%|W4ԙɂ\lд1f]^q2*[N$̊ܩ>n8*+JW-YrZ3b 2\WAyh.G&DuPymʴMݾ,]g/F. VhH霐raƲjK؂zL'I]+fGo9=hcIЧ=2N{5&:Ntq"";3ϰ3^8)%w5_xןqH DULI7pVik Ti!tHjN_fQk魂$QkUS,A|}UUW kZnm_.CɐVЪܕϥ+os!G!\8]hsD{C%**~jz)Aksz?q=r'>7ˢ7*LK5{S=]Ik22Ik"'k;jLUܹk7.f@"G5*(kضTD" ft}ŻF9,h=ekKQ pd>,pnu$bѶW[4춙~}7k]_6&DxJrk >Hkof̳/f3'@`4wQqQ271FСH*K%Ĵkd&"r~T%5/;zWn(*2CLh n@buĮS2ׯ++QZ2ۓwܶevzb8<\m1,ݟn[O|YDG1D¼֙Su,Ff,չ,A\Iő1sI&+A*嬫"% sO:{@OL3޼;l7,a,R򗄓1^vIQvMhL0RO0wBHm 6EEIilȟor\b @JgmwAmwAmwAj%bu`*kձjrDtS: C/ֆWiq axҷAZ"27tĎ qTsEA0AY?ٮBEG2OmU1pP݃?nH5Oe57kuF&덻\NpF2gU;=7!{伭N/OPQr=V>W2-$"LoADUDw1*zA^jһ[8Z/_(9R%9F&H()dn'褵3\ղ?zK&$dRVkTfJw*V@*iR )tԨvZ%"U֐ 2}u*5ԙke h,"$q\˵qkEȴHi__FT]Hs RؒDRi'U_.9'&&GM&*Wjº.=&v'9\(5)۽m2&ܩRq[4!Q.oҵXs>8#HQTHQ(&v;0ş"oVAs¨si-zEQa=t߅>" .'=6' ,2K .\Wː&I*0Q]h=jRjksz?q=r'omwmwmwer$\T¦" N#Ӻ[m^zqÈ UUkP7k"~!Ѷ#V&K{Jeh;)I~2?ܰ)\HN|ҽyg{`lnx*"SKlklk_MČV#Ġ %tk_Im4KUTpo])L ̥X"/nW G4u1m*䋕K uZzDc$q[2:Ur{ssE0jj^Dt[pQ '~r*6*|+QĹQ0HI]ё0XQҸQp}jS|ܲr{04JԧC\%ֽܵG7\JV*t,֊[=b #~q 3ӺҦ5,۠&hM$S^޵k\>Mg 4Y%DɢTң۝Rt\)i~uz**/r7k"~!S{/s׊BѨ#֖ r2⸰XFKBTՉKUQmsBxd]xeE\kU_M6Jb jCW}^_p,q (xvҶrFnL~ZKiΦJ%5{l DWMwgDUlZIoȔzoISV^=u?.8McT.rފI.vqUGuR%ɂ-<.WS&os/},K Hsz?q=r'>7M%]8LȜΊTRuޅ!â.Duhq;vM@h_^kEQMt)7WJXw5QwkJ*!DP歉c6ۯ|t hi,sMUֈZymc7wȀLtKBEObki&y2 &kJ%UW:7'jC<<ŗYas[GI'W~z*L 36)rS-kh BbDɺQjf/H$uĊ$Z.]V~D!QOh '-SIw]mM.Tqֈ/'޹M^ |q$È EܽJK̛e %SU[l޹M^ |qe:H:[]7Yy]4II$Nz/{]m-*9fHAZ!/bIf.I\Pރؚ}5u-36 U]TO9w&75m7.J]}!5hj:l|%j=Z^ &IU)aƨ_B"fDXBrPs ]+N$}rW/ +h1W6; } [l-b4slY}$*unћٌ=CDvX+drdXHiD(M|c\&y[ӚS"IDuN]c,8^ttШ#(G]5Ѳr!"-&d\:L"1QS=kk5?ϩ]2f ''dZb•x)sQ\ c5ZI?x]dm$@$%hZ4 NBڪ9!jZ'Fxq+f5Qr[K=Lvʎ]j={S Kq~;n1}#]g䭛fUYb*gMkMAkaP]D=B"Vϱ<1#0PzEuZhRHY%p%yb<<5s/iSTs#* WGZjs "Éw {W+B8RP1"HiTU5,;#/f ֘_7Z("fWI'kS Y_Z0, \Җ>ZNDmIpW]ծ%K4 Dң" cq˪ #(ફתdqdID b57ϰpn|hnIݮ|0 )"! s**לH:}%xf:ɚf:j]e`3XU 1*'-{&l(ֺ&Ǣ LjJ"-%!70kyWK/oSg'9&^@]*.O_gLDɢTң۝Gm}*{}Z9.K1[U†%z˺>-=x>(u I=l<_s{` d[hzE@?#J{=ׄI3Uem%uLĹkmw[h]~5mw[h]~5mw[h]~5mw[h]~5mw[h]~5mw[h]~5mw[h]~5*btĻ&CD֎M'4^m ?Bƶл.km ?Bƶл.km ?Bƶл.km ?Bƶл.km ?Bƶл.km ?Bƶл.km ?Bƶл.km ?Bƶл.km ?Bƶл.km ?۽t>DyaPJ|~5mw[h]~5mw[h]~5mw[h]~5mw[h]~5mw[h]~5mw[h]~5mw[h]~5mw[h]~5mw[h]~5mw[h]~5mw[h]~5mw[h]%"ކ#2u:[&Z*K++Lo(DQZ7kMmw[h]~5mw[h]~5d]2XDU@:/oʓףDؿ>tخ>XbW͢i׬V+MސELZZsEnm ?Bƶл.k dcet2 ϯay_b0$$ท4˂p9Np}:KyMWH^VXpg6&"2""u,z+8ק]юٻٻٻٻ9hCFϋLH< f⃾f⃾f⃾f⃾f⃾f⃾f⃾f⃾>?'}UƋ 췖vd^;-u+ҝW"@L*l A^0i:Iօ)tzQӍ}[dZ6{S/覆31[UĠ %zOw$nCBw/jgofUb9\I^ؙRw.>0WCC/GNElږD1/afSyX}wX#7LJ\&)*m妷ɵkۄ9.YN"aCy5Vv6炂Ip"JjwGH.z 'Uk]Y6Y{_ttP*6ĽP.9/mwaǷ{lM"\2R,z92ҽ5nFmWY7]<gF쥁ܧ8Mjr\b @JgjBH.ZX=UQiT/FyYqkC_}-Ϝl!dD?U'ؿzJTĖxDqStM_]kQ<尽2],B̛n٦JU[8{*)ب[01aL⏜"nhT[UKk 췕PJQdQ@4DOF<ԕd"N1(j5 v}ȒY.6M +՗Fۀ.6imwmwa0r)CVk=jZjĺ|8r d˯'wy8/uz55iDZ=3'_7v[TZhɎq &z S*ND%5#%^@:YȩBe_iiFyDY ʛA4&+EՑU_օ!rH"N"u-K͍'qs>Mm\)l1 :2h]\C]`^pLK/͜ȿ*A3E a)]!UWiK#"2E(-iw^ӂn:;ٮI&ЀWio"̀8S @)T9hCa![1 P@q &eHDRۗJA^0i:Iօ)tzQӍ}lٗvh(HE_ﰳ="}:/""n֪TMTSjDmE~Щj)o17~丫ţZQb~3m]&HBUQz%ґ8Jֹҹ7 NC}ZR[|atZ3Ek^J+B( =x!DReS)ɚ=-bo9&^u:v!']CZDLq"ٮߖEuq'Sҩc NJF4ޘU %L%{-#jJ B@OIyIKߑBx b85yWݡF*i"'sr]j\WBv";?Z'xqvШU\P6F]XUq7VL2@q4&+TT~~az8L# 9u!97]oIfR#U|+ykc'v<()oʉ˹u*mZ טU,9L'>Lyv%K~Gu4^ҕoڋ}@ BxU8cK$z2$!U\]'ނؼӋتXsME\9,@]k~N! +BL̿7#rBeF_mܱ׆k 1k;݄\D:}:3 yB&"|E:z@LC9u'9wMo./yŇ-Ā5U`_h&b0߱S'2hN|s"Kڿ[7)*"|M.5ĠfM;,XzW\IILRG7R^K٦!1Z_ m= {lIEd\ Қ\qs&t7.32EĀ!zr@]Ti` "Zލ!G4UM }*>˘v~ԡhjં{JJX^r.!_oIK$zQゼU-Fa7wɦif EOOG]o &hLLCxHmW &dP=&|D[mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmreuܰu :D:F靶}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}ה9E%W8+͊:Rei=ĝDJRCmHhrё.,ys-"8-3I Ί\&4RK"9.bQU;;ԉzT<鰦EK?6Y2 W 3t%T?ySR1 hRL@=8ў_͙xj(U 1n;#m)w-qFR֔˝uWUNSGï zn%LKTMvfK%*~p('yGZvI zU7ٷ4Fp- kÐ:@rvYd_F M]CV|jx t_.m+H1:ujK]mtL䃒B$ƻP&ƪ5hTmwmwmwmwhFaxfELypOH3/Jb浖J]]YZK Tr[DcU(8SkՕ.~E2ɪu+b  `m )DDv]ə9i uZbW+:^P͖ip_rd6tJF#ʊh )spE>'!ǔZ71WK F7@%IQ:h)T;W`q4&+TTzO7n' ZOms4e y?涼byV5ؓU*9ۆ%-=9H%xXei3Œ|7kḊR<_%#M#!UEH,uT!6/I#E3BHD$TD҉ULZD_׮DC  |Ș=%…Imwmwd79DH(5]uC'>nc!O5‡u5‡uwl Gp]`hE9}B첰Α cHV*kK+nnp!Jh\xŠi=t\ó Fc2&.(f$ٶ(A dZdVMJ*dZ5ĩ *:9*-}=>3Ѯ!>p.kMk!5. SSw$ Ѐ'mc'׮DC@$J *]ٕ6sm8Z* X[\2DNES;5WVkE$rM *c 3X-)iX5:k樯&|Fr'DfkЛ8:JȂH!_=mo¶ݼ> v+mGo±z80lt`*rEz= 2) 4jTGę*- :(r[N#tTk@()nTUZ;5 30'994Z-(D>fIQm&\TyoE%a@h"mwi|*!6VE]?I]jA7dJ$Ǡ*h:?$-2+!b HSy Iy$1GEe4 ϗ5 $d(+TDQԶAz5X[7<2MtTJqbJ㶤ʋh%,+)^^c_6֚mxFr5jQ(^њDU\3Hf++[9Tq`梣kֺ~Osp-+DtR^-]⼑˔MJ4 Z.jmWqF.`WQrVֈxvg(mFP עͥadf6%A$b K%>yk IjQ^x*R~SnJZՖ܆*^,ŅM<]銖Y$q;[O'L"Y^zmRPkHל;]S@^4brthTnDPm "6B 3Ե>nUWhC\ArU5a&vRqJt-V2V[E%1KJC""QpomVބI-CHQ\$sTnN'ːn)E )U)-~S҉Km9n%NM1UL8àtJMqrbʚv4hە2UϠYsc3@<&.^QM@לbܓw5xT5SJ)Rh͙G8KЯ9,JuüZlnAiҼƋ\GŬJ0y-QpY! 5i\=wr[614Ċ5ª)ĚVGy %E,ʋeNsX 5šVq"sJw?2`1FG4O8(, kyDi$%C*X[,5T[\a*A(  &%kU5JٗM}֗0ʤ'_)A_e(%y%7űθ~{r>Nj0N?)%WJMK3+Q)rbW?XS wIk+h璥 +ׅ$rxǓjY"T«6Zd<@UXIDF⊮|߆Ѥh6x'<5ͼ8TS4U݂[ ,(E~9F`0ܘGVc䛹ǔ"T(MU첔Gf?vϼ#Fl< ל]ygTfr N4Z<Ħ-f>jP"(ɚ)QTp Tujujr1<;H [TNP_i$13x75Ć!Q<ܓ^v{(}&WD3\ϚZ坯A Np m%ŞLD]H !yưJ*›myw{o8-\Yj+-7v^+/Ð -sŤQJdVEeȓӢ *"umwy(JRҟ9(:ir WsI0,ѻ^&B(Gp4ȔQ-r= Cvi:iVMO33EOkձX_:""**V׫wEIԖUCd5B-)۷=JQBUJyr]Ő1]:YLR˜n䇋IK/-#+ӓ|Ǥaǯ_iЯFrBG͡b N5)ɞ|'Ca9nhATU]zKN)&&c,yV2$**&("%"ݢƖeA yCuD߾exh`S`ykJ"EfMBT#-$wDiijDpRDxws }$M"51ֱn[Ky2 LSՈS:ok2ͼ40N)<եG"ԳE^/ b5"F5ָS+B'B#dfUߗRjKNnC$sT ҕ F]ytSWU3i EEu"Om5WB.xԵ@*ҪkmGT ˜iV[rӔhh Ja\7ZTrnJŦ-OKYv"'Uj3g70EH0Жo[45ҁW8 kRgZjա2S-2ӫuZrx- Q3,+&>2D/!7,T%AVg^I$sy瑣DJ"tLSٺXtL$Z"Q+Ֆ%fٶF/HbpIŕkE/9QxǜIE4uu%qy pJCӦ=eUsߞAV M,Q() J-sj)?o:HD`*k,2*]ve4d(0IGIUuYjΙ4Q!.ᣟ(qQ+g6N6hם 4 ZcFsZkxLX>g>~L;9ve[ h3VP'75othy>+ZSV;M:d4rA& 2DO_w/FeMX˵iE}\0Α d\M%H|*]ɍ+o81 Q3-x<uZ8h TGyQ$Sʴ"5?߿wcQa Q`** o} *n7ti3=5e4:)*dVҿUpHCr#8kII3RSjkqMZ:ъ֗ί*r4 Em{X:t~L1k]'߾?gzggHhi u vpŶ1:ےĢM(ֶ##\ %h_21 iؿEm,+lДz-.nJP)>D aoOBܹq-*4-խVjdQiJʼ<ꥯ-[|'qciR娶\+_2"!Ymrs &B Yjl;)oδn6bZZf(ù+w,G'Z6_d}\恧4m2-*8E Z"l*9$'=Vf+0aDQTK9+zɰAѡ(yVfj""#ͶޑI#\%uթ;- B4pxiirOLBJ&DZ+ZZz;I=0sUÅDWU5a:c.8t+cntŷ- %+DѭiIcl3kk筚ȟo߻NOcnS1I4}2ܱ&Gظ+L`kF?-ͦ)3P"2]RD5eͶP#\:O{*qx74T",kK%miai(J*UzվLmy9W҅KN`xVdDrh]0AW_nkwǿ~锅@˚,jBTz҄YE^ZM#X|%!UD栭wnT<C kITT*mFR dD/Rأ6Ħm ]GZ7SRPy6z鸽 Mh|8/B5NTEȟo$$n9LН52hz̔&`m M )92bqTfafkul|=7򀗁oCQ^Ŷϻm<l?>ϻm<l?>ϻm<l?KX֑N*k\ó1tɅH(SZU5sM4Zo| HNYۏʺ B"JVZeUwdmHI}sNf7TW=t-L=U\<#$*1k%z0GƭH7A䠮Hqqb:5("3"jMtX(ҧk |Sm4@ITTN8q"2Zk"~!oe\-I׭-!F;6ӄ88J%J*KHXD ƩD.hG(IEd;# c<E$P%QޒH3(U*uX`9*PE܎ }lBI-# KTnT ^ I !hL`ZaU!_1-o¶ݼ> v+mGomoSh^Է7;<T:M}H@q]NB$= uvi M"!+ؿ}p9d1tbV6u\qCF$5q.kZw -R@"pɹ B :"7FLsy/}¡늺(Zw1Id>G}8Q,J"^jeVGph 1h@J%EޕE1)F-ә8b sZ֛YاwraJ*iz:=F4*V@UU˭un/\/ý~krd 戼h"5?|ۙfTnI%k Ί+T\Lei0^];2 42%O⥧n)q %^~ܖ6n6Ҋ%9T©SfY FZ kmT =&Xtu PL10n晦x8Q:<D0QDDJ?CmoSh^Է7;<T:M}]ߧ/e k"KleY&2jWo\ó-j,gPmI PK<<+Lۑ!wkNmE4t4N^KJ:7c&8LxYԗmK*a10Q0']a ,/8͢!JյXFY+y*- ճ7~"u#4^j_4Xq3zZR.IrU̵04fA('Ep@ljOMtBTBqD@w5Sbl/2_o6^tQ+:V[gy6~ }ǟmwgy6v'uU'*9W:T<l?>ϻm<l?܍7{/ 4JΛRH,te=Z$z@&d܆KۣWo_v~RhH"{Jۚ;u $T*=UxEGiS>G2<-x}4ƍC2^GE]My0 SFg]}ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6f"ݰtnE}ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ }ǟmwgy6~ !MU)CB fqf-.km ?Bƶл.km ?BƶлBj!*Wҋݼ> v+VLQ˪`O[FG۝uCtv.jaz5;qI=;uChL&hjƝxE??uQiVfm ) ?v $ kfDo]& LOeV[+q'Ŕ&%^Zup0U:#| j4G*a՝$ ̖ .zQSr~wǏ3)2Zo88+٣Ws]ĚmjǣDJÅ{s%5&VkTiUd(DQϘZvޟ .NLTCb,qAc eE$L5]t,yEd,qMTo^ȫnP2GlXbQd?&=6ta:z4z?SnT)Hgb OoߕrUڴq1WЫ`q4&+TT͛\+A."|akRVo \"஑^trsjDÈ Eܽs ȥ4݋}ȟoId %m#*huU/# E¬s^AEe"뫢kcMzm) A)[^bdOm-GoO{RBz@;$Nr҈TRW__6qL$ENфڳ,YhQ5RfX"aqҹbJodÈ Eܽs ȥ4݋}њȟo:͒m>qlB_j)v(h\OA--xEKC7n\بg Og0&BՓuCыQ5)o-5EMs^'Em7!b[MI$!qv             >GwCCCCCCCCCCCCCדq#37!dW 3Mo3m"C=Jh/n_6?!Jc.E,e L\ދzO7vSٻ)kjWE2|#&XD[0Kj&*"oL~-qXM5?a ~XJ릡 ўnC%q+)@OB~VqzU5-A)fRܿܨ5?Ƒ>O  : ?RE&7Zugj4"uHlM_R42h/%i.۴x5;qUϢQKjdeN 邉Vc^P<]|H_|_r?Io~M3 pu3+ j04z.jVM꺲֓ 55%jDmovFRz)8DU"UU+K{K]ttǏGxp跸1qLVn8barb#%"i1mfLEơȽlO gk&wyăU棩k^i!#seԿJ/藋as})I)~aaM_e?U2YnC%m+췐z l^}x0۔}nlru L&D^ju6B -UxEGiSxGq= tTAwnK%`yƑLiQmy~YM&tpC_n8b`hv 6<])-\Ysnmi$-Xӯ{.;>^ZфM瘦'sB%TBЩ˿?L=N7 &e֟h-GxsU:nԟP͙Od*T,x81gpLWp  `Z,xC$>>vF$#TH)V';@VDε!dmG1Qh"fH#cӺ҇t|2C@^-Xop XrLӂEd0Q4F2vqujR!H' eE)чNQfbz"cΕ+b"d^|TEhѧ /i˗0e\i*~-4Ce:G?^w}Z* D&FHF|G 3\ ,`Ñ>W'ŀ(0 9!σ}9`^>b]6O,k)wñ=EP4Q KPFE1ĭx؅~Hb /ZjI9 89>+ cQÏZ F&cN^kte .BĺNĿ" ȐeQƂ.c1M* DaIS~W2X`0X5@v毤l$ç(gF:>t+$SE~JRD5x]P"1 I1Gԃ)# btwB& 쪈`UY 'G5hBw!*e 2 RdpaiVy`y.E\`A9 cg5Iy.yX C`(0 9]h!Jj%N|&QW PcdZԮwU$AG1A h!KwtfqoHF0G'T[b %e^t5 P\^\J99r%$ N ӊ2T|Xqh()wRx!U8p>DaR|p]>#kiZSq/ v(T*Q %髒WIvTXSN"&5?H>V 34'&`dgseNϗ)Hbc\m\ro)l* iHfz4s`)QKC:缿׽O3)YQq;!PwHP|r]tZ*U #09'11'FЇƿ/.\r˗/`'˗.\r˕bI0C;Dir*>H*qЄD-Ac1渱>-(P̃[20sqODz0U{oLZm* >XQG$%c%ϞQ),5|*<΋%O%ņ82ad K(bw„nc%)bᶀaX,P¡|#9!CBJ^N52v3湰-Aigu=b%.8!4jC.ϊqi d̮e(0 Wy"h,8pnkL$(T)Jog#$z{?јL>]ҋ9B6Q;W 8L1_ާOԞC;!BN[I00P\ZXso7ÔA⏽/m|6$g&SOxFx+8|/P!b#ޟ̲'\ 8B{0Ҭ9>]ҋ9:M+sϏlb ͆Ao<vfPar'*@w $H"D$H"D$H"D$H"D$H"D$H"D$H"D$H"D/댹~ $H"D$H"D$H"D$H"D$H"D$H"D$H"D$H"D#QK ;M< _YiMr>ERC%[S/gcqc TbY%2FAڀ;SbXM 3@by[g<`> D~7QCK; R 'h'!`!в}~3FAڀ;S>b]>~ R '|BRPN/SVm_®Ya(?axûvTx_ID-*ӑјq(/!WnQa!N%uƁ"8%KJ$)6| UFpKbtaJҜWUm3>K;YSFb}pbD\!s-XfnqSiFG(bwS>ɾ :{̌4ryXF `ñ G0Rsr#I1G>1\"l.N9a2ԣcQY,"| C㾰:R=rL0b'U836s ئ)v(m5 &ya2NZR\#Fr7b 'үLAqiM @=Bzo!42R0דȑo(hqA^!{e=B`U]5 df8 ;z\QZ+F S]t8v yc.7v}:b%*,$8B sWF Rr9 4` kS,Wǩ gE圾%V&:gA(F,Y{5ʉj8(ElE bj @Fc2 `(  +UP*(СE*z Q9mQ6@7$捴2R8°fN)#KqW@S'h$~02H@88LT0 D|eWMG dhmS) q3C 4@O3 8iF WcP*M20I0%hG[eWv)g>J@]>7-很gq,HatucRg<Ss 4Vlo+ 3{GjXmIjc^xJϷM(A0lx&v_2ˉ9FdG3^pG"%Nמgvi7 8ّje'1 0XrӇɎ#Zw@lɅ:t$1a;@ PZ*~L;F҄0 Ŷ5Xگ<! tj+j[irr e~iWN@7?4_$F&B݄[K+@p +aL"Ki̯3|l{Gxqbe] j)F%#d B :>w!T9fj춥Jp8917$7{>60-U"֡UI#K,i3/>4 |:# @+wz+PyjKnfY]AHXt,ok`d<19%EF \dPF TC"0DGJ)VJceʡz4>۵+ e4 =2 sв KS:s=W1Wp N#fC(bt|ٹ̨EZsrb3pcw 0|,(bt|X"L m_x D8Up,F\2B{B`f xAaA3eێc QŵB*x+88󪍸6ؚ,0(e~`cwYf,p ѓ]/b VN01}+( aȨd<qэ+bLp `Vp).lfX:$*[c;2, ]͘s :#EVn(hNS}s%4B'AZ%oaE^k2TܓG"DKlgfCGvT)<nbvip׉K!]ivgP %Irn`LR.njE!C].ɏ.XIM&U,V4&Y@^^#ʖ"Fe_óCLCdbɳר6n8_N|8t{T"N%e)Ԭ ^c-ZsX,3 nNd& 'bY,Wk"&oP :JP\g>W @9 %X;wnbּ e< h[!R s+7N0(E=f.X t pn`!.1]"GB@ o8ZTX4f s=ln0cױXvۑdx",^Kb5##.iXU1|Wϝ[Z.\V/#Lt'k@2P׭,F<?^I! ڟR5Oׯ^U. w *@plyw^Ua"XsHڵW*hT@V:SKL<30NOI{(m 0!9sqas|&QW/}i8,@~/S07Ax_`\áR9z4 jVcw r' J8D!6y k/.YCqn35;L,oB@Z)$v(S WsԒ,X"}8,P\ÃK e>ɾ) -!9\\vT`Q;Y`ZE8??F=I.B}Par'IS~vǮ(׀vයSF} ,*>S7h=Nq8a 4AIR5!_j~D/dde.CDAP6#E: DzA): , @[Kτ8L6jЉ| `0 (fwE'8 "B$( U!FuIUOM^6cu 2+ύX=-"tȼǸSsmUZ 򹜠Jd+R;UaH 1)|RE߁dR1ES |Na(EIXoRä3E#&ۃ"g 3{G,EL?'!A…/f$:N $?W% Sdҝ(Ru, "0xFm@~#&j6IWmlGepDPyv`.e2Zu '\!au 5BS*,d  1 0!9idƘSO2Ju<$0"X K OĀKVk `v'PT]i gm$P6ixDBsq3bʢL(t9o52EA9)AnWu]J FZ9}&_fZ)LX ̚Ff2aZS <.k`ی+d`sI@0`2ȸcf /`>uq^ml}NgZT8PbDɐvXə_&@Đ;@U 0!r9#,OzAVʪZZV ѳ_ct4e+&9vy Wa^33S-OqBF d !/3r24\2E$dq]YXz(0IЄvU45hC˝hv&e+.$E\-!h0KZ'& pivA2Tг,R. oYŀ*Eb&{$+buv Tv^vT> =dBVi SWȠlib4Vi\*g1p?%v+0#0q"Dh,D Pab-jf /q<2Ӷbga&Gb&)]s .8|-ɇ-Av*)8͠mn+̺hq,"k9Wa^:B4 " |&QWЈ+Ӈ @uWaYvyELÚOM)v3|+%0Dk|o&[3AK^5M 4l\PJ e EsZ9R|mUX1hN u Y ^a~4QCK;] M)k@2]2vuű 'Ir5KFcCh"ƦaBROȐ;/¿2Np2( pþP,XkEv`2JF2aj o $oB*Khd Ҡeq*,Mp̏V VBnr1{mn SD*hA*w$a8QX\0"D4TC)C~ \?8|dCLcO=m&X}afD#no"lL4TrÂ[/{82ވaX%(/U'BEhT6+Ӭr[FSvfahҹ3 3ƾ]m<,?17E79.a1ѾfXF1г 80D~K(؝sץBU9up#.-8J!|{)-p hIL{(؝~( iuuǓ-hE1iɦ)ز *Ľ%P&A-Ź .]2s%x("`!"v?D{D 07L*V?I<<@ɬ1@:O7>&z:5'IN"܄B#U#<%4`p)xg^]Bp]& ^#,~("N? ( @WdȞ3RLlCx2Ec "tz&&bf0 WKg/Vu=G hɠ` գGiԔqyFRJRW෹m|qXͳFbu߭* oXE'tDEeO.7gX?`ÃK e6DMLi<"ұÍN`$#@ "Π~TW cRlNDi+68ZΜu㍃ΡQC1]Z {'#L ڱZL>e!jy(b4_L4h\TVsd̦|5`'>|(@{uVtγ٬Ŭ#eJ"SrYLbcqmӷFbcP<4 BWyyqOPgC+1c5\JEaJ C[z`'2cP䥤qLBiDi4ѣFX8[m7ܲY\jkТ jR KO iPo O,ͺ+OҦD"Iafم@6 :su:b6s1h@~=`P\sJ, "(dy%kf` U+"h2i${kecN^",bCdR 4]оR9g3unS1``J:LLy7;j \M^@`]8.*\JC S@+S2){b48Y _ LNj|d Zn]M/=r̎lՐXs$:C60嶂c :NIygL7TJ̀W5 sR +# 0yV7uDa +d'B-daP># 0yVA@Y讫2EwlNyj;hRA59{q@lu=30d܁ٳɡ7%'EV reK[Rq,G1 !ĩ 3`6h 3hA^ wxQ@m}^ $MT(h!Hx MWGF2br02ުd$yo3L@#R]{砄S cnX&WO]s<b@\.38\,#2X ˺U,Q,emIH/cgͧe7 '=j iwnVXD'&ictNɉ:" "i,#4r^n Vljt QBDŽDN*el!V+g^S֪Gqb-<8gnZ(4'J$B4TZ"Lq V;"$Rp U+ge -;^f/EEA1a1*0㱾7,[̰hGfmA\pp FcbM)чFɊ 28.:iAʥa. }:3 %aRLgl2b@LX羬# A˥Z`:t׉yqfQ[`?5a&BHê8gcw,$P 3\FS|9ey%(1 x8r;RTY;oPN @C#1ANƸoƲ@s`,Xb)) Xn F"e(3y)+n-i&;d c='ܨbqc \Hhz05%/ToE?d%`8%@Te;ű w=hg!yC?  yQ( ( p?@p9 Y^h<M!R tە2k2ڃ:1t_PFm_ތs' K!$[aaqe2 zѫyU@".͋&hW:p!mT6V `d9/LL>,[N=ׁj}=dMf5z8@Y]DÚw[U\F~v+;`Iȟ+x /|-Ep#S uxia0VB!v 0(6=ǩrبW LM)BT^1KP()d%r6t[xFK@NhYG&(<$@1૵!؂~e\ze놘L0v~/h\nG)[ JA05mK~RǡLnMjl9\7˗.\r˗*& N 40tT$΁2 d\ 3קA8cW1/rܚZM2yD`7e6i>F4m|qϓLS-d85?֙ 7xmH1qRKs$c^T('Z&`!*eẉx$=]=JƝDkS\࠼ p4f JW4[`U][D-1b&Ǜ lPxzt]-as#^!!}ܗD4{ ^ |:heVeH"D-":PqODz0Ud(9r!Q~T'k(1#Np\`;#XWP7Zx;~/2}jTZU 9Oq(50?à J]b]L i|_\r˗/EvhQO=Ynsv*&FHFx:q9O=dn(?*-.)n3)'# DXh LRPNvNj !AQOy#X\7m~jJ!Es /Hf`DX#;hCIalIf f ,r@~@*kJD|*|΃lMcN<@4 AB4=s p#bgTZ੘rnNQJeŗOl[Ϭ1@:O4uvr |ĩd6\_9bn.HQ9Vtkfg55ʅ-֛{E)<@85u@* )A2:WU j%c9X?ZmPSr{Ur)>c9SQK ;bd,EEK̊u!P0 ?b%0SN4h@9z2׊q]^ܷk:raU h1W"H@p{NY{A!ADNdS D -H*fm* Cyy+vPfn3)X-AioOmItY\X`trGIYf:<-O"bu͟Sx8/wGKx 2 "s"`T * ockCQu}ZbQM/?#>k RhMR z#QYx tQ.Par'!1s"D$H"D pS3mH"D$H"Df}qbU"Í3U+ l!@2:WU DZZ,!Кx!U8b]L [7Aqa:Msύ]y9Tpi%bPGśsuy_m0gU['^!̵|repOub'J lMR MW@b A$قV7% gFP.1Jpgm1AHKEX9  ᡊ9>WNaNR63uGv Tà 0ODJ:ٸcX,OY[$SF =HUڄ;/lL/wt9 <[Rߐ O%`?m"}&jK8"0jcNGjOKz>fGE'؋wmr} ; K;"TGsp)ibZUp~IR*g$#.@.b4P(AR((eF/4cFf54?jà J=yJͼ+U, -6TOE5ŌA!lDtQHv_qsm犔Ҕ4RϧNӫ5u% +yyda0>^*1L2ICqF?i28̵ GM*`SJ-oaڼQHsF%jVfzaP]<9Ip2r~8$ݖ #Bpw^B/UU#ըޙԮpK\bXMb]'o7^`~G~ byȞ 73Gw&ntXr5qaT:9D@Al 0@S ꏔȳ8G9@Ww– I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$H$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$ $I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$@ I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I $I I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$ II$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I I$A$H$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$II $A$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$HI$I$ $I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$@ HI$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I HI$I$I$I$I$I$I$I$I$I$I$ $I$I$I$I$A$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$@$ $I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$ HI$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I I A$I$$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$IAA$I$HI$I$I$I$I$I$I$I$I$I$I$I$I$I$I$H$ $I$I$$I$I$I$I$I$I$I$I$I$I$I$I$I$I$HI$I$I$HI$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$AI$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$@$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$@I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$$I$I$H $II$I$A$I I$I$I$I$I$I$I I$A$A$ $A$I I$I$I$I$ $ I A @IA@$ @@ @I$I$II$I A  $ $A@$@A$ A I$I$I$I$A I H $H $@  $A$H  I @I$I$I$I$I$I$HI$I$I$I$I$I$I$I$I$I$IHH @$I I$I$I$I$I$I$I$H $A$I$I$I$I$I$I$H $II$I$I$I$I$I$I$ H$ $I$I$I$I$I$I$A I$H$I$I$I$I$I$I$I@$I$I$I$I$I$I$I$$I$I$I$A$I$I$I$I$I$I$I$ $$I$I$I$I$I$I$I$A$I$I$I$ $I$I$I$I$I$I$H I$II$I$I$I$I$I$I$ $I$I$I$I$I$I$I$I$I$I AH H $I$I$I$I$I$I$I$I$I$HI$I$I$I$I$I$H$H $I$I$I$I$I$I$I I$I$I I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$II$I$IHI$I$I$I$I$I$I$I$I$I$I$I$I$I$H$  I$I$I$II$I$I$I$I$I$I$I$I$I$I$I$I$I$@ AI$I$I$H$I$I$I$I$I$I$I$I$I$I$I$I$I$I$  $I$I$I$A$I$I$I$I$I$I$I$I$I$I$I$I$I$I$II A$I$I$I$ $I$I$I$I$I$I$I$I$I$I$I$I$I$A@I $I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$HI$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$  I I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$ I$I$I$H$@@I$I$I$I I$I$I$I$I$I$I$I$I$I$I$@$II$ @ $I$I$I$$I$I$I$I$I$I$I$I$I$I$I$HI$$I$I$I$I$I$I I$I$I$I$I$I I$I$I$I$I$I$I I$@II$I$I$I$$I$I$I$I$I$I I$I$I$I$I$I$I I$I$ $I$I$I$II$I$I$I$I$I$H$I$I$I$I$I$I$I$I$I$I$I$I$ $I$I$I$I$I$I$A$I$I$I$I$I$I$I$I$I$II$I$HI$I$I$I$I$I$I$ $I$I$I$I$I$I$I$I$I$I$ $I$ $I$I$I$A$HH$I$I$I$I$I$I$I$I$I$I$I$I$I$I$H I$I$I$I$$A$I$I$I$I$I$I$H I$I$I$I$I$I$I$A HI$I I$ $I$I$I$I$I$I$H I$I$I$I$I$I$I$ $A$I$AI$I$I$I$I$I$I$HI$I$I$I$I$I$I$II $@AHI$I$I$I$I$I$I$I$I$I$I$I$I$I$H$I$I A$I$H$I$I$I$I$I$I$I$I$I$I$I$I$I$I$A$I$I$I$A $AI$H $A H @ $I$$HA $H$I$I$ @ @H @A H$$ H  HA I$I$H$I$I$I$I$I$I$I$I$I$I$I$I$I$I$H$H$$ I$ A$I$I$I$I$I$I$A$$I$I$I$I$I$I$A$A H$I$@ $I$I$I$I$I$I$IAI$I$I$I$I$I$ $ A$I$@ I$I$I$I$I$I$I$I$I$I$I$I$I$I$@ I I$  $$I$I$I$I$I$I$I$I$I$I$I$I$I$I$H$II$A$I$I$I$I$I$I$I$I$I$I$I$I$I$I$HAII I$$I I$I$I$I$I$I$I$I$I$I$I$I$I$HH$$I$II@A$A$A$I$I$$I$I$I$I$I$I$I$I$I$I$I$ $I$I$I$ $ $A$I$I$@I$I$I$$I$I$I$I$$I$I$I$I$I$HI$I$I$$I$I$I$@I$I$I$I$$I$I$I$I$I$II$I$I$I$I$I$I$I$I$I $I$I$I$H$I$I$I$I I$I$I$I$I$I$I$I$I$I$I$I@I$I$I$@$I$I$I II$I$I$I$I$I$I$I$I$I$I$A$II$I$I$I$I$I$IH$I$I$I$I$I$I$I$I$I$I$I$ $I I$I$I$I$I$I$H$A$I$I $I$I$I$I$I$I$I$I$I$I I$I$I$I$I$I$A$I$I$I$I$I$I$I$I$I$I$I$I$H$I$I$ $I$I$I$I$$I$I$I$I$I$I IH$II$I$I$@$I$I$I$I$I$I$I$HI$I$I$I$I$I$@$H$I$I$I$A$I$I$I I$I$I$I$I$I$I$I$I$HA$I$I$I$@$I$I$HI$I$I$I$I$I$ $I$I$I I$I$I$ $I$I$I$A$I$I A$I$I$?e?e-!1AQ aq0@P`pр?RxPl2*؁&'cuDC_W<sPj> @-J}{hYG'E%0 dNUJF0߄,2%{ }觩 D!=Hց 9l vlbsh~S!ݠFKԀjܗh,.!xmm <EGpQ4R@p{;BE!a0R+ HM@ZA>Rߔd #3dH~_[YVH `4%Z) GБXJD 5rjԠ򖦎%Gr@sz_^!GB ĠNTNp TQwqUw2k*T[pQLd2Pa< jp+dᢜ(!v_r_HèhwP7H5C *10`^;>ĵPz(w)?0J/;貌IrbR@(r =q pVϚM@ZAÇumȀV>bŋ|!} Gك [. 0>3s)H0,>PQAJj$7H4 Sf0>DQ.X49ckQ!af)4<Ųd+H 6τ@(556`X@@ڽ5P"#aÇcQ -pw1`'};ċIzǏL"U`L`!h}MLXbgÇP"!V*u9"vjՂҎ~7,=;5ajGL[hz; "jԠ՚`T {@(Msc`97Qx0U{bſdFÇ?Vk :OJ#ʗB@dB|@, f MR{Be- 5AЬJřcU5,Po$}-Co@w+n+T QئH1P"w(ŽTAS/~L)h#nr Q?EQ"=!Δ zcSsIBk6UNrw} dXK5f,="WJ3֡KR'VI-L%ˏ`1"m'LF lt r8U;`5b5]iȍpW H$6NP"! -`ƴV Ii %f 66JPE6AD⭙D/qmQ!F Ey JLb(&B 1Ӑ:~Y1-8'1;ԈCK>Qڥx:XbCdP&ΞwȐA_^>~xߢ@ `/<å۔!;5ajGOܮ0xJMRjN3ےR'v mA:sr@| Խ-T{=MI*Q~_vDH^[@APoy-n&!~d,tT2?3+q @ud>࿟P"]R) i% p'}ģ/~};2KJ`m>C |a!) A;2KJ`m5"6H84 bA!;n9-\IX^O2&SR(`ca[|$A [+呫ǷqqL z?VkPZ۹5z]92&}!/Y;zhX/k와! GǏ4#)L:.fR+=T?=&QI"CL\~].܉ d,&AS/~L)h#nYbQaAٝU&(b$EIߤ`ӠU%fHh'Ϣw۬J@biȍpW H$6NP"! }Ů `*NO7:/ 2HF )=3tr$5G@ /Rgo}_՛O:vc!@ZB:QYVH<8pÇ8pÇ8pÇ8pÇ8pÇ8pÇ8pÇ8pÇ8=f8pÇ8pÇ8pÇ8pÇ8pÇ8pÇ8pÇ8pÇ~+"!jci% psVvhltv: meKe fY("Q 4z>X /FTfP=\v"X-(Ğ?VkR+!UrKSUkZxVBP%.W*՚`T U\ AE*UД"j{eKe!YDB"}h#nr3ԋނ=3<&_A݊И=4`P,xD@}bGs" @4( E=w4lU59 $ƏYJD:] 0:&c@'3zü&siCTxpŅ"&0'f:Mr Q=Dv51>j|=k4+V2ˣ3JÀYVD "&}l'L!\{'4&=%hTA&c@c'4"IQ~+"(!U5Ǽ"sBhPy0 Pgi8U U\I VE^x@nH.ՍlDoS>TJ2]Ս hI"nwB!<0_U+dcV   iZ&0 P=.qaH 6,A5cK5pB*5mQUnf;J( |8Z,,#EGJ.)ԆVvx-^|cGMRlfXQ#y0a&x4)26v- 3C>D%T#B@yŒcp@j$@E+7}Aݼvx-^vE h.QˇL(ڱ͝3d0ٕB(5U 6z GFJفW`ȷQȴBRAv"5da_.~iD=p`sNхX奺H5u \DQd.@JztB$PpDbMG` (M3v2 2E.Z5( 8LjMp*o2kfL>+cԱ.4 #Hl1-rOZPIC~>\ΝؒvWg/;/i6H"ZE8, *Vc;UUiOe;QEN{HFM&Z \$RCjz(QAa\:Გ<$&TV|6 ^iBb61 "KQ"-DN8ţeIJ.Z/FeZ2o1amnwef$\ d2IWڃ P ]$xFԨE[A3$#j|i1Qp6[bѲ-@RG (iW[娭'ɔEZTЦC Cyܴ10ں]Âs@])3P&#a@!+UUaT%taRR$Ŵ@hUn 1SxPCd,U]"ጇyʚXWY*:뤸4:j-剛kWԅVɌC`t)j?7vm+=LU""a4:v8g D8g1\~b<Y8 &Tb?t@+3䑥_ L[z6rIG.W*U# T( ͈U\(Eih ]GRO6 ЛfdKM8BR8ƪ}d0v>Ɠ.a!AKTВG)f 0}PrRSdB7Y{My b15o)'bXިpĨueƟ"_Q'΄e=Gr@piXErLP\,7h iఀ[˫H@R1woɐvL!Ɓ(A,* xbx #> DEl(iR@peX/R0A9ov ^yKTY< ^cbIDC7! mke@ZD;BܟQ$b͞#@* Mdcl{!쵳c"Ag݂=< Uht ڐÎZhT*sdp68ڣ}5%ls)/߬ !^F#z\n؞DNN]ľ0X_]GVfN?;,آ`lٞ ӈ0#%@Q lUֿV>} K̉E v5]XBMvFǎ'H`V KuآBI K*ޢof -rb袬S:H\ҍޏl5!Zld_ t ˏ@$X#]kVX^DQU즡oͼd֪kՙ7'`a Xh~%qf{M*i\:Zz(4nĠj18Ì50oӼ:gt޻JƬ| L80\* 1G) `IX8 Iǟ'I)0E$գAu⟻SJ0mt1,8+ O^zPvVȔdaEWLY0B)ƥurРf 1c0H(A#m)Y"(BbjD Otx1Q]XBMvD,uۻmb\[8݇~6'Kg7:+y{h*[ T*%%!vֲD@÷J0mt1b#d" 8Ԟs N j8(q–<_P×d g/H)TzVTڸth>oX Xjo-1ˠƚ hjtFjtT7#aPÆ`p-(H/:sQϒO/@fEAex @rOWW1kbˁV*` ADOPIu3uZrsb#qGHLcȺo]~cV6LG9e#Dq5;zZǢGwaD\5'C qU"+6J@q`ZXRy)݇~6'aiB^[N^j9d[Ծ26WsidC\D(mMd;l >" ~_Dr!pEUb&-'BhmUx,Xb02# ,lQ-Opbő\-U Q\6a AEbŶyAEaUUPDWAc*T\-PG^3u =,h\PLfق"ju !`&E:CnJBBf+k԰.B<ÀZۊtJpʱ`AS5:}k!A|ŴI@dCҬ!pf&ʓ7f쬤8l B& C(hJDLˆ~C˧C,pD>6jS!i_xFƻ͋d[@4&z *)t'd;tç\M5y}ijtpѳ" UWlc0!!J`LZ+p];h3nIk@$&U2RQ`hQ-^m!,A(sBօMMȸkd(MA@D7|bl5$bH7@, s&OS )H.5oʶ(2HH1(/dI6(sQ<k{'@J 9 Qw7àu C % [86mתA6D1sjc @W&ʵ*vBŦ 6=f)ʇ&s%YQuƳUH.jT`p* anhvCoy,JH&Bur FWk̂L@pϪA%uP65` #)WU "f4q И.{&UlU01re3gBפ!@V9m k;J uA~QvG`){XY;z H7Qق(!R±B6Ű !t:Īp#b&Id2GׅP&uv$,@I@)b1XR2ҞÇZ 1T j ̙qt|I (eS?c1((T]%+ \tP}y18;uԋϕ A@- ֻxªI}s8{?-H#lwBB"+.K"hcZ|r ](J!7%e$ ]3G 6ڻJb(ЕPjwPW aÅ КR>oڱ͝=_z]XP?G;"@w(,HT,:A-(b<"C y}N3PےpCNhD(zXE>ePB(ux֎ăRX1{\U"m@m3c!Ba(GcFRZ( UPQ0Z0%KՒ7/Ɩȗ2[yoyD>Re½BWFKo?v{vۀ$I"8HuP=P[=+E} NjEX; =co@Eu$vc+i(DG-,r6CsKuocPQm6І Ph+EL邲ڴNIءvK]@0@ҍ D |b,y "}T80!TZ gpG31W`#Ԏ5֜4ΆBI <- 0*1`8_ yTRf 1 *ةN3ђ" ?Vk'> P,b,H +?J TiheVtG* 2Aa5m3Ƞp"nq"{{ ='Q~GTFOe㐰fXU AAJesrU  1}! `y_ KWBA SӇ}:d<"0*hA^4B"Ō[rHLD=)D*D][Ju,=%^FZٿo\rTMU]waUy&W!F7ODq' * H,)P% KH )T_f6͘XU-C xdh0` 0` 0`اװ %yLPCҳt@||oV O8TxS{@TEB#[`+VQ`V `+Xr=t %@YA)xS҂t"Vk UW+6%# }87 fGD5vê(o@1h |7iE|܏ٳy HrB#kW4.E1+W_l#g0O>A?Է!_0U0V)U #J2sU8=)]0vDC~U" L*@ZB:QQ\,"E0*:6H@R ; R;1禬 cgNlYIЈ>O#fYE?~Çubbɦ*Kp#rbUxnb{̌bpm:BЀSIf$ #,+)c~)J6T1RIxğlbCd|+ScZ\DO7B @$j-y#m>3"s;7_3Oٓ"*g u"E}≘V(!2i c,8jyMBGBŀ] R̄=u`@3y84fL%J! @FqXװ,yRW5V" )'?i)&j!u ɍQa/cn4(ԉZ~oc&aXpt)*`7 ?Z ^ 0(vzN8! .zng1j'.w0#GN "%8~+"LDPl[K<@B8=@v}rƷYuyB$ .!ξ$gt͙!;nmd1!W9!Pւ?pvo zrffz EQ1  7軮:?&ȓ(6vQ9+2R2!R]}i8x`"@V)7r Q>y Hh3B8mK%^~`b"25*҆OfL-X!(S%6'2vP[µ;) ЈPg>D%T8pÇ8pÇ8pÇ8pÇ8pÇ8pÇ8pÇ8pb#ft pÇ8pÇ8pÇ8pÇ8pÇ8pÇ8pÇ8pÇ~D-PBSL}\(ܜ 0RfǑĂ,׹9)R[9",1 ͮzgp渲 }8p¿՚`U AQ͢p̠up"{phH!jā<( 5IX,@OG)S$5N@{Vg{@(M/qY/ E6 xFt`(* ҂~+"]I 5$؉d_nD$L[d?V`(<@{Dx!'nEP#8uV(,mIG6{07k("dd">8Q 5`NƇ$U@]cmm\&7eA٣dҹ "B@Z.!6q p7"Px_5-5 +@=_%MP>ڽBGB ĠDr HjFcHٔfFx{eqP/'E8T 0`bl["@@ZQA֌)/lt)a\u%mT'h*t]4Q}em2,py!DRs%;0 4keŒAIX*dSD4*[ԞhUjPa}?_=5Ƅ m]|["·BVEwӯj CҎB[X8Z0mdz154 A@OPK'z/ 8$&t z, IqȖв8HsL,S̙T:_΃S~ˎؚDڽ<)ΚaFr8PKP'@ZC7`lq E'BZu93$t~ TD&BWvSF/ thXDJ~0UzRTƈ2Rc+ehXe;G JH3x3~3x/_}#Y2Gkj@qiJxdc DF 1*~\e!vRQ3*#&&Ȉf7\N9l)ogw ?U&< )cb]Ҳ"ȽI,R[<WB!",5]3hD:[ltȜXCqΑjy Q17 /i&N@!!g'q3vnuA x3٥0Cr(c$C8N&e>Q0ɯufCvS, INTI8^0|ǵ{M i#sT+ ҜgMKvn!ФnPHeU&dJJp':#{;o`:c!!"h$`(O*'Ե9 3P!'Km)kXۺQ654%B!s#{^3^dhqkSP48B!Mij:&NBx&Ch)˽A<\</ܾIG #5 8P4<2B1eLgS 6.dCGTSat OD.$teh 6ۋC "4$@gcRq62M6e8+#ifvV_"xkhXaf('CAx@chu~1߫BCj' @躏>%Ի~:mf\E\kRLQ5 ̒.;dA0D& W lm0h#USNOl oJ_ [iq8KD1 <3sz%z=Cz^R{q)kJNrM[uU@|u9p.qCA[| A9"M;Ù]>KD@L3@aRZnT`8A,1 ,*L] $w j:|@.vӭZpɀȝUZBxtϾ @+ER ^mfJ}K_',')~2'U!^ܔ4 e ٭G IR*qUQ!w87sD M(UMG,bbitژ0py$JWPs`(ǎ-Jd%!~I&?H[R*.}>Bb]\p8!Ϫ4@Mx"2 -V J9tvZxN#pjco NB* ;k]W jzW/o , aN8Ʉ9Y#`~jJ5IQYI4!z,KN1++J F<"sB 3aFī,8WښX*ldFJAWlH(~@_RX:(pB OM'7̑+H']TCJx&ASBBPLr Qh܈+f T~2`_m(X՚`T RqaSؑv"X-(ČDv51>jtl(9ko'5'QR?Y@X^ԺD€nۜ)492]ԍlό6fiF*UА ">B` ?_[KާG03 Î7ڱpQ)4QG 5sZP2, ʼˢ- I0cTd_[4:z)J[*;W +pcNb{ ~"S}1 w*8 P&2R O).dʼ+.+dԾ;(TiAL~3(q.:R=fv֏ߋ(+o>EnsB "=pA|lLB۱M1<>h-178sq!ż<'~ tj"Қk!Phj=HMP 0:Le Gϼ>|'nZBˣo(SM :n`)/~UwoJK@%/\1e͊P)˸c"je͊P!ɸ*W!Zr@.BH߶wyvtÅcm?6i8Q.穀&xyQ HP1T7h 3N a0p$B`o],f:{lyCqFRkHhT<6 C"#"o$K ໌\?hƊ ҔTXQ}A@F5d# 8_l*P@бF7YǏY?=-e~2[ayؘdN#B׆ *ԖA8a0'aZs\BDQ~๔bhs/TuK秷dJX?>DH,JgJL!yCdU:0YZ;۹F6K, ovojg }tAub`ɶY5 L\ZQcI^H2@ (M*A B .ia5rk \r$fjD+42;SFh y U&H(=N>|'R qǏdǏO 6$qq՘!B&L%XM!>%^oDULocaUڱ]}`|`O8Ǐ}Ҿ}s 1k~#z;;=~ q(q"cX.B$l=j{L hLKVN0( c,8]~ ܓ+ }1^5!5OvX~FP/S#wtYKyņڱ]3N0*CcC0ނ=3<&_쯚7\ R' +'}M~D-PB0(v=v`@f>{:z^!\~E>$S؁ ]] KN0Y 8pÇK͍@ [!p2ɟN a\xǴVĸ}b:'H0>@`4pM"|M>O Y^&L%XM!韴f~B w )==K) =w`"Ǐ(P[OldS#7?h"DVA =GK Xqn IY?_4o4FD8}@v`5ȀDD$ld_x}y. P,ToU'afp j Qh;#?}H&qe@*gȀ|.aC\@i(.z!RJðB`6} 9G5ȀDDD@UcȂ@>а[$SWҋwk&d=ߎɉ6E'zRz}9Mh:#Lr Q>_LW?IM86'^|]kg$Q}|U+g-QO˫Z,#c>cW_ogZi(:P٫bIx qhW45Gb}{h(YS԰J 9.t)tHk%FvHw|b, cyw"4"!5W_g#1U"#jGp s-^#d:Q h Pa${`GcCb}# B@([&~N0(i% p|b,X!p~I0`tDiKl8pÇ8pJ @lÇ8pÇ,iKbJhZ nnHRݮ@DF)-s" 0Bw,VW@8g򙏮XC;+3-W@ `/<å۔!/kG1)PċdyWSb忥9ұ"Fy.9]d#"n+N-5n%1]j2.*vTqŀbR1!M”S{g c;0TlC -fHHxBI.S8AIS 8Hr Dt+d~&85.(ޒhLT}:b ٨ VGJ:}@|j {i3~ >\5 Y3!] L1ނ=3<&_A݊И@nYwB!.Ռh{ 3O$ hU4$2dᠶL#aFiͅƨ@jvpxr8J W쾱 *!sTƕMB ZG@:@`醑fY(x؏՚`T oP~#yA y+4ԊC@?Ӳh#9q!nz?~p0MyXz߽^oԭ`,g?Gsgperftools-0.2.0/README.md010064400007650000024000000113521343325671600134070ustar0000000000000000# Gperftools for Rust > This code is an extension of the work in [AtheMathmo/cpuprofiler](https://github.com/AtheMathmo/cpuprofiler). This library provides bindings to Google's [gperftools](https://github.com/gperftools/gperftools). ## Why use this? There are other profiling tools for Rust, [cargo-profiler](https://github.com/pegasos1/cargo-profiler) is particularly good! This library certainly doesn't replace those but adds a some different tools to the mix: - Makes it easy to profile only sections of code. - Uses statistical sampling wwhich means low overhead. - Works with [pprof](https://github.com/google/pprof) for a range of output formats. - Allows memory profiling out of the box (on linux and macOS). ## Installation In order to use this library you will need to install [gperftools](https://github.com/gperftools/gperftools). There are instructions in their repository but it's roughly the following: 1. Download package from [releases](https://github.com/gperftools/gperftools/releases) 2. Run `./configure` 3. Run `make install` There may be some other dependencies for your system - these are explained well in their [INSTALL](https://github.com/gperftools/gperftools/blob/master/INSTALL) document. For example [libunwind](http://download.savannah.gnu.org/releases/libunwind/) (> 0.99.0) is required for 64 bit systems. ## Usage Add `gperftools` to your `Cargo.toml` manifest. ``` [dependencies] gperftools = "0.1.0" ``` Add the dependency to your root: ``` extern crate gperftools; ``` Start and stop the profiler around the code you'd like to draw samples. This will save the profile to a file you specify. ```rust // CPU use gperftools::profiler::PROFILER; PROFILER.lock().unwrap().start("./my-prof.prof").unwrap(); // Code you want to sample goes here! PROFILER.lock().unwrap().stop().unwrap(); // HEAP use gperftools::heap_profiler::HEAP_PROFILER; HEAP_PROFILER.lock().unwrap().start("./my-prof.hprof").unwrap(); // Code you want to sample goes here! HEAP_PROFILER.lock().unwrap().stop().unwrap(); ``` Now you can just run the code as you would normally. Once complete the profile will be saved to `./my-prof.prof`. The final step is the fun part - analyzing the profile! ### Heap Profiling To use the heap profiler, a custom allocator is used. This feature requires setting the feature `heap`, to enable it. When enabled the global allocator will be changed to use tcmalloc, which is required for gperftools to analyse allocations. You can find additional documentation about heap profiling [here](https://gperftools.github.io/gperftools/heapprofile.html). ### Analyzing the profile To analyze the profile use Google's [pprof](https://github.com/google/pprof) tool. You can find some documentation on how to use it with gperftools [here](https://gperftools.github.io/gperftools/cpuprofile.html). If you have issues with smybols not being displayed make sure - you enable debug symbols (`RUSTFLAGS=-g`) - `llvm-symbolize` is in your path ## The Result The output format is entirely dependent on [pprof](https://github.com/google/pprof) but here are some examples from a Rust program: #### Text ``` Total: 855 samples 207 24.2% 24.2% 207 24.2% matrixmultiply::gemm::masked_kernel::hfdb4f50027c4d91c 156 18.2% 42.5% 853 99.8% _$LT$rusty_machine..learning..optim..grad_desc..StochasticGD$u20$as$u20$rusty_machine..learning..optim..OptimAlgorithm$LT$M$GT$$GT$::optimize::h2cefcdfbe42a4db8 79 9.2% 51.7% 79 9.2% _$LT$$RF$$u27$a$u20$rulinalg..vector..Vector$LT$T$GT$$u20$as$u20$core..ops..Mul$LT$T$GT$$GT$::mul::h21ce4ecb4bbcb555 66 7.7% 59.4% 73 8.5% __ieee754_exp_sse2 61 7.1% 66.5% 95 11.1% _$LT$rusty_machine..learning..toolkit..regularization..Regularization$LT$T$GT$$GT$::l2_reg_grad::h4dff2e22567a587e 57 6.7% 73.2% 274 32.0% matrixmultiply::gemm::dgemm::h2d985771431fcfd4 41 4.8% 78.0% 42 4.9% _$LT$rulinalg..matrix..Matrix$LT$T$GT$$GT$::transpose::h736b18b122958bcd 31 3.6% 81.6% 32 3.7% sdallocx ``` The first column is the number of samples from each function. The second is the percentage of samples which were found directly in this function, and the third column is the percentage of samples which were in this function or it's children. _I think..._ #### Graphviz Below is a snippet of an interactive graph output. ![Function call graph](./images/pprof-gz.jpg) The above graph is produced by pprof and shows which functions the samples belong too. In the above we see that there were 513 samples in the `compute_grad` function and 119 of these were matrix multiplication. ### TODO - Better crate documentation - Expose other functions ## License This project has a BSD license to match the gperftools license. Which makes sense, I think? gperftools-0.2.0/src/error.rs010064400007650000024000000013201343325407700144060ustar0000000000000000//! Error handling for the cpuprofiler thanks to error_chain! use state::ProfilerState; use std::ffi; use std::io; use std::str; error_chain! { foreign_links { Io(io::Error); Nul(ffi::NulError); Utf8(str::Utf8Error); } errors { InternalError { description("Internal library error!") display("Internal library error!") } InvalidState(state: ProfilerState) { description("Operation is invalid for profiler state") display("Operation is invalid for profiler state: {}", state) } InvalidPath { description("Invalid path") display("Invalid path provided") } } } gperftools-0.2.0/src/heap_profiler.rs010064400007650000024000000125361343325705300161040ustar0000000000000000//! Heap Profiler //! //! //! # Usage //! //! ``` //! use gperftools::HEAP_PROFILER; //! //! // Start profiling //! HEAP_PROFILER.lock().unwrap().start("./my-profile.mprof"); //! //! { //! // do some work //! let v = vec![1; 1000]; //! println!("{:?}", v); //! // sleep a bit so we have time to profile //! std::thread::sleep_ms(1000); //! } //! //! // stop profiling //! HEAP_PROFILER.lock().unwrap().stop(); //! ``` //! //! The following environment flags can change the behaviour of the profiler. //! //! - `HEAP_PROFILE_ALLOCATION_INTERVAL` (Default: 1GB) - If non-zero, dump heap profiling information once every specified number of bytes allocated by the program since the last dump. //! - `HEAP_PROFILE_DEALLOCATION_INTERVAL` (Default: 0) - If non-zero, dump heap profiling information once every specified number of bytes deallocated by the program since the last dump. //! - `HEAP_PROFILE_INUSE_INTERVAL` (Default: 100MB) - If non-zero, dump heap profiling information whenever the high-water memory usage mark increases by the specified number of bytes. //! - `HEAP_PROFILE_INUSE_INTERVAL` (Default: 0) - If non-zero, dump heap profiling information once every specified number of seconds since the last dump. //! - `HEAP_PROFILE_MMAP_LOG` (Default: false) - Should mmap/munmap calls be logged? //! - `HEAP_PROFILE_MMAP` (Default: false) - If heap-profiling is on, also profile mmap, mremap, and sbrk //! - `HEAP_PROFILE_ONLY_MMAP` (Default: false) - If heap-profiling is on, only profile mmap, mremap, and sbrk; do not profile malloc/new/etc //! //! The profiler is accessed via the static `HEAP_PROFILER: Mutex`. //! We limit access this way to ensure that only one profiler is running at a time - //! this is a limitation of the heap-profiler library. use std::ffi::CString; use std::os::raw::{c_char, c_int}; use std::sync::Mutex; use error::{Error, ErrorKind}; use state::ProfilerState; use util::check_file_path; lazy_static! { /// Static reference to the HEAP_PROFILER /// /// The heap-rofiler library only supports one active profiler. /// Because of this we must use static access and wrap in a `Mutex`. #[derive(Debug)] pub static ref HEAP_PROFILER: Mutex = Mutex::new(HeapProfiler { state: ProfilerState::NotActive, }); } #[allow(non_snake_case)] extern "C" { fn HeapProfilerStart(fname: *const c_char); fn HeapProfilerStop(); fn HeapProfilerDump(resaon: *const c_char); fn IsHeapProfilerRunning() -> c_int; } /// The `HeapProfiler` /// /// The `HeapProfiler` gives access to the _heap-profiler_ library. /// By storing the state of the profiler and limiting access /// we make the FFI safer. #[derive(Debug)] pub struct HeapProfiler { state: ProfilerState, } impl HeapProfiler { /// Returns the profiler state. /// /// # Examples /// /// ``` /// use gperftools::heap_profiler::HEAP_PROFILER; /// /// println!("{}", HEAP_PROFILER.lock().unwrap().state()); /// ``` pub fn state(&self) -> ProfilerState { self.state } /// Checks if the heap profiler is running. /// /// # Examples /// /// ``` /// use gperftools::heap_profiler::HEAP_PROFILER; /// /// println!("running? {}", HEAP_PROFILER.lock().unwrap().is_running()); /// ``` pub fn is_running(&self) -> bool { let state = unsafe { IsHeapProfilerRunning() }; state == 1 } /// Start the heap profiler /// /// Will begin sampling once this function has been called /// and will not stop until the `stop` function has been called. /// /// This function takes as an argument a filename. The filename must be /// both valid Utf8 and a valid `CString`. /// /// # Failures /// /// - The profiler is currently `Active`. /// - `fname` is not a valid `CString`. /// - `fname` is not valid Utf8. /// - `fname` is not a file. /// - The user does not have write access to the file. /// - An internal failure from the gperftools library. pub fn start>>(&mut self, fname: T) -> Result<(), Error> { if self.state == ProfilerState::NotActive { let c_fname = try!(CString::new(fname)); check_file_path(c_fname.clone().into_string().unwrap())?; unsafe { HeapProfilerStart(c_fname.as_ptr()); } self.state = ProfilerState::Active; Ok(()) } else { Err(ErrorKind::InvalidState(self.state).into()) } } /// Stop the heap profiler. /// /// This will stop the profiler if it `Active` and return /// an error otherwise. /// /// # Failures /// /// - The profiler is `NotActive`. pub fn stop(&mut self) -> Result<(), Error> { if self.state == ProfilerState::Active { unsafe { HeapProfilerStop(); } self.state = ProfilerState::NotActive; Ok(()) } else { Err(ErrorKind::InvalidState(self.state).into()) } } /// Manually trigger a dump of the current profile. pub fn dump>>(&mut self, reason: T) -> Result<(), Error> { let c_reason = try!(CString::new(reason)); check_file_path(c_reason.clone().into_string().unwrap())?; unsafe { HeapProfilerDump(c_reason.as_ptr()); } Ok(()) } } gperftools-0.2.0/src/lib.rs010064400007650000024000000006411343325700700140240ustar0000000000000000#![warn(missing_debug_implementations)] #[macro_use] extern crate error_chain; #[macro_use] extern crate lazy_static; mod state; mod util; pub mod error; pub mod profiler; pub use profiler::*; #[cfg(feature = "heap")] pub mod heap_profiler; #[cfg(feature = "heap")] pub use heap_profiler::*; #[cfg(feature = "heap")] mod tcmalloc; #[cfg(feature = "heap")] static GLOBAL: tcmalloc::TCMalloc = tcmalloc::TCMalloc; gperftools-0.2.0/src/profiler.rs010064400007650000024000000103261343325437700151100ustar0000000000000000//! Cpu Profiler //! //! This crate provides safe bindings to google's gperftools library. //! This allows us to use statistical sampling to profile sections of code //! and consume the output in a number of ways using [pprof](https://github.com/google/pprof). //! //! # Installation //! //! In order to use this library you will need to install [gperftools](https://github.com/gperftools/gperftools). There are instructions //! in their repository but it's roughly the following: //! //! 1. Download package from [releases](https://github.com/gperftools/gperftools/releases) //! 2. Run `./configure` //! 3. Run `make install` //! //! There may be some other dependencies for your system - these are explained well in their //! [INSTALL](https://github.com/gperftools/gperftools/blob/master/INSTALL) document. //! For example [libunwind](http://download.savannah.gnu.org/releases/libunwind/) (> 0.99.0) is required for 64 bit systems. //! //! # Usage //! //! ``` //! use gperftools::profiler::PROFILER; //! //! PROFILER.lock().unwrap().start("./my-profile.prof"); //! // Code you want to sample goes here! //! PROFILER.lock().unwrap().stop(); //! ``` //! //! The profiler is accessed via the static `PROFILER: Mutex`. //! We limit access this way to ensure that only one profiler is running at a time - //! this is a limitation of the gperftools library. use std::ffi::CString; use std::os::raw::c_char; use std::sync::Mutex; use error::{Error, ErrorKind}; use state::ProfilerState; use util::check_file_path; lazy_static! { /// Static reference to the PROFILER /// /// The gperftools library only supports one active profiler. /// Because of this we must use static access and wrap in a `Mutex`. #[derive(Debug)] pub static ref PROFILER: Mutex = Mutex::new(Profiler { state: ProfilerState::NotActive, }); } #[allow(non_snake_case)] extern "C" { fn ProfilerStart(fname: *const c_char) -> i32; fn ProfilerStop(); } /// The `Profiler` /// /// The `Profiler` gives access to the _gperftools_ library. /// By storing the state of the profiler and limiting access /// we make the FFI safer. #[derive(Debug)] pub struct Profiler { state: ProfilerState, } impl Profiler { /// Returns the profiler state /// /// # Examples /// /// ``` /// use gperftools::profiler::PROFILER; /// /// println!("{}", PROFILER.lock().unwrap().state()); /// ``` pub fn state(&self) -> ProfilerState { self.state } /// Start the profiler /// /// Will begin sampling once this function has been called /// and will not stop until the `stop` function has been called. /// /// This function takes as an argument a filename. The filename must be /// both valid Utf8 and a valid `CString`. /// /// # Failures /// /// - The profiler is currently `Active`. /// - `fname` is not a valid `CString`. /// - `fname` is not valid Utf8. /// - `fname` is not a file. /// - The user does not have write access to the file. /// - An internal failure from the gperftools library. pub fn start>>(&mut self, fname: T) -> Result<(), Error> { if self.state == ProfilerState::NotActive { let c_fname = try!(CString::new(fname)); check_file_path(c_fname.clone().into_string().unwrap())?; unsafe { let res = ProfilerStart(c_fname.as_ptr()); if res == 0 { Err(ErrorKind::InternalError.into()) } else { self.state = ProfilerState::Active; Ok(()) } } } else { Err(ErrorKind::InvalidState(self.state).into()) } } /// Stop the profiler. /// /// This will stop the profiler if it `Active` and return /// an error otherwise. /// /// # Failures /// /// - The profiler is `NotActive`. pub fn stop(&mut self) -> Result<(), Error> { if self.state == ProfilerState::Active { unsafe { ProfilerStop(); } self.state = ProfilerState::NotActive; Ok(()) } else { Err(ErrorKind::InvalidState(self.state).into()) } } } gperftools-0.2.0/src/state.rs010064400007650000024000000007511336134374700144070ustar0000000000000000use std::fmt; /// The state of the profiler #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ProfilerState { /// When the profiler is active Active, /// When the profiler is inactive NotActive, } impl fmt::Display for ProfilerState { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match *self { ProfilerState::Active => write!(f, "Active"), ProfilerState::NotActive => write!(f, "NotActive"), } } } gperftools-0.2.0/src/tcmalloc.rs010064400007650000024000000011001343325703000150370ustar0000000000000000use std::alloc::{GlobalAlloc, Layout}; use std::os::raw::c_void; #[allow(non_snake_case)] extern "C" { fn tc_memalign(alignment: usize, size: usize) -> *mut c_void; // fn tc_free(ptr: *mut c_void); fn tc_free_sized(ptr: *mut c_void, size: usize); } pub struct TCMalloc; unsafe impl GlobalAlloc for TCMalloc { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { tc_memalign(layout.align(), layout.size()) as *mut u8 } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { tc_free_sized(ptr as *mut c_void, layout.size()); } } gperftools-0.2.0/src/util.rs010064400007650000024000000007031343325442000142260ustar0000000000000000use error::{Error, ErrorKind}; use std::path::Path; /// Check if the provided path provides a valid file reference. pub fn check_file_path>(path: P) -> Result<(), Error> { match path.as_ref().parent() { Some(p) => { if p.exists() { Ok(()) } else { Err(ErrorKind::InvalidPath.into()) } } None => Err(ErrorKind::InvalidPath.into()), } } gperftools-0.2.0/.cargo_vcs_info.json0000644000000001120000000000000132500ustar00{ "git": { "sha1": "9add5c3014c29bc785f4ee443b3a4a50b4e11fb0" } }