روابط سريعة
هل تريد معرفة المدة التي تستغرقها عملية ما وغير ذلك الكثير؟ يقوم أمر الوقت في Linux بإرجاع إحصائيات الوقت، مما يمنحك رؤى رائعة حول الموارد التي تستخدمها برامجك.
الزمن له أقارب كثيرون
هناك العديد من توزيعات لينكس وأنظمة تشغيل مختلفة شبيهة بيونكس. ولكل منها غلاف أوامر افتراضي. الغلاف الافتراضي الأكثر شيوعًا في توزيعات لينكس الحديثة هو غلاف bash. ولكن هناك العديد من الغلافات الأخرى، مثل غلاف Z (zsh) وغلافة Korn (ksh).
تتضمن كل هذه القذائف أمر الوقت الخاص بها، إما كـ مدمج أمر أو كـ كلمة محجوزةعندما تكتب time في نافذة المحطة الطرفية، سيقوم shell بتنفيذ الأمر الداخلي الخاص به بدلاً من استخدام ملف GNU time الثنائي المقدم كجزء من توزيع Linux الخاص بك.
نريد استخدام إصدار GNU من الوقت لأنه يحتوي على المزيد خيارات وهي أكثر مرونة.
أي وقت سوف يعمل؟
يمكنك التحقق من الإصدار الذي سيتم تشغيله باستخدام الأمر type. سيتيح لك الأمر type معرفة ما إذا كانت الواجهة ستتعامل مع تعليماتك بنفسها، باستخدام روتيناتها الداخلية، أو تمررها إلى الملف الثنائي GNU. في نافذة المحطة الطرفية، اكتب الكلمة يكتب، مسافة، ثم الكلمة وقتواضغط على Enter.
type time
يمكننا أن نرى أن الوقت في غلاف bash هو كلمة محجوزة. وهذا يعني أن Bash سوف يستخدم روتينات الوقت الداخلية الخاصة به افتراضيًا.
type time
في غلاف Z (zsh)، يكون الوقت كلمة محجوزة، لذا سيتم استخدام روتينات الغلاف الداخلية بشكل افتراضي.
type time
في غلاف Korn، يعد الوقت عبارة عن كلمة رئيسية. سيتم استخدام روتين داخلي بدلاً من أمر الوقت في GNU.
تشغيل أمر GNU time
إذا كان الغلاف الموجود على نظام Linux الخاص بك يحتوي على روتين وقت داخلي، فسوف تحتاج إلى توضيح رغبتك في استخدام ملف GNU الثنائي للوقت. يجب عليك إما:
- قم بتوفير المسار الكامل للملف الثنائي، مثل /usr/bin/time. قم بتشغيل الأمر which time للعثور على هذا المسار.
- يستخدم
command time
. - استخدم الشرطة المائلة للخلف مثل
\time
.
ال which time
يعطينا الأمر المسار إلى الملف الثنائي.
يمكننا اختبار ذلك باستخدام /usr/bin/time
كأمر لتشغيل ملف GNU الثنائي. هذا يعمل. نحصل على استجابة من time
أمر يخبرنا بأننا لم نقدم أي معلمات سطر أوامر لكي يعمل عليها.
الكتابة command time
يعمل أيضًا، ونحصل على نفس معلومات الاستخدام من time
. ال command
يخبر الأمر shell بتجاهل الأمر التالي حتى تتم معالجته خارج shell.
استخدام \
الحرف قبل اسم الأمر هو نفس استخدام command
قبل اسم الأمر.
أبسط طريقة للتأكد من استخدامك لبرنامج GNU time
الثنائي هو استخدام خيار الشرطة المائلة للخلف.
time
\time
time
يستدعي إصدار shell الخاص بالوقت. \time
يستخدم time
ثنائي.
استخدام أمر الوقت
دعونا نحدد وقت بعض البرامج. نحن نستخدم برنامجين يسميان loop1
و loop2
تم إنشاؤها من loop1.c وloop2.c. ولا تقدم أي شيء مفيد بخلاف إظهار تأثيرات نوع واحد من عدم كفاءة الترميز.
هذه هي الحلقة 1.ج. يلزم تحديد طول السلسلة داخل الحلقتين المتداخلتين. يتم الحصول على الطول مسبقًا، خارج الحلقتين المتداخلتين.
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int main (int argc, char* argv())
{
int i, j, len, count=0;
char szString()="how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek";
len = strlen( szString );
for (j=0; j<500000; j++) {
for (i=0; i < len; i++ ) {
if (szString(i) == '-')
count++;
}
}
printf("Counted %d hyphens\n", count);
exit (0);
}
هذه هي الحلقة 2.ج. يتم الحصول على طول السلسلة مرة تلو الأخرى لكل دورة من الحلقة الخارجية. يجب أن يظهر هذا النقص في الكفاءة في التوقيتات.
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int main (int argc, char* argv())
{
int i, j, count=0;
char szString()="how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek";
for (j=0; j<500000; j++) {
for (i=0; i < strlen(szString); i++ ) {
if (szString(i) == '-')
count++;
}
}
printf("Counted %d hyphens\n", count);
exit (0);
}
دعونا نطلق النار loop1
البرنامج والاستخدام time
لقياس أدائها.
\time ./loop1
الآن دعونا نفعل نفس الشيء بالنسبة لـ loop2
.
\time ./loop2
لقد أعطانا ذلك مجموعتين من النتائج، ولكنها بتنسيق قبيح للغاية. يمكننا أن نفعل شيئًا حيال ذلك لاحقًا، ولكن دعنا نختار بعض المعلومات من النتائج.
عند تشغيل البرامج، هناك وضعان للتنفيذ يتم التبديل بينهما ذهابًا وإيابًا. ويطلق على هذين الوضعين وضع المستخدم ووضع النواة.
باختصار، لا تستطيع العملية في وضع المستخدم الوصول مباشرة إلى الأجهزة أو الذاكرة المرجعية خارج تخصيصها الخاص. وللوصول إلى مثل هذه الموارد، يجب على العملية تقديم طلبات إلى النواة. إذا وافقت النواة على الطلب، تدخل العملية في وضع تنفيذ النواة حتى يتم تلبية المتطلب. ثم يتم تحويل العملية مرة أخرى إلى وضع تنفيذ المستخدم.
النتائج ل loop1
أخبرنا بذلك loop1
لقد أمضى 0.09 ثانية في وضع المستخدم. إما أنه أمضى صفرًا من الوقت في وضع النواة أو أن الوقت في وضع النواة منخفض جدًا بحيث لا يمكن تسجيله بمجرد تقريبه إلى الأسفل. وكان إجمالي الوقت المنقضي 0.1 ثانية. loop1
تم منحه متوسط 89% من وقت وحدة المعالجة المركزية طوال مدة الوقت المنقضي الإجمالي.
غير فعال loop2
استغرق البرنامج وقتًا أطول بثلاث مرات للتنفيذ. ويبلغ إجمالي الوقت المنقضي 0.3 ثانية. وتبلغ مدة وقت المعالجة في وضع المستخدم 0.29 ثانية. ولا يتم تسجيل أي شيء لوضع النواة. loop2
حصل على متوسط 96% من وقت وحدة المعالجة المركزية طوال مدة تشغيله.
تنسيق الناتج
يمكنك تخصيص الإخراج من time
باستخدام سلسلة تنسيق. يمكن أن تحتوي سلسلة التنسيق على نص ومواصفات تنسيق. يمكن أن تكون قائمة مواصفات التنسيق تم العثور على هذا في صفحة الدليل ل time
يمثل كل من مواصفات التنسيق جزءًا من المعلومات.
عند طباعة السلسلة، يتم استبدال مواصفات التنسيق بالقيم الفعلية التي تمثلها. على سبيل المثال، مواصفات التنسيق لنسبة وحدة المعالجة المركزية هي الحرف P
. للإشارة إلى time
أن محدد التنسيق ليس مجرد حرف عادي، أضف إليه علامة النسبة المئوية، مثل %P
دعونا نستخدمه في مثال.
ال -f
يتم استخدام خيار (تنسيق السلسلة) لإخبار time
أن ما يلي هو سلسلة تنسيق.
سوف يقوم تنسيق السلسلة لدينا بطباعة الأحرف “البرنامج: ” واسم البرنامج (وأي معلمات سطر أوامر تمررها إلى البرنامج). %C
يشير مُحدِّد التنسيق إلى “اسم وحجج سطر الأوامر للأمر الذي يتم توقيته”. \n
يؤدي إلى نقل الإخراج إلى السطر التالي.
هناك الكثير من مواصفات التنسيق وهي حساسة لحالة الأحرف، لذا تأكد من إدخالها بشكل صحيح عندما تفعل ذلك بنفسك.
بعد ذلك، سنقوم بطباعة الأحرف “إجمالي الوقت: ” متبوعة بقيمة إجمالي الوقت المنقضي لهذه العملية من البرنامج (يمثلها %E).
نستخدم \n لإنشاء سطر جديد آخر. ثم نقوم بطباعة الأحرف “User Mode (s) “، متبوعة بقيمة وقت وحدة المعالجة المركزية الذي قضاه في وضع المستخدم، والذي يتم الإشارة إليه بواسطة %U.
نستخدم \n لإعطاء سطر جديد آخر. هذه المرة نستعد لقيمة وقت النواة. نطبع الأحرف “Kernel Mode (s) “، متبوعة بمواصفات التنسيق لوقت وحدة المعالجة المركزية المستغرق في وضع النواة، وهو %S.
أخيرًا، سنطبع الأحرف “\nCPU: ” لنحصل على سطر جديد وعنوان لقيمة البيانات هذه. سيعطينا مُحدد تنسيق %P النسبة المئوية المتوسطة لوقت وحدة المعالجة المركزية المستخدم بواسطة العملية المحددة بالوقت.
يتم وضع سلسلة التنسيق بأكملها بين علامتي اقتباس. كان بإمكاننا تضمين بعض الأحرف \t لوضع علامات التبويب في الإخراج إذا كنا حريصين على محاذاة القيم.
\time -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop1
إرسال الناتج إلى ملف
للاحتفاظ بسجل لتوقيتات الاختبارات التي أجريتها، يمكنك إرسال الناتج من time إلى ملف. للقيام بذلك، استخدم خيار -o (الإخراج). سيظل الناتج من برنامجك معروضًا في نافذة المحطة الطرفية. سيتم إعادة توجيه الناتج من time فقط إلى الملف.
يمكننا إعادة تشغيل الاختبار وحفظ الناتج في ملف test_results.txt على النحو التالي:
\time -o test_results.txt -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop1
cat test_results.txt
يتم عرض مخرجات برنامج loop1 في نافذة المحطة الطرفية وتنتقل النتائج من وقت لآخر إلى ملف test_results.txt.
إذا كنت تريد التقاط المجموعة التالية من النتائج في نفس الملف، فيجب عليك استخدام الخيار -a (إضافة) على النحو التالي:
\time -o test_results.txt -a -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop2
cat test_results.txt
يجب أن يكون من الواضح الآن سبب استخدامنا لمواصفات التنسيق %C لتضمين اسم البرنامج في الإخراج من سلسلة التنسيق.
لقد انتهى وقتنا
ربما يكون الأمر time مفيدًا للغاية للمبرمجين والمطورين لضبط الكود الخاص بهم، كما أنه مفيد أيضًا لأي شخص يريد اكتشاف المزيد حول ما يحدث تحت الغطاء في كل مرة تقوم فيها بتشغيل برنامج.