به دست آوردن زمان اجرا با دقت بسیار زیاد

Acquiring high-resolution time stamps

[box type=”info”] توجه: API های استفاده شده در این آموزش فقط برای استفاده در  محیط های برنامه نویسی در ویندوز قابل استفاده است. در ضمن در کامپیوترهایی که از چند پردازنده ( نه پردازنده ای با چند هسته!) و یا چند مادربورد استفاده می کنند که در آن ها دامنه فرکانس کلاک پردازنده یکسان نیست، نتایج غیر معتبر خواهد شد. (برای کاربران لینوکس و سیستم های مبتنی بر BSD مانند یونیکس، توابع قابل اطمینان و یا بسیار دقیق پیدا نکردم!)[/box]

 

برای اندازه گیری زمان اجرای یک تابع یا بخشی از آن، کلاک های لازم برای اجرای آن را بر فرکانس کلاک پردازنده تقسیم می کنیم. در واقع فرکانس کلاک بیان کننده زمان مصرف شده برای یک کلاک است و ما با تقسیم کلاک ها بر فرکانس میخواهیم پیدا کنیم که کل زمان کلاک های محدوده مورد نظر ما در برنامه، چه کسری از زمان را لازم داشته است. با این روش ما در اندازه گیری زمان اجرا به دقت میکرو ثانیه و بهتر می رسیم.

[box type=”info”] نکته: توابع و ساختارهای این آموزش در هدر فایل Windows.h قرار دارد. و در ضمن برای جا دادن اعداد صحیح بزرگ هم از ساختار LARGE_INTEGER استفاده می شود که به صورت جزیی ساختار آن در این لینک آورده شده است.[/box]

ابتدا متغیرهای  StartingTime, EndingTime, ElapsedMicroseconds به ترتیب برای نگه داری تعداد کلاک های زده شده از زمانی که سیستم کامپیوتر شما شروع به کار کرده تا قبل از اجرای بخش مورد نظر، برای نگه داری کلاک های زده شده از زمانی که سیستم کامپیوتر شما شروع به کار کرده تا آخر اجرای بخش مورد نظر و متغیر سوم هم برای نگه داری تفریق مقادیر دو متغیر قبلی و همچنین محاسبه زمان صرف شده با دقت مورد نظر را تعریف می کنیم.

متغیر Frequency را نیز برای نگه داری مقدار فرکانس پردازنده تعریف می کنیم. به یاد داشته باشید که فرکانس پردازنده شما در طول اجرای برنامه تغییر نخواهد کرد.

 

حالا با تابع ()QueryPerformanceFrequency مقدار فرکانس پردازنده را می گیریم و با فراخوانی تابع ()QueryPerformanceCounter کلاک های زده شده در کامپیوتر از لحظه روشن شدن تا زمان فراخوانی را می گیریم.

و اما پس از این همه مقدمه چینی به اجرای تابع یا تکه کد مورد نظر می رسیم. در اینجا به گذاشتن یک کامنت برای مثال بسنده می کنیم.

بعد از اجرا، دوباره مقدار کلاک های زده شده در پردازنده را می گیریم و حاصل تفریق این مقدار با مقدار کلاک های زده شده قبل از اجرای بخش مورد نظر را در متقیر ElapsedMicroseconds و در بخش ۶۴ بیتی آن یعنی QuadPart (به فرض ۶۴ بیتی بودن پردازنده) قرار می دهیم.

و اما نکته مهمی که حالا باید به آن پرداخت این است که قبل از تقسیم کلاک های زده شده برای اجرای بخش مورد نظر برفرکانس پردارنده، برای جلوگیری از از بین رفتن دقت (اعداد اعشاری بسیار کوچک) در این تقسیم، باید دقت مورد نظر را اعمال کنید (حاصل تفریق را در توان دقت دلخواه ضرب کنید). ما برای آموزش مطلب دقت نانوثانیه را انتخاب می کنیم. دقت کنید که اگر پیش بینی می کنید که زمان اجرای برنامه شما از نانوثانیه هم کمتر است و یا بعد از اندازه گیری زمان عدد صفر حاصل شد، دقت های بالاتر را (پیکو ثانیه) امتحان کنید.

تمام شد! حالا مقدار ElapsedMicroseconds.QuadPart (با فرض ۶۴ بیتی بودن پردازنده) زمان اجرای الگوریتم یا تکه کد شما با دقت دلخواه تان است.

در روز های آینده مقایسه ای میان زمان اجرای چند الگوریتم مرتب سازی با ورودی های مختلف با استفاده از این آموزش روی وبسایت می آید.

 

مطالب این پست به کمک آمورشی در شبکه توسعه دهندگان مایکروسافت، نوشته شده است. پس برای کسب اطلاعات جزیی از API استفاده شده در این مطلب می توانید به صفحه آموزش ذکر شده مراجعه کنید.

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

۶ دیدگاه

  • بسیار مفید بود!
    این روش برای موقعی صادقه که thread سی پی یوی ما به اجرای همین کد مشغول باشه و با پروسه دیگه‌ای share نشده باشه، یا نه؟ در اون حالت هم جواب درست خواهد داد؟

    • با فراخوانی QPC ما یک عدد داریم که تعداد کلاک های زده شده در پردازنده (یا پردازنده های هم فرکانس) از زمان شروع کار سیستم است. پس اگر شما در حین اجرای بخش مورد نظر، اجرای یک thread دیگر را هم بر عهده پردازنده گذاشته باشید، دیگر نباید انتظار نتایج معتبر را داشته باشید!

      • ممنون (: خب حالا سوال اینجاست که چطور میشه سیستم عامل یا دیباگر رو مجبور کرد یک thread رو اختصاصاْ برای کد ما رزرو کنه.

        • خواهش می کنم
          فرشاد شما سوالای خیلی خوبی می پرسید ها! 😀
          کنترل و استفاده از هسته های یک پردازنده در سطح برنامه نویسی امکان پذیر نیست. این کار رو خود سیستم عامل مدیریت می کنه. مثلاً تصمیم می گیره که اجرای برنامه شما رو بین چند هسته تقسیم بکنه یا نه و …
          اما اگر چند پردازنده داشته باشیم جریان کمی متفاوت هستش. با برنامه نویسی موازی میشه دقیقاً کنترل پردازنده ها رو برای اجرای بخشی از کدها به دست گرفت. اون وقت اگر توابع QPC و QPF هم اجراشون بر عهده همون پردازنده ای باشه که اجرای برنامه مورد نظر ما برای اندازه گیری زمان اجرا به اون سپرده شده، ما نتایج معتبری خواهیم داشت. اما حالت دیگری که پیش میاد اینه که اجرای برنامه بین چند پردازنده تقسیم شده باشه، در اون حالت اگر پردازنده ها هم فرکانس باشن باز هم نتیجه معتبر خواهد بود.

          • باز هم ممنون از توضیح کاملتون.
            🙂 اگه سوال میکنم بخاطر مطالب پربار و مفید شماستک، و با علم به اینکه بی‌جواب نمیگذارید.

          • خواهش
            ممنون از اینکه می خونید، اهمیت می دید، در موردش فکر می کنید و سوال می پرسید
            شاد باشید

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *