זהו הפקודה perlperf שניתן להריץ בספק האירוח החינמי של OnWorks באמצעות אחת מתחנות העבודה המקוונות המרובות שלנו, כגון Ubuntu Online, Fedora Online, אמולטור מקוון של Windows או אמולטור מקוון של MAC OS
תָכְנִית:
שֵׁם
perlperf - טכניקות ביצועים ואופטימיזציה של Perl
תיאור
זהו מבוא לשימוש בטכניקות ביצועים ואופטימיזציה שיכולים להיות
משמש בהתייחסות מיוחדת לתוכניות perl. בעוד מפתחי perl רבים הגיעו
משפות אחרות, ויכולים להשתמש בידע הקודם שלהם במידת הצורך, יש הרבה
אנשים אחרים שעשויים להפיק תועלת מכמה עצות ספציפיות ל-perl. אם אתה רוצה את
גרסה דחוסה, אולי העצה הטובה ביותר מגיעה מהסמוראי היפני הנודע,
מיאמוטו מוסאשי, שאמר:
"אל תעסוק בפעילות חסרת תועלת"
ב 1645.
סקירה כללית
אולי הטעות הנפוצה ביותר של מתכנתים היא לנסות לייעל את הקוד שלהם
לפני שתוכנית באמת עושה משהו מועיל - זה רעיון גרוע. אין טעם
עם תוכנית מהירה במיוחד שלא עובדת. העבודה הראשונה היא לקבל תוכנית
צורה נכונה עשה משהו מועיל, (שלא לדבר על הבטחת חבילת הבדיקה מלאה
פונקציונלי), ורק אז לשקול לבצע אופטימיזציה שלו. לאחר שהחליט לייעל את הקיים
קוד עובד, ישנם מספר שלבים פשוטים אך חיוניים שיש לקחת בחשבון שהם מהותיים
לכל תהליך אופטימיזציה.
ONE שלב הַצִידָה
ראשית, עליך לקבוע זמן בסיס עבור הקוד הקיים, אשר תזמון צריך
להיות אמין וניתן לחזור עליו. סביר להניח שתרצה להשתמש ב-"Benchmark" או
מודולי "Devel::NYTProf", או משהו דומה, עבור השלב הזה, או אולי מערכת יוניקס
כלי השירות "זמן", המתאים מביניהם. עיין בבסיס המסמך הזה לרשימה ארוכה יותר
של מודולי מידוד ופרופילים, ומומלץ לקריאה נוספת.
ONE שלב קָדִימָה
לאחר מכן, לאחר בחינת התוכנית עבור חם נקודות, (מקומות שבהם נראה שהקוד פועל
לאט), שנה את הקוד מתוך כוונה לגרום לו לרוץ מהר יותר. משתמש בגרסה
תוכנת שליטה, כמו "חתרנות", תבטיח שאין שינויים בלתי הפיכים. זה יותר מדי
קל לקשקש כאן ולקשקש שם - אל תשתנה יותר מדי בכל פעם או אולי
לא לגלות איזה פיסת קוד בֶּאֱמֶת היה החלק האיטי.
אחר שלב הַצִידָה
לא מספיק להגיד: "זה יגרום לזה לרוץ מהר יותר", צריך לבדוק את זה. הפעל מחדש את
קוד בשליטה של מודולי ההשוואה או הפרופיל, מהשלב הראשון למעלה,
ובדקו שהקוד החדש הוציא לפועל את אותו משימה in פחות זמן. שמור את עבודתך ו
חזור...
כללי הנחיות
הדבר הקריטי כאשר שוקלים ביצועים הוא לזכור שאין דבר כזה
"כדור הזהב", ובגלל זה אין חוקים, רק הנחיות.
ברור שקוד מוטבע הולך להיות מהיר יותר מקריאות תת-שגרה או שיטה,
כי יש פחות תקורה, אבל לגישה הזו יש את החסרון שהיא פחות
ניתן לתחזוקה ובעל עלות של שימוש רב יותר בזיכרון - אין דבר כזה א
ארוחת צהריים חינם. אם אתה מחפש אלמנט ברשימה, זה יכול להיות יעיל יותר
אחסן את הנתונים במבנה גיבוב, ואז פשוט בדוק אם המפתח הוא
מוגדר, במקום לבצע לולאה דרך המערך כולו באמצעות grep() לדוגמה. substr ()
יכול להיות (הרבה) מהיר יותר מאשר grep() אבל לא כל כך גמיש, אז יש לך עוד פשרה
גִישָׁה. הקוד שלך עשוי להכיל שורה שלוקח 0.01 של שנייה לבצע אותה אם אתה
קוראים לזה 1,000 פעמים, סביר להניח שבתוכנה שמנתחת אפילו קבצים בגודל בינוני עבורם
למשל, כבר יש לך עיכוב של 10 שניות, רק במיקום קוד בודד אחד, ואם אתה
התקשר לקו הזה 100,000 פעמים, כל התוכנית שלך תאט לזחילה בלתי נסבלת.
שימוש בתתי שגרה כחלק מהמיון שלך הוא דרך רבת עוצמה להשיג בדיוק את מה שאתה רוצה,
אבל בדרך כלל יהיה איטי יותר מהמובנה אלפביתי "cmp" ו מספרי מיון "<=>".
מפעילים. אפשר לבצע מעברים מרובים על הנתונים שלך, לבנות מדדים ל
להפוך את המיון הקרוב ליעיל יותר, ולהשתמש במה שמכונה "OM" (Orcish
תמרון) כדי לשמור את מפתחות המיון מראש. חיפוש המטמון, אמנם רעיון טוב, יכול
עצמו להיות מקור להאטה על ידי אכיפת מעבר כפול על הנתונים - פעם אחת להגדרה
המטמון, ופעם אחת כדי למיין את הנתונים. שימוש ב-"pack()" כדי לחלץ את מפתח המיון הנדרש
לתוך מחרוזת עקבית יכולה להיות דרך יעילה לבנות מחרוזת יחידה להשוואה,
במקום להשתמש במספר מפתחות מיון, מה שמאפשר להשתמש בסטנדרט, הכתוב
ב-"c" ומהר, פונקציית "sort()" פרל על הפלט, והיא הבסיס של "GRT"
(גטמן רוסלר טרנספורם). שילובי מיתרים מסוימים יכולים להאט את ה-"GRT" רק על ידי
להיות מורכב מדי לטובתו.
עבור יישומים המשתמשים ב-backends של מסד נתונים, מרחב השמות הסטנדרטי "DBIx" ניסה לעזור
עם שמירה על דברים נקיים, לא רק בגלל שהיא מנסה לֹא שאילתה במסד הנתונים עד ל
הרגע האחרון האפשרי, אבל תמיד קרא את המסמכים שמגיעים עם הבחירה שלך בספריות.
בין הבעיות הרבות שעומדות בפני מפתחים העוסקים בבסיסי נתונים צריכים להישאר מודעים
להשתמש תמיד במצייני מיקום "SQL" ולשקול אחזור מראש של ערכות נתונים כאשר הדבר עשוי
להוכיח יתרון. פיצול קובץ גדול על ידי הקצאת תהליכים מרובים לניתוח
קובץ בודד, באמצעות נגיד "POE", "threads" או "fork" יכול להיות גם דרך שימושית לאופטימיזציה
השימוש שלך במשאבי ה-"CPU" הזמינים, אם כי טכניקה זו עמוסה
בעיות במקביל ודורשת תשומת לב גבוהה לפרטים.
לכל מקרה יש בקשה ספציפית וחריגים אחד או יותר, ואין
תחליף להפעלת כמה בדיקות ולברר איזו שיטה עובדת הכי טוב עבורך
סביבה מסוימת, זו הסיבה שכתיבת קוד אופטימלי אינה מדע מדויק, ומדוע
אנחנו כל כך אוהבים להשתמש בפרל - TMTOWTDI.
ספסלים
להלן מספר דוגמאות להדגמת השימוש בכלי ההשוואה של Perl.
מקצה ו התייחסות משתנים
אני בטוח שרובנו ראינו קוד שנראה כך (או גרוע מזה):
if ( $obj->{_ref}->{_myscore} >= $obj->{_ref}->{_yourscore} ) {
...
סוג זה של קוד יכול להיות כאב עיניים לקריאה, כמו גם להיות רגיש מאוד לשגיאות הקלדה,
וזה הרבה יותר ברור לבטל את ההתייחסות המפורשת למשתנה. אנחנו עוזבים את
בעיה של עבודה עם טכניקות תכנות מונחה עצמים כדי לכלול משתנה
גישה באמצעות שיטות, נגיש רק דרך אובייקט. כאן אנחנו רק דנים ב
יישום טכני של בחירה, והאם יש לכך השפעה על הביצועים. אנחנו יכולים
ראה אם לפעולת ההתייחסות הזו יש תקורה כלשהי על ידי הכנסת קוד השוואתי
קובץ והפעלת בדיקת "Benchmark".
# התייחסות
#!/usr/bin/perl
השתמש מחמירים;
להשתמש באזהרות;
השתמש ב- Benchmark;
$ref שלי = {
'ref' => {
_myscore => '100 + 1',
_yourscore => '102 - 1',
},
};
timethese(1000000, {
'direct' => משנה {
my $x = $ref->{ref}->{_myscore} . $ref->{ref}->{_yourscore} ;
},
'dereference' => תת {
שלי $ref = $ref->{ref};
שלי $myscore = $ref->{_myscore};
my $yourscore = $ref->{_yourscore};
שלי $x = $myscore . $yourscore;
},
});
זה חיוני להפעיל כל מדידות תזמון מספר מספיק של פעמים כך המספרים
להסתפק בממוצע מספרי, אחרת כל ריצה תתנוד באופן טבעי עקב
וריאציות בסביבה, כדי להפחית את השפעת המחלוקת על משאבי "CPU" ו
רוחב הפס של הרשת למשל. אנחנו יכולים להריץ את הקוד לעיל במשך מיליון איטרציות
עיין בפלט הדוח על ידי מודול "Benchmark", כדי לראות איזו גישה היא
הכי יעיל.
$> הפניית פרל
אמת מידה: תזמון של 1000000 חזרות של התייחסות ישירה...
התייחסות: 2 שניות שעון קיר (1.59 usr + 0.00 sys = 1.59 CPU) @ 628930.82/s (n=1000000)
ישיר: 1 שעון קיר שניות (1.20 usr + 0.00 sys = 1.20 CPU) @ 833333.33/s (n=1000000)
ברור לראות את ההבדל וגישת ההתייחסות איטית יותר. בזמן שזה הצליח
לבצע ממוצע של 628,930 פעמים בשנייה במהלך הבדיקה שלנו, הגישה הישירה
הצליח לרוץ עוד 204,403 פעמים, למרבה הצער. לצערי, כי שם
הן דוגמאות רבות לקוד שנכתב באמצעות גישה ישירה למשתנה מרובה שכבות, ו
זה בדרך כלל נורא. עם זאת, זה מהיר יותר. נותרה השאלה האם
הרווח הדקה למעשה שווה את מאמץ העיניים, או אובדן יכולת התחזוקה.
חיפוש ו להחליף or tr
אם יש לנו מחרוזת שצריך לשנות, בעוד ש-Regex יהיה כמעט תמיד הרבה
גמיש יותר, "tr", כלי שמשתמשים בו מעט מדי, עדיין יכול להיות שימושי. תרחיש אחד יכול להיות
להחליף את כל התנועות עם תו אחר. הפתרון הרגולרי עשוי להיראות כך:
$str =~ s/[aeiou]/x/g
החלופה "tr" עשויה להיראות כך:
$str =~ tr/aeiou//
אנחנו יכולים להכניס את זה לקובץ בדיקה שנוכל להריץ כדי לבדוק איזו גישה היא המהירה ביותר,
שימוש במשתנה $STR גלובלי כדי להקצות למשתנה "my $str" כדי למנוע perl
מנסה לייעל כל אחת מהעבודה על ידי שימת לב שהיא הוקצתה רק פעם אחת.
# regex-transliterate
#!/usr/bin/perl
השתמש מחמירים;
להשתמש באזהרות;
השתמש ב- Benchmark;
my $STR = "$$-זה וזה";
timethese( 1000000, {
'sr' => sub { my $str = $STR; $str =~ s/[aeiou]/x/g; החזר $str; },
'tr' => sub { my $str = $STR; $str =~ tr/aeiou//; החזר $str; },
});
הפעלת הקוד נותנת לנו את התוצאות שלנו:
$> perl regex-transliterate
אמת מידה: תזמון 1000000 איטרציות של sr, tr...
sr: 2 שניות שעון קיר ( 1.19 usr + 0.00 sys = 1.19 CPU) @ 840336.13/s (n=1000000)
tr: 0 שעון קיר שניות ( 0.49 usr + 0.00 sys = 0.49 CPU) @ 2040816.33/s (n=1000000)
גרסת "tr" היא מנצחת ברורה. פתרון אחד גמיש, השני מהיר - ו
זה כראוי הבחירה של המתכנת באיזה להשתמש.
עיין במסמכי "Benchmark" לקבלת טכניקות שימושיות נוספות.
פרופילינג כלי עבודה
פיסת קוד קצת יותר גדולה תספק משהו שעליו יכול פרופילי ליצור
סטטיסטיקות דיווח נרחבות יותר. דוגמה זו משתמשת בתוכנית הפשטנית "wordmatch".
שמנתח קובץ קלט נתון ומוציא דוח קצר על התוכן.
# התאמת מילה
#!/usr/bin/perl
השתמש מחמירים;
להשתמש באזהרות;
=head1 NAME
מילות קובץ - ניתוח מילים של קובץ קלט
=ראש1 תקציר
מילות קובץ -f inputfilename [-d]
=head1 תיאור
תוכנית זו מנתחת את שם הקובץ הנתון, שצוין עם C<-f>, ומציגה א
ניתוח פשוט של המילים שנמצאו בו. השתמש במתג C<-d> כדי להפעיל
איתור באגים בהודעות.
=חתוך
השתמש ב-FileHandle;
השתמש ב-Getopt::Long;
$debug שלי = 0;
$file שלי = '';
שלי $result = GetOptions (
'debug' => \$debug,
'file=s' => \$file,
);
die("invalid args") אלא אם כן $result;
אלא אם כן (-f $file) {
die("שימוש: $0 -f שם קובץ [-d]");
}
my $FH = FileHandle->new("< $file") או die("לא יכול לפתוח קובץ($file): $!");
שלי $i_LINES = 0;
שלי $i_WORDS = 0;
%count שלי = ();
שלי @lines = <$FH>;
foreach my $line ( @lines ) {
$i_LINES++;
$line =~ s/\n//;
my @words = split(/ +/, $line);
my $i_words = scalar(@words);
$i_WORDS = $i_WORDS + $i_words;
debug("line: $i_LINES מספק מילות $i_words: @words");
שלי $i_word = 0;
foreach my $word (@words) {
$i_word++;
$count{$i_LINES}{spec} += matches($i_word, $word, '[^a-zA-Z0-9]');
$count{$i_LINES}{only} += matches($i_word, $word, '^[^a-zA-Z0-9]+$');
$count{$i_LINES}{cons} += matches($i_word, $word, '^[(?i:bcdfghjklmnpqrstvwxyz)]+$');
$count{$i_LINES}{vows} += matches($i_word, $word, '^[(?i:aeiou)]+$');
$count{$i_LINES}{caps} += matches($i_word, $word, '^[(AZ)]+$');
}
}
הדפס דוח(%count);
תת התאמות {
my $i_wd = shift;
שלי $word = shift;
my $regex = shift;
שלי $יש = 0;
if ( $word =~ /($regex)/ ) {
$has++ אם $1;
}
debug("word: $i_wd ".($has ? 'matches' : 'לא תואם')." chars: /$regex/");
החזר $יש;
}
דוח משנה {
%report שלי = @_;
%rep שלי;
foreach my $line ( keys %report ) {
foreach my $key (מפתחות %{ $report{$line} } ) {
$rep{$key} += $report{$line}{$key};
}
}
$report שלי = qq|
דוח $0 עבור $file:
שורות בקובץ: $i_LINES
מילים בקובץ: $i_WORDS
מילים עם תווים מיוחדים (שאינם מילים): $i_spec
מילים עם תווים מיוחדים (שאינם מילים) בלבד: $i_only
מילים עם עיצורים בלבד: $i_cons
מילים עם אותיות גדולות בלבד: $i_caps
מילים עם תנועות בלבד: $i_vows
|;
החזר $rapport;
}
תת באגים {
שלי $הודעה = משמרת;
if ($debug) {
הדפס STDERR "DBG: $message\n";
}
}
יציאה 0;
פיתוח :: DProf
מודול מכובד זה היה הסטנדרט דה פקטו לפרופיל קוד פרל במשך יותר מ
עשור, אבל הוחלף במספר מודולים אחרים שהחזירו אותנו
המאה ה-21. למרות שמומלץ לך להעריך את הכלי שלך מתוך כמה
מוזכר כאן ומתוך רשימת ה-CPAN בבסיס מסמך זה, (וכיום
נראה כי Devel::NYTProf הוא הנשק המועדף - ראה להלן), נסתכל במהירות על
את הפלט מ-Devel::DProf תחילה, כדי להגדיר קו בסיס לכלי פרופיל פרל. הפעל את
תוכנית לעיל תחת שליטה של "Devel::DPof" באמצעות מתג "-d" בפקודה-
קו.
$> perl -d:DPof wordmatch -f perl5db.pl
<...שורות מרובות נחתכו...>
דוח wordmatch עבור perl5db.pl:
שורות בקובץ: 9428
מילים בקובץ: 50243
מילים עם תווים מיוחדים (שאינם מילים): 20480
מילים עם תווים מיוחדים בלבד (שאינם מילים): 7790
מילים עם עיצורים בלבד: 4801
מילים באותיות גדולות בלבד: 1316
מילים עם תנועות בלבד: 1701
"Devel::DProf" מייצר קובץ מיוחד, הנקרא tmon.out כברירת מחדל, והקובץ הזה נקרא
על ידי תוכנית "dprofpp", שכבר מותקנת כחלק מ-"Devel::DProf"
הפצה. אם אתה קורא ל"dprofpp" ללא אפשרויות, הוא יקרא את tmon.out קובץ ב
את הספרייה הנוכחית ולהפיק דוח סטטיסטיקה קריא אנושי של הריצה שלך
תכנית. שימו לב שזה עשוי לקחת קצת זמן.
$> dprofpp
סה"כ זמן שחלף = 2.951677 שניות
זמן משתמש+מערכת = 2.871677 שניות
Times בלעדי
%Time ExclSec CumulS #Calls sec/call Csec/c שם
102. 2.945 3.003 251215 0.0000 0.0000 main::matches
2.40 0.069 0.069 260643 0.0000 0.0000 main::debug
1.74 0.050 0.050 1 0.0500 0.0500 main::report
1.04 0.030 0.049 4 0.0075 0.0123 main::BEGIN
0.35 0.010 0.010 3 0.0033 0.0033 יצואן::as_heavy
0.35 0.010 0.010 7 0.0014 0.0014 IO::קובץ::BEGIN
0.00 - -0.000 1 - - Getopt::Long::FindOption
0.00 - -0.000 1 - - סמל::BEGIN
0.00 - -0.000 1 - - Fcntl::BEGIN
0.00 - -0.000 1 - - Fcntl::bootstrap
0.00 - -0.000 1 - - אזהרות::BEGIN
0.00 - -0.000 1 - - IO::bootstrap
0.00 - -0.000 1 - - Getopt::Long::ConfigDefaults
0.00 - -0.000 1 - - Getopt::Long::הגדר
0.00 - -0.000 1 - - סמל::gensym
"dprofpp" יפיק דיווח מפורט למדי על הפעילות של "wordmatch"
תכנית. שעון הקיר, המשתמש והמערכת, הזמנים נמצאים בראש הניתוח ואחריו
אלו העמודות העיקריות שמגדירות את הדוח. בדוק את המסמכים "dprofpp" עבור
פרטים על האפשרויות הרבות שבהן הוא תומך.
ראה גם "Apache::DProf" שמחבר את "Devel::DProf" ל-"mod_perl".
Devel::Profiler
הבה נסתכל על אותה תוכנית באמצעות פרופיל אחר: "Devel::Profiler", א
תחליף ל-Perl בלבד עבור "Devel::DProf". השימוש מעט שונה מאוד ב
שבמקום להשתמש בדגל "-d:" המיוחד, אתה מושך את "Devel::Profiler" ישירות בתור א
מודול באמצעות "-M".
$> perl -MDevel::Profiler wordmatch -f perl5db.pl
<...שורות מרובות נחתכו...>
דוח wordmatch עבור perl5db.pl:
שורות בקובץ: 9428
מילים בקובץ: 50243
מילים עם תווים מיוחדים (שאינם מילים): 20480
מילים עם תווים מיוחדים בלבד (שאינם מילים): 7790
מילים עם עיצורים בלבד: 4801
מילים באותיות גדולות בלבד: 1316
מילים עם תנועות בלבד: 1701
"Devel::Profiler" יוצר קובץ tmon.out התואם ל-"dprofpp"
תוכנית, ובכך חוסכת בניית תוכנית ייעודית לקורא סטטיסטיקות. "dprofpp"
לכן השימוש זהה לדוגמא שלעיל.
$> dprofpp
סה"כ זמן שחלף = 20.984 שניות
זמן משתמש+מערכת = 19.981 שניות
Times בלעדי
%Time ExclSec CumulS #Calls sec/call Csec/c שם
49.0 9.792 14.509 251215 0.0000 0.0001 main::matches
24.4 4.887 4.887 260643 0.0000 0.0000 main::debug
0.25 0.049 0.049 1 0.0490 0.0490 main::report
0.00 0.000 0.000 1 0.0000 0.0000 Getopt::Long::GetOptions
0.00 0.000 0.000 2 0.0000 0.0000 Getopt::Long::ParseOptionSpec
0.00 0.000 0.000 1 0.0000 0.0000 Getopt::Long::FindOption
0.00 0.000 0.000 1 0.0000 0.0000 IO::קובץ::חדש
0.00 0.000 0.000 1 0.0000 0.0000 IO::ידית::חדש
0.00 0.000 0.000 1 0.0000 0.0000 סמל::gensym
0.00 0.000 0.000 1 0.0000 0.0000 IO::קובץ::פתוח
מעניין שאנחנו מקבלים תוצאות מעט שונות, וזה בעיקר בגלל האלגוריתם
שיוצר את הדוח שונה, למרות שפורמט קובץ הפלט היה לכאורה
זֵהֶה. הזמן שחלף, המשתמש והמערכת מראים בבירור את הזמן שנדרש
"Devel::Profiler" כדי לבצע ריצה משלו, אבל רשימות העמודות מרגישות מדויקות יותר
איכשהו מאלה שהיו לנו קודם מ"Devel::DProf". הנתון של 102% יש
נעלם, למשל. זה המקום שבו עלינו להשתמש בכלים העומדים לרשותנו, ו
לזהות את היתרונות והחסרונות שלהם, לפני השימוש בהם. מעניין לציין את מספרי השיחות עבור
כל תת-שגרה זהה בשני הדוחות, האחוזים הם שונים. כפי ש
המחבר של "Devel::Proviler" כותב:
...ריצת HTML::חבילת הבדיקה של Template תחת Devel::DProf מציגה פלט()
לא לוקח זמן אבל Devel::Profiler מראה ש-10% מהזמן הוא ב-output().
אני לא יודע על מי לסמוך אבל הבטן שלי אומר לי שמשהו לא בסדר
Devel::DProf. HTML::Template::output() היא שגרה גדולה שמתבקשת
כל מבחן. בכל מקרה, משהו צריך לתקן.
YMMV.
ראה גם "Devel::Apache::Profiler" שמחבר את "Devel::Profiler" ל-"mod_perl".
Devel::SmallProf
הפרופיל "Devel::SmallProf" בוחן את זמן הריצה של תוכנית Perl שלך ומפיק
רשימה שורה אחר שורה כדי להראות כמה פעמים כל שורה נקראה, וכמה זמן כל שורה
לקח לביצוע. זה נקרא על ידי אספקת הדגל "-d" המוכר לפרל בזמן הריצה.
$> perl -d:SmallProf wordmatch -f perl5db.pl
<...שורות מרובות נחתכו...>
דוח wordmatch עבור perl5db.pl:
שורות בקובץ: 9428
מילים בקובץ: 50243
מילים עם תווים מיוחדים (שאינם מילים): 20480
מילים עם תווים מיוחדים בלבד (שאינם מילים): 7790
מילים עם עיצורים בלבד: 4801
מילים באותיות גדולות בלבד: 1316
מילים עם תנועות בלבד: 1701
"Devel::SmallProf" כותב את הפלט שלו לקובץ שנקרא smallprof.out, כברירת מחדל. ה
פורמט הקובץ נראה כך:
:
כאשר התוכנית הסתיימה, ניתן לבחון ולמיין את הפלט באמצעות כל תקן
כלי עזר לסינון טקסט. משהו כמו הבא עשוי להספיק:
$> cat smallprof.out | grep \d*: | מיון -k3 | טק | ראש -n20
251215 1.65674 7.68000 75: if ( $word =~ /($regex)/ ) {
251215 0.03264 4.40000 79: debug("word: $i_wd ".($has ? 'matches' :
251215 0.02693 4.10000 81: החזר $has;
260643 0.02841 4.07000 128: if ( $debug ) {
260643 0.02601 4.04000 126: הודעה $ שלי = משמרת;
251215 0.02641 3.91000 73: שלי $has = 0;
251215 0.03311 3.71000 70: my $i_wd = shift;
251215 0.02699 3.69000 72: שלי $regex = shift;
251215 0.02766 3.68000 71: שלי $word = shift;
50243 0.59726 1.00000 59: $count{$i_LINES}{cons} =
50243 0.48175 0.92000 61: $count{$i_LINES}{spec} =
50243 0.00644 0.89000 56: my $i_cons = matches($i_word, $word,
50243 0.48837 0.88000 63: $count{$i_LINES}{caps} =
50243 0.00516 0.88000 58: my $i_caps = matches($i_word, $word, '^[(A-
50243 0.00631 0.81000 54: my $i_spec = matches($i_word, $word, '[^a-
50243 0.00496 0.80000 57: my $i_vows = matches($i_word, $word,
50243 0.00688 0.80000 53: $i_word++;
50243 0.48469 0.79000 62: $count{$i_LINES}{only} =
50243 0.48928 0.77000 60: $count{$i_LINES}{vows} =
50243 0.00683 0.75000 55: my $i_only = matches($i_word, $word, '^[^a-
אתה יכול מיד לראות מיקוד שונה במקצת ממודולי הפרופיל של תת-השגרה,
ואנחנו מתחילים לראות בדיוק איזו שורת קוד לוקחת הכי הרבה זמן. הקו הרגולרי הזה
נראה קצת חשוד, למשל. זכור שכלים אלה אמורים להיות
בשימוש יחד, אין דרך אחת הטובה ביותר ליצור פרופיל בקוד שלך, אתה צריך להשתמש בטוב ביותר
כלים לעבודה.
ראה גם "Apache::SmallProf" המחברת את "Devel::SmallProf" ל-"mod_perl".
Devel::FastProf
"Devel::FastProf" הוא עוד מפרט קו פרל. זה נכתב במטרה לקבל
פרופיל קו מהיר יותר ממה שאפשר עם "Devel::SmallProf", למשל, כי זה
כתוב ב-C. כדי להשתמש ב-"Devel::FastProf", ספק את הארגומנט "-d" לפרל:
$> perl -d:FastProf wordmatch -f perl5db.pl
<...שורות מרובות נחתכו...>
דוח wordmatch עבור perl5db.pl:
שורות בקובץ: 9428
מילים בקובץ: 50243
מילים עם תווים מיוחדים (שאינם מילים): 20480
מילים עם תווים מיוחדים בלבד (שאינם מילים): 7790
מילים עם עיצורים בלבד: 4801
מילים באותיות גדולות בלבד: 1316
מילים עם תנועות בלבד: 1701
"Devel::FastProf" כותב נתונים סטטיסטיים לקובץ fastprof.out בספרייה הנוכחית.
ניתן לפרש את קובץ הפלט, שניתן לציין, באמצעות ה- "fprofpp"
תוכנית שורת הפקודה.
$> fprofpp | ראש -n20
# פורמט הפלט fprofpp הוא:
# שם קובץ:ספירת זמן שורה: מקור
wordmatch:75 3.93338 251215: if ( $word =~ /($regex)/ ) {
wordmatch:79 1.77774 251215: debug("word: $i_wd ".($has? 'matches' : 'לא תואם')." chars: /$regex/");
wordmatch:81 1.47604 251215: return $has;
wordmatch:126 1.43441 260643: my $message = shift;
wordmatch:128 1.42156 260643: if ( $debug ) {
wordmatch:70 1.36824 251215: my $i_wd = shift;
wordmatch:71 1.36739 251215: שלי $word = shift;
wordmatch:72 1.35939 251215: my $regex = shift;
מיד נוכל לראות שמספר הפעמים שנקרא לכל שורה זהה
הפלט "Devel::SmallProf", והרצף שונה רק מעט מאוד בהתבסס על
הסדר של משך הזמן שלקח כל שורה לביצוע, "if ( $debug ) { " ו-"my
$message = shift;", למשל. ההבדלים בזמנים שנרשמו בפועל עשויים להיות ב
האלגוריתם בשימוש פנימי, או שזה יכול להיות בגלל מגבלות של משאבי המערכת או
מַחֲלוֹקֶת.
ראה גם את ה-DBIx::Profile אשר יבצע פרופיל של שאילתות מסד נתונים הפועלות תחת "DBIx::*"
מרחב שמות.
פיתוח :: NYTProf
"Devel::NYTProf" הוא ה- הבא דור של פרופיל הקוד של Perl, תיקון חסרונות רבים ב
כלים אחרים ויישום תכונות מגניבות רבות. קודם כל זה יכול לשמש גם בתור א
קו פרופילי, א בלוק או תת-נוהל פרופילי, בבת אחת. זה יכול גם להשתמש בתת-
רזולוציית מיקרו-שנייה (100ns) במערכות המספקות "clock_gettime()". זה יכול להיות
התחילה ונעצרה אפילו על ידי התוכנית שנקבעה בפרופיל. זה כניסה בשורה אחת לפרופיל
יישומי "mod_perl". זה כתוב ב-"c" והוא כנראה הפרופיל המהיר ביותר
זמין עבור Perl. רשימת המגניבות פשוט ממשיכה. די עם זה, בוא נראה איך עושים זאת
זה עובד - פשוט השתמש במתג "-d" המוכר כדי לחבר אותו ולהפעיל את הקוד.
$> perl -d:NYTProf wordmatch -f perl5db.pl
דוח wordmatch עבור perl5db.pl:
שורות בקובץ: 9427
מילים בקובץ: 50243
מילים עם תווים מיוחדים (שאינם מילים): 20480
מילים עם תווים מיוחדים בלבד (שאינם מילים): 7790
מילים עם עיצורים בלבד: 4801
מילים באותיות גדולות בלבד: 1316
מילים עם תנועות בלבד: 1701
"NYTProf" יפיק מסד נתונים של דוחות לתוך הקובץ nytprof.out כברירת מחדל. בן אנוש
ניתן להפיק דוחות קריא מכאן באמצעות ה-"nytprofhtml" (HTML
פלט) ותוכניות "nytprofcsv" (פלט CSV). השתמשנו במערכת יוניקס "html2text"
כלי להמרת ה nytprof/index.html קובץ מטעמי נוחות כאן.
$> html2text nytprof/index.html
אינדקס פרופילי ביצועים
עבור wordmatch
הפעל ביום שישי 26 בספטמבר 13:46:39 2008
דווח ביום שישי 26 בספטמבר 13:47:23 2008
15 תתי-השגרות המובילות - מוזמנות לפי זמן בלעדי
|שיחות |P |F |כולל|בלעדי|תתי שגרה |
| | | |זמן |זמן | |
|251215|5 |1 |13.09263 |10.47692 |ראשי:: |התאמות |
|260642|2 |1 |2.71199 |2.71199 |ראשי:: |באגים |
|1 |1 |1 |0.21404 |0.21404 |ראשי:: |דוח |
|2 |2 |2 |0.00511 |0.00511 |XSLoader:: |טען (xsub) |
|14 |14|7 |0.00304 |0.00298 |יצואן:: |יבוא |
|3 |1 |1 |0.00265 |0.00254 |יצואן:: |כמו_כבד |
|10 |10|4 |0.00140 |0.00140 |vars:: |יבוא |
|13 |13|1 |0.00129 |0.00109 | קבוע:: |יבוא |
|1 |1 |1 |0.00360 |0.00096 |Handle File:: |יבוא |
|3 |3 |3 |0.00086 |0.00074 |אזהרות::register::|יבוא |
|9 |3 |1 |0.00036 |0.00036 |strict:: |bits |
|13 |13|13|0.00032 |0.00029 |מחמיר:: |יבוא |
|2 |2 |2 |0.00020 |0.00020 |אזהרות:: |יבוא |
|2 |1 |1 |0.00020 |0.00020 | Getopt::Long:: |ParseOptionSpec|
|7 |7 |6 |0.00043 |0.00020 |strict:: |לא ייבוא |
למידע נוסף עיין ברשימה המלאה של 189 תתי שגרות.
החלק הראשון של הדו"ח כבר מציג את המידע הקריטי לגביו
תתי שגרות משתמשות הכי הרבה זמן. הבא נותן כמה סטטיסטיקות על המקור
קבצים עם פרופיל.
קובצי קוד מקור -- מסודרים לפי זמן בלעדי ואז לפי שם
|Stmts |בלעדי|ממוצע |דוחות |קובץ מקור |
| |זמן | | | |
|2699761|15.66654 |6e-06 |שורה . לחסום . sub|wordmatch |
|35 |0.02187 |0.00062|שורה . לחסום . sub|IO/Handle.pm |
|274 |0.01525 |0.00006|שורה . לחסום . sub|getopt/Long.pm |
|20 |0.00585 |0.00029|שורה . לחסום . sub|Fcntl.pm |
|128 |0.00340 |0.00003|שורה . לחסום . sub|יצואן/כבד.pm |
|42 |0.00332 |0.00008|שורה . לחסום . sub|IO/File.pm |
|261 |0.00308 |0.00001|שורה . לחסום . sub|Exporter.pm |
|323 |0.00248 |8e-06 |שורה . לחסום . sub|constant.pm |
|12 |0.00246 |0.00021|שורה . לחסום . תת|קובץ/מפרט/Unix.pm |
|191 |0.00240 |0.00001|שורה . לחסום . sub|vars.pm |
|77 |0.00201 |0.00003|שורה . לחסום . sub|FileHandle.pm |
|12 |0.00198 |0.00016|שורה . לחסום . sub|Carp.pm |
|14 |0.00175 |0.00013|שורה . לחסום . sub|Symbol.pm |
|15 |0.00130 |0.00009|שורה . לחסום . sub|IO.pm |
|22 |0.00120 |0.00005|שורה . לחסום . sub|IO/Seekable.pm |
|198 |0.00085 |4e-06 |שורה . לחסום . sub|warnings/register.pm|
|114 |0.00080 |7e-06 |שורה . לחסום . sub|strict.pm |
|47 |0.00068 |0.00001|שורה . לחסום . sub|warnings.pm |
|27 |0.00054 |0.00002|שורה . לחסום . sub|overload.pm |
|9 |0.00047 |0.00005|שורה . לחסום . sub|SelectSaver.pm |
|13 |0.00045 |0.00003|שורה . לחסום . sub|File/Spec.pm |
|2701595|15.73869 | |סה"כ |
|128647 |0.74946 | |ממוצע |
| |0.00201 |0.00003|חציון |
| |0.00121 |0.00003|סטייה |
דוח שהופק על ידי הפרופיל של NYTProf 2.03 Perl, שפותח על ידי Tim Bunce ו
אדם קפלן.
בשלב זה, אם אתה משתמש ב- html דוח, אתה יכול ללחוץ על הקישורים השונים
התעמק בכל תת-שגרה וכל שורת קוד. כי אנחנו משתמשים בטקסט
מדווח כאן, ויש ספרייה שלמה מלאה בדוחות שנבנו עבור כל קובץ מקור,
אנו רק נציג חלק מהמתאים wordmatch-line.html קובץ, מספיק כדי
תן מושג על סוג הפלט שאתה יכול לצפות מהכלי המגניב הזה.
$> html2text nytprof/wordmatch-line.html
פרופיל ביצועים -- -block view-.-line view-.-sub view-
עבור wordmatch
הפעל ביום שישי 26 בספטמבר 13:46:39 2008
דווח ביום שישי 26 בספטמבר 13:47:22 2008
קובץ wordmatch
תתי שגרות - מסודרות לפי זמן בלעדי
|שיחות |P|F|כולל|בלעדי|משנה |
| | | |זמן |זמן | |
|251215|5|1|13.09263 |10.47692 |main::|matches|
|260642|2|1|2.71199 |2.71199 |main::|ניפוי באגים |
|1 |1|1|0.21404 |0.21404 |ראשי::|דוח |
|0 |0|0|0 |0 |main::|BEGIN |
|קו|סטמטס.|בלעדי|ממוצע |קוד |
| | |זמן | | |
|1 | | | |#!/usr/bin/perl |
|2 | | | | |
| | | | |שימוש קפדני; |
|3 |3 |0.00086 |0.00029|# בילה 0.00003 שניות בביצוע קריאות 1 ל-strict:: |
| | | | |יבוא |
| | | | |אזהרות שימוש; |
|4 |3 |0.01563 |0.00521|# בילה 0.00012 שניות בביצוע קריאות 1 לאזהרות:: |
| | | | |יבוא |
|5 | | | | |
|6 | | | |=head1 שם |
|7 | | | | |
|8 | | | |filewords - ניתוח מילים של קובץ קלט |
<...חתוך...>
|62 |1 |0.00445 |0.00445|הדפס דוח( %count ); |
| | | | |# בילה 0.21404 שניות בביצוע שיחות 1 ל-main::report|
|63 | | | | |
| | | | |# בילה 23.56955 שניות (10.47692+2.61571) בתוך |
| | | | |main::matches שנקרא 251215 פעמים, |
| | | | |ממוצע 0.00005 שניות/קריאה: # 50243 פעמים |
| | | | |(2.12134+0.51939s) בשורה 57 של wordmatch, avg|
| | | | |0.00005s/call # 50243 פעמים (2.17735+0.54550s) |
|64 | | | |בשורה 56 של wordmatch, ממוצע 0.00005s/call # |
| | | | |50243 פעמים (2.10992+0.51797s) בשורה 58 מתוך |
| | | | |wordmatch, ממוצע 0.00005s/call # 50243 פעמים |
| | | | |(2.12696+0.51598s) בשורה 55 של wordmatch, avg|
| | | | |0.00005s/call # 50243 פעמים (1.94134+0.51687s) |
| | | | |בשורה 54 של wordmatch, ממוצע 0.00005s/call |
| | | | |sub matches { |
<...חתוך...>
|102 | | | | |
| | | | |# בילה 2.71199 שניות בתוך main::debug שהיה |
| | | | |התקשר 260642 פעמים, ממוצע 0.00001s/קריאה: # |
| | | | |251215 פעמים (2.61571+0s) לפי main::matches ב- |
|103 | | | |שורה 74 של wordmatch, ממוצע 0.00001s/call # 9427 |
| | | | |פעמים (0.09628+0s) בשורה 50 של wordmatch, avg|
| | | | |0.00001s/שיחה |
| | | | |sub debug { |
|104 |260642|0.58496 |2e-06 |my $message = shift; |
|105 | | | | |
|106 |260642|1.09917 |4e-06 |if ($debug) { |
|107 | | | |print STDERR "DBG: $message\n"; |
|108 | | | |} |
|109 | | | |} |
|110 | | | | |
|111 |1 |0.01501 |0.01501|יציאה 0; |
|112 | | | | |
המון מידע שימושי מאוד שם - נראה שזו הדרך קדימה.
ראה גם "Devel::NYTProf::Apache" המחברת את "Devel::NYTProf" ל-"mod_perl".
מִיוּן
מודולי Perl אינם הכלים היחידים שעומדים לרשות מנתח ביצועים, מערכת
אין להתעלם מכלים כמו "זמן", כפי שמראה הדוגמה הבאה, שבה אנו לוקחים א
מבט מהיר במיון. ספרים רבים, תזות ומאמרים, נכתבו על יעיל
אלגוריתמי מיון, וזה לא המקום לחזור על עבודה כזו, יש כמה דברים טובים
מיון מודולים שראוי להסתכל עליהם גם: "Sort::Maker", "Sort::Key" קפוץ אל
אכפת. עם זאת, עדיין ניתן לבצע כמה תצפיות על פרל ספציפי
פרשנויות בנושאים הקשורים למיון מערכי נתונים ולתת דוגמה או שתיים איתם
לגבי האופן שבו מיון נפחי נתונים גדולים יכול להשפיע על הביצועים. ראשית, לעתים קרובות
נקודה שמתעלמת ממנה בעת מיון כמויות גדולות של נתונים, אפשר לנסות לצמצם את הנתונים
מוגדר לטיפול ובמקרים רבים "grep()" יכול להיות שימושי למדי כמסנן פשוט:
@data = sort grep { /$filter/ } @incoming
פקודה כזו יכולה להפחית במידה ניכרת את נפח החומר למיין בפועל
מלכתחילה, ואין להתעלם ממנו קלות מדי רק על רקע שלו
פַּשְׁטוּת. לעתים קרובות מדי מתעלמים מעיקרון ה"נשיקה" - הדוגמה הבאה משתמשת ב-
כלי פשוט של מערכת "זמן" להדגמה. בואו נסתכל על דוגמה ממשית של
למיין את התוכן של קובץ גדול, קובץ יומן אפאצ'י יעשה זאת. לזה יש מעל א
רבע מיליון שורות, בגודל 50M, וקטע ממנו נראה כך:
# קובץ לוג
188.209-65-87.adsl-dyn.isp.belgacom.be - - [08/Feb/2007:12:57:16 +0000] "GET /favicon.ico HTTP/1.1" 404 209 "-" "Mozilla/ 4.0 (תואם; MSIE 6.0; Windows NT 5.1; SV1)"
188.209-65-87.adsl-dyn.isp.belgacom.be - - [08/Feb/2007:12:57:16 +0000] "GET /favicon.ico HTTP/1.1" 404 209 "-" "Mozilla/ 4.0 (תואם; MSIE 6.0; Windows NT 5.1; SV1)"
151.56.71.198 - - [08/Feb/2007:12:57:41 +0000] "GET /suse-on-vaio.html HTTP/1.1" 200 2858 "http://www.linux-on-laptops.com/sony.html" "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1"
151.56.71.198 - - [08/Feb/2007:12:57:42 +0000] "GET /data/css HTTP/1.1" 404 206 "http://www.rfi.net/suse-on-vaio.html" "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1"
151.56.71.198 - - [08/Feb/2007:12:57:43 +0000] "GET /favicon.ico HTTP/1.1" 404 209 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.2; en- ארה"ב; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1"
217.113.68.60 - - [08/Feb/2007:13:02:15 +0000] "GET / HTTP/1.1" 304 - "-" "Mozilla/4.0 (תואם; MSIE 6.0; Windows NT 5.1; SV1)"
217.113.68.60 - - [08/Feb/2007:13:02:16 +0000] "GET /data/css HTTP/1.1" 404 206 "http://www.rfi.net/" "Mozilla/4.0 (תואם; MSIE 6.0; Windows NT 5.1; SV1)"
debora.to.isac.cnr.it - - [08/Feb/2007:13:03:58 +0000] "GET /suse-on-vaio.html HTTP/1.1" 200 2858 "http://www.linux-on-laptops.com/sony.html" "Mozilla/5.0 (תואם; Konqueror/3.4; Linux) KHTML/3.4.0 (כמו Gecko)"
debora.to.isac.cnr.it - - [08/Feb/2007:13:03:58 +0000] "GET /data/css HTTP/1.1" 404 206 "http://www.rfi.net/suse-on-vaio.html" "Mozilla/5.0 (תואם; Konqueror/3.4; Linux) KHTML/3.4.0 (כמו Gecko)"
debora.to.isac.cnr.it - - [08/Feb/2007:13:03:58 +0000] "GET /favicon.ico HTTP/1.1" 404 209 "-" "Mozilla/5.0 (תואם; Konqueror/ 3.4; Linux) KHTML/3.4.0 (כמו Gecko)"
195.24.196.99 - - [08/Feb/2007:13:26:48 +0000] "GET / HTTP/1.0" 200 3309 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.9 .20061206) Gecko/1.5.0.9 Firefox/XNUMX"
195.24.196.99 - - [08/Feb/2007:13:26:58 +0000] "GET /data/css HTTP/1.0" 404 206 "http://www.rfi.net/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9"
195.24.196.99 - - [08/Feb/2007:13:26:59 +0000] "GET /favicon.ico HTTP/1.0" 404 209 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9"
crawl1.cosmixcorp.com - - [08/Feb/2007:13:27:57 +0000] "GET /robots.txt HTTP/1.0" 200 179 "-" "voyager/1.0"
crawl1.cosmixcorp.com - - [08/Feb/2007:13:28:25 +0000] "GET /links.html HTTP/1.0" 200 3413 "-" "voyager/1.0"
fhm226.internetdsl.tpnet.pl - - [08/Feb/2007:13:37:32 +0000] "GET /suse-on-vaio.html HTTP/1.1" 200 2858 "http://www.linux-on-laptops.com/sony.html" "Mozilla/4.0 (תואם; MSIE 6.0; Windows NT 5.1; SV1)"
fhm226.internetdsl.tpnet.pl - - [08/Feb/2007:13:37:34 +0000] "GET /data/css HTTP/1.1" 404 206 "http://www.rfi.net/suse-on-vaio.html" "Mozilla/4.0 (תואם; MSIE 6.0; Windows NT 5.1; SV1)"
80.247.140.134 - - [08/Feb/2007:13:57:35 +0000] "GET / HTTP/1.1" 200 3309 "-" "Mozilla/4.0 (תואם; MSIE 6.0; Windows NT 5.1; .1.1.4322 CLR .XNUMX)"
80.247.140.134 - - [08/Feb/2007:13:57:37 +0000] "GET /data/css HTTP/1.1" 404 206 "http://www.rfi.net" "Mozilla/4.0 (תואם; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)"
pop.compuscan.co.za - - [08/Feb/2007:14:10:43 +0000] "GET / HTTP/1.1" 200 3309 "-" "www.clamav.net"
livebot-207-46-98-57.search.live.com - - [08/Feb/2007:14:12:04 +0000] "GET /robots.txt HTTP/1.0" 200 179 "-" "msnbot/ 1.0 (+http://search.msn.com/msnbot.htm)"
livebot-207-46-98-57.search.live.com - - [08/Feb/2007:14:12:04 +0000] "GET /html/oracle.html HTTP/1.0" 404 214 "-" " msnbot/1.0 (+http://search.msn.com/msnbot.htm)"
dslb-088-064-005-154.pools.arcor-ip.net - - [08/Feb/2007:14:12:15 +0000] "GET / HTTP/1.1" 200 3309 "-" "www.clamav .נֶטוֹ"
196.201.92.41 - - [08/Feb/2007:14:15:01 +0000] "GET / HTTP/1.1" 200 3309 "-" "MOT-L7/08.B7.DCR MIB/2.2.1 Profile/MIDP -2.0 Configuration/CLDC-1.1"
המשימה הספציפית כאן היא למיין את 286,525 השורות של קובץ זה לפי קוד תגובה, שאילתה,
דפדפן, כתובת אתר מפנה ולבסוף תאריך. פתרון אחד יכול להיות להשתמש בקוד הבא,
אשר חוזר על הקבצים שניתנו בשורת הפקודה.
# מיון-apache-log
#!/usr/bin/perl -n
השתמש מחמירים;
להשתמש באזהרות;
הנתונים שלי;
קַו:
while ( <> ) {
שלי $line = $_;
אם
$line =~ m/^(
([\w\.\-]+) # לקוח
\s*-\s*-\s*\[
([^]]+) # תאריך
\]\s*"\w+\s*
(\S+) # שאילתה
[^"]+"\s*
(\d+) מצב #
\s+\S+\s+"[^"]*"\s+"
([^"]*) # דפדפן
"
.*
)$/x
) {
my @chunks = split(/ +/, $line);
שלי $ip = $1;
$date = $2;
שלי $שאילתה = $3;
$status שלי = $4;
$דפדפן שלי = $5;
push(@data, [$ip, $date, $query, $status, $browser, $line]);
}
}
my @sorted = מיון {
$a->[3] cmp $b->[3]
||
$a->[2] cmp $b->[2]
||
$a->[0] cmp $b->[0]
||
$a->[1] cmp $b->[1]
||
$a->[4] cmp $b->[4]
} @נתונים;
foreach my $data (@sorted) {
הדפס $data->[5];
}
יציאה 0;
בעת הפעלת תוכנית זו, הפנה מחדש את "STDOUT" כך שניתן יהיה לבדוק מהו הפלט
לתקן את ריצות הבדיקה הבאות ולהשתמש בכלי השירות "זמן" של המערכת כדי לבדוק את המצב הכולל
זמן ריצה.
$> זמן ./sort-apache-log logfile > out-sort
אמיתי 0m17.371s
משתמש 0m15.757s
sys 0m0.592s
לתוכנית לקח קצת יותר מ-17 שניות לשעון קיר לרוץ. שימו לב לערכים השונים "זמן"
תפוקות, חשוב להשתמש תמיד באותו אחד, ולא לבלבל מה כל אחד
אומר.
זמן אמת שחלף
הזמן הכולל, או שעון הקיר, בין הרגע שבו נקרא "זמן" למועד שבו
מסתיים. הזמן שחלף כולל גם את זמני המשתמש וגם את זמני המערכת, ואת זמן השהייה
מחכה למשתמשים אחרים ולתהליכים במערכת. בהכרח, זה הכי הרבה
משוער של המידות שניתנו.
זמן מעבד משתמש
זמן המשתמש הוא משך הזמן בו השקיע התהליך כולו בשם המשתמש
מערכת זו מבצעת תוכנית זו.
זמן מעבד המערכת
זמן המערכת הוא משך הזמן שהקרנל עצמו בילה בביצוע שגרות, או
שיחות מערכת, מטעם משתמש בתהליך זה.
הפעלת אותו תהליך כמו "טרנספורמציה שוורציאנית" אפשר לבטל את
מערכי קלט ופלט לאחסון כל הנתונים, ועבודה על הקלט ישירות כמותו
מגיע גם. אחרת, הקוד נראה די דומה:
# sort-apache-log-schwarzian
#!/usr/bin/perl -n
השתמש מחמירים;
להשתמש באזהרות;
הדפסה
מפה $_->[0] =>
סוג {
$a->[4] cmp $b->[4]
||
$a->[3] cmp $b->[3]
||
$a->[1] cmp $b->[1]
||
$a->[2] cmp $b->[2]
||
$a->[5] cmp $b->[5]
}
מפה [ $_, m/^(
([\w\.\-]+) # לקוח
\s*-\s*-\s*\[
([^]]+) # תאריך
\]\s*"\w+\s*
(\S+) # שאילתה
[^"]+"\s*
(\d+) מצב #
\s+\S+\s+"[^"]*"\s+"
([^"]*) # דפדפן
"
.*
)$/xo ]
=> <>;
יציאה 0;
הפעל את הקוד החדש מול אותו קובץ יומן, כמו לעיל, כדי לבדוק את השעה החדשה.
$> זמן ./sort-apache-log-schwarzian logfile > out-schwarz
אמיתי 0m9.664s
משתמש 0m8.873s
sys 0m0.704s
הזמן קוצץ בחצי, וזה שיפור מהירות מכובד בכל קנה מידה.
מטבע הדברים, חשוב לבדוק שהפלט תואם את הפעלת התוכנית הראשונה,
כאן נכנס לתמונה כלי השירות "cksum" של מערכת יוניקס.
$> cksum out-sort out-schwarz
3044173777 52029194 מיון
3044173777 52029194 אאוט-שווארץ
אגב. היזהר גם מלחץ של מנהלים שרואים אותך להאיץ תוכנית ב-50% מהסכום
זמן ריצה פעם אחת, רק כדי לקבל בקשה חודש לאחר מכן לעשות את אותו הדבר שוב (סיפור אמיתי) -
אתה רק צריך לציין שאתה רק אנושי, גם אם אתה מתכנת Perl, ו
אתה תראה מה אתה יכול לעשות...
יומן
חלק מהותי בכל תהליך פיתוח טוב הוא טיפול מתאים בשגיאות
מסרים אינפורמטיביים כראוי, אולם קיימת אסכולה אשר
מציע שקובצי יומן צריכים להיות פטפטנית, כאילו שרשרת הפלט הבלתי נשברת איכשהו
מבטיח את הישרדות התוכנית. אם מהירות היא בעיה כלשהי, גישה זו היא
לא בסדר.
מראה נפוץ הוא קוד שנראה בערך כך:
logger->debug( "הודעת רישום באמצעות process-id: $$ INC: " . Dumper(\%INC) )
הבעיה היא שהקוד הזה תמיד ינותח ויבוצע, גם כאשר ה-debug
הרמה שנקבעה בקובץ תצורת הרישום היא אפס. פעם ה לנפות() שגרת המשנה הייתה
הוזן, והמשתנה $debug הפנימי אושר להיות אפס, למשל, ההודעה
אשר נשלח יימחק והתוכנית תמשיך. בדוגמה
עם זאת, ה-hash "\%INC" כבר נזרק, ומחרוזת ההודעה
נבנה, שאת כל העבודה ניתן לעקוף על ידי משתנה באגים במשפט
רמה, ככה:
logger->debug( "הודעת רישום באמצעות process-id: $$ INC: " . Dumper(\%INC) ) if $DEBUG;
ניתן להדגים השפעה זו על ידי הגדרת סקריפט בדיקה עם שני הטפסים, כולל א
תת-שגרת "debug()" כדי לחקות פונקציונליות טיפוסית של "logger()".
# ifdebug
#!/usr/bin/perl
השתמש מחמירים;
להשתמש באזהרות;
השתמש ב- Benchmark;
השתמש ב Data :: Dumper;
$DEBUG שלי = 0;
תת באגים {
my $msg = shift;
if ($DEBUG) {
הדפס "DEBUG: $msg\n";
}
};
timethese(100000, {
'debug' => משנה {
debug( "הודעת רישום של $0 באמצעות process-id: $$" . Dumper(\%INC) )
},
'ifdebug' => משנה {
debug( "הודעת רישום של $0 באמצעות process-id: $$" . Dumper(\%INC) ) if $DEBUG
},
});
בוא נראה מה "Benchmark" עושה מזה:
$> perl ifdebug
אמת מידה: תזמון 100000 חזרות של קבוע, תת...
ifdebug: 0 שעון קיר שניות ( 0.01 usr + 0.00 sys = 0.01 CPU) @ 10000000.00/s (n=100000)
(אזהרה: מעט מדי חזרות לספירה אמינה)
איתור באגים: 14 שניות שעון קיר (13.18 usr + 0.04 sys = 13.22 CPU) @ 7564.30/s (n=100000)
במקרה האחד הקוד, שעושה בדיוק את אותו הדבר באשר לפלט כל
מידע על ניפוי באגים מודאג, במילים אחרות שום דבר, לוקח 14 שניות, וב-
במקרה אחר הקוד לוקח מאית השנייה. נראה די סופי. תשתמש ב
משתנה $DEBUG לפני שאתה קורא לתת-השגרה, במקום להסתמך על החכם
פונקציונליות בתוכו.
רישום if DEBUG (קָבוּעַ)
אפשר לקחת את הרעיון הקודם קצת יותר רחוק, על ידי שימוש בזמן הידור "DEBUG"
קָבוּעַ.
# ifdebug-constant
#!/usr/bin/perl
השתמש מחמירים;
להשתמש באזהרות;
השתמש ב- Benchmark;
השתמש ב Data :: Dumper;
השתמש בקבוע
DEBUG => 0
;
תת באגים {
if (DEBUG) {
my $msg = shift;
הדפס "DEBUG: $msg\n";
}
};
timethese(100000, {
'debug' => משנה {
debug( "הודעת רישום של $0 באמצעות process-id: $$" . Dumper(\%INC) )
},
'קבוע' => משנה {
debug( "הודעת רישום של $0 באמצעות process-id: $$" . Dumper(\%INC) ) if DEBUG
},
});
הפעלת תוכנית זו מייצרת את הפלט הבא:
$> perl ifdebug-constant
אמת מידה: תזמון 100000 חזרות של קבוע, תת...
קבוע: 0 שניות שעון קיר (-0.00 usr + 0.00 sys = -0.00 CPU) @ -7205759403792793600000.00/s (n=100000)
(אזהרה: מעט מדי חזרות לספירה אמינה)
משנה: 14 שניות שעון קיר (13.09 usr + 0.00 sys = 13.09 CPU) @ 7639.42/s (n=100000)
הקבוע "DEBUG" מנגב את הרצפה אפילו עם משתנה $debug, ונכנס במינוס
אפס שניות, ומייצר הודעת "אזהרה: מעט מדי חזרות לספירה אמינה".
לתוך המציאה. לראות מה באמת קורה, ולמה היו לנו מעט מדי איטרציות מתי
חשבנו שביקשנו 100000, נוכל להשתמש ב-"B::Deparse" השימושי מאוד כדי לבדוק את החדש
קוד:
$> perl -MO=בטל את ifdebug-constant
השתמש ב- Benchmark;
השתמש ב Data :: Dumper;
השתמש בקבוע ('DEBUG', 0);
תת באגים {
להשתמש באזהרות;
השתמש ב-'refs' קפדניים;
0;
}
להשתמש באזהרות;
השתמש ב-'refs' קפדניים;
timethese(100000, {'sub', sub {
נפה באגים "הודעת רישום של $0 באמצעות process-id: $$" . Dumper(\%INC);
}
, 'constant', sub {
0;
}
});
תחביר ifdebug-constant בסדר
הפלט מציג את קָבוּעַ() תת-שגרת שאנו בודקים מוחלפת בערך של
קבוע "DEBUG": אפס. הקו שייבדק עבר אופטימיזציה לחלוטין, ו
אתה לא יכול להיות הרבה יותר יעיל מזה.
פוסטסקריפט
מסמך זה סיפק מספר דרכים לזיהוי נקודות חמות ובדיקה
האם שינויים כלשהם שיפרו את זמן הריצה של הקוד.
כמחשבה אחרונה, זכרו שלא ניתן (בזמן כתיבת שורות אלו) לייצר א
תוכנית שימושית אשר תפעל בזמן אפס או שלילי ועקרון בסיסי זה יכול להיות
כתוב כ: מועיל תוכניות יש לו להאט לפי עצם ההגדרה שלהם. זה כמובן אפשרי
לכתוב תוכנית כמעט מיידית, אבל זה לא הולך לעשות הרבה, הנה
אחד יעיל:
$> perl -e 0
אופטימיזציה לכך היא עבודה עבור "p5p".
השתמש ב-perlperf באינטרנט באמצעות שירותי onworks.net