Salut.
M-am apucat sa studiez problema si asta e ce am gasit:
(gdb) disassemble epoll_wait
Dump of assembler code for function epoll_wait:
0x00007ffff78ff160 <+0>: cmpl $0x0,0x2bc659(%rip) #
0x7ffff7bbb7c0 <__libc_multiple_threads>
0x00007ffff78ff167 <+7>: jne 0x7ffff78ff17c <epoll_wait+28>
0x00007ffff78ff169 <+0>: mov %rcx,%r10
0x00007ffff78ff16c <+3>: mov $0xe8,%eax
0x00007ffff78ff171 <+8>: syscall
0x00007ffff78ff173 <+10>: cmp $0xfffffffffffff001,%rax
0x00007ffff78ff179 <+16>: jae 0x7ffff78ff1af <epoll_wait+79>
0x00007ffff78ff17b <+18>: retq
0x00007ffff78ff17c <+28>: sub $0x8,%rsp
0x00007ffff78ff180 <+32>: callq 0x7ffff790c630
<__libc_enable_asynccancel>
0x00007ffff78ff185 <+37>: mov %rax,(%rsp)
0x00007ffff78ff189 <+41>: mov %rcx,%r10
0x00007ffff78ff18c <+44>: mov $0xe8,%eax
0x00007ffff78ff191 <+49>: syscall
Aici e epoll_wait
0x00007ffff78ff193 <+51>: mov (%rsp),%rdi
0x00007ffff78ff197 <+55>: mov %rax,%rdx
0x00007ffff78ff19a <+58>: callq 0x7ffff790c690
<__libc_disable_asynccancel>
0x00007ffff78ff19f <+63>: mov %rdx,%rax
0x00007ffff78ff1a2 <+66>: add $0x8,%rsp
0x00007ffff78ff1a6 <+70>: cmp $0xfffffffffffff001,%rax
0x00007ffff78ff1ac <+76>: jae 0x7ffff78ff1af <epoll_wait+79>
Dupa cum se observa, epoll_wait este inconjurat de un *_asynccancel.
Care sint implementate cu futex-i. Care sint 'light', dar, mult mai scumpi
decit 'nimic'. Si asta se vede in profiling perfect:
--------------------------------------------------------------------------------
Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw Bc Bcm
Bi Bim file:function
--------------------------------------------------------------------------------
958,390 1,147 138 273,249 60 1 196,462 979 914 113,819 3,104 57,236
19,158 ???:???
501,410 7 7 160,414 0 0 160,404 58 0 60,165 73 0
0 ???:Log
107,328 1 1 26,832 3 0 0 0 0 26,832 0 0
0 ???:__libc_disable_asynccancel
98,417 2 2 26,841 2 0 0 0 0 26,841 0 0
0 ???:__libc_enable_asynccancel
86,000 5 5 30,000 0 0 16,000 2 1 6,000 4 0
0 ???:Conn_enqueue_wait
76,000 7 7 14,000 2 1 18,000 9 6 12,000 3 0
0 ???:Conn_printf
(Scuze pentru liniile lungi.)
Deci, in thread-uri, daca ai multe syscall-uri, vei plati acest cost.
Pe cind la procese obisnuite nu.
Daca faci doar calcule matematice (putine syscall-uri), acest cost chiar
nu conteaza.
Am ajuns la concluzia ca pentru un webserver performant, thread-urile nu
ajuta, dimpotriva.
Cind o sa am timp sa reiau lucrul la web server, o sa compar performantele
si o sa le postez aici, daca o sa-mi mai aduc aminte... ;)
On Thu, 3 Sep 2015, tiberiu socaciu wrote:
> acum ce spun e poveste, din cele traite de mine: threaduri 1/core --
> corect!, incearca sa nu faci nimic pompos in thread-uri (IO sau comun icare
> sau etc). eu am folosit 2 threaduri la implementarea unui ADI pentru un PDE
> cu 2 dimensiuni spatiale, la care am reusit sa rup operatorul ecuatiei in
> doua. cu un doctorand de la ubb (cu care colaborez de aproape un an si pe
> care il "co-indrum") incerc sa rupem operatorul n+1 dimensional (spatial)
> si sa vedem daca putem pune de o ADI. altfel, cu procese era putintel
> (parca) mai incetut (asta fuse acum 1000 de ani cand mai scriam cod; acum
> numai latru si urmaresc minciunele).
>
> t.
>
> 2015-09-03 7:46 GMT+03:00 Catalin(ux) M. BOIE <[email protected]>:
>
>> Salut.
>>
>> On Wed, 2 Sep 2015, tiberiu socaciu wrote:
>>
>>> cate thread-uri? ia incearca cu 2 thread-uri pe un procesor cu minim 2
>>> core-uri.
>>
>> 1 thread per core.
>>
>> Dar nu vad ce ar schimba asta. Problema este ca apare overhead de la
>> inserarea, inainte si dupa anumite zone de cod, a codului de setare a
>> cancel-abilitatii thread-ului. Folosind thread-uri nu vad cum pot sa scap
>> de acel overhead. Si apar foarte sus in profiling.
>>
>> Ai idee cum pot sa scap de overhead?
>> Evident, la procese nu apare.
>>
>>> t.
>>>
>>> 2015-09-02 6:47 GMT+03:00 Catalin(ux) M. BOIE <[email protected]>:
>>>
>>>> Salut.
>>>>
>>>> Lucrind la un web server folosind libraria Conn (LGPL, la mine pe site)
>>>> am trecut de la procese la thread-uri. Si am avut o surpriza mare.
>>>> La profiling imi aparea o functie foarte des:
>> __libc_disable_asynccancel,
>>>> __libc_enable_asynccancel, __pthread_disable_asynccancel,
>>>> __pthread_enable_asynccancel. Toate 4 in primele 15 intrari, ordonate
>> dupa
>>>> cit timp dureaza. Cea ce doare.
>>>> Asa ca am cautat ce fac aceste functii. Se pare ca au treaba cu functia
>>>> pthread_cancel; pare ca o tona de locuri din cod sint invelite in
>>>> disable/enable cancel. Si asta costa. Cel putin se observa in valgrind,
>>>> dar daca imi aduc aminte, am observat si la timpul de executie.
>>>>
>>>> Deci, daca poti sa mergi cu procese, uita de thread-uri.
>>>> Si procesele le poti mapa pe CPU-uri diferite cu
>>>> pthread_attr_setaffinity_np.
>>>> La thread-uri, poti partaza usor datele, dar trebuie sa ai grija cum.
>>>> Foarte probabil o sa ai nevoie de functiile specifice de locking alre
>>>> pthread sau de RCU (userspace-rcu, recomandat).
>>>>
>>>> --
>>>> Catalin(ux) M. BOIE
>>>> http://kernel.embedromix.ro/
>>>>
>>>> On Tue, 1 Sep 2015, Alex 'CAVE' Cernat wrote:
>>>>
>>>>> Salut
>>>>>
>>>>> Am mai lucrat cu multiprocess prin facultate, si de atunci pe ici pe
>>>>> colo, treaba e simpla: fork() * n, n copii ale datelor, wait() &
>>>>> friends, toata lumea fericita.
>>>>>
>>>>> Insa (mai nou ... sau mai vechi, ca e de multi ani), thread-urile au un
>>>>> overhead mult mai mic decat procesele, dar din cate am inteles lucreaza
>>>>> cu acelasi set de date, ceea ce nu e bine, pentru ca pe mine ma
>>>>> intereseaza sa execut in paralel aceeasi bucata de cod dar pentru mai
>>>>> multe seturi de date.
>>>>>
>>>>> Practic ma intereseaza sa paralelizez ceva de genul:
>>>>>
>>>>> operatii_de_inceput();
>>>>> for(i = 0; i <= N; i++)
>>>>> operatii_in_paralel(i); <<<< paralelizare
>>>>> operatii_de_final();
>>>>>
>>>>> in cazul meu operatiile de final (daca exista) nu se bazeaza pe cele
>> in
>>>>> paralel (decat cel mult niste coduri de ok / eroare), astfel incat cu
>>>>> procese le-as putea scoate usor, dar daca se poate cu thread-uri si e
>>>>> mai performant ... de ce nu ?
>>>>>
>>>>> problema la care nu-i dau de cap (cel mai probabil pentru ca nu am
>>>>> inteles inca prea bine cum functioneaza threadurile) este cum fac o
>>>>> copie locala a unei variabile, astfel incat variabila respectiva sa
>> aiba
>>>>> valorea doar pentru threadul respectiv, in alt thread putand avea o
>> alta
>>>>> valoare, iar o asignare a acelei variabile intr-un thread sa nu
>>>>> influenteze valoarea aceleiasi variabile dintr-un altul
>>>>>
>>>>> rezumand, in principiu ma intereseaza daca se poate face exact acelasi
>>>>> lucru ce as putea sa fac cu multiproces ('copie' a datelor), dar
>>>>> folosind threaduri (cel putin unele variabile sa fie 'locale'
>> threadului)
>>>>>
>>>>> Mersi
>>>>> Alex
>>>>> _______________________________________________
>>>>> RLUG mailing list
>>>>> [email protected]
>>>>> http://lists.lug.ro/mailman/listinfo/rlug
>>>>>
>>>> _______________________________________________
>>>> RLUG mailing list
>>>> [email protected]
>>>> http://lists.lug.ro/mailman/listinfo/rlug
>>>>
>>> _______________________________________________
>>> RLUG mailing list
>>> [email protected]
>>> http://lists.lug.ro/mailman/listinfo/rlug
>>>
>> _______________________________________________
>> RLUG mailing list
>> [email protected]
>> http://lists.lug.ro/mailman/listinfo/rlug
>>
> _______________________________________________
> RLUG mailing list
> [email protected]
> http://lists.lug.ro/mailman/listinfo/rlug
>
--
Catalin(ux) M. BOIE
http://kernel.embedromix.ro/
_______________________________________________
RLUG mailing list
[email protected]
http://lists.lug.ro/mailman/listinfo/rlug