Ιχνηλάτηση: παρακολούθηση της ροής εκτέλεσης#
Αυτό το κεφάλαιο καλύπτει ίχνη που καταγράφουν τι έκανε ένα πρόγραμμα χωρίς να το σταματούν: η εντολή t του αποσφαλματωτή και οι επιλογές ιχνηλάτησης, η οικογένεια αρθρωμάτων Devel::Trace, και ο ιχνηλάτης της μηχανής regex. Χρησιμοποιήστε ιχνηλάτηση όταν το σφάλμα είναι «ποια διαδρομή κώδικα έτρεξε στην πραγματικότητα;» αντί για «τι τιμή έχει το X στη γραμμή N;».
Οι αναγνώστες που έρχονται γνωρίζουν πώς να ορίζουν breakpoints και να επιθεωρούν κατάσταση. Ένα ίχνος είναι το συμπλήρωμα - «ακολούθα κάθε βήμα και πες μου γι” αυτό» αντί για «σταμάτα σε ένα ενδιαφέρον σημείο».
t: ιχνηλάτηση μέσα στον αποσφαλματωτή#
Η t εναλλάσσει την ιχνηλάτηση ανά δήλωση. Κάθε γραμμή στην οποία μπορεί να σπάσει η εκτέλεση εκτυπώνει έναν δείκτη θέσης πριν εκτελεστεί:
DB<1> t
Trace = on
DB<2> c
main::(app.pl:5): my $key = 'welcome';
main::(app.pl:6): my %data = (
main::handle_request(app.pl:42): my $user = load_user($req);
main::load_user(app.pl:87): my ($req) = @_;
main::load_user(app.pl:88): return unless $req;
...
Περιορισμός του βάθους:
DB<3> t 2 # toggle with maximum sub-depth 2
DB<4> t 0 my_work() # trace one expression only
Η επιλογή frame ελέγχει τι εκτυπώνει το ίχνος σε κλήσεις και επιστροφές sub:
Bit | Σημαία | Αποτέλεσμα |
|---|---|---|
1 | enter | Εκτύπωση κατά την είσοδο σε sub. |
2 | exit | Εκτύπωση κατά την έξοδο από sub. |
4 | ctx+args | Συμπερίληψη περιβάλλοντος κλήσης και ορισμάτων. |
8 | tied/ref | Σήμανση κλήσεων sub μέσω tied μεταβλητής και αναφοράς. |
16 | return | Εκτύπωση της τιμής επιστροφής. |
Ορίστε το frame μέσω της o:
DB<5> o frame=15 # enter + exit + ctx/args + tied/ref
Συνηθισμένοι συνδυασμοί:
frame=2: μόνο ίχνη εισόδου/εξόδου, μία γραμμή ανά κλήση - η όψη δέντρου κλήσεων.frame=6: προσθήκη περιβάλλοντος καλούντος και dump ορισμάτων - πλήρες ίχνος.frame=30: σανframe=6συν τις τιμές επιστροφής.
Η έξοδος ίχνους πηγαίνει στη ροή εξόδου του αποσφαλματωτή. Ανακατευθύνετέ την σε αρχείο ώστε να μην πνίγει τη διαδραστική συνεδρία:
DB<6> o LineInfo=trace.out
Διαβάστε το αρχείο σε άλλο τερματικό:
tail -f trace.out
Μη διαδραστική ιχνηλάτηση: NonStop + AutoTrace#
Για «καταγραφή πλήρους ίχνους εκτέλεσης χωρίς αλληλεπίδραση», συνδυάστε NonStop=1 (χωρίς προτροπές) και AutoTrace=1 (ιχνηλάτηση ενεργή από την αρχή):
PERLDB_OPTS="NonStop=1 AutoTrace=1 frame=2 LineInfo=trace.out" \
perl -d script.pl
Το πρόγραμμα τρέχει χωρίς διακοπές· το trace.out συλλαμβάνει κάθε γραμμή στην οποία μπορεί να σπάσει η εκτέλεση και κάθε είσοδο σε sub. Ιδανικό για σύλληψη αποτυχίας σε λειτουργία CI, διακομιστές χωρίς οθόνη, ή κάθε περιβάλλον όπου προτροπή TTY δεν είναι διαθέσιμη.
Προσθέστε inhibit_exit=0 για να αφήσετε το πρόγραμμα να φτάσει στο τέλος χωρίς την προτροπή «Debugged program terminated».
Devel::Trace: κάθε γραμμή, χωρίς τον αποσφαλματωτή#
Το Devel::Trace ιχνηλατεί κάθε γραμμή κάθε αρχείου στο STDERR. Καμία αλληλεπίδραση γραμμής εντολών. Κανένα breakpoint. Απλό και θορυβώδες:
perl -d:Trace script.pl 2> trace.out
>> app.pl:4: my $key = 'welcome';
>> app.pl:5: my %data = (
>> app.pl:11: print "$data{$key}\n";
Τρέξτε το μία φορά, κάντε grep στην έξοδο για τον γρίφο. Το μέγεθος της εξόδου είναι ανάλογο της διάρκειας εκτέλεσης του προγράμματος - χρησιμοποιήστε σε ελάχιστο αναπαραγωγέα, όχι σε ολόκληρη τη σουίτα δοκιμών.
Παραλλαγές:
Devel::DumpTrace- το ίδιο συν τιμές μεταβλητών ανά γραμμή.Devel::TraceUse- «ποια αρθρώματα φορτώθηκαν, με ποια σειρά, από ποιον»:perl -d:TraceUse script.pl
Devel::TraceINC- στενότερο: μόνο η αλυσίδαrequireμε χρονομέτρηση.Devel::Trace::Subs- γεννήτρια ροής κλήσεων και ίχνους στοίβας για «ποιες sub έτρεξαν στην πραγματικότητα».
Ιχνηλάτηση συγκεκριμένης περιοχής#
Η μεταβλητή $DB::trace εναλλάσσει την ιχνηλάτηση από κώδικα Perl:
$DB::trace = 1;
interesting_region();
$DB::trace = 0;
Η ανάθεση στο $DB::trace όταν δεν τρέχετε υπό -d αυτο-δημιουργεί τη μεταβλητή αβλαβώς - ο κώδικας είναι ασφαλές να γίνει commit και τρέχει ως no-op εκτός του αποσφαλματωτή.
Ίδιο μοτίβο για βηματική εκτέλεση μιας περιοχής:
$DB::single = 1; # break here when next statement runs under -d
Ιχνηλάτηση regex: use re 'debug'#
Η μηχανή regex έχει δικό της ιχνηλάτη. Ενεργοποιήστε τον λεξιλογικά μέσα σε περιοχή, ή στη γραμμή εντολών:
{
use re 'debug';
$str =~ /(\w+)\s+(\w+)/;
}
perl -Mre=debug -e '"hello world" =~ /(\w+)\s+(\w+)/'
Η έξοδος της φάσης μεταγλώττισης δείχνει τι έκανε ο βελτιστοποιητής:
Compiling REx 'PATTERN'- το αρχικό μοτίβο.size N- μέγεθος εσωτερικού πίνακα κόμβων.anchored 'SUB' at K/floating 'SUB' at K..LIMIT- ποια υποσυμβολοσειρά θα ψάξει η μηχανή ως προφίλτρο.stclass TYPE- η κλάση χαρακτήρα εκκίνησης.minlen N- καμία αντιστοιχία δεν είναι δυνατή σε είσοδο μικρότερη από N.Λίστα κόμβων - το μεταγλωττισμένο πρόγραμμα.
Η έξοδος χρόνου εκτέλεσης δείχνει κάθε βήμα:
POS <PRE-MATCH> <POST-MATCH> | NODE_NUM: OPNAME
Η εσοχή αντικατοπτρίζει το βάθος της οπισθοχώρησης· τα failed... και failed, try continuation... σημαίνουν οπισθοχωρήσεις· τα Match successful! / Match failed. κλείνουν το ίχνος.
Αν δεν εμφανιστεί καθόλου έξοδος χρόνου εκτέλεσης, ο βελτιστοποιητής αποφάσισε την αντιστοιχία χωρίς είσοδο στη μηχανή - είτε το minlen έκανε προφιλτράρισμα είτε το μοτίβο πτυχώθηκε σε έλεγχο σταθεράς.
Η μηχανή regex της pperl είναι μια ντόπια εκ νέου υλοποίηση, όχι μεταφορά αυτής της perl5. Το ίχνος είναι λειτουργικά ισοδύναμο αλλά τα ακριβή ονόματα κόμβων και οι μορφές πεδίων δεν είναι byte-πανομοιότυπες με αυτές του upstream. Η προγραμματιστική ανάλυση του ίχνους (λίγα εργαλεία το κάνουν) θα χρειαστεί προσαρμογή.
Μερικοί διακόπτες στενεύουν την έξοδο:
use re 'debugcolor'; # ANSI colour
use re debug => 'EXECUTE'; # runtime only, no compile output
Devel::TraceUse για σφάλματα φόρτωσης αρθρωμάτων#
Ένα πρόγραμμα που τρέχει αργά στην εκκίνηση, ή ένα «γιατί φορτώνεται καν αυτό το άρθρωμα;», είναι σχεδόν πάντα ζήτημα γράφου αρθρωμάτων. Το Devel::TraceUse εκτυπώνει το πλήρες δέντρο use/require:
perl -d:TraceUse script.pl
Modules used from script.pl:
1. strict 1.12, script.pl line 2 [main]
2. warnings 1.58, script.pl line 2 [main]
3. DBI 1.643, script.pl line 5 [main]
4. Carp 1.52, DBI line 13 [DBI]
5. DynaLoader 1.47, DBI line 14 [DBI]
...
Η εσοχή δείχνει την αλυσίδα εξαρτήσεων. Αντιπαραβάλετε με τον αριθμό γραμμής στο γονικό αρχείο για να δείτε πού συμβαίνει κάθε φόρτωση.
Συνδυασμός ιχνών με τον αποσφαλματωτή#
Ιχνηλάτηση σε αρχείο, βηματική εκτέλεση διαδραστικά:
PERLDB_OPTS="frame=6 LineInfo=trace.out" perl -d app.pl
Η προτροπή του αποσφαλματωτή εμφανίζεται κανονικά· το trace.out συσσωρεύει το δέντρο κλήσεων καθώς κάνετε βηματική εκτέλεση και συνεχίζετε. Χρήσιμο όταν μια αλυσίδα κλήσεων είναι πολύ βαθιά για να ακολουθηθεί βηματικά αλλά εξακολουθείτε να θέλετε να σταματάτε σε συγκεκριμένα σημεία για επιθεώρηση.
Μάθετε περισσότερα#
breakpoints - διακοπή σε συγκεκριμένο σημείο αντί καταγραφής κάθε βήματος.
inspecting-state - οι εντολές που απαντούν στο «τι είναι αυτή η τιμή;».