Een pipe is sneller: hoe heet dit fenomeen?

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • aawe mwan
  • Registratie: December 2002
  • Laatst online: 21-09 20:59

aawe mwan

Wat ook leuk is:

Topicstarter
Ik wilde de snelheid van een Raspberry Pi 4B testen, door over een bestand van 9 GB (dit past dus niet in z'n geheugen) de MD5 waarde te berekenen.

Ik heb 3 commando's uitgevoerd:
  1. time md5sum bestand.mkv
  2. time pv bestand.mkv | md5sum
  3. time cat bestand.mkv | md5sum
Quizvraag: welke van deze 3 is "sneller" ?
Voor wie het niet kent: pv is "pipeviewer" en dit toont een fancy voortgangsbalkje voor een pipe.

spoiler: Het antwoord
de variant met pv is het snelst


Toelichting:
Als ik met htop meekijk, dan zie ik dat mijn commando's blijkbaar allemaal single-core processen zijn en dat er voor de pipes 2 cores actief zijn.

Als alleen md5sum draait, dan heeft de core ongeveer 100% CPU belasting.
Als pv en md5sum draaien, dan hebben de cores 40% cq 100% CPU belasting.
Als cat en md5sum draaien, dan hebben de cores 70% cq 85% CPU belasting.

Al met al zijn de doorlooptijden: 60 seconden, 54 seconden, 59 seconden.

Hoe kan het dat de berekening sneller wordt door de data via een pipe en via pv te laten lopen en op welk woord moet je googelen om meer over dit fenomeen te lezen?

„Ik kan ook ICT, want heel moeilijk is dit niet”

Alle reacties


Acties:
  • 0 Henk 'm!

  • edeboeck
  • Registratie: Maart 2005
  • Laatst online: 11-09 13:47

edeboeck

mie noow noooothing ...

Voor de zekerheid: je hebt deze runs minimaal een tiental keer uitgevoerd (kwestie van de invloed van toevalligheden zoveel mogelijk uit te schakelen)?

Acties:
  • 0 Henk 'm!

  • aawe mwan
  • Registratie: December 2002
  • Laatst online: 21-09 20:59

aawe mwan

Wat ook leuk is:

Topicstarter
edeboeck schreef op zaterdag 25 juli 2020 @ 18:00:
Voor de zekerheid: je hebt deze runs minimaal een tiental keer uitgevoerd (kwestie van de invloed van toevalligheden zoveel mogelijk uit te schakelen)?
Uiteraard.

„Ik kan ook ICT, want heel moeilijk is dit niet”


Acties:
  • 0 Henk 'm!

  • Mijzelf
  • Registratie: September 2004
  • Niet online
Het lijkt me niet onlogisch dat md5sum alléén het meeste tijd kost. Tenslotte is hij singlethreaded, en moet hij ook nog de file lezen. Door te pipen heb je een extra thread toegevoegd.

Over cat en pv, het valt op dat cat niet in staat is om de md5sum thread snel genoeg van data te voorzien. Zijn core is maar 85% belast, terwijl cat ook nog tijd over heeft. Ondertussen kan pv wèl md5sum verzadigen, en heeft daarbij zelf nog wat minder processortijd nodig.
Conclusie: pv is gewoon efficiënter dan cat in deze toepassing. Aangezien pv is ontworpen om met pipes te werken, en cat eigenlijk bedoelt is om naar console te printen, lijkt het logisch dat je het hier moet zoeken.
man cat:
It is unspecified whether standard output is or is not buffered in the default case. This is sometimes of interest when standard output is associated with a terminal, since buffering may delay the output. The presence of the −u option guarantees that unbuffered I/O is available. It is implementation-defined whether the cat utility buffers output if the −u option is not specified. Traditionally, the −u option is implemented using the equivalent of the setvbuf() function defined in the System Interfaces volume of POSIX.1‐2008.
Oftewel, probeer het eens met 'cat -u'.

Acties:
  • 0 Henk 'm!

  • hcQd
  • Registratie: September 2009
  • Laatst online: 09:56
Je zou het ook eens kunnen kijken of dd met een redelijke blocksize pv kan verslaan.

Acties:
  • 0 Henk 'm!

  • jeroen3
  • Registratie: Mei 2010
  • Nu online
okee, de programma's in kwestie (op mijn rpi3 voor octoprint Raspbian GNU/Linux 9.11 (stretch))
http://www.ivarch.com/programs/pv.shtml
https://github.com/coreut...s/blob/v8.26/src/md5sum.c

md5sum werkt via dus md5_stream in md5.h. Welke van libcrypto is? Die source kan ik niet vinden.
https://github.com/coreut...0720761/src/md5sum.c#L624

Maar in pv is het wel interessant.
main.c is best complex, kan threads starten e.d. onduidelijk is of hij dat ook doet.
Maar in transfer.c zit het interessante stuk,
code:
1
2
long pv_transfer(pvstate_t state, int fd, int *eof_in, int *eof_out,
         unsigned long long allowed, long *lineswritten)

En daar werkt hij volgens mij op blok basis, want in main loop word buffer via deze define geinitialiseerd.
code:
1
#define BUFFER_SIZE     409600   /* default transfer buffer size */

Dat heeft ongetwijfeld enorme performance impact. Zeker als libcrypto per de 4 bytes alignment van md5 leest.
Dat zijn een hoop kernel switches meer!

[ Voor 3% gewijzigd door jeroen3 op 25-07-2020 20:41 ]


Acties:
  • 0 Henk 'm!

  • aawe mwan
  • Registratie: December 2002
  • Laatst online: 21-09 20:59

aawe mwan

Wat ook leuk is:

Topicstarter
Ik heb de variant met cat -u geprobeerd, maar dit duurde 61 seconden.
Op de manpages van cat op de Raspberry Pi staat bij de optie -u letterijk: (ignored) en dat klopt dus niet.

Maar het lijkt wel met buffering of in elk geval buffergrootte te maken te hebben.

Met unbuffer cat bestand.mkv werd het heel erg traag (ik heb afgebroken na een paar minuten).
Met buffer -i bestand.mkv werd hij al wat sneller: 52 seconden met de default buffergrootte.

Het beste resultaat tot nu toe komt van dd met blokgrootte 10kB of 12kB: dan is hij tussen 50.0 en 51.0 seconden klaar. Met 11kB blokgrootte duurt het 57 seconden. Ook als je de blokgrootte gaat vergroten of gaat verkleinen, heb je al heel gauw dat md5sum niet meer optimaal kan draaien.

„Ik kan ook ICT, want heel moeilijk is dit niet”


Acties:
  • 0 Henk 'm!

  • jeroen3
  • Registratie: Mei 2010
  • Nu online
Ik denk dat het ook wel erg afhankelijk is van je sd kaart.

Op mijn rpi 3 duurt het al een minuut om 1 GB in md5 te gooien. Er is dan ook geen verschil bij mij. De SD kaart is de bottleneck met 20.000 KB/s. (zie iostat)

Geinig effect wel, goed gevonden.

[ Voor 7% gewijzigd door jeroen3 op 25-07-2020 21:05 ]


Acties:
  • 0 Henk 'm!

  • aawe mwan
  • Registratie: December 2002
  • Laatst online: 21-09 20:59

aawe mwan

Wat ook leuk is:

Topicstarter
Het bestand dat ik lees komt van een NVMe die ik via USB aangesloten heb, vandaar de snelheid. Je had het net over 4 byte longs en toen bedacht ik me dat ik de testen steeds draai op 32-bits Raspberry Pi OS.

Ik heb het ook met 64-bits Ubuntu geprobeerd en op verder identieke hardware is de score daarmee:
  • md5sum kaal: 51 seconden
  • dd bs=8k | md5sum: 47 seconden
  • dd bs=16k | md5sum: 46 seconden
Het beeld in 64-bits modus is ook veel rustiger: de md5sum core draait constant rond 100% en dd 60-70%.

„Ik kan ook ICT, want heel moeilijk is dit niet”


Acties:
  • 0 Henk 'm!

  • Mijzelf
  • Registratie: September 2004
  • Niet online
Ik heb wat testjes gedaan, en bij mij wint

md5sum <bestand

/Edit: Om terug te komen op de vraag in de topic titel, volgens mij heet dit fenomeen multithreading of multiprocessing, en ben je nu aan het optimaliseren naar de meest efficiënte manier om om de data van proces 1 naar proces 2 te krijgen.

[ Voor 66% gewijzigd door Mijzelf op 26-07-2020 13:02 ]


Acties:
  • +1 Henk 'm!

  • Douweegbertje
  • Registratie: Mei 2008
  • Laatst online: 20-09 20:54

Douweegbertje

Wat kinderachtig.. godverdomme

Ik denk dat er niet echt een fenomeen hier is, maar dat je meer tegen meerdere limitaties aan loopt van zowel matige CPU power alsmede weinig geheugen en mogelijk USB / type NVMe. Wellicht cached je disk toch wel iets, of juist maar delen.
Om exact te weten hoe/wat moet je denk ik op zowel disk, memory als kernel niveau heel diep gaan kijken wat er nu precies gebeurd.

Maar wat misschien al helpt is om de --buffer-percent param mee te geven aan PV ;) En zelfs nog te spelen met -B, de buffer size.

Acties:
  • 0 Henk 'm!

  • aawe mwan
  • Registratie: December 2002
  • Laatst online: 21-09 20:59

aawe mwan

Wat ook leuk is:

Topicstarter
Ik ben gaan Googlen en vond het volgende.

Wat er oorspronkelijk aan de hand was, was dat (door de snelle drive) md5sum CPU-gelimiteerd draaide, terwijl dat normaal gesproken I/O-gelimiteerd is. Door het inlezen van de data in een apart proces te zetten, kan je dan de totale doorlooptijd verkorten. Dat kan je doen met een pipe, zoals ik (onbewust). Er zijn mensen die vinden dat standaard Unix commando's aangepast zouden moeten worden, zodat input en output in aparte processen draait, maar dat is vooral vanwege de winst die je hiermee haalt als je I/O juist traag is.

Als commando's intern de C-functie splice() zouden gebruiken, dan zou dat een versnelling kunnen geven bij pipes; als data van een bestand naar een pipe gaat, of omgekeerd, dan kan splice() dat doen zonder de data zelf van en naar userspace te kopiëren en dat levert tijdwinst op. Er zijn mensen die vinden dat dit in cat ingebouwd zou moeten worden (voorbeelden: "fastcat" en "fcat"). Ik zie dat pv wel splice() gebruikt, dus dit zal de reden zijn dat pv sneller is dan cat.

Het variëren met buffergrootte/blokgrootte en het overstappen van 32-bit op 64-bit hadden meer effect dan ik had verwacht.

Wat ik me nu nog afvraag, is waarom er zo veel overhead is als je een pipe gebruikt: om +/- 10% eerder het eindresultaat te hebben, moet je +/- 40% extra CPU-kracht inzetten. Dat moet toch beter kunnen?

@Douweegbertje Je voorgevoel was juist:
time pv --buffer-size 16k <bestand.mkv | md5sum is klaar in 44-45 seconden, sneller dan dd.

[ Voor 5% gewijzigd door aawe mwan op 26-07-2020 15:23 ]

„Ik kan ook ICT, want heel moeilijk is dit niet”


Acties:
  • 0 Henk 'm!

  • Mijzelf
  • Registratie: September 2004
  • Niet online
aawe mwan schreef op zondag 26 juli 2020 @ 15:05:
Wat ik me nu nog afvraag, is waarom er zo veel overhead is als je een pipe gebruikt: om +/- 10% eerder het eindresultaat te hebben, moet je +/- 40% extra CPU-kracht inzetten. Dat moet toch beter kunnen?
Je bent tijd aan het opsouperen aan general purpose interprocess synchronisatie. In dit geval een pipe. De synchronisatie vind plaats doordat de schrijvende partij 'op hold' gaat als de pipe vol is, en de lezende partij als hij leeg is, en beiden op de een of andere manier gewekt moeten worden als die situatie veranderd. Dat is niet gratis. Verder zitten er nogal wat kopieer actie in. De schrijvende partij leest de file, kopieert dat naar de pipe, en de lezende partij leest de pipe, en kopieert dat naar een intern buffer.

Natuurlijk kan dat efficiënter, maar dan moet je gaan optimaliseren voor specifiek dit probleem. Een enkel programma met een ringbuffer of iets dergelijks, waarbij één thread de file direct in het buffer schrijft, en een andere thread direct op het buffer de md5sum uitrekent, en dat samen met een goedkoop synchronisatie object zal een forse efficiëntie sprong geven. Dat had natuurlijk de default actie van 'md5sum bestand' kunnen zijn, ware het niet dat md5sum daarmee een stuk complexer zou worden, en je ook nog met een hoop randvoorwaarden rekening moet houden:
  • Bij kleine files is de overhead van een extra thread starten groter dan het te verwachten effect. En de grens is systeem specifiek.
  • Bij single core systemen is de situatie anders dan bij multicore
  • Een systeem waarop de file lezen meer tijd kost dan het berekenen van de md5sum heeft een andere benadering nodig dan een systeem waar het omgekeerd is.
  • Het feit dat md5sum hier allemaal rekening mee moet houden alléén maakt hem al duurder.

Acties:
  • 0 Henk 'm!

  • jeroen3
  • Registratie: Mei 2010
  • Nu online
Plus dat als md5sum op hele directories gaat zit de winst wel in je multithreading.
Ik denk dat md5sum toch niet helemaal is wat je zoekt als benchmark.
Wellicht moet je even herzien wat wel de beste methode is.

Voor Synology is er hier een unpacking benchmark.
[Synology] RAR unpacking performance

Maar misschien kun je ook wel met par2 of de smartphone benchmarks spelen.
Pagina: 1