linux process scheduling

90
1 STUDENT: KARPOUZIS ATHANASIOS LINUX PROCESS SCHEDULING

Upload: luann

Post on 22-Feb-2016

54 views

Category:

Documents


0 download

DESCRIPTION

Linux Process Scheduling. Student: KARPOUZIS ATHANASIOS. Διεργασία / Process (1). Μία διεργασία ( process) είναι στην ουσία μία συλλογή από δομές δεδομένων που περιγράφουν πόσο μακριά έχει φτάσει κάποιο πρόγραμμα που εκτελείται. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Linux Process Scheduling

1S T U D E N T: K A R P O U Z I S AT H A N A S I O S

LINUX PROCESS SCHEDULING

Page 2: Linux Process Scheduling

2

Διεργασία / Process (1)

• Μία διεργασία (process) είναι στην ουσία μία συλλογή από δομές δεδομένων που περιγράφουν πόσο μακριά έχει φτάσει κάποιο πρόγραμμα που εκτελείται.

• Μοιάζουν στην ουσία με τους ανθρώπους, γεννιούνται, έχουν κάποιο χρόνο ζωής, έχουν την δυνατότητα να δημιουργήσουν απογόνους – νέες διεργασίες και τελικά πεθαίνουν (κύκλος ζωής).

• Μια διεργασία είναι:• Ένα πρόγραμμα σε εκτέλεση • Μια ασύγχρονη δραστηριότητα, • Μια εκτελούμενη διαδικασία που συσχετίζεται με την ύπαρξη μιας

δομής δεδομένων στο ΛΣ, τον περιγραφέα διεργασίας (process descriptor) ή μπλοκ ελέγχου διεργασίας (Process Control Block).

Page 3: Linux Process Scheduling

3

Διεργασία / Process (2)

• Μια διεργασία είναι μια οντότητα με τον δικό της χώρο διευθύνσεων, που αποτελείται από: την περιοχή κώδικα (text region), περιέχει τον κώδικα που εκτελεί ο επεξεργαστής

• Την περιοχή δεδομένων (data region), όπου αποθηκεύονται οι μεταβλητές και η δυναμικά παραχωρούμενη μνήμηπου χρησιμοποιεί ο επεξεργαστής κατά τη διάρκεια της εκτέλεσης

• Την περιοχή στοίβας (stack region), όπου αποθηκεύονται οι εντολές και οι τοπικές μεταβλητές για τις ενεργές κλήσεις διαδικασιών

Page 4: Linux Process Scheduling

4

Διεργασία / Process (3)

• Οι διεργασίες μπορούν να προχωρήσουν μόνον όταν υπάρχει το μέσον που θα εκτελέσει τα σχετικά προγράμματα. Αυτό το μέσο είναι ο επεξεργαστής (processor).

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

• Παράδειγμα: • μια CPU είναι ένας επεξεργαστής για εκτέλεση εντολών γλώσσας

μηχανής, ενώ μια CPU μαζί με έναν διερμηνευτή (interpreter) μιας γλώσσας προγραμματισμού συνθέτουν έναν επεξεργαστή που εκτελεί εντολές της συγκεκριμένης γλώσσας προγραμματισμού.

Page 5: Linux Process Scheduling

5

Διεργασία / Process (4)

• Ένας επεξεργαστής εκτελεί εντολές μηχανής που βρίσκονται στην κύρια μνήμη σε μορφή προγράμματος.

• Για να εκτελεσθεί ένα πρόγραμμα δημιουργείται μια διεργασία για το συγκεκριμένο πρόγραμμα.

• Κατά τη διάρκεια του χρόνου οι εντολές προγράμματος που εκτελούνται δημιουργούν μια λίστα που ονομάζεται αποτύπωση της διεργασίας.

• Ένας επεξεργαστής μπορεί να απασχοληθεί σε διαφορετικές διεργασίες μέσω ενός αλγορίθμου χρονοδρομολόγησης (scheduling) που καθορίζει πότε και ποια διεργασία θα έχει κάθε φορά το δικαίωμα αποκλειστικής χρήσης του.

• Το ζητούμενο είναι να εξισορροπηθούν οι ανταγωνιστικές απαιτήσεις για την αποδοτικότητα (efficiency) όλου του συστήματος και για τις σχέσεις δικαιοσύνης (fairness) μεταξύ των διεργασιών.

Page 6: Linux Process Scheduling

6

• Scheduler (Χρονοδρομολογητής)

Page 7: Linux Process Scheduling

7

Χρονοδρομολογητής (1)

• Όταν μια διεργασία βρίσκεται σε μια ουρά το Λ.Σ. με κάποιον τρόπο πρέπει να επιλέξει μια διεργασία από την ουρά, η λειτουργία αυτή επιτελείται από έναν χρονο-δρομολογητή.

• Long-term scheduler (or job scheduler) – αποφασίζει και επιλέγει τις διεργασίες που θα περιληφθούν στην ουρά των έτοιμων προς εκτέλεση διεργασιών (ready queue). Ελέγχει τον βαθμό πολυπρογραμματισμού.

• Short-term scheduler (or CPU scheduler) – επιλέγει ποια διεργασία θα είναι η επόμενη προς εκτέλεση και εκχωρεί τη χρήση της CPU.

• Medium-term scheduler – χρησιμοποιείται ειδικά σε time-sharing συστήματα ως ένα ενδιάμεσο επίπεδο χρονοδρομολόγησης. Χρησιμοποιεί ένα σχήμα εναλλαγής που μετακινεί περιοδικά διεργασίες από τη μνήμη και τις εγκαθιστά αργότερα για να συνεχίσουν από το σημείο που είχαν σταματήσει.

Page 8: Linux Process Scheduling

8

Χρονοδρομολογητής (2)

Page 9: Linux Process Scheduling

9

• Περιγραφέας Διεργασίας (Process Descriptor)

Page 10: Linux Process Scheduling

10

Περιγραφέας Διεργασίας (Process Descriptor) (1)

• Πρόκειται για μία δομή που διατηρεί πληροφορίες όσον αφορά την προτεραιότητα της διεργασίας, των χώρο διευθύνσεων που της αντιστοιχεί (address space), την κατάσταση της διεργασίας κτλ.

• Στην υλοποίηση του λειτουργικού συστήματος Linux είναι η struct task_struct.

• struct task_struct {• 1118 volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */• 1119 void *stack;• 1120 atomic_t usage;• 1121 unsigned int flags; /* per process flags, defined below */• 1122 unsigned int ptrace;• 1123• 1124 int lock_depth; /* BKL lock depth */• 1125• 1126#ifdef CONFIG_SMP• 1127#ifdef __ARCH_WANT_UNLOCKED_CTXSW• 1128 int oncpu;• 1129#endif• 1130#endif• 1131• 1132 int prio, static_prio, normal_prio;• 1133 unsigned int rt_priority;• 1134 const struct sched_class *sched_class;• 1135 struct sched_entity se;• 1136 struct sched_rt_entity rt;• 1137 ……………….

Page 11: Linux Process Scheduling

11

Περιγραφέας Διεργασίας (Process Descriptor) (2)

• Περιγραφέας Διεργασίας

• Η δομή task_struct.

Page 12: Linux Process Scheduling

12

Περιγραφέας Διεργασίας (Process Descriptor) (3)Κατάσταση Διεργασίας (Process State)

• Παρατηρούμε στην δομή του περιγραφέα διεργασίας το πεδίο state που δηλώνει την κατάσταση της διεργασίας.

• Κάθε φορά η διεργασία μπορεί να έχει μόνο μία κατάσταση, η οποία μπορεί να αλλάζει.

• Μαζί με την κατάσταση της διεργασίας υπάρχεις και η κατάσταση εξόδου της διεργασίας σε ξεχωριστό πεδίο.

Page 13: Linux Process Scheduling

13

Περιγραφέας Διεργασίας (Process Descriptor) (4)Κατάσταση Διεργασίας (Process State)

• Καταστάσεις Διεργασίας:

• TASK_RUNNING• Η διεργασία τρέχει στον επεξεργαστή η περιμένει στην ουρά για να

εκτελεστεί.

• TASK_INTERRUPTIBLE• Η διεργασία κοιμάται, μέχρι κάποιο σήμα που προέρχεται από μία

κατάσταση που άλλαξε, να την ξυπνήσει. Η διεργασία μπορεί να περίμενε κάποιους πόρους, ή να έγινε κάποιο hardware interrupt, ή κάποιο άλλο σήμα. Γυρίζει σε κατάσταση TASK_RUNNING.

• TASK_UNINTERRUPTIBLE• Όπως η παραπάνω κατάσταση με την διαφορά ότι κάποιο σήμα δεν

ξυπνάει την διεργασία και παραμένει μπλοκαρισμένη. Γενικά είναι σπάνιο να βρεθεί διεργασία σε αυτή την κατάσταση.

Page 14: Linux Process Scheduling

14

Περιγραφέας Διεργασίας (Process Descriptor) (5)Κατάσταση Διεργασίας (Process State)

• Καταστάσεις Διεργασίας:

• TASK_STOPPED• H εκτέλεση της διεργασία σταματάει, η διεργασία σταματά κατόπιν

κάποιων από αυτών των σημάτων• SIGSTOP• SIGTSTP• SIGTTIN• SIGTTOU

• TASK_TRACED• Η εκτέλεση μια διεργασίας σταμάτησε από τον debugger. Όταν μια

διεργασία παρακολουθείται από κάποια άλλη όπως πχ ένας debugger με την ptrace() κλήση συστήματος, κάποιο σήμα μπορεί να φέρει την διεργασία σε αυτή την κατάσταση.

Page 15: Linux Process Scheduling

15

Περιγραφέας Διεργασίας (Process Descriptor) (5α)Κατάσταση Διεργασίας (Process State)

Page 16: Linux Process Scheduling

16

Περιγραφέας Διεργασίας (Process Descriptor) (5β)Στιγμιότυπο Εκτέλεσης

Page 17: Linux Process Scheduling

17

Περιγραφέας Διεργασίας (Process Descriptor) (6)Κατάσταση Εξόδου Διεργασίας (Process State)

• Καταστάσεις εξόδου (τερματισμού) διεργασίας:

• EXIT_ZOMBIE• Η διεργασία τερματίστηκε αλλά η διεργασία πατέρας δεν έχει

εκτελέσει την κλήση συστήματος waitpid ή wait ώστε να επιστρέψει πληροφορίες για την νεκρή διεργασία. Πριν ολοκληρωθεί η κλήση αυτή συστήματος ο πυρήνας δεν μπορεί να ελευθερώσει / απομακρύνει δεδομένα που αφορούν την νεκρή διεργασία γιατί ο πατέρας μπορεί να τα χρειάζεται.

• EXIT_DEAD• Τελική κατάσταση, η διεργασία αφαιρείται από το σύστημα γιατί ο

πατέρας πήρε αποτέλεσμα από την κλήση συστήματος waitpid ή wait.

Page 18: Linux Process Scheduling

18

Περιγραφέας Διεργασίας (Process Descriptor) (7)Αναγνωρίζοντας μία Διεργασία

• Κάθε διεργασία έχει δείκτες σε περιγραφέα διεργασιών με μέγεθος 32-bit

• Κάθε διεργασία έχει το δικό της αναγνωριστικό διεργασίας (Process ID (PID)) 16-bit (~32767 για συμβατότητα)

• Το σύστημα Linux αντιστοιχεί διαφορετικά PID με κάθε διεργασία.

• Για να πάρουμε το αναγνωριστικό της διεργασίας χρησιμοποιούμε την κλήση συστήματος getpipd() και για να πάρουμε το αναγνωριστικό της διεργασίας πατέρα χρησιμοποιούμε την κλήση συστήματος getppid().

Page 19: Linux Process Scheduling

19

Περιγραφέας Διεργασίας (Process Descriptor) (8)Διάγραμμα Καταστάσεων στο Linux (Process State)

Page 20: Linux Process Scheduling

20

• Αλλαγή Διεργασίας (Process Switch)

Page 21: Linux Process Scheduling

21

Αλλαγή Διεργασίας (Process Switch) (1)

• Ο πυρήνας μπορεί να μπλοκάρει την εκτέλεση μίας διεργασίας που τρέχει στον επεξεργαστή ώστε να συνεχίσει την εκτέλεση κάποιας άλλης που προηγουμένως είχε μπλοκαριστεί.

• Όλες οι διεργασίες μοιράζονται τους καταχωρητές του επεξεργαστή αλλά έχουν τον δικό τους χώρο διευθύνσεων (address space). Πριν συνεχίσει ο επεξεργαστής μία διεργασία που είχε μπλοκαριστεί πρέπει να φορτωθούν στους καταχωρητές οι τιμές που αφορούσαν την διεργασία αυτή.

• Το σύνολο των δεδομένων που πρέπει να φορτωθούν στους καταχωρητές πριν συνεχίσει η διεργασία ονομάζεται hardware context.

• Στο Linux ένα τμήμα του hardware context βρίσκεται στον file descriptor ενώ το υπόλοιπο αποθηκεύεται σε μία άλλη δομή την Kernel Mode Stack.

Page 22: Linux Process Scheduling

22

Αλλαγή Διεργασίας (Process Switch) (2)

• Θα χρησιμοποιήσουμε δύο μεταβλητές:• Prev: τοπική μεταβλητή που αναφέρεται στον file descriptor της

διεργασίας που βγαίνει.• Next: τοπική μεταβλητή που αναφέρεται στην διεργασία που μπαίνει

για να εκτελεστεί.

• Η αλλαγή διεργασίας συμβαίνει μόνο σε επίπεδο πυρήνα με τα ανώτερα δικαιώματα.

• Οι παλαιότερες εκδόσεις του Linux εκμεταλλεύονται από την υποστήριξη σε υλικό που έδινε η αρχιτεκτονική 80x86 και μπορούσαν να κάνουν την αλλαγή διεργασίας με μία far jmp εντολή.

Page 23: Linux Process Scheduling

23

Αλλαγή Διεργασίας (Process Switch) (3)

• Η αλλαγή της διεργασίας γίνεται βηματικά με ένα σύνολο από mov (move) εντολές οι οποίες εξασφαλίζουν την εγκυρότητα των δεδομένων που φορτώνονται.

• Ειδικά ελέγχονται οι τιμές των καταχωρητών ds, es που μπορεί να έχουν πειραχτεί από έναν κακόβουλο χρήστη. Αυτό το είδος ελέγχου δεν είναι δυνατό όταν πραγματοποιείται αλλαγή με την εντολή far jmp που αναφέρθηκε.

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

• Οι τιμές των καταχωρητών που χρησιμοποιούνται από την διεργασία σε επίπεδο χρήστη αποθηκεύονται όλες στην Kernel Mode Stack πριν γίνει η αλλαγή διεργασίας.

Page 24: Linux Process Scheduling

24

Αλλαγή Διεργασίας (Process Switch) (4)Εκτελώντας την Αλλαγή Διεργασίας

• Γίνεται σε δύο (2) βήματα:

• Αλλάζοντας το Page Global Directory για να εγκατασταθεί ένα νέο address space.

• Αλλάζοντας το Kernel Mode Stack και το hardware context που διαθέτουν όλες τις πληροφορίες που χρειάζονται για να εκτελέσει ο πυρήνας την νέα διεργασία. (καταχωρητές επεξεργαστή)

• Το δεύτερο βήμα γίνεται μέσω ενός macro του switch_to macro το οποίο δέχεται τρεις (3) παραμέτρους: prev, next, last.

• Η τελευταία παράμετρος χρησιμοποιείται ώστε να διατηρήσει μία αναφορά στην διεύθυνση του file descriptor της τελευταίας ενεργής διεργασίας, ώστε να μπορεί ο πυρήνας να γράφει στους καταχωρητές τα δεδομένα που χρειάζεται στο process switching.

Page 25: Linux Process Scheduling

25

Αλλαγή Διεργασίας (Process Switch) (5)Εκτελώντας την Αλλαγή Διεργασίας

• Η αλλαγή από την διεργασία Α->Β, διατηρεί την πληροφορία για την Α διεργασία στην διεύθυνση μνήμης που βρίσκεται η last μεταβλητή, ώστε να μπορούν να γραφτούν στον eax καταχωρητή τα δεδομένα για την τελευταία διεργασία που έχει μπλοκαριστεί.

Page 26: Linux Process Scheduling

26

• Πολιτική Δρομολόγησης (Scheduling Policy)

Page 27: Linux Process Scheduling

27

Πολιτική Δρομολόγησης (1)

• H πολιτική δρομολόγησης του Linux βασίζεται σε time sharing technique.

• Πολλαπλές διεργασίες τρέχουν με τεχνικές πολυπλεξίας χρόνου καθώς ο επεξεργαστής διαιρείται σε τμήματα (slices), ένα για κάθε διεργασία που πρόκειται να εκτελεστεί.

• Διακρίνουμε τρεις (3) κλάσεις από διεργασίες:

• Interactive Processes• Batch Processes• Real – time Processes

Page 28: Linux Process Scheduling

28

Πολιτική Δρομολόγησης (2)

• Interactive Processes:• Ασχολούνται συνεχώς με τους χρήστες και σπαταλούν πολύ χρόνο

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

• Batch Processes:• Δεν χρειάζονται την παρέμβαση του χρήστη και κυρίως τρέχουν στο

παρασκήνιο εκτελώντας σημαντικές για το σύστημα διαδικασίες.

• Real – Time Processes:• Έχουν μεγάλη σημασία για το σύστημα, δεν μπορούν να μπλοκαριστούν

από χαμηλότερης προτεραιότητας διεργασίες και πρέπει να τρέχουν όσο το δυνατόν συντομότερα. (video or audio processing)

Page 29: Linux Process Scheduling

29

Πολιτική Δρομολόγησης (3)Κλήσεις Συστήματος που αφορούν την δρομολόγηση

Page 30: Linux Process Scheduling

30

Πολιτική Δρομολόγησης (4)

• Αλλαγή διεργασίας για δύο (2) λόγους:

• Διεργασία με μεγαλύτερη προτεραιότητα από την τρέχουσα διεργασία• Αλλαγή διεργασίας όταν λήξει το κβάντο χρόνου που της έχει δοθεί από

το σύστημα (time quantum). Όταν συμβαίνει αυτό το TIF_NEED_RESCHED πεδίο στην δομή thread_info παίρνει λογική τιμή true οπότε ο χρονοδρομολογητής αναλαμβάνει την αλλαγή.

• Οι διεργασίες στο Linux είναι preemptive ενώ σε αντίθεση με την προηγούμενη έκδοση την 2.5 που δεν είναι preemptive.

• Preemptive: Το να μπορείς να τρέχεις πολλαπλές διεργασίες / νήματα στον ίδιο επεξεργαστή δίνοντας την εντύπωση πως τρέχουν παράλληλα, η κάθε μία στο κβάντο χρόνου που της αντιστοιχεί.

Page 31: Linux Process Scheduling

31

Πολιτική Δρομολόγησης (5)Thread info Structure

Page 32: Linux Process Scheduling

32

• Αλγόριθμος Δρομολόγησης (Scheduling Algorithm)

Page 33: Linux Process Scheduling

33

Πότε συμβαίνει μία δρομολόγηση (1)

Page 34: Linux Process Scheduling

34

Πότε συμβαίνει μία δρομολόγηση (2)

• Χρειαζόμαστε όλους τους επεξεργαστές στο σύστημα να δουλεύουν

• Συνήθως έχουμε πολλές διεργασίες που είναι στην ουρά των έτοιμων προς εκτέλεση διεργασιών και περιμένουν τον επεξεργαστή.

• Δεν πρέπει να καταναλώνει μία διεργασία πλήρως τον επεξεργαστή για μεγάλο χρονικό διάστημα.

• Ο πυρήνας του Linux 2.6 είναι preemptive αλλά χρησιμοποιεί spinlocks(SMP), έχει δε την δυνατότητα να απενεργοποιεί την δυνατότητα του αυτή σε ειδικές περιστάσεις.

Page 35: Linux Process Scheduling

35

Ο αλγόριθμος δρομολόγησης (1)

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

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

• Δεν γινόταν βέλτιστη αξιοποίηση πολλαπλών επεξεργαστών σε μεγάλα υπολογιστικά συστήματα (high end systems).

Page 36: Linux Process Scheduling

36

Ο αλγόριθμος δρομολόγησης (2)

• Στις νεότερες εκδόσεις δηλαδή στην έκδοση του Linux 2.6 ο αλγόριθμος βελτιώθηκε, έγινε περισσότερο πολύπλοκος.

• Δυνατότητα επιλογής της διεργασίας που θα τρέξει σε πολύ γρηγορότερο χρονικό διάστημα, συγκεκριμένα με χρονική πολυπλοκότητα Ο(1) (constant time) χωρίς ουσιαστικά να εξαρτάται από το σύνολο των διεργασιών που βρίσκονται στο σύστημα.

• Βελτιώθηκε η διαχείριση πολλαπλών επεξεργαστών καθώς κάθε επεξεργαστής έχει το δικό του σύνολο (ουρά) από διεργασίες που βρίσκονται σε φάση εκτέλεσης.

Page 37: Linux Process Scheduling

37

Ο αλγόριθμος δρομολόγησης (3)

• Τρεις (3) κλάσεις δρομολόγησης:

• SCHED_FIFO

• SCHED_RR

• SCHED_NORMAL

Page 38: Linux Process Scheduling

38

Ο αλγόριθμος δρομολόγησης (4)

• SCHED_FIFO• First in First Out (FIFO) σε πραγματικό χρόνο διεργασία. Όταν ο

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

• SCHED_RR• Round Robin σε πραγματικό χρόνο διεργασία. Όταν ο

χρονοδρομολογητής βάζει μία διεργασία στον επεξεργαστή αφήνει τον περιγραφέα διεργασίας στην τελική θέση στην λίστα με τις διεργασίες που βρίσκονται για εκτέλεση.

• SCHED_NORMAL• Συμβατική διεργασία με κβάντα χρόνου.

Page 39: Linux Process Scheduling

39

Ο αλγόριθμος δρομολόγησης (5)

• Στατική προτεραιότητα, είναι μια τιμή που χρησιμοποιεί ο χρονοδρομολογητής για να δηλώσει την προτεραιότητα της διεργασίας.

• Εύρος τιμών• 100 = μέγιστη προτεραιότητα• 139 = ελάχιστη προτεραιότητα

• Μια νέα διεργασία κληρονομεί την στατική προτεραιότητα του πατέρα, όμως κάποιος χρήστης μπορεί να αλλάξει την τιμή αυτή με τις κλήσεις συστήματος nice() ή set_priority().

Page 40: Linux Process Scheduling

40

Ο αλγόριθμος δρομολόγησης (6)Base time Quantum

• Είναι το κβάντο χρόνου που δίνει ο χρονοδρομολογητής σε μία διεργασία που έχει καταναλώσει το προηγούμενο κβάντο.

• Μαθηματικός τύπος για την στατική προτεραιότητα και το κβάντο χρόνου:

• Παρατηρούμε ότι όσο μεγαλύτερη στατική προτεραιότητα τόσο μεγαλύτερο και το κβάντο χρόνου.

Page 41: Linux Process Scheduling

41

Ο αλγόριθμος δρομολόγησης (7)Τυπικές τιμές στατικής προτεραιότητας για μία συμβατική

διεργασία

Page 42: Linux Process Scheduling

42

Ο αλγόριθμος δρομολόγησης (8)Δυναμική Προτεραιότητα και μέσος χρόνος αδράνειας

• Πέρα από την στατική προτεραιότητα ορίζεται και η δυναμική προτεραιότητα που είναι και αυτός ένας αριθμός από το 100-139 και ορίζεται από την παρακάτω φόρμουλα:

• Dynamic priority = max (100, min( static_priority – bonus + 5, 139) )

• H τιμή bonus κυμαίνεται από 0 έως 10.

• Τιμή μικρότερη από 5 δηλώνει penalty και μειώνει την δυναμική προτεραιότητα ενώ τιμή μεγαλύτερη από 5 δηλώνει premium και αυξάνει την δυναμική προτεραιότητα.

• Η τιμή του bonus εξαρτάται από τις προηγούμενες τιμές της διεργασίας, μάλιστα από τις τιμές του μέσου χρόνου όπου η διεργασία βρίσκεται σε κατάσταση αδράνειας (sleep time).

Page 43: Linux Process Scheduling

43

Ο αλγόριθμος δρομολόγησης (9)

Page 44: Linux Process Scheduling

44

Ο αλγόριθμος δρομολόγησης (10)

• Για να αποφασιστεί αν μία διεργασία είναι interactive ή batch χρησιμοποιείται η ακόλουθη φόρμουλα:

• Είναι interactive εάν:• dynamic_priority <= 3* static_priority/4+28

• Που είναι ισοδύναμο με:• Bonus-5 >= static_priority/4-28

• Ο όρος static_priority/4-28 ονομάζεται interactive delta και τιμές του αυτού παρουσιάζονται στον παρακάτω πίνακα.

Page 45: Linux Process Scheduling

45

Ο αλγόριθμος δρομολόγησης (11)

Description

Static priority Nice value Base time

quantumInteractivedelta

Sleep time threshold

Highest static priority

100 -20 800 ms -3 299 ms

High static priority 110 -10 600 ms -1 499 ms

Default static priority

120 0 100 ms +2 799 ms

Low static priority 130 +10 50 ms +4 999 ms

Lowest static priority

139 +19 5 ms +6 1199 ms

Page 46: Linux Process Scheduling

46

Ο αλγόριθμος δρομολόγησης (12)Ενεργές(Active) / Περατωμένες(Expired) Διεργασίες

• Ενεργές ονομάζονται οι διεργασίες που δεν έχουν ξεπεράσει το κβάντο χρόνου που τους έχει ανατεθεί και για αυτό τον λόγο μπορούν να τρέχουν.

• Περατωμένες ονομάζονται οι διεργασίες που έχουν ολοκληρώσει το κβάντο χρόνου τους και για αυτό το λόγο πρέπει να περιμένουν μέχρι κάποια από τις ενεργές διεργασίες τελειώσει.

• Περιοδικά, ο ρόλος των διεργασιών αλλάζει δυναμικά.

Page 47: Linux Process Scheduling

47

Ο αλγόριθμος δρομολόγησης (13)Real time process scheduling

• Κάθε διεργασία πραγματικού χρόνου σχετίζεται με μία τιμή προτεραιότητας πραγματικού χρόνου που είναι μία τιμή που κυμαίνεται:• 1 = μέγιστη προτεραιότητα• 99 = ελάχιστη προτεραιότητα

• Οι διεργασίες πραγματικού χρόνου θεωρούνται πάντα ενεργές με την μέγιστη προτεραιότητα η οποία μπορεί να αλλάξει από την χρήστη με την βοήθεια κλήσεων συστήματος όπως οι:• sched_setparam( )• sched_set_scheduler( )

Page 48: Linux Process Scheduling

48

Ο αλγόριθμος δρομολόγησης (14)Real time process scheduling replacement (1)

• Μια διεργασία πραγματικού χρόνου αντικαθίσταται μόνο όταν ικανοποιούνται κάποια ή κάποιες από τις παρακάτω συνθήκες:

• Η διεργασία αντικαθίσταται από μία άλλη με μεγαλύτερη προτεραιότητα

• Η διεργασία εκτελεί μία διαδικασία μπλοκαρίσματος και μπαίνει σε κατάσταση αδράνειας (TASK_INTERRUPTIBLE ή TASK_UNINTERRUPTIBLE)

• Η διεργασία σταματά (TASK_STOPPED ή TASK_TRACED), ή σκοτώνεται με κατάσταση (EXIT_ZOMBIE ή EXIT_DEAD).

• Η διεργασία εθελοντικά απελευθερώνει τον επεξεργαστή καλώντας την κλήση συστήματος sched_yield( )

Page 49: Linux Process Scheduling

49

Ο αλγόριθμος δρομολόγησης (15)Real time process scheduling replacement (2)

• Μια διεργασία πραγματικού χρόνου αντικαθίσταται μόνο όταν ικανοποιούνται κάποια ή κάποιες από τις παρακάτω συνθήκες:

• Η διεργασία είναι Round Robin (SCHED_RR) και έχει εξαντλήσει το χρονικό κβάντο της.

• Οι κλήσεις συστήματος nice( ) και setpriority( ) όταν εφαρμόζονται σε μία διεργασία τύπου Round Robin δεν αλλάζουν την προτεραιότητα της σε πραγματικό χρόνο, αλλά αλλάζουν το χρονικό κβάντο της διεργασίας.

• Το βασικό κβάντο αυτών των διεργασιών δεν εξαρτάται από την προτεραιότητα σε πραγματικό χρόνο των διεργασιών αυτών, αλλά από την στατική προτεραιότητα.

Page 50: Linux Process Scheduling

50

Ο αλγόριθμος δρομολόγησης (16)Δομές που χρησιμοποιούνται από τον χρονοδρομολογητή (1)

• Σημαντικότερη από όλες τις δομές είναι η δομή Runqueue για τον χρονοδρομολογητή σε Linux λειτουργικά συστήματα με πυρήνα 2.6

• Κάθε επεξεργαστής στο σύστημα έχει την δική του δομή Runqueue.

• Όλες οι Runqueue δομές αποθηκεύονται σε μεταβλητές ανά επεξεργαστή τύπου Runqueue.

• this_rq( ) macro: Δηλώνει την διεύθυνση στην μνήμη της δομής για τον τοπικό επεξεργαστή

• cpu_rq(n) macro: Δηλώνει την διεύθυνση στην μνήμη της δομής για τον επεξεργαστή με αναγνωριστικό (n).

Page 51: Linux Process Scheduling

51

Ο αλγόριθμος δρομολόγησης (17)Δομές που χρησιμοποιούνται από τον χρονοδρομολογητή (2)

Type Name Descriptionspinlock_t lock Spin lock protecting the lists of processes

unsigned long nr_running Number of runnable processes in the runqueue lists

unsigned long cpu_load CPU load factor based on the average number of processes in the runqueue

unsigned long nr_switches Number of process switches performed by the CPU

unsigned long nr_uninterruptible

Number of processes that were previously in the runqueue lists and are now sleeping in TASK_UNINTERRUPTIBLE state (only the sum of these fields across all runqueues is meaningful)

unsigned long expired_timestamp Insertion time of the eldest process in the expired lists

unsigned long long timestamp_last_tick Timestamp value of the last timer interrupt

task_t * currProcess descriptor pointer of the currently running process (same as current for the local CPU)

task_t * idle Process descriptor pointer of the swapper process for this CPU

Page 52: Linux Process Scheduling

52

Ο αλγόριθμος δρομολόγησης (18)Δομές που χρησιμοποιούνται από τον χρονοδρομολογητή (3)

Type Name Description

struct mm_struct * prev_mmUsed during a process switch to store the address of the memory descriptor of the process being replaced

prio_array_t * active Pointer to the lists of active processesprio_array_t * expired Pointer to the lists of expired processesprio_array_t [2] arrays The two sets of active and expired

processesint best_expired_prio The best static priority (lowest value)

among the expired processes

atomic_t nr_iowaitNumber of processes that were previously in the runqueue lists and are now waiting for a disk I/O operation to complete

struct sched_domain * sd Points to the base scheduling domain of this CPU

int active_balanceFlag set if some process shall be migrated from this runqueue to another (runqueue balancing)

int push_cpu Not usedtask_t * migration_thread Process descriptor pointer of the

migration kernel threadstruct list_head migration_queue List of processes to be removed from the

runqueue

Page 53: Linux Process Scheduling

53

Ο αλγόριθμος δρομολόγησης (19)Δομές που χρησιμοποιούνται από τον χρονοδρομολογητή (4)

• Το πεδίο arrays είναι ένας πίνακας που αποτελείται από δύο δομές τύπου prio_array_t.

• Κάθε μία από τις δομές αυτές αντιπροσωπεύει ένα σύνολο από διεργασίες και περιέχει 140 συνδεδεμένες λίστες, η κάθε μία από αυτές για μία πιθανή προτεραιότητα της διεργασίας, ένα priority bitmap και ένα μετρητή για το πόσες διεργασίες υπάρχουν στο σύνολο.

• struct prio_array {• 212 unsigned int nr_active;• 213 unsigned long bitmap[BITMAP_SIZE];• 214 struct list_head queue[MAX_PRIO];• 215 };

Page 54: Linux Process Scheduling

54

Ο αλγόριθμος δρομολόγησης (20)Δομές που χρησιμοποιούνται από τον χρονοδρομολογητή (5)

Παρατηρούμε ότι το πεδίο active δείχνει σε έναν από τους δύο πίνακες όπως επίσης και το πεδίο expired.

Page 55: Linux Process Scheduling

55

Ο αλγόριθμος δρομολόγησης (21)Πεδία που χρησιμοποιούνται από τον περιγραφέα διεργασίας

(process descriptor) για την δρομολόγηση

Type Name Description

unsigned long thread_info->flags Stores the TIF_NEED_RESCHED flag, which is set if the scheduler must be invoked

unsigned int thread_info->cpu Logical number of the CPU owning the runqueue to which the runnable process belongs

unsigned long state The current state of the processint prio Dynamic priority of the processint static_prio Static priority of the process

struct list_head run_list Pointers to the next and previous elements in the runqueue list to which the process belongs

prio_array_t * array Pointer to the runqueue's prio_array_t set that includes the process

unsigned long sleep_avg Average sleep time of the process

unsigned long long timestampTime of last insertion of the process in the runqueue, or time of last process switch involving the process

unsigned long long last_ran Time of last process switch that replaced the process

int activated Condition code used when the process is awakened

unsigned long policy The scheduling class of the process (SCHED_NORMAL, SCHED_RR, or SCHED_FIFO)

cpumask_t cpus_allowed Bit mask of the CPUs that can execute the process

unsigned int time_slice Ticks left in the time quantum of the process

unsigned int first_time_slice Flag set to 1 if the process never exhausted its time quantum

unsigned long rt_priority Real-time priority of the process

Page 56: Linux Process Scheduling

56

Ο αλγόριθμος δρομολόγησης (22)Πεδία που χρησιμοποιούνται από τον περιγραφέα διεργασίας

(process descriptor) για την δρομολόγηση

Κατά την δημιουργία μιας νέας διεργασίας η copy_process() καλεί την sched_fork() και θέτει το time_slice τόσο για την διεργασία όσο και για τον πατέρα της διεργασίας με τον ακόλουθο τρόπο:

• p->time_slice = (current->time_slice + 1) >> 1;• current->time_slice >>= 1;

• Current = διεργασία πατέρας• P = διεργασία παιδί

• Ο αριθμός των tick που απομένουν για τον πατέρα μοιράζονται σε δύο μισά, ένα για τον πατέρα και ένα για την διεργασία παιδί.

• Επίσης η κλήση συστήματος copy_process() αρχικοποιεί τα εξής:• p->first_time_slice = 1;• p->timestamp = sched_clock( );

Page 57: Linux Process Scheduling

57

• Functions Used by the scheduler(Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή)

Page 58: Linux Process Scheduling

58

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή

• scheduler_tick( )

• try_to_wake_up( )

• recalc_task_prio( )

• schedule( )

• load_balance()

Page 59: Linux Process Scheduling

59

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (1)

scheduler_tick( )

• Κώδικας από το αρχείο sched.c

• void scheduler_tick(void)• 5135 {• 5136 int cpu = smp_processor_id();• 5137 struct rq *rq = cpu_rq(cpu);• 5138 struct task_struct *curr = rq->curr;• 5139 • 5140 sched_clock_tick();• 5141 • 5142 spin_lock(&rq->lock);• 5143 update_rq_clock(rq);• 5144 update_cpu_load(rq);• 5145 curr->sched_class->task_tick(rq, curr, 0);• 5146 spin_unlock(&rq->lock);• 5147 • 5148 perf_counter_task_tick(curr, cpu);• 5149 • 5150 #ifdef CONFIG_SMP• 5151 rq->idle_at_tick = idle_cpu(cpu);• 5152 trigger_load_balance(rq, cpu);• 5153 #endif• 5154 }

Page 60: Linux Process Scheduling

60

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητής (2)

scheduler_tick( )

• Αποθηκεύει στο πεδίο timestamp_last_tick της Runqueue δομής την τιμή του καταχωρητή Time Stamp Counter (TSC) αφού έχει γίνει η μετατροπή της σε nanoseconds. Η τιμή αυτή λαμβάνεται από την συνάρτηση sched_clock( ).

• Ελέγχει αν η τωρινή διεργασία είναι μία διεργασία αντικατάστασης (swapper process) της τοπικής CPU. Αν είναι τότε εκτελούνται τα ακόλουθα:

• Ελέγχει αν το current->array δείχνει στην ενεργή λίστα της τοπικής δομής runqueue. Εάν όχι τότε η διεργασία έχει εξαντλήσει το κβάντο χρόνου αλλά δεν έχει ακόμα αντικατασταθεί. Θέτει το TIF_NEED_RESCHED ώστε να γίνει βιαίως η επαναχρονοδρομολόγηση.

• Λαμβάνει γνώση για το this_rq()->lock.

Page 61: Linux Process Scheduling

61

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (3)

scheduler_tick( )

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

• Απελευθερώνει τον this_rq()->lock.

• Καλεί την συνάρτηση rebalance_tick( ) που διασφαλίζει ότι οι δομές runqueues τον CPUs θα έχουν τον ίδιο αριθμό από διεργασίες που δύναται να εκτελεστούν.

Page 62: Linux Process Scheduling

62

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (4)

scheduler_tick( )

Εάν η διεργασία είναι FIFO διεργασία πραγματικού χρόνου η συνάρτηση δεν κάνει τίποτα, αν είναι όμως Round Robin μικραίνει το κβάντο χρόνου και ελέγχει αν το κβάντο έχει εξαντληθεί.

• if (current->policy == SCHED_RR && !--current->time_slice) {• current->time_slice = task_timeslice(current);• current->first_time_slice = 0;• set_tsk_need_resched(current);• list_del(&current->run_list);• list_add_tail(&current->run_list,• this_rq( )->active->queue+current->prio);• }

Page 63: Linux Process Scheduling

63

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (5)

scheduler_tick( )

• Σαν πρώτο βήμα γεμίζεται ο μετρητής με την κλήση της task_timeslice.

• Το πεδίο first_time_slice γίνεται μηδέν. Το πεδίο αυτό παίρνει τιμή από την copy_process() κατά την διαδικασία δημιουργίας διεργασίας από την fork().

• Καλείται η set_tsk_need_resched( ) με σκοπό να θέσει την τιμή της σταθεράς TIF_NEED_RESCHED.

• Καλείται η βασικότατη συνάρτηση schedule ώστε να γίνει η αλλαγή της διεργασίας με μία νέα διεργασία που θα έχει μεγαλύτερη προτεραιότητα.

Page 64: Linux Process Scheduling

64

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (5)

try_to_wake_up( )

• Η συνάρτηση αυτή ξυπνάει μία διεργασία που είναι είτε σταματημένη είτε σε κατάσταση αδράνειας και την θέτει σε κατάσταση TASK_RUNNING τοποθετώντας την στην runqueue του τοπικού επεξεργαστή.

• Παράμετροι που δέχεται η συνάρτηση:

• Τον δείκτη περιγραφέα (p) της διεργασίας που πρόκειται να ξυπνήσει.• Μία μάσκα από την κατάσταση της διεργασίας που πρόκειται να

ξυπνήσει• Μια μεταβλητή (sync) που εμποδίζει την διεργασία που θα ξυπνήσει να

βγάλει από τον επεξεργαστή (preempt) την διεργασία που εκτελείται.

Page 65: Linux Process Scheduling

65

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (6)

try_to_wake_up( )

• Καλεί την task_rq_lock( ) συνάρτηση για να απενεργοποιήσει τα τοπικά interrupts.

• Ελέγχει αν η κατάσταση της διεργασίας ανήκει στην μάσκα με τις καταστάσεις states που περνιέται σαν όρισμα στην συνάρτηση.

• Αν το p->array δεν είναι NULL, η διεργασία ανήκει ήδη στην δομή runqueue.

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

Page 66: Linux Process Scheduling

66

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (7)

try_to_wake_up( )

• Κριτήρια επιλογής runqueue.• Εάν κάποιος επεξεργαστής στο σύστημα είναι αδρανής, επιλέγει την

δική του runqueue για στόχο.• Εάν ο φόρτος του προηγούμενου σε χρήστη επεξεργαστή είναι

σημαντικά μικρότερος από τον φόρτο του τωρινού επιλέγει το runqueue του προηγούμενου.

• Εάν η διεργασία έχει εκτελεστεί πρόσφατα επιλέγει το παλαιό runqueue για στόχο.

• Εάν η μεταφορά της διεργασίας στην τοπική CPU μειώσει τον φόρτο ανάμεσα στους επεξεργαστές τότε η επιλογή είναι το τοπικό runqueue.

Page 67: Linux Process Scheduling

67

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (8)

recalc_task_prio( )

• Ενημερώνει τον μέσο όρο του χρόνου που η διεργασία βρίσκεται σε κατάσταση αναστολής και την δυναμική προτεραιότητα της διεργασίας.

• Παίρνει σαν παράμετρο ένα δείκτη στον περιγραφέα διεργασίας (p) και ένα timestamp now το οποίο υπολογίζεται κατόπιν της κλήσης συστήματος sched_clock( ).

Page 68: Linux Process Scheduling

68

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (9)

recalc_task_prio( )

• Η συνάρτηση εκτελεί τα παρακάτω:

• Αποθηκεύει στην μεταβλητή sleep_time το αποτέλεσμα από το παρακάτω• min (now - p->timestamp, 109 )

• Εάν το sleep_time δεν είναι μεγαλύτερο από το μηδέν, δεν υπολογίζει τον μέσο χρόνο που η διεργασία κοιμάται, απλά υπολογίζει την δυναμική προτεραιότητα.

• Ελέγχει αν η διεργασία δεν είναι ένα νήμα πυρήνα, εάν ξυπνάει από κατάσταση TASK_UNINTERRUPTIBLE και εάν βρισκόταν σε κατάσταση αναστολής περισσότερο από ένα δοσμένο χρονικό διάστημα. Αν οι τρεις αυτές συνθήκες αληθεύουν τότε η συνάρτηση θέτει το p->sleep_avg στην τιμή των 900 ticks.

• Εκτελεί το CURRENT_BONUS macro για να υπολογίσει την bonus τιμή του προηγούμενο μέσου χρόνου αδράνειας.

Page 69: Linux Process Scheduling

69

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (10)

recalc_task_prio( )

• Η συνάρτηση εκτελεί τα παρακάτω:

• Εάν η διεργασία είναι TASK_UNINTERRUPTIBLE και δεν είναι νήμα πυρήνα εκτελεί τα παρακάτω βήματα:• Ελέγχει αν το p->sleep_avg είναι >= από το κατώφλι το sleep time,

αν είναι τότε μηδενίζει την τοπική μεταβλητή sleep_avg.• Ελέγχει αν το άθροισμα του sleep_avg + p->sleep_avg είναι >= από

το κατώφλι του sleep time και θέτει το p->sleep_avg να είναι το κατώφλι του sleep time.

• Προσθέτει sleep_time στον μέσο χρόνο αδράνειας.

• Ελέγχει αν το p->sleep_avg υπερβαίνει τα 1000 ticks σε nanoseconds, αν ναι η συνάρτηση τα κόβει στα 1000 πάντα σε nanoseconds.

Page 70: Linux Process Scheduling

70

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (11)

recalc_task_prio( )

• Η συνάρτηση εκτελεί τα παρακάτω:

• Εάν η διεργασία είναι TASK_UNINTERRUPTIBLE και δεν είναι νήμα πυρήνα εκτελεί τα παρακάτω βήματα:• Ελέγχει αν το p->sleep_avg είναι >= από το κατώφλι το sleep time,

αν είναι τότε μηδενίζει την τοπική μεταβλητή sleep_avg.• Ελέγχει αν το άθροισμα του sleep_avg + p->sleep_avg είναι >= από

το κατώφλι του sleep time και θέτει το p->sleep_avg να είναι το κατώφλι του sleep time.

• Προσθέτει sleep_time στον μέσο χρόνο αδράνειας.

• Ελέγχει αν το p->sleep_avg υπερβαίνει τα 1000 ticks σε nanoseconds, αν ναι η συνάρτηση τα κόβει στα 1000 πάντα σε nanoseconds.

Page 71: Linux Process Scheduling

71

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (12)

schedule( ) (2.4)

• Πρόκειται για την βασική συνάρτηση που κάνει το scheduling δηλαδή την αλλαγή της τρέχουσας διεργασίας με μία άλλη από την ουρά των προς εκτέλεση διεργασιών.

• Αλλαγές σε σχέση με τις προηγούμενες εκδόσεις πυρήνα 2.4, • 1400 γραμμές κώδικα• Τρεις μόνο βασικές δομές• Η βασική δομή είναι η schedule_data(), περιέχει ένα δείκτη προς την

διεργασία που τρέχει και το timestamp από την τελευταία εκτέλεση της συνάρτησης.

• Υπάρχει μόνο μία runqueue και αυτή έχει την δομή της συνδεδεμένης λίστας

Page 72: Linux Process Scheduling

72

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (13)

schedule( ) (2.4)

• struct schedule_data {• struct task_struct * curr;• cycles_t last_schedule;• } schedule_data;• char __pad [SMP_CACHE_BYTES];

• Πολύ απλή δομή• Ορίζεται στο αρχείο sched.c• Περιέχει το time stamp της τελευταίας αλλαγής διεργασίας• Περιέχει επίσης ένα δείκτη στην διεργασία που τρέχει.

Page 73: Linux Process Scheduling

73

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (14)

schedule( ) (2.4)

• Reschedule_idle κοιτάζει απλά αν η διεργασία που βγήκε από την κατάσταση εκτέλεσης πρέπει να μεταβεί σε διαφορετικό επεξεργαστή.

• Δεν χρησιμοποιεί counter και nice άμεσα, χρησιμοποιεί μία συνάρτηση με όνομα goodness() για να ελέγξει τις προτεραιότητες.

• Η συνάρτηση goodness() λαμβάνει υπ' όψιν το κόστος της μετάβασης από έναν επεξεργαστή σε έναν άλλο.

Page 74: Linux Process Scheduling

74

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (15)

schedule( ) (2.6)

• 5700 γραμμές κώδικα.

• Καλείται όταν η τρέχουσα διεργασία πρέπει να μπλοκαριστεί, άμεση κλήση.

• Στην περίπτωση αυτή:• Εισάγεται η τρέχουσα διεργασία στην ουρά αυτών που περιμένων.• Αλλάζει η κατάσταση της τρέχουσας σε ASK_INTERRUPTIBLE ή σε

TASK_UNINTERRUPTIBLE.• Καλείται η συνάρτηση schedule().• Ελέγχεται αν υπάρχουν πόροι, αν υπάρχουν βγαίνει η διεργασία από

την ουρά αναμονής.

Page 75: Linux Process Scheduling

75

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (16)

schedule( ) (2.6)

• Καλείται και έμμεσα με ένα «τεμπέλικο» τρόπο (lazy invocation) με το να θέσουμε την TIF_NEED_RESCHED μεταβλητή σε 1.

• Παραδείγματα αυτής της μεθόδου:• Όταν η τρέχουσα διεργασία έχει εξαντλήσει το κβάντο χρόνου της.• Όταν μια διεργασία που ξυπνάει έχει προτεραιότητα μεγαλύτερη από

αυτή της τρέχουσας.• Όταν πραγματοποιείται μία sched_setscheduler( ) κλήση

συστήματος.

• Βασικός στόχος είναι να κάνει την next μεταβλητή να δείχνει στον περιγραφέα διεργασίας της διεργασίας που έχει επιλεγεί για να αντικαταστήσει την τρέχουσα (current).

Page 76: Linux Process Scheduling

76

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (17)

schedule( ) (2.6)

• Η συνάρτηση ξεκινά αρχικά με το να απενεργοποιεί το preemption και να αρχικοποιεί κάποιες μεταβλητές:

• need_resched:• preempt_disable( );• prev = current;• rq = this_rq( );

• if (prev->lock_depth >= 0)• up(&kernel_sem);• now = sched_clock( );• run_time = now - prev->timestamp;• if (run_time > 1000000000)• run_time = 1000000000;

Page 77: Linux Process Scheduling

77

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (18)

schedule( ) (2.6)

• Κατόπιν η συνάρτηση εξετάζει την κατάσταση της προηγούμενης διεργασίας.

• if (prev->state != TASK_RUNNING &&• !(preempt_count() & PREEMPT_ACTIVE)) {• if (prev->state == TASK_INTERRUPTIBLE && signal_pending(prev))• prev->state = TASK_RUNNING;• else {• if (prev->state == TASK_UNINTERRUPTIBLE)• rq->nr_uninterruptible++;• deactivate_task(prev, rq);• }• }

• Η deactivate_task απομακρύνει την διεργασία από το runqueue.

Page 78: Linux Process Scheduling

78

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (19)

schedule( ) (2.6)

• rq->nr_running--;• dequeue_task(p, p->array);• p->array = NULL;

• Κατόπιν η συνάρτηση ελέγχει για τον αριθμό των διεργασιών που βρίσκονται στο runqueue. • Αν υπάρχουν καλείται η dependent_sleeper( )• Αν ο πυρήνας υποστηρίζει τεχνολογία hyper threading, τότε η διεργασία που πρόκειται

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

• if (rq->nr_running) {• if (dependent_sleeper(smp_processor_id( ), rq)) {• next = rq->idle;• goto switch_tasks;• }• }

Page 79: Linux Process Scheduling

79

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (20)

schedule( ) (2.6)

• Αν δεν υπάρχουν διεργασίες προς εκτέλεση τότε επιλέγονται μερικές από την συνάρτηση idle_balance( ) από κάποιο άλλο runqueue στο τοπικό runqueue.

• if (!rq->nr_running) {• idle_balance(smp_processor_id( ), rq);• if (!rq->nr_running) {• next = rq->idle;• rq->expired_timestamp = 0;• wake_sleeping_dependent(smp_processor_id( ), rq);• if (!rq->nr_running)• goto switch_tasks;• }• }

Page 80: Linux Process Scheduling

80

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (21)

schedule( ) (2.6)

• Ελέγχονται αν υπάρχουν διεργασίες που είναι ενεργές.

• Αν δεν υπάρχουν ανταλλάσσονται τα περιεχόμενα από τα πεδία active / expired της runqueue δομής.

• array = rq->active;• if (!array->nr_active) {• rq->active = rq->expired;• rq->expired = array;• array = rq->active;• rq->expired_timestamp = 0;• rq->best_expired_prio = 140;• }

Page 81: Linux Process Scheduling

81

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (22)

schedule( ) (2.6)

• Αναζητάτε μία διεργασία προς εκτέλεση στον πίνακα prio_array_t της δομής.

• idx = sched_find_first_bit(array->bitmap);• next = list_entry(array->queue[idx].next, task_t, run_list);

• if (next->prio >= 100 && next->activated > 0) {• unsigned long long delta = now - next->timestamp;• if (next->activated == 1)• delta = (delta * 38) / 128;• array = next->array;• dequeue_task(next, array);• recalc_task_prio(next, next->timestamp + delta);• enqueue_task(next, array);• }• next->activated = 0;

Page 82: Linux Process Scheduling

82

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (23)

schedule( ) (2.6)

• Η συνάρτηση πρέπει να επιλέξει την κατάλληλη διεργασία για να αντικαταστήσει την υπάρχουσα διεργασία.

• switch_tasks:• prefetch(next);

• Το prefetch macro βελτιώνει την απόδοση της συνάρτησης schedule.

• Πριν γίνει η αντικατάσταση της διεργασίας εκτελούνται οι ακόλουθες συναρτήσεις:

• clear_tsk_need_resched(prev);• rcu_qsctr_inc(prev->thread_info->cpu);

• Η clear_tsk_need_resched(prev) αλλάζει την τιμή της μεταβλητής TIF_NEED_RESCHED.

Page 83: Linux Process Scheduling

83

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (24)

schedule( ) (2.6)

• Κατόπιν η συνάρτηση schedule μειώνει τον μέσο χρόνο αδράνειας της προηγούμενης διεργασίας.

• prev->sleep_avg -= run_time;• if ((long)prev->sleep_avg <= 0)• prev->sleep_avg = 0;• prev->timestamp = prev->last_ran = now;

• Σε περίπτωση που η διεργασία που αντικαθίσταται είναι η ίδια με αυτή που πρέπει να αντικαταστήσει την υπάρχουσα κάτι το οποίο συμβαίνει αν δεν υπάρχουν άλλες με ίση η μεγαλύτερη προτεραιότητα στο runqueue, συμβαίνει το εξής:

• if (prev == next) {• spin_unlock_irq(&rq->lock);• goto finish_schedule;• }

Page 84: Linux Process Scheduling

84

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (25)

schedule( ) (2.6)

• Αμέσως μετά το content switch και την συνάρτηση schedule ακολουθούν οι συναρτήσεις:

• barrier( );• finish_task_switch(prev);

• Η πρώτη θέτει ένα φράγμα στην χρήση της μνήμης οδηγώντας έτσι στην βελτίωση του κώδικα, ενώ η δεύτερη απελευθερώνει το spin lock της runqueue και ενεργοποιεί τα τοπικά interrupts.

• mm = this_rq( )->prev_mm;• this_rq( )->prev_mm = NULL;• prev_task_flags = prev->flags;• spin_unlock_irq(&this_rq( )->lock);• if (mm)• mmdrop(mm);• if (prev_task_flags & PF_DEAD)• put_task_struct(prev);

Page 85: Linux Process Scheduling

85

Συναρτήσεις που χρησιμοποιούνται από τον χρονοδρομολογητή (26)

schedule( ) (2.6)

• Τελευταίες γραμμές κώδικα για την συνάρτηση:• finish_schedule:• prev = current;• if (prev->lock_depth >= 0)• _ _reacquire_kernel_lock( );• preempt_enable_no_resched();• if (test_bit(TIF_NEED_RESCHED, &current_thread_info( )->flags)• goto need_resched;• return;

• Παρατηρούμε ότι αποκτάται το kernel lock και ενεργοποιείται ξανά το kernel preemption και ελέγχεται αν κάποια άλλη διεργασία έχει θέσει την TIF_NEED_RESCHED για την διεργασία αυτή, αν ναι όλη η συνάρτηση schedule ξαναεκτελείται από την αρχή αλλιώς η συνάρτηση τερματίζει.

Page 86: Linux Process Scheduling

86

Κλήσεις συστήματος που σχετίζονται με την δρομολόγηση (1)

• Nice() : Επιτρέπει στην διεργασία να αλλάζει την προτεραιότητα της, η ακέραια τιμή που υπάρχει στην παράμετρο increment χρησιμοποιείται για να αλλάξει το nice πεδίο του περιγραφέα διεργασίας.

• GetPriority / SetPriority

• GetPriority: Επιστρέφει 20 – την κατώτατη τιμή της nice.

• SetPriority: Θέτει τις προτεραιότητες για όλες τις διεργασίες που ανήκουν σε κάποιο group.

• sched_getaffinity( ) και sched_setaffinity( ) : Επιστρέφουν και θέτουν την τιμή της affinity mask . Αυτή η μάσκα αποθηκεύεται στην cpus_allowed μεταβλητή του περιγραφέα διεργασίας.

Page 87: Linux Process Scheduling

87

Σχηματική Αναπαράσταση (1)

Page 88: Linux Process Scheduling

88

Σχηματική Αναπαράσταση (2)