PDA

View Full Version : Performance Tip: Variable Preload


DarthMoul
23-07-2004, 08:17
Αν υποθέσουμε ότι έχουμε να προσθέσουμε δύο ακεραίους. Πχ a = b + c;
Η CPU θα κάνει ένα αίτημα στον memory controller για την ανάκτηση της μεταβλητής b. Αν αυτή δεν υπάρχει μέσα στο L1 cache, τότε έχουμε την περίπτωση του cache miss. Κατόπιν ο memory controller θα την αναζητήσει στο L2 cache, στο L3 cache και στο τέλος στην μνήμη αν χρειαστεί. Το ίδιο θα κάνει και με την c. Αφού μεταφερθούν και οι δύο μεταβλητές μέσα σε κάποιους registers, θα γίνει η πρόσθεση.

Κατά την αναζήτηση των μεταβλητών στα caches και την μνήμη, η CPU αναγκάζεται να περιμένει τον memory controller, οπότε λέμε ότι έχουμε CPU stall. Το πόσο θα μας κοστίσει το cache miss εξαρτάται από την αρχιτεκτονική καθώς και από την ποιότητα και τον τύπο της μνήμης που χρησιμοποιεί το σύστημα μας. Συνήθως είναι από 21 μέχρι και 206 κύκλους μηχανής για P4EE και από από 16 εώς 101 για Athlon64. Με άλλα λόγια, στην παραπάνω περίπτωση, μπορεί να έχουμε μέχρι και 412 κύκλους μηχανής την CPU να κάθεται, περιμένοντας τον memory controller να φέρει τα περιεχόμενα των μεταβλητών από την μνήμη στους καταχωρητές για να γίνει μία πρόσθεση, της οποίας το κόστος είναι ένας μόνο κύκλος.

Για να αποφύγουμε το CPU stall, θα χρησιμοποιήσουμε ένα χαρακτηριστικό του memory controller που ονομάζεται data parallelism. Ο memory controller έχει την ικανότητα να δέχεται περισσότερα από ένα αιτήματα προς διεκπεραίωση. Συνεπώς για να μειώσουμε το stall αυτό που μπορούμε να κάνουμε variable preload. Πχ.
t = b;
t = c;
a = b + c;

Μπορεί να φαίνεται πιο χαζό και αργό, αλλά στην πραγματικότητα δεν είναι. Εδώ εκδίδουμε δύο αιτήματα προς τον memory controller για να διεκπεραιωθούν ταυτόχρονα. Όταν θα έρθει η ώρα της πρόσθεσης, οι μεταβλητές b και c θα βρίσκονται ήδη στο L1 cache. Το κόστος μεταφοράς τους όμως θα έχει κοστίσει μόνο 206 κύκλους μηχανής λόγω του παραλληλισμού και όχι 412 όπως πριν αν μιλάμε για Pentium.

Αυτά ισχύουν μόνο για μεμονωμένες μεταβλητές. Για πίνακες και memory blocks, ακολουθούμε άλλη τεχνική και θα την πούμε σε άλλο thread.

vagalati
27-07-2004, 18:09
Πού ξέρουμε αν οι εντολές (αιτήματα προς τον Μemory-Controller):
t = b;
t = c;
θα διεκπαιρεωθούν ταυτόχρονα; Είναι θέμα compiler;
Και κάτι άλλο: Είχα την εντύπωση ότι κάτι τέτοια κάνει ο compiler στο optimization phase, δηλ. κάνει preload κάποια δεδομένα πριν γίνουν πράξεις, μεταξύ των άλλων. Κάνω λάθος;

DarthMoul
27-07-2004, 18:48
Πού ξέρουμε αν οι εντολές (αιτήματα προς τον Μemory-Controller):
t = b;
t = c;
θα διεκπαιρεωθούν ταυτόχρονα; Είναι θέμα compiler;
Και κάτι άλλο: Είχα την εντύπωση ότι κάτι τέτοια κάνει ο compiler στο optimization phase, δηλ. κάνει preload κάποια δεδομένα πριν γίνουν πράξεις, μεταξύ των άλλων. Κάνω λάθος;
Δεν είναι θέμα compiler αλλά memory controller.
Για ποιόν compiler μιλάς;
Και για ποιό λειτουργικό;
Τα tips έχουν τον σκοπό να είναι γενικής χρήσης. Ο optimizer κάνει πολλά και διάφορα ανάλογα με τον κατασκευαστή. Θα κάνουμε άλλο thread για τους compilers και θα τα πούμε εκεί με λεπτομέρια. Αλλά για να μας καταλάβουν όλοι όμως, πρέπει πρώτα να πούμε άλλα.

float_e
16-01-2006, 18:36
Προσθεσεις και αφαιρεσεις το ιδιο , ετσι ?
Διαιρεσεις και πολλαπλασιασμοι το ιδιο ?

DarthMoul
16-01-2006, 19:05
Προσθεσεις και αφαιρεσεις το ιδιο , ετσι ?
Διαιρεσεις και πολλαπλασιασμοι το ιδιο ?
Συνήθως η πρόσθεση και η αφαίρεση είναι το ίδιο. Η διαίρεση είναι πιο αργή από τον πολλαπλασιασμό. Και λέω συνήθως γιατί δεν είναι κανόνας. Πχ στους alpha η διαίρεση πραγματικών είναι 7 φορές πιο γρήγορη από την διαίρεση ακεραίων. Στους x86 αυτό δεν ισχύει αφού δεν υπάρχουν fp και int registers αλλά όλοι είναι το ίδιο και χρήση τους εξαρτάται από την εντολή με την οποια συντάσσονται. Το γνωστό register renaming των x86. Αν θέλεις να κάνεις micro-optimization όπως αυτό που λέμε εδώ θα πρέπει να έχεις το architecture handbook δίπλα σου και το συμβουλεύεσαι.