-- Leo's gemini proxy

-- Connecting to magaz.hellug.gr:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

Αγάπη μου, Συρρίκνωσα τον Πυρήνα!


Παντελής Κουκούσουλας
Φεβ 2006

Βελτιστοποιώντας ένα πυρήνα της σειράς 2.6 για χρήση σε παλαιότερα / ενσωματωμένα συστήματα.


1. Εισαγωγή


2. Ξεκινώντας - Διαμόρφωση του πυρήνα


3. Παίζοντας με τις επιλογές του μεταγλωττιστή


4. Το -tiny patchset


5. Άλλες επεμβάσεις


6. Συμπεράσματα


7. Αναφορές


[1. Εισαγωγή]


Είναι γεγονός! Η νέα σειρά πυρήνων 2.6 είναι εδώ και υπόσχεται να κάνει τη συμβίωση με τον υπολογιστή μας αρκετά πιο ευχάριστη! Preemptible kernel, βελτιωμένο σύστημα διαχείρισης μνήμης και άλλες αλλαγές όλα συμβάλλουν σε ακόμα καλύτερη απόδοση των μηχανημάτων μας!


Στο άρθρο αυτό, θα προσπαθήσουμε να εκμεταλλευτούμε τα οφέλη από τις παραπάνω καινοτομίες και σε παλαιότερα μηχανήματα που πιθανώς χρησιμοποιούμε, μέσω μιας σειράς παρεμβάσεων στον πυρήνα, οι οποίες στοχεύουν στη μείωση των απαιτήσεών του σε μνήμη, καθώς και του χρόνου που χρειάζεται για την εκκίνηση (booting time). Για να βεβαιωθούμε ότι οι τεχνικές μας είναι εφαρμόσιμες σε όσο το δυνατόν περισσότερα συστήματα, θα τις δοκιμάσουμε σε ένα μηχάνημα που πλησιάζει τις ελάχιστες απαιτήσεις του Linux, δηλ. σε ένα 386sx/25 με 4mb RAM και 40 Mb σκληρό. Έτσι, όσοι έχουν ανώτερα από αυτό συστήματα θα μπορέσουν να υιοθετήσουν μόνο τις αναγκαίες γι αυτούς παρεμβάσεις από αυτές που θα παρουσιαστούν στη συνέχεια.


Για την αξιολόγηση κάθε τεχνικής, μετράμε σε κάθε ενδιάμεσο στάδιο το μέγεθος του ασυμπίεστου πυρήνα (vmlinux), το μέγεθος του συμπιεσμένου πυρήνα (system size


vmlinux.bin), το μέγεθος του συμπιεσμένου αρχείου (bzImage), την ελεύθερη μνήμη που αφήνει για τις εφαρμογές ο πυρήνας αμέσως μετά την εκκίνηση (από τα 4mb)


και το χρόνο από το πάτημα του κουμπιού "power" στον 386 μέχρι την εμφάνιση του prompt (χρόνος εκκίνησης). Ειδικά τα δύο τελευταία μετρούν σε μεγάλο βαθμό την εφαρμοσιμότητα του πυρήνα σε κάποιο μηχάνημα. Για την εκκίνηση του μηχανήματος χρησιμοποιείται το init του busybox, το οποίο τρέχει ένα ιδιαίτερα στοιχειώδες bootscript (/etc/rcS) που δεν αναμένεται να προσθέσει περισσότερο από μισό με ένα δευτερόλεπτο στο χρόνο εκκίνησης. Έτσι, ο τελευταίος καθορίζεται σε μεγάλο βαθμό από τον πυρήνα.


Εννοείται ότι καθώς οι επεμβάσεις στον πυρήνα και το BIOS είναι εξίσου επικίνδυνες για την υγεία του υλικού σας με τον υπερχρονισμό (overclocking), ο γράφων δεν δίνει καμία εγγύηση ότι οι παρακάτω ενέργειες θα δουλέψουν για εσάς χωρίς προβλήματα κλπ. καθώς και παραιτείται από κάθε ευθύνη για τις επιπτώσεις του υπόλοιπου άρθρου στη λειτουργία του Η/Υ σας, τις σχέσεις με το έτερον ήμισυ, την ψυχική υγεία του σκύλου σας ή οτιδήποτε άλλο.


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


[2. Ξεκινώντας - Διαμόρφωση του πυρήνα]


Για να μπορούμε να μετρήσουμε το όφελος των βελτιστοποιήσεων μας, χρειαζόμαστε ένα σύστημα αναφοράς. Ξεκινάμε λοιπόν κατεβάζοντας ένα πυρήνα 2.6.5 από το gr.kernel.org. Καθώς θέλουμε το ελάχιστο δυνατό μέγεθος για το bzImage του, (ώστε να φορτώνει γρήγορα στη μνήμη κατά την εκκίνηση), θα μεταγλωττίσουμε μόνο την απαραίτητη λειτουργικότητα για την εκκίνηση και την προσάρτηση του θεμελιώδους (root) partition στον πυρήνα. Όλη η υπόλοιπη λειτουργικότητα (δηλ. οι δυνατότητες που δεν θα χρησιμοποιούνται συνέχεια και ταυτόχρονα), θα μεταγλωττιστεί ως modules. Έτσι πετυχαίνουμε γρήγορη εκκίνηση χωρίς να θυσιάζουμε λειτουργικότητα (δεν φορτώνουμε modules κατά την εκκίνηση παρά μόνο τη στιγμή που θα χρειαστούν).


Στην περίπτωσή μου, έκανα τις εξής επιλογές: (όποιο μενού δεν αναφέρω, σημαίνει ότι τα αφήνουμε όλα ως έχουν):


Στο μενού General Setup: Επιλέγουμε μόνο την υποστήριξη για swap και System V IPC. Επίσης μπαίνουμε στο μενού Remove kernel features και αφήνουμε επιλεγμένα μόνο τον deadline I/O scheduler και το futex support. Δεν επιλέγουμε το optimize for size γιατί θέλουμε να αρχίσουμε με ένα vanilla (και όσο το δυνατόν πιο σταθερό) kernel.

Στο μενού Loadable module Support: Επιλέγουμε μόνο τα "Enable loadable module support" και "Module unloading".

Στο Μενού Processor type and features: Επιλέγουμε μόνο τον τύπο του επεξεργαστή μας (σε εμένα pc-compatible και 386), το "preemptible kernel" και το math emulation (εκτός αν ο υπολογιστής μας έχει FPU - από 486dx και πάνω δηλαδή)

Στο Μενού Power management options: Αποεπιλέγουμε τα πάντα (προσοχή γιατί το ACPI είναι επιλεγμένο).

Στο Μενού Bus Options: Αφήνουμε μόνο το ISA Support (καθώς οι 386 έχουν μόνο ISA slots).

Στο Executable File Formats: Αφήνουμε μόνο το elf.

Στο device drivers: Επιλέγουμε μόνο τα ATA/ATAPI/κλπ support, Old hard disk driver, Networking support, Network device support, TCP Networking, i8042 PC Keyboard controller, keyboards, AT Keyboard support, Virtual Terminal, console on virtual terminal και Unix98 PTY Support.

Στο μενού file systems, επιλέγουμε μόνο το minix (ή το ext2) filesystem και το /proc filesystem.

Αποεπιλέγουμε όλες τις επιλογές των υπόλοιπων μενού. (Ότι χρειαζόμαστε, το διαλέγουμε ως module)


Για να μην πληκτρολογείτε άσκοπα, μπορείτε να βρείτε το .config που χρησιμοποίησα εδώ[1]. Για να το χρησιμοποιήσετε, απλώς το τοποθετείτε στον κύριο κατάλογο του κώδικα του Linux και το ονομάζετε .config. Μετά κάνετε: make oldconfig


1: http://www.intelligence.tuc.gr/~pantelis/linuxlite/initial.config


Ονομάζουμε τον πυρήνα που προέκυψε από αυτή τη διαδικασία (με make bzImage) "kernel-initial". Ο πυρήνας αυτός έχει τα ακόλουθα χαρακτηριστικά:


Μέγεθος vmlinux:  1.5Mb
Μέγεθος system:   604kb
Μέγεθος bzImage:  612kb
Ελεύθερη μνήμη:   1484kb
Χρόνος εκκίνησης: 32s



Για τη μεταγλώττιση του παραπάνω πυρήνα χρησιμοποιήσαμε τη gcc-2.95.3 που συνιστά η ομάδα ανάπτυξης του πυρήνα, για μέγιστη δυνατή σταθερότητα. Αν και όπως παρατηρούμε ο πυρήνας που προέκυψε (στο εξής θα αναφερόμαστε σε αυτόν ως kernel-initial) είναι ήδη αρκετά μικρός, θα προσπαθήσουμε για ακόμα καλύτερα αποτελέσματα, δεδομένου ότι στον 386 κάθε βελτίωση είναι αισθητή.


[3. Παίζοντας με τις επιλογές του μεταγλωττιστή]


Ως γνωστόν, το μεγαλύτερο μέρος του Linux είναι γραμμένο στη γλώσσα προγραμματισμού C, η οποία όπως όλες οι γλώσσες υψηλού επιπέδου, βασίζεται σε ένα ειδικό πρόγραμμα (το μεταγλωττιστή) για την μετατροπή της σε γλώσσα μηχανής. Είναι λοιπόν λογικό, ότι ενεργοποιώντας συγκεκριμένες επιλογές του τελευταίου, θα μπορέσουμε να επηρεάσουμε λίγο ως πολύ τα χαρακτηριστικά του τελικού πυρήνα.


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


Καταρχήν, για να έχουμε τα καλύτερα δυνατά αποτελέσματα, θα χρησιμοποιήσουμε την πιο πρόσφατη έκδοση του μεταγλωττιστή gcc (3.4.0). Στην έκδοση αυτή, το υποσύστημα που αναλαμβάνει τη βελτιστοποίηση έχει βελτιωθεί αρκετά, οδηγώντας σε μικρότερο και γρηγορότερο κώδικα. Οι επιλογές (options) που θα χρησιμοποιήσουμε φαίνονται παρακάτω:


-Os. Η πιο γνωστή επιλογή για τέτοιες δουλειές, λέει στο μεταγλωττιστή να μικρύνει όσο μπορεί τον τελικό κώδικα ακόμη και σε βάρος της απόδοσης. Βέβαια, λόγω του τρόπου με τον οποίο λειτουργούν τα σύγχρονα μηχανήματα, διάφορες φήμες λένε ότι στην πραγματικότητα οι πυρήνες γίνονται εξίσου ή ίσως και λίγο πιο γρήγοροι με αυτή την επιλογή. Για να ενεργοποιήσουμε την -Os, επιλέγουμε "optimize for size" στο μενού "Remove kernel features"

-funit-at-a-time. Επιλέγεται αυτόματα αν χρησιμοποιούμε τη gcc-3.4.0 ή νεώτερη. Λέει στο μεταγλωττιστή να φορτώνει ολόκληρο το κάθε αρχείο στη μνήμη, πριν αρχίσει την παραγωγή τελικού κώδικα (μηχανής). Η περισσότερη πληροφορία που έχει έτσι ο μεταγλωττιστής στη διάθεσή του, οδηγεί στην καλύτερη απόρριψη άχρηστου κώδικα μεταξύ άλλων. Το μόνο κόστος αυτής της επιλογής είναι λίγη παραπάνω μνήμη στο μηχάνημα που θα κάνει τη μεταγλώττιση.

-mregparm=3. Η λιγότερο ασφαλής από τις επιλογές, αλλά και αυτή με το μεγαλύτερο όφελος. Αν ενεργοποιηθεί, αλλάζει τον τρόπο κλήσης των συναρτήσεων στον κώδικα του πυρήνα. Έτσι, για τα πρώτα τρία ορίσματα κάθε συνάρτησης δεν θα χρησιμοποιείται πλέον η στοίβα (μικρή περιοχή της RAM) αλλά οι καταχωρητές, δηλ η γρηγορότερη (και μικρότερη) μορφή μνήμης σε ένα υπολογιστή. Έτσι ο πυρήνας γίνεται όχι μόνο μικρότερος αλλά και γρηγορότερος. Το μειονέκτημα είναι ότι λόγω αυτής της αλλαγής, τυχόν binary modules που χρησιμοποιούμε (π.χ. drivers της nVidia ή ασύρματων καρτών γραφικών) παύουν αυτομάτως να λειτουργούν! Βέβαια, επειδή πρακτικά όλοι οι οδηγοί για ένα παλιό μηχάνημα είναι λογισμικό ανοιχτού κώδικα, η επιλογή αυτή θα μπορέσει να ωφελήσει τους περισσότερους, χωρίς τέτοιου είδους προβλήματα.


Θα ονομάσουμε τον πυρήνα που προέκυψε από αυτές τις αλλαγές kernel-opts. Τα χαρακτηριστικά του φαίνονται παρακάτω:


Μέγεθος vmlinux:  1.4Mb
Μέγεθος system:   527kb
Μέγεθος bzImage:  536kb
Ελεύθερη μνήμη:   1616Kb
Χρόνος εκκίνησης: 27s



Όπως παρατηρούμε, καταφέραμε να γλιτώσουμε περίπου 100kb από ένα ήδη σχετικά μικρό πυρήνα, απλώς με την αναβάθμιση της gcc και την ενεργοποίηση 2 επιλογών! Σε μεγαλύτερους πυρήνες μάλιστα έχουν αναφερθεί μειώσεις μεγέθους της τάξεως των 300kb. Τις παραπάνω επιλογές καλό θα ήταν να σκεφτούν και οι κάτοχοι καινούργιων μηχανημάτων, τουλάχιστον όσοι δε χρησιμοποιούν binary drivers.


[4. Το -tiny patchset]


Για ακόμα δραστικότερες μειώσεις μεγέθους, ο μόνος τρόπος είναι να επέμβουμε στον κώδικα του πυρήνα. Αυτό άλλωστε είναι ένα από τα σημαντικότερα πλεονεκτήματα του open source! Ο μόνος κίνδυνος είναι ότι με τις επεμβάσεις μας μπορεί να εισάγουμε νέα λάθη τα οποία θα κάνουν ίσως κάποιο καιρό να ανακαλυφθούν, ανάλογα και με τη δημοτικότητα των αλλαγών μας. Αν δεν είμαστε προγραμματιστές, ή θέλουμε κάποιο καλό σημείο εκκίνησης, ο Matt Mackall διατηρεί ένα σύνολο τέτοιων επεμβάσεων (patches) που σκοπό έχουν να κάνουν τον καινούργιο πυρήνα φιλικότερο σε παλαιότερα ή ενσωματωμένα μηχανήματα, καθώς διαπιστώνει ότι η προσοχή του Linux μετακινήθηκε από αυτά "από τότε που ο Linus βρήκε μια πραγματική δουλειά".


Οι αλλαγές αυτές αποτελούν το -tiny patchset, διαθέσιμο στη διεύθυνση www.selenic.com/tiny. Εφαρμόζοντας το patch αυτό στον πυρήνα μας, παρατηρούμε ότι μια σειρά από νέες επιλογές εμφανίζονται κάτω από το μενού "Remove kernel features", το οποίο μάλιστα αλλάζει όνομα σε "Configure standard kernel features (for small devices)". Οι επιλογές αυτές ρυθμίζουν διάφορες παραμέτρους του "εσωτερικού" του πυρήνα δίνοντάς μας τη δυνατότητα να μικρύνουμε το μέγεθος διάφορων εσωτερικών δομών αλλά και γενικότερα να προσαρμόσουμε τον πυρήνα στα ιδιαίτερα χαρακτηριστικά του μηχανήματός μας.


Οι επιλογές που αξίζει να ενεργοποιήσουμε σε αυτό το μενού είναι: "various size reductions for core" (και networking), futex support, POSIX file locking API, Deadline I/O Scheduler, Optimize for size (και with register passing), Set compiler arch flags .. (-march=i386), sys file system (υποχρεωτικά!), support for executable shell scripts, block device support και από supported processor vendors, μόνο αυτόν που έχει φτιάξει τον επεξεργαστή μας (για μένα intel). Επίσης number of swap files = 0 (δηλαδή επιτρέπουμε ένα μόνο swap file (δεν ξέρω κανένα να χρησιμοποιεί παραπάνω από 1 έτσι κι αλλιώς, πόσο μάλλον σε ένα σκληρό των 40Mb!), 4 tty line disciplines (είναι αρκετά), 10 realtime priority levels (μικραίνει τις δομές του δρομολογητή - scheduler) και 100Hz timer interrupts per second. Η τελευταία επιλογή είναι πολύ σημαντική για τη γρήγορη λειτουργία του υπολογιστή μας καθώς με περισσότερα Hz έχουμε μεν μεγαλύτερη ακρίβεια και καλύτερο χρόνο απόκρισης αλλά και μεγαλύτερο overhead το οποίο αφαιρεί πολύτιμους κύκλους από τους ήδη λίγους του επεξεργαστή μας. Τα 100Hz είναι κατά τη γνώμη μου ένας καλός συμβιβασμός για προ pentium επεξεργαστές.


Φυσικά και πάλι για να μην πληκτρολογείτε άσκοπα, το .config που χρησιμοποίησα βρίσκεται εδώ[2]. Τα χαρακτηριστικά του πυρήνα που προκύπτει από αυτή τη διαμόρφωση (kernel-tiny) φαίνονται παρακάτω.


2: http://www.intelligence.tuc.gr/~pantelis/linuxlite/tiny.config


Μέγεθος vmlinux:  1.2Mb
Μέγεθος system:   446kb
Μέγεθος bzImage:  456kb
Ελεύθερη μνήμη:   2052kb
Χρόνος εκκίνησης: 43s



Είναι εύκολο να παρατηρήσουμε τη σημαντική οικονομία σε μνήμη που πετύχαμε με τις παραπάνω επιλογές, διατηρώντας παράλληλα τη λειτουργικότητα που θέλαμε και ένα σχετικά σταθερό πυρήνα. Το περίεργο που προέκυψε είναι ότι ο χρόνος αποσυμπίεσης του νέου πυρήνα έγινε σημαντικά μεγαλύτερος, πράγμα που αποτελεί την κύρια αιτία για την (ομολογουμένως σημαντική) αύξηση του χρόνου εκκίνησης. Η αύξηση αυτή πιστεύω ότι οφείλεται στις αλλαγές στον κώδικα αποσυμπίεσης του πυρήνα που περιλαμβάνονται στο -tiny patchset και σκοπό έχουν τη μείωση του μεγέθους εις βάρος της ταχύτητας. Παρόλα αυτά, το πρόβλημα αυτό δεν μας αφορά ιδιαίτερα καθώς θα προτείνουμε μια πολύ καλύτερη λύση για τη συμπίεση στην επόμενη ενότητα.


[5. Άλλες επεμβάσεις]


Έχοντας δοκιμάσει τον προηγούμενο πυρήνα και βεβαιωθεί ότι δουλεύει και μάλιστα πολύ καλά και σταθερά για τις εφαρμογές που θέλουμε να τον χρησιμοποιήσουμε, μπορούμε να προβούμε και σε πιο δραστικές λύσεις, προκειμένου να ελευθερώσουμε ακόμα περισσότερη μνήμη, όπως το να απενεργοποιήσουμε τα μηνύματα του πυρήνα (printk) και τον κώδικα ανίχνευσης και αναφοράς των kernel panics. Οι επιλογές αυτές είναι αρκετά πιο επικίνδυνες από τις προηγούμενες και επίσης δεν προσφέρουν τόσα οφέλη, αλλά σε ένα μηχάνημα με π.χ. 2mb RAM είναι μάλλον αναγκαίες για να μπορέσει να λειτουργήσει έστω και στοιχειωδώς.


Τέλος, για ιδιαίτερα γρηγορότερη αποσυμπίεση καθώς και ακόμα μικρότερο μέγεθος bzImage, μπορούμε να συμπιέσουμε τον πυρήνα μας με το upx 1.90. Αν και ο συμπιεστής αυτός δεν είναι ανοιχτό λογισμικό, ο αποσυμπιεστής (που βάζει στο αρχείο του πυρήνα) είναι και μας δίνει το πλεονέκτημα αφενός της καλύτερης συμπίεσης από το gzip (376kb αντί για 436kb τελικό αρχείο) και αφετέρου της τρομερά γρηγορότερης αποσυμπίεσης (περίπου 2x). Επίσης, ο αποσυμπιεστής έχει μέγεθος μόνο μερικά bytes! (είναι γραμμένος σε assembly).


Έτσι φτάνουμε στον τελικό πυρήνα που έχει τα παρακάτω χαρακτηριστικά:


Μέγεθος vmlinux:  1.2Mb
Μέγεθος system:   424kb
Μέγεθος bzImage:  376kb
Ελεύθερη μνήμη:   2112kb
Χρόνος εκκίνησης: 15s



Από εδώ κι εμπρός, υπάρχουν μεν κι άλλα πράγματα που μπορεί κάποιος να κάνει για ακόμα μικρότερους πυρήνες αλλά όλα περιλαμβάνουν αρκετό κόπο για ελάχιστα παραπάνω οφέλη, όποτε θα σταματήσουμε εδώ. Έτσι κι αλλιώς, τα 15s του χρόνου εκκίνησης είναι ήδη λιγότερα από τους χρόνους των περισσότερων φίλων μου με πολύ γρηγορότερους υπολογιστές από τα 8.19 BogoM*ps του 386! (οι οποίοι όμως τρέχουν μη βελτιστοποιημένους πυρήνες και init sequences).


[6. Συμπεράσματα]


Εκμεταλλευόμενοι το νεότερο μεταγλωττιστή και τις μεγαλύτερες δυνατότητες διαμόρφωσης του νέου πυρήνα, καταφέραμε να μειώσουμε σημαντικά το μέγεθός του (από 612 σε 376kb για το bzImage) καθώς και το χρόνο εκκίνησης του συστήματος (σε λιγότερο από το μισό - από 32 σε 15 second!) φέρνοντας μάλιστα τον τελευταίο κοντά στα επίπεδα του dos ( 12s γιατί το dos χρειάζεται περισσότερες λειτουργίες από το BIOS τις οποίες μπορούμε να απενεργοποιήσουμε όταν χρησιμοποιούμε το Linux).


Ο πυρήνας που προέκυψε μπορεί άνετα να χρησιμοποιηθεί σε μηχανήματα με ακόμα και 4 (ή και 3Mb) RAM, επιτρέποντάς τους να εκμεταλλευτούν τις νέες δυνατότητες που προσφέρει (καλύτερη δικτύωση, καλύτερη υποστήριξη εφαρμογών πραγματικού χρόνου κλπ). Στη δική μου περίπτωση, ο 386 μπόρεσε με αυτό τον τρόπο να βγει από την αχρησία και απέκτησε αρκετές πρωτότυπες εφαρμογές (streaming video σε ascii-art! αλλά αυτό είναι μια άλλη ιστορία).


Αναστήστε λοιπόν κι εσείς τους παλιούς σας υπολογιστές και γελάστε άφοβα στα μούτρα όσων σας πουν ότι τα Longhorn θα χρειάζονται επεξεργαστή 2GHz και μνήμη 512Mb μόνο για να ξεκινήσουν!!!.


[7. Αναφορές]


Shrinking the kernel with gcc (LWN) - http://lwn.net/Articles/67175/[3]

Linux: Reducing Disk And Memory Footprint - http://kerneltrap.org/node/view/1769[4]

UPX 1.90: http://upx.sourceforge.net/[5]


3: http://lwn.net/Articles/67175/

4: http://kerneltrap.org/node/view/1769

5: http://upx.sourceforge.net/


Αρχική Σελίδα

-- Response ended

-- Page fetched on Sat May 11 09:53:19 2024