View Full Version : کار با زمان
1485159
یک شنبه 30 آبان 1389, 14:55 عصر
سلام
میخواستم بدونم که برای محاسبه دقیق زمان باید از چه توابعی استفاده کنم؟ ممنون.
سپول
یک شنبه 30 آبان 1389, 21:50 عصر
بهترین راه : (گرفتن تغداد سایکل های cpu(
QueryPerformanceCounter
QueryPerformanceFrequency
راههای دیگه هم هست مثل timeGetTime و اینجور چیزا که اونها دقت کافی ندارند و در بازی ها و برنامه های time critical ضعیف عمل می کنند.
این هم نمونه کد ساده.
LARGE_INTEGER tick;
QueryPerformanceCounter( &tick );
LARGE_INTEGER freq;
QueryPerformanceFrequency( &freq );
double t = (double)tick.QuadPart/(double)freq.QuadPart;
البته این کد باز هم کمی دقت سر اعداد اعشاری از دست می ده که بهتره tick رو از یک عدد اولیه کم کنید. (startTick)
1485159
یک شنبه 30 آبان 1389, 22:47 عصر
خیلی ممنون... فقط یه چیزی رو نمیفهمم!!! :
double t = (double)tick.QuadPart/(double)freq.QuadPart;
یا مشابه دیگه:
diff = ((end - start) * 1000) / freq;
سپول
یک شنبه 30 آبان 1389, 22:53 عصر
همینی که نوشتی درسته. فقط اون 1000 که ضرب می شه بهت میلی ثانیه می ده.
1485159
یک شنبه 30 آبان 1389, 23:02 عصر
همینی که نوشتی درسته. فقط اون 1000 که ضرب می شه بهت میلی ثانیه می ده. خوب وقتی به 1000 ضرب نکنم چی؟
وقتی به 1000000 ضرب کنم میکرو ثانیه بهم میده؟
در ضمن چرا اصلا باید به freq تقسیمش کنم؟
سپول
دوشنبه 01 آذر 1389, 12:57 عصر
خوب وقتی به 1000 ضرب نکنم چی؟
وقتی به 1000000 ضرب کنم میکرو ثانیه بهم میده؟
در ضمن چرا اصلا باید به freq تقسیمش کنم؟
QueryPerformanceCounter زمان رو نمیده بلکه تعداد سایکل های cpu رو می ده.
Frequency هم در حقیقت تعداد cycle در هر ثانیه رو می ده (فرکانس Cpu که در واقع واحد سرعت اون هم هست - 2.0 GHZ ....) با تقسیم counter بر freq، زمان به دست میاد که دقیق ترین حالتیه که می تونید از کامپیوتر زمان بگیرید.
1485159
دوشنبه 01 آذر 1389, 13:30 عصر
ممنون. فقط چنتا سوال:
وقتی به 1000000 ضرب کنم میکرو ثانیه بهم میده؟
یکبار استفاده از QueryPerformanceFrequency کافیه؟ منظورم اینه که مقدارش در طول کار برنامه عوض نمیشه؟
pswin.pooya
دوشنبه 01 آذر 1389, 18:38 عصر
یکبار استفاده از QueryPerformanceFrequency کافیه؟ منظورم اینه که مقدارش در طول کار برنامه عوض نمیشه؟
اگر این سوال رو یه هفت هشت سال پیش میپرستی میگفنم آره. چون فرکانس کار پردازندها ثابت بود اما امروزه با توجه به overload پردازنده فرکانس کم یا زیاد میشه. حتی توی هسته لینوکس هم یک گزینه برای تنظیم این مساله وجود داره که آیا هسته به شکلی کامپایل بشه که فرکانس فرق نکنه و ثابت باشه و یا برعکس. من در مورد ساختار ویندوز اطلاعات کاملی ندارم اما فکر میکنم ویندوز هم از این قاعده مستثنی نیست.
1485159
دوشنبه 01 آذر 1389, 19:53 عصر
اگر این سوال رو یه هفت هشت سال پیش میپرستی میگفنم آره. چون فرکانس کار پردازندها ثابت بود اما امروزه با توجه به overload پردازنده فرکانس کم یا زیاد میشه. حتی توی هسته لینوکس هم یک گزینه برای تنظیم این مساله وجود داره که آیا هسته به شکلی کامپایل بشه که فرکانس فرق نکنه و ثابت باشه و یا برعکس. من در مورد ساختار ویندوز اطلاعات کاملی ندارم اما فکر میکنم ویندوز هم از این قاعده مستثنی نیست.
اگه فرض کنیم که این مقدار فرق میکنه باید هر وقت که خواستیم زمان رو حساب کنیم باید freq رو هم حساب کنیم؟ یا کی؟
درضمن اگه تابع مقدار false برگردونه یعنی چی؟ همیشه باید مقدار خروجی تابع رو چک کنیم که false نباشه؟ اگه باشه چیکار کار باید بکنیم؟ خود مقدار freq هم ممکنه صفر باشه؟ کی صفر میشه؟ چاره چیه؟
چقدر سوال پرسیدم.:لبخند:
ممنون.
سپول
دوشنبه 01 آذر 1389, 23:38 عصر
اگر این سوال رو یه هفت هشت سال پیش میپرستی میگفنم آره.
جواب این سوال الان هم مثل 7-8 سال پیش آره هست.
شما فقط کافیه یکبار frequency رو بگیرید، اون مقداری که تابع QueryPerformanceFrequency برمیگردونه در طول اجرای سیستم ثابت هست.
در صورتی این مشکل تغییر فرکانی پیش میاد که از توابع اسمبلی سیستمی RDTSC برای گرفتن کلاک و فرکانس cpu استفاده کنید.
در لینوکس نمی دونم چیه .
pswin.pooya
سه شنبه 02 آذر 1389, 14:01 عصر
شما فقط کافیه یکبار frequency رو بگیرید، اون مقداری که تابع QueryPerformanceFrequency برمیگردونه در طول اجرای سیستم ثابت هست.
در صورتی این مشکل تغییر فرکانی پیش میاد که از توابع اسمبلی سیستمی RDTSC برای گرفتن کلاک و فرکانس cpu استفاده کنید.
در لینوکس نمی دونم چیه
این مشکل اصلا مربوط به توابع اسمبلی و یا موارد دیگه نیسش این مورد برای همه سیستم عامل ها وجود داره مگر اینکه سیستم عامل پردازنده رو ملزم کنه که کلاک ثابت کار کنه. اتفاقا RDTSC بهتره چون یه عدد دقیق از فرکانس کاری رو میده. فقط باید این مقدار مرتبا گرفته بشه. لینوکس یه تنظیم زمان کامپایل به اسم CONFIG_NO_HZ داره که میتونه خاصیت tickless رو معرفی کنه . این مورد باعث میشه که با توجه به overhead در مورد tick میکروپروسس PIT تصمیم گیری بشه اما این یه جنبه قضیه هست و جنبه دیگه مربوط به ساختار خود سخت افزار هست که اینکار رو به صورت اتوماتیک انجام بده. تست های خود من نشون داده که فرکانس کاری متغییر هست. بازهم تا اونجا که میدونم برای موارد خاصی مثلا سیستم های بلادرنگ این امکان فراهم شده که فرکانس رو ثابت کرد.
من خودم از دستور GetTickCount استفاده می کنم. که دقتش میلی ثانبه هست.
سپول
چهارشنبه 03 آذر 1389, 23:33 عصر
تست های خود من نشون داده که فرکانس کاری متغییر هست. بازهم تا اونجا که میدونم برای موارد خاصی مثلا سیستم های بلادرنگ این امکان فراهم شده که فرکانس رو ثابت کرد.
http://msdn.microsoft.com/en-us/library/ee417693%28VS.85%29.aspx
Call QueryPerformanceFrequency only once, because the frequency will not change while the system is running.
pswin.pooya
چهارشنبه 03 آذر 1389, 23:53 عصر
Call QueryPerformanceFrequency only once, because the frequency will not change while the system is running. شاید این مورد در مورد این تابع صدق کنه اما دلیل بر تغییر فرکانس پردازنده نمیشه. تست هایی که من گرفتم کدهای خودم رو یه سیستم واقعی بوده که این مطلب رو کاملا به من اثبات کرده. من برای اولین بار این موضوع رو داخل یکی از کتابهای توسعه هسته لینوکس و نوشتن درایور برای اون خوندم.
همنطور که گفتم در مورد ساختار ویندوز اطلاعات دقیقی ندارم. اما در مورد سه سیستم عاملی که در موردشون مطالعه داشتم مطمئن هستم که این شکلی هست.
SeganX
پنج شنبه 04 آذر 1389, 11:16 صبح
تغییر فرکانس CPU ربطی به سیستم عامل نداره. مثلا میشه کدهایی نوشت که واسه بعضی کارها CPU رو overclock کرد. ( من خودم این کارو نکردم اما دیدم و خوندم ) بعضی از سیستمهای power management و power saver هم فرکانس CPU رو کم و زیاد می کنند.
اما نکته ای که باید بهش توجه کنیم اینه که وجود برنامه ای که فرکانس CPU رو تغییر بده و در مجموع احتمال بروز این موارد در حین اجرای یک بازی خیلی خیلی کمه و روی کنسول ها که اصلا بعید می دونم فرکانس CPU رو کسی تغییر بده و خود ماکروسافت هم تاکید کرده که سیستمش این کارو نمیکنه.
من خودم از timeGetTime استفاده میکنم و از به نظر شخصی خودم clock های high res تنها واسه تست performance واسه بعضی از tools هایی که مینویسیم بدرد می خوره :لبخند:
seyedof
پنج شنبه 04 آذر 1389, 15:59 عصر
این مشکل اصلا مربوط به توابع اسمبلی و یا موارد دیگه نیسش این مورد برای همه سیستم عامل ها وجود داره مگر اینکه سیستم عامل پردازنده رو ملزم کنه که کلاک ثابت کار کنه. اتفاقا RDTSC بهتره چون یه عدد دقیق از فرکانس کاری رو میده. فقط باید این مقدار مرتبا گرفته بشه. لینوکس یه تنظیم زمان کامپایل به اسم CONFIG_NO_HZ داره که میتونه خاصیت tickless رو معرفی کنه . این مورد باعث میشه که با توجه به overhead در مورد tick میکروپروسس PIT تصمیم گیری بشه اما این یه جنبه قضیه هست و جنبه دیگه مربوط به ساختار خود سخت افزار هست که اینکار رو به صورت اتوماتیک انجام بده. تست های خود من نشون داده که فرکانس کاری متغییر هست. بازهم تا اونجا که میدونم برای موارد خاصی مثلا سیستم های بلادرنگ این امکان فراهم شده که فرکانس رو ثابت کرد.
من خودم از دستور GetTickCount استفاده می کنم. که دقتش میلی ثانبه هست.
سلام
موضوع این نیست که فرکانس کلاک CPU ثابت میمونه یا نه، بحث سر محاسبه زمانه که QueryPerformanceCounter این کارو انجام میده و حتی اگر فرکانس هم عوض بشه لابد خودش داخلی رفع و رجوع میکنه در حالی که RDTSC اینطور نیست. خود تابع Query... هم داخلش از RDTSC استفاده میکنه. قدیما این تابع مشکل داشت حتی این Instruction RDTSC از یک زمانی توی CPU های فکر کنم Pentium گنجانده شد (به Manualهای اینتل مراجعه کنید) و به همین دلیل نمیشد ازش استفاده کرد چون همه پردازنده ها این رو نداشتند. تابع QueryPerfor.... هم مشکلاتی داشت از جمله روی سیستم های چند پردازنده ای یا چند هسته ای، یه سری مشکلاتی به اسم Retro timing هم داشت، با CPU های چند وضعیتی و مخصوصا مال نوت بوکها مشکل داشت (سر همین تغییر فرکانس کاری CPU) و... که انگار به مرور زمان حل شده و توی نسخه های جدید مطابق لینکی که سپهر داده مشکلی نداره.
ضمنا دقت اوون تابع که گفتید میلی ثانیه نیست. زمان رو به میلی ثانیه میده اما در هر میلی ثانیه به روز رسانی نمیشه. نرخ به روز رسانیش روی ورژن های مختلف ویندوز متفاوته مثلا فکر کنم توی نسخه های خیلی قدیمی مثل 95 , 98 این فاصله 50 میلی ثانیه بود و توی نسخه هایی شد 20 و توی جدیدها 10 میلی ثانیه. یعنی اگر از این تابع پشت هم استفاده کنید توی یک حلقه سریع مقادیری که به شما میده اینطوری میشه : 7 17 27 37 47
به این ترتیب زمانهای زیر 10 میلی ثانیه قابل اندازه گیری نیستند. 10 میلی ثانیه یعنی یک صدم ثانیه. این دقت ممکنه برای خیلی کارها کافی باشه اما برای خیلی کارها از جمله محاسبات موتور فیزیک اصلا کافی نیست.
پس این تابع بدرد نمیخوره اگر میخورد بازیها ازش استفاده میکردن.
به همین دلیل ما همیشه توی پروژه هامون دو نوع تایمر میذاریم یکی کم دقت با همین GetTickCount یکی دیگه High Resolution با QueryPerformanceCounter
اینم لینک منبع: http://msdn.microsoft.com/en-us/library/ms724408%28VS.85%29.aspx
ممنون علی
http://www.tochalco.com/blog
1485159
پنج شنبه 04 آذر 1389, 21:38 عصر
ضمنا دقت اوون تابع که گفتید میلی ثانیه نیست.
منظورتون timeGetTime هست؟ این تابع کجا تعریف شده؟
pswin.pooya
جمعه 05 آذر 1389, 09:03 صبح
ضمنا دقت اوون تابع که گفتید میلی ثانیه نیست. زمان رو به میلی ثانیه میده اما در هر میلی ثانیه به روز رسانی نمیشه. نرخ به روز رسانیش روی ورژن های مختلف ویندوز متفاوته مثلا فکر کنم توی نسخه های خیلی قدیمی مثل 95 , 98 این فاصله 50 میلی ثانیه بود و توی نسخه هایی شد 20 و توی جدیدها 10 میلی ثانیه. یعنی اگر از این تابع پشت هم استفاده کنید توی یک حلقه سریع مقادیری که به شما میده اینطوری میشه : 7 17 27 37 47
GetTickCount تعداد تیکهای میکروی PIT رو بر می گردوته. من توی یک راهنما خونده بودم که ویندوز تنظیم میکنه که pit توی هر ثانیه ۱۰۰۰ تیک (وقفه شماره صفر)رو تولید کنه. که البته توی ویرایشهای قدیمی ویندوز این مقدار ۲۰۰ بوده. اینکه شما داری هر ۱۰ میلی ثانیه جواب میگری ممکنه یکی از دو حالت زیر باشه:
۱. ویندوزتون PIT رو برای کمتر از ۱۰۰۰ تیک در ثانیه تنظیم کرده باشه.
۲. چند برنامهگی منجر شده باشه که هر ۱۰ میلی ثانیه بتونین تایم بگیرین (که بعید می دونم)
البته به نکته جالب اشاره کردین که اصلا خود من بهش دقت نکرده بودم.
اگر فرکانس داخل ویندوز ثابت باشه فکر کنم همون QueryPerformanceCounter بهترین گزینه برای اینکار باشه.
seyedof
جمعه 05 آذر 1389, 10:05 صبح
GetTickCount تعداد تیکهای میکروی PIT رو بر می گردوته. من توی یک راهنما خونده بودم که ویندوز تنظیم میکنه که pit توی هر ثانیه ۱۰۰۰ تیک (وقفه شماره صفر)رو تولید کنه. که البته توی ویرایشهای قدیمی ویندوز این مقدار ۲۰۰ بوده. اینکه شما داری هر ۱۰ میلی ثانیه جواب میگری ممکنه یکی از دو حالت زیر باشه:
۱. ویندوزتون PIT رو برای کمتر از ۱۰۰۰ تیک در ثانیه تنظیم کرده باشه.
۲. چند برنامهگی منجر شده باشه که هر ۱۰ میلی ثانیه بتونین تایم بگیرین (که بعید می دونم)
البته به نکته جالب اشاره کردین که اصلا خود من بهش دقت نکرده بودم.
اگر فرکانس داخل ویندوز ثابت باشه فکر کنم همون QueryPerformanceCounter بهترین گزینه برای اینکار باشه.
سلام
نه دقیقا همینطوره. حتی فکر کنم Mark Russinovich هم یه برنامه تست برای این نوشته بود. اوون لینکی که براتون فرستادم و مال خود msdn بود توی راهنمای این تابع این نکته رو صریحا گفته (قدیما ننوشته بودن).
ممنون علی
http://www.tochalco.com/blog
سپول
جمعه 05 آذر 1389, 10:43 صبح
تغییر فرکانس CPU ربطی به سیستم عامل نداره. مثلا میشه کدهایی نوشت که واسه بعضی کارها CPU رو overclock کرد. ( من خودم این کارو نکردم اما دیدم و خوندم ) بعضی از سیستمهای power management و power saver هم فرکانس CPU رو کم و زیاد می کنند.
اما نکته ای که باید بهش توجه کنیم اینه که وجود برنامه ای که فرکانس CPU رو تغییر بده و در مجموع احتمال بروز این موارد در حین اجرای یک بازی خیلی خیلی کمه و روی کنسول ها که اصلا بعید می دونم فرکانس CPU رو کسی تغییر بده و خود ماکروسافت هم تاکید کرده که سیستمش این کارو نمیکنه.
من خودم از timeGetTime استفاده میکنم و از به نظر شخصی خودم clock های high res تنها واسه تست performance واسه بعضی از tools هایی که مینویسیم بدرد می خوره :لبخند:
زمانی که به پیاده سازی فیزیک یا انیمیشن برسی احتمالا نظرت عوش می شه و از QueryPerformance.... استفاده می کنی.
kochol
جمعه 05 آذر 1389, 12:17 عصر
من دو سال پیش از این روش استفاده می کردم تایمینگم اشتباه حساب می شد.
الان از sdl timer استفاده می کنم نمی دونم دقتش چه قدر است
الان تو بازی vsync روشنه و فریم ریت بالای 60 نمی ره یعنی یه تایمر با دقت 1/60 ثانیه هم کافیه ایا درست می گم.
ایا با دستور
MMRESULT timeBeginPeriod(
UINT uPeriod
);
می شه دقت تایمر های ویندوز رو زیاد کرد
1485159
جمعه 05 آذر 1389, 12:34 عصر
من دو سال پیش از این روش استفاده می کردم تایمینگم اشتباه حساب می شد.
الان از sdl timer استفاده می کنم نمی دونم دقتش چه قدر است
الان تو بازی vsync روشنه و فریم ریت بالای 60 نمی ره یعنی یه تایمر با دقت 1/60 ثانیه هم کافیه ایا درست می گم.
ایا با دستور
MMRESULT timeBeginPeriod(
UINT uPeriod
);
می شه دقت تایمر های ویندوز رو زیاد کرد
والا اگه راستشو بخوای من که نمهمیدم می میگی!!!:لبخند:
سپول
شنبه 06 آذر 1389, 12:30 عصر
من دو سال پیش از این روش استفاده می کردم تایمینگم اشتباه حساب می شد.
الان از sdl timer استفاده می کنم نمی دونم دقتش چه قدر است
الان تو بازی vsync روشنه و فریم ریت بالای 60 نمی ره یعنی یه تایمر با دقت 1/60 ثانیه هم کافیه ایا درست می گم.
ایا با دستور
MMRESULT timeBeginPeriod(
UINT uPeriod
);
می شه دقت تایمر های ویندوز رو زیاد کرد
به فرض انیمشن ای که شما وارد می کنید دقتش 30fps هست، اما فریم ریت بازی شما بالا یا پایین می شه، در این مواقع انیمیشن رو interpolate هم می کنند، یعنی بین دو فریم از انیمیشن یک عمل lerp یا Slerp بر حسب زمان صورت می گیره، که برای اینکار زمان باید دقیق باشه.
مثلا اگر فریم اول انیمشن در تایم 1.0 آپدیت شده، فریم دوم در تایم 1.23235 آپدیت می شه. هر چی این مقدار دقیق تر باشه عملیات فیزیک و lerp در انیمیشن دقیق تر هستند و هر چی کم دقت تر باشه انیمیشن ها و حرکان فیزیک در جاهایی که تفاوت دقت زیاد می شه حالت blocky و پرشی پیدا می کنه.
حالا اگه به نظرتون نمیاد و مهم نیست استفاده timeGetTime مشکلی نداره، ولی کلا در سیستم های انیمیشن و بازی ها از timer های دقت بالا استفاده می کنند به خاطر همین چیزا. فرق خاصی هم از نظر استفاده ندارن
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.