Ë A±‡Ã*/õÞãó&—ddlZddlZddlZddlZddlZddlZddlZddlmZddl m Z m Z m Z m Z d„Zd„Zd„Ze j"s e j$rdZe j$Znd Zd Zdd „Z dd „Zdd „Zd„Zdd„Ze j$reZd„ZyeZeZd„Zy)éNé)Ú_)ÚencodingÚerrorÚpycompatÚscmutilcóð— ttjd««}|dkDr|S tt j d«}|dkDr|S y#ttf$rYŒ7wxYw#ttf$rYywxYw)z-try to count the number of CPUs on the systemÚSC_NPROCESSORS_ONLNrsNUMBER_OF_PROCESSORSr)ÚintÚosÚsysconfÚAttributeErrorÚ ValueErrorrÚenvironÚKeyError)Úns ú4usr/lib/python3.12/site-packages/mercurial/worker.pyÚ countcpusrs‘€ð Ü ”— ‘ Ð0Ó1Ó 2ˆØ ˆqŠ5؈Hð ð  Ü ”× Ñ Ð!8Ñ9Ó :ˆØ ˆqŠ5؈Hð ð øô œJÐ 'ò Ù ð ûô ”jÐ !ò Ø à ð ús"‚$A©"A#ÁA ÁA Á#A5Á4A5cóä—|jdd«}|r t|«}|dk\r|S t tt«d«d«S#t$rtjt d««‚wxYw)Nóworkersnumcpusrs!number of cpus must be an integeréé ) Úconfigr rrÚAbortrÚminÚmaxr)ÚuiÚsrs rÚ _numworkersr0su€Ø � ‰ �)˜ZÓ(€AÙð GÜ�A“ˆAØ�AŠvØ�ðô Œs”9“; Ó" BÓ 'Ð'øôò GÜ—+‘+œaÐ DÓEÓFÐ Fð Gús –AÁ(A/cóT—tj«tj«k(S©N)Ú threadingÚcurrent_threadÚ main_thread©órÚ ismainthreadr'<s€Ü × #Ñ #Ó %¬×)>Ñ)>Ó)@Ñ @Ð@r&g{®Gáz„?gꌠ9Y>)FFcób—|stry||z}t|«}|t|z||z zz }|dk\S)zetry to determine whether the benefit of multiple processes can outweigh the cost of starting themFg333333Ã?)Ú_DISALLOW_THREAD_UNSAFErÚ _STARTUP_COST)rÚ costperopÚnopsÚ threadsafeÚlinearÚworkersÚbenefits rÚ worthwhiler1KsC€ñ Õ1Øà ˜Ñ €Fܘ"‹o€GØœ ¨Ñ/°&¸7Ñ2BÑBÑC€GØ �d‰?Ðr&có—|jdd«}|rttur t«sd}|r)t ||t |«|¬«rt||||||¬«S|||fzŽS)arun a function, possibly in parallel in multiple worker processes. returns a progress iterator costperarg - cost of a single task func - function to run. It is expected to return a progress iterator. staticargs - arguments to pass to every invocation of the function args - arguments to split into chunks, to pass to individual workers hasretval - when True, func and the current function return an progress iterator then a dict (encoded as an iterator that yield many (False, ..) then a (True, dict)). The dicts are joined in some arbitrary order, so overlapping keys are a bad idea. threadsafe - whether work items are thread safe and can be executed using a thread-based worker. Should be disabled for CPU heavy tasks that don't release the GIL. prefork - a parameterless Callable that is invoked prior to forking the process. fork() is only used on non-Windows platforms, but is also not called on POSIX platforms if the work amount doesn't warrant a worker. rsenabledF)r-)Úprefork)Ú configboolÚ_platformworkerÚ _posixworkerr'r1Úlen) rÚ costperargÚfuncÚ staticargsÚargsÚ hasretvalr-r3Úenableds rÚworkerr>Xsl€ðJ�m‰m˜I zÓ2€GÙ”?¤lÑ2¼<¼>ðˆá”:˜b *¬c°$«iÀJÕOÜØ ��j $¨ ¸7ô ð ñ �˜t˜gÑ%Ð &Ð&r&c #ó ‡‡‡‡‡‡‡‡‡‡‡‡‡ ‡!K—t|«}tjtj«Štjtjtj«t «dgcŠŠˆˆfd„Šdˆˆfd„ Š ˆˆˆ fd„}tjtj |«Š|j«tj«}gŠi} |r|«t|t|t|«««D�]Štj«\ŠŠ!‰j‰‰!f«d} tj«} | dk(rhtjtj‰«tjtj ‰«ˆˆˆˆˆˆ!fd„} t!j"|| «} tj«|k7r) |j«tj.| d z«‰j1 «�Œt3j4«Š‰D]O\ŠŠ!tj6‰!«‰j9tj:‰d d «t2j<«ŒQd „Šˆfd „}ˆˆˆˆˆ fd„} t‰«}|dkDrV‰j?«D]=\}} ||j@«D]"}|r|dr| jC|d«Œ|–—Œ$Œ?|dkDrŒV|«}|rC|dkr)tjHtj«| «tKjL|«‚|rd| f–—yy#tj«|k(r‚t%j&«d} t)| t*« }|j-|¬«Y�ŒáxYw#Y�ŒÁxYw#tj.| d z«wxYw#tj«|k7rO |j«n#YnxYwtj.| d z«w#tj.| d z«wxYwwxYw#tD$r>‰jG|j@«|j@j7«|dz}Y�ŒÌwxYw#‰«|«‚xYw­w)NrcóÄ•—tjtj‰«‰D]'} tj|tj«Œ)y#t $rYŒ6wxYwr!)ÚsignalÚSIGCHLDr ÚkillÚSIGTERMÚProcessLookupError)ÚpÚoldchldhandlerÚpidss €€rÚ killworkersz!_posixworker..killworkers�sLø€ô � ‰ ”f—n‘n nÔ5ãˆAð Ü—‘˜œ6Ÿ>™>Õ*ñøô&ò Ùð ús¬$AÁ AÁATcó*•—‰j«D]_}dx}} tj||rdntj«\}}|sŒ6‰j |«t |«}|sŒU‰drŒ[|‰d<Œay#t$r‰j |«YŒLwxYw©Nr)Úcopyr ÚwaitpidÚWNOHANGÚChildProcessErrorÚdiscardÚ _exitstatus)ÚblockingÚpidrFÚstrHÚproblems €€rÚwaitforworkersz$_posixworker..waitforworkersœsŒø€Ø—9‘9–;ˆC؈JˆA�ð "ÜŸ ™  3©h©¼B¿J¹JÓH‘��2ñ ðØ �L‰L˜ŒOܘR“ˆBÚ˜' !›*Ø�˜’ ñøô%ò "ð— ‘ ˜SÖ!ð "úsš+A5Á5BÂBcó2•—‰d¬«‰dr‰«yy)NF)rRrr%)ÚsignumÚframerIrUrVs €€€rÚsigchldhandlerz$_posixworker..sigchldhandler®sø€Ù Õ&Ø �1Š:Ù �Mð r&éÿÿÿÿcó^•—‰ddD]/\}}tj|«tj|«Œ1tj‰«tj‰ d«5}‰‰‰fzŽD](}tj||«|j «Œ* ddd«y#1swYyxYw)Nr[Úwbr)r ÚcloseÚfdopenÚpickleÚdumpÚflush) ÚrÚwÚwfÚresultr9ÚpargsÚpipesÚrfdr:Úwfds €€€€€€rÚ workerfuncz _posixworker..workerfuncÒs�ø€Ø % c r£ ™˜˜1ÜŸ™ œ ÜŸ™ � ð!+ô—H‘H˜S”MÜŸ™ 3¨Ô-°Ù&*¨Z¸5¸(Ñ-BÓ&D˜FÜ"ŸK™K¨°Ô3ØŸH™H�Jñ'E÷.ð÷ .ðús Á$5B#Â#B,)ÚforceéÿÚrbicó¶—tj|j«d«|j«}tj|j«d«|S©NFT)r Ú set_blockingÚfilenoÚpeek)ÚfÚress rÚ peek_nonblockz#_posixworker..peek_nonblockös:€Ü �‰˜Ÿ™›  EÔ*Ø�f‰f‹hˆÜ �‰˜Ÿ™›  DÔ)؈ r&c3ó¾•K—tj|«–—t‰|««dkDr-tj|«–—t‰|««dkDrŒ,yy­wrK)r`Úloadr7)rtrvs €rÚload_allz_posixworker..load_allüsKøèø€ô�k‰k˜!‹nÒÜ‘- Ó"Ó# aÒ'Ü—+‘+˜a“.Ò ô‘- Ó"Ó# aÕ'ùs ƒAAÁAcóÌ•—tjtj‰«‰«tjtj‰«‰j«‰dSrK)rAÚSIGINTrBr^)rGÚ oldhandlerrUÚselectorrVs€€€€€rÚcleanupz_posixworker..cleanupsAø€Ü� ‰ ”f—m‘m ZÔ0ÙÔÜ� ‰ ”f—n‘n nÔ5Ø�‰ÔØ�q‰zÐr&r©T)'rrAÚ getsignalr{ÚSIG_IGNÚsetrBrbr ÚgetpidÚ partitionrr7ÚpipeÚappendÚforkrÚ callcatchÚsysÚexc_infoÚ issubclassÚKeyboardInterruptÚ tracebackÚ_exitÚaddÚ selectorsÚDefaultSelectorr^Úregisterr_Ú EVENT_READÚselectÚfileobjÚupdateÚEOFErrorÚ unregisterrCrÚ WorkerError)"rr9r:r;r<r3r/rZÚ parentpidÚretvalÚretrSrkÚexctyperlryr~Ú openpipesÚkeyÚeventsruÚstatusrIrGr|rgrvrHrhrUrir}rVrjs" `` @@@@@@@@@@@@rr6r6Šs„ÿýèø€Ü˜"‹o€GÜ×!Ñ!¤&§-¡-Ó0€JÜ ‡M�M”&—-‘-¤§¡Ô0Ü“E˜A˜3€M€Dˆ'õ ö ö$ô —]‘]¤6§>¡>°>ÓB€N؇H�H„JÜ— ‘ “ €IØ €EØ €FáÙŒ ä˜4¤ W¬c°$«iÓ!8×9ˆô —7‘7“9‰ˆˆSØ � ‰ �c˜3�ZÔ ðˆð (Ü—'‘'“)ˆCØ�aŠxÜ— ‘ œfŸm™m¨ZÔ8Ü— ‘ œfŸn™n¨nÔ=÷ ñ ô×'Ñ'¨¨JÓ7�ô�y‰y‹{˜iÒ'ð(Ø—H‘H”Jô—H‘H˜S 3™YÔ'Ø �‰�Ž ða:ôb×(Ñ(Ó*€HÛ‰ˆˆSÜ �‰�Œ ð ×Ñœ"Ÿ)™) C¨¨tÓ4´i×6JÑ6JÕKð òô !÷ððܘ“Jˆ ؘ!ŠmØ'Ÿ™Ö0‘ ��Vð #Ù'¨¯ © Ö4˜Ù$¨¨QªØ"ŸM™M¨#¨a©&Õ1à"%›Iñ 5ð 1ð˜!‹mñ$‹Y€FÙ Ø �AŠ:Ü �G‰G”B—I‘I“K & Ô )Ü×Ñ Ó'Ð'ÙØ�FˆlÓðøðO &Ü�y‰y‹{˜iÒ'ØÜ—l‘l“n QÑ'ˆGÜ" 7Ô,=Ó>Ð>ˆEØ �L‰L˜uˆL× %ûð Úûä—H‘H˜S 3™YÕ'ûô �y‰y‹{˜iÒ'ð(Ø—H‘H•JøðÙúä—H‘H˜S 3™YÕ'ø”B—H‘H˜S 3™YÕ'úð (ûôb ò#Ø×'Ñ'¨¯ © Ô4à—K‘K×%Ñ%Ô'à ‘N“Ið #ûð ÙŒ ÙŒ Ø üs¹�D'R Ä8BMÆ9R ÇNÇ!B%R Ê&Q7Ê.7P-Ë%Q7Ë-AR ÍANÎOÎN"ÎN%Î%N?Î?R ÏP*ÏO,Ï+P Ï,O0 Ï.P Ï3P*Ð P& Ð&P*Ð*R Ð-AQ4Ñ0Q7Ñ3Q4Ñ4Q7Ñ7RÒR có®—tj|«rtj|«Stj|«rtj|« Sy)zˆconvert a posix exit status into the same form returned by os.spawnv returns None if the process was stopped instead of exitingN)r Ú WIFEXITEDÚ WEXITSTATUSÚ WIFSIGNALEDÚWTERMSIG)Úcodes rÚ_posixexitstatusr¨)sB€ô  ‡|�|�DÔÜ�~‰~˜dÓ#Ð#Ü �‰˜Ô Ü—‘˜TÓ"Ð#Ð#ð r&c#ó@‡‡K—Gd„dtj«}gŠˆˆfd„}t‰«}tjj «} tjj «} i} t ||dz«D]} | j| «Œt|«D].} || | ||«}‰j|«|j«Œ0 t‰«dkDrÄ| j«sA| j«}|r|dr| j|d«n|–—| j«sŒA‰djd«‰D�cgc]}|j!«rŒ|‘Œ}}|D]+}|j"� |j"‚‰j%|«Œ-t‰«dkDrŒÄ| j«sA| j«}|r|dr| j|d«n|–—| j«sŒA|rd| f–—yycc}w#t&t(f$r |«‚wxYw­w) Ncó—eZdZd„Zd„Zd„Zy)ú_windowsworker..Workercó¬—tjj|g|¢­i|¤Ž||_||_||_||_d|_d|_d|_ yrp) r"ÚThreadÚ__init__Ú _taskqueueÚ _resultqueueÚ_funcÚ _staticargsÚ _interruptedÚdaemonÚ exception)ÚselfÚ taskqueueÚ resultqueuer9r:r;Úkwargss rr®z'_windowsworker..Worker.__init__6sV€ô × Ñ × %Ñ % dÐ <¨TÒ <°VÒ <Ø'ˆDŒOØ +ˆDÔ ØˆDŒJØ)ˆDÔ Ø %ˆDÔ ØˆDŒKØ!ˆD�Nr&có—d|_y)NT)r³)r¶s rÚ interruptz(_windowsworker..Worker.interruptBs €Ø $ˆDÕ r&có¸— |jj«sƒ |jj«}|j|j|fzŽD]+}|j j |«|jsŒ+y |jj«sŒ‚yy#tjj$rYywxYw#t$r }||_ ‚d}~wwxYwr!) r¯ÚemptyÚ get_nowaitr±r²r°Úputr³rÚqueueÚEmptyÚ Exceptionrµ)r¶r;ruÚes rÚrunz"_windowsworker..Worker.runEs¾€ð ØŸ/™/×/Ñ/Ô1ð Ø#Ÿ™×9Ñ9Ó;˜Ø#- 4§:¡:¨t×/?Ñ/?À4À'Ñ/IÓ#J˜CØ ×-Ñ-×1Ñ1°#Ô6ð $×0Ó0Ù &ñ $KðŸ/™/×/Ñ/×1øô$Ÿ>™>×/Ñ/òÙðûäò ð"#�”Øûð  úsG‚C�A!B Á?B ÂB ÂC CÂ=CÂ?CÃCà Cà CÃCN)Ú__name__Ú __module__Ú __qualname__r®r»rÄr%r&rÚWorkerr«5s„ò "ò %ó r&rÈcó•—tj«dz}‰D]}|j«Œ‰D]V}|tj«z }|j|«|j«sŒ<‰j t d««yy)Nrs:failed to kill worker threads while handling an exception )Útimer»ÚjoinÚis_aliveÚwarnr)Ú cleanupendÚtÚ remainingtimeÚthreadsrs €€rÚtrykillworkersz&_windowsworker..trykillworkers[stø€ä—Y‘Y“[ 1‘_ˆ ÛˆAØ �K‰K�MðãˆAØ&¬¯©«Ñ4ˆMØ �F‰F�=Ô !Ø�z‰z�|ð —‘Üð3óôñ ñr&érrgš™™™™™©?T)r"r­rrrÀÚQueuer„r¿Úranger†Ústartr7r½Úgetr–rËrÌrµÚremoverÂrŒ)rr9r:r;r<r3rÈrÒr/r¸r·r›rgÚ_irÏruÚ_tÚfinishedthreadsrÑs` @rÚ_windowsworkerrÜ4sêùèø€ô"”×!Ñ!ô"ðH€Gõô*˜"‹o€GÜ—.‘.×&Ñ&Ó(€KÜ—‘×$Ñ$Ó&€IØ €Fô˜4 ¨2¡Ö.ˆØ� ‰ �eÕð/ä�GŽnˆÙ �9˜k¨4°Ó <ˆØ�‰�qÔØ �‰� ððÜ�'‹l˜QÒØ!×'Ñ'Ô)Ø!—o‘oÓ'�Ù  Q¢Ø—M‘M # a¡&Õ)à’Ið "×'Ñ'Õ)ð �A‰J�O‰O˜DÔ !Ù,3ÓI©G b¸2¿;¹;½=šr¨GˆOÐIÛ$�Ø—;‘;Ð*ØŸ+™+Ð%Ø—‘˜qÕ!ð%ô�'‹l˜QÓð ×ÑÔ!Ø�o‰oÓˆÙ ˜˜QšØ �M‰M˜#˜a™&Õ !àŠIð ×ÑÕ!ñ Ø�FˆlÓðùòJøô Ô(Ð )òÙÔØ ðüsE„C HÃAHÄ0HÅG>ÅG>Å"AHÆ#AHÇ4 HÇ>HÈHÈHc#ó@K—t|«D] }||d|…–—Œy­w)aæpartition a list into N slices of roughly equal size The current strategy takes every Nth element from the input. If we ever write workers that need to preserve grouping in input we should consider allowing callers to specify a partition strategy. olivia is not a fan of this partitioning strategy when files are involved. In his words: Single-threaded Mercurial makes a point of creating and visiting files in a fixed order (alphabetical). When creating files in order, a typical filesystem is likely to allocate them on nearby regions on disk. Thus, when revisiting in the same order, locality is maximized and various forms of OS and disk-level caching and read-ahead get a chance to work. This effect can be quite significant on spinning disks. I discovered it circa Mercurial v0.4 when revlogs were named by hashes of filenames. Tarring a repo and copying it to another disk effectively randomized the revlog ordering on disk by sorting the revlogs by hash and suddenly performance of my kernel checkout benchmark dropped by ~10x because the "working set" of sectors visited no longer fit in the drive's cache and the workload switched from streaming to random I/O. What we should really be doing is have workers read filenames from a ordered queue. This preserves locality and also keeps any worker from getting more than one file out of balance. N)rÕ)ÚlstÚnslicesÚis rr„r„žs&èø€ô:�7Ž^ˆØ�!�*�W�*‰oÓñùs‚r)FTNr!)r r`r�rAr‰r"rÊÚi18nrÚrrrrrrr'ÚisposixÚ iswindowsr*r)r1r>r6r¨rÜr5rQr„r%r&rÚrås¹ðó Û ÛÛ Û ÛÛ å÷óò ò, (òAð ×Ò�x×)Ò)Ø€Mð'×0Ñ0Ñà€MØ#Ðó ð&ØØ ó/'ód\ò~$ó`ðF ×ÒØ$€Oó ð #€OØ"€Kór&