Προγραμματισμός

Γιατί ο αποτελεσματικός παράλληλος προγραμματισμός πρέπει να περιλαμβάνει κατανομή μνήμης με δυνατότητα κλιμάκωσης

Επεξεργαστής πολλαπλών πυρήνων; Ναί.

Εγγραφή προγράμματος για παράλληλη εκτέλεση; Ναί.

Θυμηθήκατε να χρησιμοποιήσετε έναν επεκτάσιμο μνήμη Allocator; Οχι? Στη συνέχεια, διαβάστε…

Σύμφωνα με την εμπειρία μου, το να βεβαιωθώ ότι η "κατανομή μνήμης" για ένα πρόγραμμα είναι έτοιμη για παραλληλισμό είναι ένα στοιχείο που συχνά παραβλέπεται για να λειτουργήσει ένα παράλληλο πρόγραμμα. Μπορώ να σας δείξω έναν απίστευτα εύκολο τρόπο για να δείτε αν αυτό είναι πρόβλημα για ένα μεταγλωττισμένο πρόγραμμα (C, C ++, Fortran κ.λπ.) - καθώς και πώς να το διορθώσετε.

Ένα κρίσιμο μέρος οποιουδήποτε παράλληλου προγράμματος είναι η κλιμακούμενη κατανομή μνήμης, η οποία περιλαμβάνει τη χρήση τουνέοςκαθώς και ρητές κλήσεις προςmalloc, calloc ή realloc. Οι επιλογές περιλαμβάνουν TBBmalloc (Intel Threading Building Blocks), jemalloc και tcmalloc. Το TBBmalloc διαθέτει μια νέα δυνατότητα «διακομιστή μεσολάβησης» που καθιστά εύκολη τη δοκιμή σε λιγότερο από 5 λεπτά σε οποιοδήποτε μεταγλωττισμένο πρόγραμμα.

Τα οφέλη απόδοσης από τη χρήση ενός επεκτάσιμου κατανεμητή μνήμης είναι σημαντικά. Το TBBmalloc ήταν από τους πρώτους ευρέως χρησιμοποιούμενους επεκτάσιμους κατανεμητές μνήμης, σε μικρό βαθμό, επειδή κυκλοφόρησε δωρεάν με το TBB για να τονίσει τη σημασία της συμπερίληψης της κατανομής μνήμης σε οποιοδήποτε παράλληλο πρόγραμμα. Παραμένει εξαιρετικά δημοφιλές σήμερα και εξακολουθεί να είναι ένας από τους καλύτερους διαθέσιμους διανομείς μνήμης.

Μια εύκολη λύση χωρίς αλλαγή κώδικα

Χρησιμοποιώντας τις μεθόδους μεσολάβησης, μπορούμε να αντικαταστήσουμε παγκοσμίως νέος/διαγράφω και malloc/κάλκο/ανακατανομή/Ελεύθερος/και τα λοιπά. ρουτίνες με μια τεχνική αντικατάστασης δυναμικής διεπαφής μνήμης. Αυτός ο αυτόματος τρόπος αντικατάστασης των προεπιλεγμένων λειτουργιών για δυναμική κατανομή μνήμης είναι μακράν ο πιο δημοφιλής τρόπος χρήσης του TBBmalloc. Είναι εύκολο και επαρκές για τα περισσότερα προγράμματα.

Οι λεπτομέρειες του μηχανισμού που χρησιμοποιείται σε κάθε λειτουργικό σύστημα διαφέρουν λίγο, αλλά το καθαρό αποτέλεσμα είναι το ίδιο παντού.

Ξεκινάμε τη δοκιμή 5 λεπτών κατεβάζοντας και εγκαθιστώντας το Threading Building Blocks (δωρεάν από το //threadingbuildingblocks.org. Περιλαμβάνεται επίσης ως μέρος των προϊόντων Intel Parallel Studio).

Χρησιμοποιήστε διακομιστή μεσολάβησης σε Linux

Στο Linux, μπορούμε να κάνουμε την αντικατάσταση είτε φορτώνοντας τη βιβλιοθήκη μεσολάβησης κατά το χρόνο φόρτωσης του προγράμματος χρησιμοποιώντας το LD_PRELOAD μεταβλητή περιβάλλοντος (χωρίς αλλαγή του εκτελέσιμου αρχείου) ή με σύνδεση του κύριου εκτελέσιμου αρχείου με τη βιβλιοθήκη διακομιστή μεσολάβησης (-ltbbmalloc_proxy). Ο φορτωτής προγράμματος Linux πρέπει να είναι σε θέση να βρει τη βιβλιοθήκη μεσολάβησης και την επεκτάσιμη βιβλιοθήκη κατανομής μνήμης κατά το χρόνο φόρτωσης του προγράμματος. Για αυτό μπορεί να συμπεριλάβουμε τον κατάλογο που περιέχει τις βιβλιοθήκες στο LD_LIBRARY_PATH μεταβλητή περιβάλλοντος ή να την προσθέσετε /etc/ld.so.conf.

Δοκιμάστε τα εξής:

ώρα ./a.out (ή οτιδήποτε ονομάζεται το πρόγραμμά μας)

εξαγωγή LD_PRELOAD = libtbbmalloc_proxy.so.2

ώρα ./a.out (ή οτιδήποτε ονομάζεται το πρόγραμμά μας)

Χρησιμοποιήστε διακομιστή μεσολάβησης σε macOS

Στο macOS, μπορούμε να κάνουμε την αντικατάσταση είτε φορτώνοντας τη βιβλιοθήκη μεσολάβησης κατά το χρόνο φόρτωσης του προγράμματος χρησιμοποιώντας το DYLD_INSERT_LIBRARIES μεταβλητή περιβάλλοντος (χωρίς αλλαγή του εκτελέσιμου αρχείου) ή με σύνδεση του κύριου εκτελέσιμου αρχείου με τη βιβλιοθήκη διακομιστή μεσολάβησης (-ltbbmalloc_proxy). Ο φορτωτής προγράμματος macOS πρέπει να είναι σε θέση να εντοπίσει τη βιβλιοθήκη μεσολάβησης και τη βιβλιοθήκη κατανομής μνήμης με δυνατότητα κλιμάκωσης κατά το χρόνο φόρτωσης του προγράμματος. Για αυτό, ενδέχεται να συμπεριλάβουμε τον κατάλογο που περιέχει τις βιβλιοθήκες στο DYLD_LIBRARY_PATH μεταβλητή περιβάλλοντος.

Δοκιμάστε τα εξής:

ώρα ./a.out (ή οτιδήποτε ονομάζεται το πρόγραμμά μας)

εξαγωγή DYLD_INSERT_LIBRARIES = $ TBBROOT / lib / libtbbmalloc_proxy.dylib

ώρα ./a.out (ή οτιδήποτε ονομάζεται το πρόγραμμά μας)

Χρησιμοποιήστε διακομιστή μεσολάβησης στα Windows

Στα Windows, πρέπει να τροποποιήσουμε το εκτελέσιμο. Μπορούμε είτε να αναγκάσουμε τη φόρτωση της βιβλιοθήκης μεσολάβησης προσθέτοντας ένα # συμπερίληψη "tbb / tbbmalloc_proxy.h" στον πηγαίο κώδικα μας ή χρησιμοποιώντας συγκεκριμένες επιλογές σύνδεσης κατά τη δημιουργία του εκτελέσιμου:

Για win32:

            tbbmalloc_proxy.lib / ΠΕΡΙΛΑΜΒΑΝΕΙ: "___ TBB_malloc_proxy"

Για win64:

            tbbmalloc_proxy.lib / ΠΕΡΙΛΑΜΒΑΝΕΙ: "__ TBB_malloc_proxy"

Ο φορτωτής προγράμματος των Windows πρέπει να είναι σε θέση να βρει τη βιβλιοθήκη μεσολάβησης και τη βιβλιοθήκη κατανομής μνήμης με δυνατότητα κλιμάκωσης κατά το χρόνο φόρτωσης του προγράμματος. Για αυτό, ενδέχεται να συμπεριλάβουμε τον κατάλογο που περιέχει τις βιβλιοθήκες στο ΜΟΝΟΠΑΤΙ μεταβλητή περιβάλλοντος. Δοκιμάστε το χρησιμοποιώντας το Visual Studio "Performance Profiler" για να ορίσετε το πρόγραμμα με και χωρίς την επιλογή συμπερίληψης ή σύνδεσης.

Δοκιμή της χρήσης της βιβλιοθήκης μεσολάβησης με ένα μικρό πρόγραμμα

Σας ενθαρρύνω να δοκιμάσετε με το δικό σας πρόγραμμα όπως περιγράφεται παραπάνω. Εκτελέστε με και χωρίς το διακομιστή μεσολάβησης και δείτε πόσο όφελος λαμβάνει η εφαρμογή σας. Οι εφαρμογές με πολλούς παραλληλισμούς και πολλές εκχωρήσεις μνήμης βλέπουν συχνά 10-20% ενισχύσεις (έχω δει επίσης μια αύξηση 400% μια φορά), ενώ τα προγράμματα με λίγο παραλληλισμό ή λίγες κατανομές ενδέχεται να μην έχουν καθόλου αποτέλεσμα. Οι γρήγορες δοκιμές, που περιγράφηκαν προηγουμένως, με τη βιβλιοθήκη μεσολάβησης θα σας πουν σε ποια κατηγορία ανήκει η εφαρμογή σας.

Έγραψα επίσης ένα σύντομο πρόγραμμα για να επεξηγήσω τα εφέ καθώς και να παράσχω έναν εύκολο τρόπο για να ελέγξετε ότι τα πράγματα είναι εγκατεστημένα και λειτουργούν όπως αναμενόταν. Μπορούμε να δοκιμάσουμε τη βιβλιοθήκη μεσολάβησης με ένα απλό πρόγραμμα:

#περιλαμβάνω

# συμπερίληψη "tbb / tbb.h"

χρησιμοποιώντας το namespace tbb;

const int N = 1000000;

int main () {

διπλό * α [Ν];

parallel_for (0, N-1, [&] (int i) {a [i] = νέο διπλό;});

parallel_for (0, N-1, [&] (int i) {διαγράψτε ένα [i];});

επιστροφή 0;

}

Το πρόγραμμα παραδειγμάτων μου χρησιμοποιεί πολύ χώρο στοίβας, οπότε "ulimit –s απεριόριστο"(Linux / macOS) ή"/ STACK: 10000000"(Visual Studio: Properties> Configuration Properties> Linker> System> Stack Reserve Size) θα είναι σημαντικό για την αποφυγή άμεσων διακοπών.

Μετά τη σύνταξη, εδώ είναι οι διάφοροι τρόποι που έτρεξα το μικρό μου πρόγραμμα για να δω την ταχύτητα με και χωρίς τη βιβλιοθήκη μεσολάβησης.

Εκτέλεση και συγχρονισμός tbb_mem.cpp σε ένα τετράγωνο εικονικός Μηχανή Linux, είδα τα εξής:

% χρόνος ./tbb_mem

πραγματική 0m0.160s

χρήστης 0m0.072s

sys 0m0.048s

%

% exportLD_PRELOAD = $ TBBROOT / lib / libtbbmalloc_proxy.dylib

%

% χρόνος ./tbb_mem

πραγματικό 0m0.043s

χρήστης 0m0.048s

sys 0m0.028s

Τρέχοντας και συγχρονίζοντας tbb_mem.cpp σε ένα quadcore iMac (macOS), είδα τα εξής:

% χρόνος ./tbb_mem

πραγματικό 0m0.046s

χρήστης 0m0.078s

sys 0m0.053s

%

% εξαγωγή DYLD_INSERT_LIBRARIES = $ TBBROOT / lib / libtbbmalloc_proxy.dylib

%

% χρόνος ./tbb_mem

πραγματικά 0m0.019s

χρήστης 0m0.032s

sys 0m0.009s

Στα Windows, χρησιμοποιώντας το Visual Studio "Performance Profiler" σε ένα τετράγωνο Intel NUC (Core i7), είδα χρόνους 94 ms χωρίς το επεκτάσιμο προφίλ μνήμης και 50 ms μαζί του (προσθήκη # συμπερίληψη "tbb / tbbmalloc_proxy.h"στο παράδειγμα προγράμματος).

Στοιχεία συλλογής

Προσωπικά δεν είχα πρόβλημα με τους μεταγλωττιστές να κάνουν «βελτιστοποιήσεις malloc», αλλά τεχνικά θα πρότεινα ότι κατά τη σύνταξη με προγράμματα που θα πρέπει να απενεργοποιηθούν αυτές οι μεταγλωττιστές «malloc optimization» Ίσως είναι καλό να ελέγξετε την τεκμηρίωση του μεταγλωττιστή του αγαπημένου σας μεταγλωττιστή. Για παράδειγμα, με τους επεξεργαστές Intel ή το gcc, είναι καλύτερο να περάσετε στις ακόλουθες σημαίες:

-fno-builtin-malloc (στα Windows: / Qfno-builtin-malloc)

-fno-builtin-calloc (στα Windows: / Qfno-builtin-calloc)

-fno-builtin-realloc (στα Windows: / Qfno-builtin-realloc)

-fno-builtin-free (στα Windows: / Qfno-builtin-free)

Η αποτυχία χρήσης αυτών των σημαιών ενδέχεται να μην προκαλεί πρόβλημα, αλλά δεν είναι κακή ιδέα να είστε ασφαλείς.

Περίληψη

Η χρήση ενός επεκτάσιμου κατανεμητή μνήμης είναι βασικό στοιχείο σε οποιοδήποτε παράλληλο πρόγραμμα. Έχω δείξει ότι το TBBmalloc μπορεί εύκολα να εγχυθεί χωρίς να απαιτείται αλλαγή κώδικα (αν και η προσθήκη ενός "συμπερίληψης" στα Windows είναι η αγαπημένη μου λύση στα Windows). Μπορεί να δείτε μια καλή επιτάχυνση με μόνο 5 λεπτά εργασίας και μπορείτε να την εφαρμόσετε εύκολα σε πολλές εφαρμογές. Σε Linux και macOS ίσως να μπορείτε να επιταχύνετε τα προγράμματα χωρίς να έχετε τον πηγαίο κώδικα!

Κάντε κλικ εδώ για να κατεβάσετε τη δωρεάν δοκιμή 30 ημερών του Intel Parallel Studio XE.

$config[zx-auto] not found$config[zx-overlay] not found