Προς το περιεχόμενο

rsync vs cp, strace και άλλες αλχημείες


firewalker

Προτεινόμενες αναρτήσεις

ΥΣ. Άσχετο- Apoike/NullScan, πώς εξηγείτε ότι η rsync σε local copy (προς κενή τοποθεσία) ιεραρχίας καταλόγων με πολλά μικρά αρχεία (βλ. portage tree) είναι *πολύ* (~50%) πιο γρήγορη από... cp -r; Μια απλή αντιγραφή αρχείο-αρχείο είναι, τι περιθώριο έχει να την κάνει διαφορετικά; :fear:

 

Μήπως έχει κάποια redurancy checks η cp;

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δεν έχω ιδέα, αλλά η θεωρία λέει οτι το cp είναι για να κάνεις copy ενώ το rsync είναι για backup. Αυτό μπορεί να σημαίνει ότι εκτός από τα permissions του εκάστοτε αρχείου συμπεριφέρεται διαφορετικά και στο ίδιο το αρχείο. Κάτι μου λέει πάντως ότι έχει να κάνει με το authentication και με το πώς κάνει build το directory tree.

Έλα τώρα μην είσαι τεμπέλης: strace, ldd, nm, objdump.

Το ξέρεις το σύστημα :-)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δεν είναι θέμα fs caching, το πρόσεξα.

 

Σε κατά τα άλλα idle μηχάνημα, με 2 sata δίσκους σε raid0, με ext3 (journal size 256MB, directory_index, ordered journaling mode) :

 

# for x in `seq 1 5`; do time rsync -rpE linux-2.6.24-hardened-r3 linux2; rm -rf linux2/*; done

 

>real	0m40.770s
user	0m2.129s
sys	0m2.684s

real	0m31.514s
user	0m2.090s
sys	0m2.582s

real	0m30.318s
user	0m2.152s
sys	0m2.444s

real	0m31.922s
user	0m2.201s
sys	0m2.513s

real	0m31.605s
user	0m2.118s
sys	0m2.485s

 

# for x in `seq 1 5`; do time cp -rp linux-2.6.24-hardened-r3/ linux2/; rm -rf linux2/*; done

 

>real	0m47.037s
user	0m0.113s
sys	0m1.508s

real	0m47.373s
user	0m0.114s
sys	0m1.619s

real	0m50.739s
user	0m0.115s
sys	0m1.588s

real	0m45.366s
user	0m0.110s
sys	0m1.455s

real	0m50.167s
user	0m0.119s
sys	0m1.489s

 

Στο portage tree η διαφορά ήταν μεγαλύτερη.

 

@NullScan: no thanks, είμαι περισσότερο τεμπέλης απ' ότι περίεργος :-)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

rsync.txt :

 

for x in `seq 1 5`; do /usr/bin/time -v rsync -rpE linux-2.6.24-hardened-r3 linux2; rm -rf linux2/*; echo -e "**** END of run $x \n"; done

 

cp.txt:

 

for x in `seq 1 5`; do /usr/bin/time -v cp -rp linux-2.6.24-hardened-r3 linux2; rm -rf linux2/*; echo -e "**** END of run $x \n"; done

 

Tree files: 24.467

Totaling: 305M

 

Φαίνεται ότι η rsync κάνει κάτι παραπάνω, τι άραγε; :)

rsync.txt

cp.txt

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Φαίνεται ότι η rsync κάνει κάτι παραπάνω, τι άραγε; :)

 

Ή κάτι λιγότερο...

 

Έχει βάλει κάτω του κώδικες ο apoikos και το ψάχνει. Αργεί λίγο και ανησυχώ...

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δεν το πιστεύω οτι κατάφερα καλοκαιριάτικα και ΣΚ να ασχοληθώ αλλά το έκανα απο καθαρή περιέργεια. Από μια πρόχειρη ανάγνωση του κώδικα του rsync 3.0.3 από εδώ φαίνεται οτι το rsync προσπαθεί να βρεί τον μέγιστο αριθμό αρχείων που μπορεί να μεταφέρει ταυτόχρονα βασιζόμενο σε ένα in-house μηχανισμό piping που λαμβάνει υπ' όψη αν το socket είναι local ή tcp, καθώς επίσης και κάποια limitations που βάζουν γνωστά shells του UNIX αλλά και το ssh. Επίσης έχουν φτιάξει και ένα hash table "object" το οποίο υποτίθεται οτι είναι memory efficient. Αυτό που δεν ξέρω είναι αν το cp (αν και είμαι σχεδόν σίγουρος πως οχι) μπορεί να κάνει ταυτόχρονη μεταφορά αρχείων.

Σε άλλη παρατήρηση, απογοητεύτηκα πολύ όταν είδα goto στον κώδικα. Αλλά εδώ που τα λέμε τέτοια έχει μέχρι και ο κώδικας του kernel, το rsync θα ντρεπόταν...

Θα επιστρέψω αν ρίξω και καμιά ματιά στον κώδικα του cp για συγκρίσεις.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Just an idea: μπορεί να έχει να κάνει με τους ενσωματωμένους buffers των προγραμμάτων, π.χ. το rsync να διαβάζει 1 Mb και μετά να γράφει 1 Mb, ενώ το cp να διαβάζει 1 Kb και μετά να γράφει 1 Kb, προκαλώντας έτσι περισσότερες μετακινήσεις της κεφαλής του δίσκου.

 

Αν κάποιος έχει όρεξη μπορεί να τσεκάρει αν ισχύει η υπόθεσή μου κάνοντας rsync/cp από το δίσκο προς ramfs, ώστε να μην μετακινείται η κεφαλή. Xρειάζεται όμως μπόλικη RAM για να μη γίνεται swapping.

 

edit: NullScan τώρα είδα το post σου, η ταυτόχρονη μεταφορά αρχείων μήπως είναι μόνο για δικτυακές περιπτώσεις; Δε νομίζω ότι έχει νόημα σε τοπικό file system, πιο αργά θα πήγαινε με ταυτόχρονες μεταφορές.

Το goto πάντως σε ορισμένες περιπτώσεις όχι μόνο κάνει πιο ευανάγνωστο τον κώδικα, αλλά επιβάλλεται... Μην ανησυχείς, αν γράφουν kernel code ξέρουν πότε να το χρησιμοποιούν και πότε όχι! :)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Εγώ τώρα που ήρθα στο σπίτι (single, not multithreading cpu) το cp είναι ποιο γρήγορο από το rsync. Γιατί δάσκαλε; Το rsync εκμεταλλεύεται καλύτερα τα multi cores cpus;

 

Δεν είναι τέλειο σε τι "περιπέτειες" μας βάζει μία απλή ερώτηση; Γουστάρω τρελά!!!

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Αποτελέσματα από 10 consecutive runs στο προηγούμενο μηχάνημα που δεν ήταν SMP, amd64, με 1 GB RAM και ext3 πάνω από 2disk raid0 array:

 

http://nske.hackbox.gr/atch/rsync_unip.txt

http://nske.hackbox.gr/atch/cp_unip.txt

 

Αποτελέσματα από 10 consecutive runs σε μηχάνημα με SMP, amd64 x2, 2GB RAM, επίσης σε ext3 πάνω από έναν SATA hard disk αυτή τη φορά:

 

http://nske.hackbox.gr/atch/rsync_smp.txt

http://nske.hackbox.gr/atch/cp_smp.txt

 

Βλέπουμε ότι στην 2η περίπτωση η διαφορά ανάμεσα στους χρόνους της CP και της Rsync είναι σχεδόν ανύπαρκτη, οι χρόνοι είναι συνολικά πολύ μικρότεροι και η rsync εξακολουθεί να χρησιμοποιεί πολύ περισσότερη CPU.

 

Τι συμπέρασμα θα μπορούσαμε να βγάλουμε (πέρα από το ότι πρέπει να αναβαθμίσω το desktop μου :P); :rolleyes:

 

ΥΣ. Πρέπει να δημιουργήσουμε τις προϋποθέσεις για περισσότερα threads με μέσα NullScan, Apoiko και Alkisg :)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

nske: Κατά παράβαση των αρχών του πειραματισμού, αλλάζεις πολλές παραμέτρους ταυτόχρονα :P. Σε κάθε περίπτωση, οφείλουμε να παρατηρήσουμε τα εξής:

  • Η απλή αντιγραφή με cp (λογικά) είναι I/O bound στα σύγχρονα μηχανήματα. Αυτό φαίνεται από το χαμηλό cpu utilization, user και system time που έχει η cp στο πρώτο παράδειγμα του nske: Αν εκείνη την ώρα έτρεχες vmstat, θα έβλεπες ότι πρακτικά το 99% του χρόνου η cp είναι σε "I/O wait" state. Το ίδιο ισχύει σε ένα βαθμό και με το rsync.
  • Το rsync, ακόμα και στο local μηχάνημα, σηκώνει περισσότερα από ένα processes, πράγμα το οποίο σημαίνει ότι σε SMP συστήματα έχει το περιθώριο να τρέχει ταυτόχρονα τον receiver και τον sender. Ωστόσο αυτό θα του έδινε πλεονέκτημα μόνο εφόσον το bottleneck ήταν το CPU capacity ενός επεξεργαστή και όχι το I/O (πράγμα λίγο δύσκολο σε ένα σημερινό κοινό μηχάνημα).

 

Επομένως, διαπιστώνουμε (από την αναλογία (user + system):wall time) ότι το bottleneck είναι όντως το I/O, παρ' όλα αυτά έχουμε μια περίπτωση στην οποία το rsync αποδίδει καλύτερα. Γιατί συμβαίνει αυτό; Ας δούμε ένα απλό παράδειγμα σε ένα μεγάλο αρχείο:

>
$ dd if=/dev/urandom of=koko bs=1k count=100000
$ strace -o cp.out cp koko lala
$ rm lala
$ strace -o rsync.out rsync koko lala

 

Στο cp.out βλέπουμε:

>
open("koko", O_RDONLY|O_LARGEFILE)      = 3
....
read(3, "\356\37\267n\316i\36\261_\27f\261\311\225N\253V\274\232"..., 8192) = 8192
write(4, "\356\37\267n\316i\36\261_\27f\261\311\225N\253V\274\232"..., 8192) = 8192
read(3, "d{\327\343&\260X\277F\'ZML2\24\215\333;\365\237IC3\'t)"..., 8192) = 8192
write(4, "d{\327\343&\260X\277F\'ZML2\24\215\333;\365\237IC3\'t)"..., 8192) = 8192
read(3, "\223\311\366$`\363\235G\341\5\324\3\300N\234\346\271\275"..., 8192) = 8192
write(4, "\223\311\366$`\363\235G\341\5\324\3\300N\234\346\271\275"..., 8192) = 8192
....

 

ενώ στο rsync.out:

>
socketpair(PF_FILE, SOCK_STREAM, 0, [3, 4]) = 0
socketpair(PF_FILE, SOCK_STREAM, 0, [5, 6]) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7e5c6f8) = 8296
close(6)                                = 0
close(3)                                = 0
...
open("koko", O_RDONLY|O_LARGEFILE)      = 3
....
read(3, "\356\37\267n\316i\36\261_\27f\261\311\225N\253V\274\232"..., 262144) = 262144
select(5, NULL, [4], [4], {60, 0})      = 1 (out [4], left {60, 0})
write(4, "\374\17\0\7", 4)              = 4
select(5, NULL, [4], [4], {60, 0})      = 1 (out [4], left {60, 0})
write(4, "\1\0\240\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\0\0\356"..., 4092) = 4092
select(5, NULL, [4], [4], {60, 0})      = 1 (out [4], left {60, 0})
write(4, "\374\17\0\7", 4)              = 4
select(5, NULL, [4], [4], {60, 0})      = 1 (out [4], left {60, 0})
write(4, "\365\25M1\216-\20\212\305\330\360\342&\305\16\352\251\357"..., 4092) = 4092
...

 

Εδώ παρατηρούμε τα εξής:

  • Το rsync φτιάχνει 2 socketpairs, στους file descriptors 3,4 και 5,6, τους οποίους χρησιμοποιεί για να επικοινωνήσει με το child process.
  • Καλεί την clone(), οπότε ουσιαστικά κάνει (κάτι σαν) fork, διατηρώντας τους ίδιους file descriptors και signal handlers.
  • Κλείνει τις άκρες 6 και 3, οπότε θα χρησιμοποιεί τους file descriptors 4 και 5 για επικοινωνία με την άλλη πλευρά.
  • Βλέπουμε ότι ανοίγει το αρχικό αρχείο (koko) και διαβάζει ένα block 256 kB (σε αντίθεση με τα 8k τη φορά που διαβάζει η cp). Είναι προφανές ότι κάνουμε trace το sender process.
  • Στη συνέχεια κάνει μια select() για να δει αν ο filedescriptor 4 μπορεί να γραφτεί. Υπενθυμίζω ότι ο filedescriptor 4 ανήκει στο socketpair που στο απέναντι άκρο του «ακούει» ο receiver
  • Όταν η select επιστρέψει, γράφει 4 kB στο socket που το παίρνει ο receiver. Για κάποιο μυστήριο λόγο, τα 4 kB τα γράφει σε 2 δόσεις, μια των 4 bytes, και μια των 4092 (!!).
  • Το άλλο ενδιαφέρον είναι ότι κάνοντας strace και στον receiver, βλέπουμε ότι παρ' όλο που η μεταξύ τους επικοινωνία γίνεται με 4kB-sized buffers, ο receiver γράφει όπως διαβάζει ο sender, δηλαδή 256 kB τη φορά.

 

Βγάζουμε λοιπόν τα εξής συμπεράσματα:

  • Η rsync έχει μεγαλύτερο CPU utilization, ακριβώς επειδή όπως είδαμε είναι αρκετά πιο πολύπλοκη η λειτουργία της. Ενώ η cp κάνει μια αλληλουχία από read() και write(), η rsync διαβάζει ένα μεγάλο chunk, το μεταφέρει με select() και write() στο άλλο process, το οποίο το γράφει σε μεγάλα chunks πάλι.
  • Η rsync έχει (δυνητικά) λιγότερα I/O operations στο δίσκο, αφού επιχειρεί να διαβάσει/γράψει 256 kB τη φορά, δηλαδή 32 φορές περισσότερα bytes από τη cp.
  • Κατά την άποψή μου, αν και δεν είμαι 100% σίγουρος, η διαφορά ταχύτητας οφείλεται στο chunk size που διαβάζει το rsync σε συνδυασμό με το software RAID-0 που έχει ο nske. Φαίνεται ότι το RAID-0 μπορεί να αποδόσει καλύτερα διαβάζοντας παραπάνω από 8kB τη φορά που διαβάζει η cp. Θα είχε ενδιαφέρον να δούμε πως αυτό συσχετίζεται με το stripe size του RAID για παράδειγμα.

 

Αυτά τα ολίγα.

Γουστάρω τέτοια θέματα για να καθόμαστε να ψάχνουμε :-)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...