دليل عملي لتحقيق soft real-time قدر الإمكان على Windows العادي

· آخر تحديث: · · تطوير Windows, Soft Real-Time, التصميم, القياس

سجل التعديلات (2 تحديثات، آخر تحديث 2 Sep، 2026)

سجل بالتغييرات التي أُجريت على هذا المقال. وحيثما حُفظت نسخة سابقة، تبقى متاحة للقراءة عبر رابط دائم يحمل معرّف DOI.

أُعيدَت الترجمة العربية كترجمة كاملة عن النص الياباني الأصلي، وأُضيفَت خريطة المعرفة.
أعيدت الترجمة كترجمة كاملة عن النص الياباني الأصلي. كانت النسخة العربية السابقة مختصراً يسقط أبواباً وجداول ورسوم Mermaid وتعليقات الأشكال وFAQ. أُعيدت هذه العناصر وفق الأصل الياباني، والادّعاءات التقنية مطابقة للنسخة اليابانية.
النشر الأول
الاستشهاد بهذا المقال(DOI: 10.5281/zenodo.21621315)

هذا المقال محفوظ على Zenodo. يرد أدناه معرّف DOI الذي يشير دائمًا إلى أحدث نسخة، ومعرّف DOI المثبَّت على النسخة التي تقرؤها.

小村 豪 (2026). دليل عملي لتحقيق soft real-time قدر الإمكان على Windows العادي. شركة كومورا سوفت ذ.م.م.. https://doi.org/10.5281/zenodo.21621315 https://comcomponent.com/ar/blog/2026/03/09/000-windows-soft-realtime-practical-guide-natural/

DOI (أحدث نسخة)
10.5281/zenodo.21621315
DOI (هذه النسخة)
10.5281/zenodo.22240803

حين تصنع على Windows معالجة «يضرّها التأخير» مثل المعالجة الدوريّة والصوت والصورة والقياس والتحكّم بالأجهزة، يشيع الانطباع أنّ «Windows صعب هنا». هذا الانطباع نصف صحيح ونصف خاطئ: Windows ليس نظام hard real-time، لكن إن أحكمت التصميم والتنفيذ والقياس والتشغيل وصلت إلى حالة عمليّة جدّاً كـ soft real-time.

ما يعالجه هذا المقال هو Windows 10 / 11 العادي، بلا امتداد RTOS خاص ولا برنامج تشغيل نواة مخصّص ولا متحكّم مستقل. الحديث عملي: إلى أيّ حد يمكن ضغط التأخير والـ jitter في تطبيق user-mode على حاسوب مكتبي أو محمول عادي. تختلف التفاصيل بين الصوت والصورة والتحكّم الدوري والحصول على البيانات، لكنّ المواضع التي تضيق متقاربة كثيراً، لذلك جمعت الجزء المشترك هنا في شكل قائمة فحص.

القرّاء المستهدفون ولغة أمثلة الشيفرة

المقال موجَّه إلى من يصنع على Windows معالجة «يضرّها التأخير» (تحكّم دوري، صوت وصورة، قياس، تحكّم بأجهزة). المفترض تطوير تطبيق user-mode، وتنفيذ برامج تشغيل وضع النواة خارج النطاق.

تتقسّم لغة الأمثلة كالتالي.

المحتوى اللغة الموضع
الحلقة الدوريّة و MMCSS و QoS الطاقة وغيرها ممّا يستدعي Win32 API مباشرة C++ (Win32) 4.1، 4.3، 4.5
طريقة استدعاء Win32 API نفسه من C# C# (P/Invoke) 4.5
قياس الوقت و GC وملاحظات التخصيص .NET (C#) فقرة «فحص جانب .NET» في 4.4، و 5.2

حديث الأسباب حتّى الفصل 3، وجسم قائمة الفحص في الفصل 4، لا يعتمد على اللغة. إن كنت تستخدم C# فقط، فاقرأ شيفرة C++ كشرح لـ «أيّ API يُستدعى وبأيّ ترتيب».

المحتويات

  1. الخلاصة أوّلاً (في جملة)
    • 1.1. جدول سريع حسب نطاق الدورة (من أين تبدأ القراءة)
  2. ماذا يعني «soft real-time» على Windows العادي
    • 2.1. «Windows العادي» في هذا المقال
    • 2.2. ما الذي يمكن، ومن أين يصعب الأمر
    • 2.3. المصطلحات في جملة أوّلاً
  3. الأسباب الرئيسة للتأخير والـ jitter
    • 3.1. المجدول والأولويّة
    • 3.2. DPC / ISR وبرامج التشغيل
    • 3.3. page fault والذاكرة
    • 3.4. دقّة المؤقّت وإدارة الطاقة
    • 3.5. انتقال النواة والحرارة
  4. قائمة فحص عمليّة لتقليل التأخير على Windows العادي
    • 4.1. الحلقة الدوريّة وطريقة الانتظار
    • 4.2. fast path / slow path وطابور ثابت الطول
    • 4.3. الأولويّة / MMCSS / background mode
    • 4.4. الذاكرة / GC / تكلفة المرّة الأولى
    • 4.5. إعدادات الطاقة / EcoQoS / timer resolution
    • 4.6. توزيع CPU / انتقال النواة / الحرارة
    • 4.7. برامج التشغيل / DPC / ISR / فصل الاضطراب الخارجي
  5. القياس والتقييم
    • 5.1. ماذا تسجّل
    • 5.2. قراءة p99 / p99.9 / max
    • 5.3. بماذا تنظر
    • 5.4. أسلوب الاختبار
  6. تقسيم تقريبي للاستخدام
  7. الخلاصة
  8. مراجع

في المخطّط، يشير الخطّ المتّصل إلى علاقة قائمة دائماً، ويشير الخطّ المتقطّع إلى علاقة مشروطة (شروط قيامها مذكورة في شرح كلّ علاقة في الصفحة التفصيليّة). القائمة الكاملة للعلاقات (المجموع 20، مع الأدلّة ودرجة اليقين) وتعريفات المفاهيم الرئيسة مجمّعة في صفحة تفاصيل خريطة المعرفة (باليابانية). البيانات: JSON-LD / Turtle

1. الخلاصة أوّلاً (في جملة)

  • ما يُستهدف على Windows العادي ليس ضمان hard real-time، بل تكوين soft real-time «يصعب تأخيره، وإن تأخّر لا ينكسر».
  • أكبر أثر هو جعل المسار الساخن قصيراً وثابت الطول وغير حاجب.
  • افصل fast path (الحصول / التحكّم) عن slow path (الحفظ / الاتّصال / واجهة المستخدم)، وصِلهما بطابور ثابت الطول.
  • لا تترك الحلقة الدوريّة لـ Sleep(1)، بل أدِرها بأجل مطلق.
  • في تيّار مستمر مثل الصوت والصورة، انظر أوّلاً في MMCSS.
  • لقياس الوقت استخدم QueryPerformanceCounter (QPC)، وفي .NET Stopwatch.
  • قدّم في الانتظار حدث الجهاز أو waitable timer عالي الدقّة (مؤقّت قابل للانتظار).
  • استخدم timeBeginPeriod للمدّة اللازمة فقط. لا تصمّم على افتراض أنّه دائم التشغيل.
  • في التشغيل الفعلي ينفع التيار المتردّد / وضع الطاقة / التعامل مع EcoQoS / ترتيب الحمل في الخلفيّة.
  • لا تقيّم بالمتوسّط وحده، بل بـ p99 (الحدّ الذي يبدأ عنده ظهور المرّة الأبطأ من 100) / p99.9 / max / عدد الـ miss / DPC / ISR / page fault / عمق الطابور.

بعبارة أخرى، على Windows العادي ينفع تقليل أسباب التأخير بالتصميم أكثر من رفع الأولويّة. الأولويّة وإعدادات الطاقة مهمّة، لكنّها وحدها لا تصنع الثبات.

الثبات يُصنع بالتصميم لا بالأولويّةيبيّن الخلاصة أنّ أكبر أثر هو جعل المسار الساخن قصيراً وثابت الطول وغير حاجب لتقليل أسباب التأخير من التصميم، وأنّ ضبط الأولويّة والطاقة مهمّ لكنّه وحده لا يكفي لصنع الثبات.مسار ساخن قصير وثابت الطولأسباب التأخير تقلّ من التصميمتكوين يصعب تأخيره وإن تأخّر لا ينكسرضبط الأولويّة وإعدادات الطاقةمهمّ لكنّه وحده لا يكفي

الشكل 1: أكبر أثر ليس ضبط الأولويّة، بل تقليل أسباب التأخير نفسها بالتصميم.

1.1. جدول سريع حسب نطاق الدورة (من أين تبدأ القراءة)

المقال طويل، لذا نضع أوّلاً جدولاً سريعاً لتقرأ الصفّ الذي يطابق حالتك فقط. كان هذا المحتوى في النهاية (الفصل 6) فنُقل إلى هنا.

الدورة والمتطلّب التكوين الذي تبنيه أوّلاً الفقرات التي تُقرأ بتركيز
فئة 10 إلى 20ms، ويمكن امتصاص اهتزاز عابر فصل fast path / slow path، طابور ثابت الطول، أولويّة عاديّة إلى أعلى قليلاً، تحريك بالأحداث. كثيراً ما يكفي هذا 4.1، 4.2
فئة 1 إلى 5ms، وتريد اللحاق باستمرار بالإضافة إلى ما سبق: مسار ساخن بلا تخصيص، خيط مخصّص، MMCSS أو ضبط أولويّة حذر، waitable timer عالي الدقّة، مراجعة التيار المتردّد وإعدادات الطاقة 4.1 إلى 4.5
الاقتراب من أقل من 1ms، ولا تريد الفوات حتّى مع تشغيل طويل وحمل عالٍ تطبيق user-mode وحده على Windows العادي صعب جدّاً. انظر أوّلاً في تصميم يُخرج الجزء الحرج إلى موضع آخر (برمجيّة الجهاز، متحكّم مخصّص، FPGA، RTOS) 2.2، 6
تريد إيواء واجهة المستخدم والسجلّ والاتّصال وقاعدة البيانات كلّها معاً لا تحتضن «كلّ شيء في عمليّة واحدة وحلقة واحدة». فصل المسؤوليّات. مقتضيات المرحلة اللاحقة تفسد أجل المرحلة السابقة بسهولة 4.2، 4.3، 6

فصل الأسباب وأسلوب القياس مشتركان لكلّ نطاق (الفصل 3 والفصل 5).

2. ماذا يعني «soft real-time» على Windows العادي

2.1. «Windows العادي» في هذا المقال

Windows العادي هنا يفترض تقريباً ما يلي.

  • حاسوب مكتبي أو محمول شائع بـ Windows 10 / 11
  • بلا امتداد RTOS مخصّص
  • بلا تطوير برنامج تشغيل وضع نواة مخصّص
  • تطبيق user-mode عادي
  • الضبط بواجهات Windows وإعداداته العامّة

أي أنّ الحديث ليس «بناء جهاز مخصّص بالكامل للتحكّم في الوقت الحقيقي»، بل «إلى أيّ حد يمكن الضغط واقعيّاً على حاسوب Windows عادي».

حاسوب Windows 10 / 11 عاديتطبيق user-modeاستهداف soft real-timeخفض التأخيرتصغير الـ jitterرصد deadline miss بحيث لا ينكسر النظامأريد ضمان صفر مخالفات للأجلRTOS / متحكّم مخصّص / FPGA / معالجة في الجهاز

الشكل 2: ما يُستهدف في تطبيق user-mode على Windows العادي هو soft real-time، وضمان صفر مخالفات للأجل مجال RTOS ونحوه.

2.2. ما الذي يمكن، ومن أين يصعب الأمر

حتّى على Windows العادي يمكن، في معالجات مثل هذه، صنع حالة «يصعب تأخيرها» بواقعيّة كبيرة.

  • معالجة دوريّة بفترة من بضعة ملّي ثانية إلى عشرات الملّي ثانية
  • تحريك الصوت / الصورة بالـ buffer
  • حلقة الحصول من حسّاس والتحكّم
  • معالجة دوريّة ثابتة بطابع PLC برمجي
  • خط أنابيب منخفض التأخير يعمل في خيط منفصل عن واجهة المستخدم

غير أنّ «يمكن» هنا لا يعني تصفير قفزات التأخير العابرة تماماً؛ المستهدف هو هذه الحالة فحسب.

  • خفض التأخير في التشغيل العادي
  • تصغير الـ jitter
  • ألّا ينكسر النظام إن فات الأجل أحياناً
  • أن يمكن رصد واقعة الفوات

بالمقابل، مع متطلّبات كهذه يصعب كثيراً الاكتفاء بـ user-mode على Windows العادي.

  • ضمان صفر مخالفات للأجل
  • الالتزام بأقل من مئات الميكروثانية بثبات طويل
  • الإيواء مع واجهة مستخدم ثقيلة وشبكة وتخزين
  • المضي مع تفضيل البطارية وتوفير الطاقة
  • عدم احتمال قفزات آتية من برنامج تشغيل أو جهاز

هنا أأمن أن تنظر في نقل الجزء الصارم زمنيّاً فقط إلى برمجيّة الجهاز أو متحكّم مخصّص أو FPGA أو RTOS.

الحالة المستهدَفة في soft real-time وحكم الإخراجيبيّن أنّ المستهدف على Windows العادي خفض التأخير العادي وتصغير الـ jitter وحالة لا ينكسر فيها النظام إن فات الأجل مع إمكان رصد الفوات، وأنّ المتطلّبات الصارمة مثل صفر مخالفات للأجل تُخرَج في الجزء الصارم زمنيّاً فقط إلى الخارج.الحالة المستهدَفة في soft real-timeخفض التأخير في التشغيل العاديتصغير الـ jitterإن فات الأجل لا ينكسر ويمكن الرصدمتطلّب صفر مخالفات للأجلالنقل إلى الجهاز أو RTOS

الشكل 3: مضمون «يمكن» ليس صفر قفزات، بل حالة يصعب تأخيرها ولا تنكسر ويمكن رصدها.

2.3. المصطلحات في جملة أوّلاً

نضبط أوّلاً معنى المصطلحات الواردة في هذا المقال.

المصطلح في جملة كيف يُرى في العمل
soft real-time تأخير عابر ممكن، لكنّك تصغّر التأخير وتصمم بحيث لا ينكسر النظام إن تأخّر هذا أوّل ما يُستهدف على Windows العادي
hard real-time عالم يريد ضمان صفر مخالفات للأجل ليس هدفاً لتطبيق user-mode وحده على Windows العادي
jitter اهتزاز الدورة أو زمن الاستجابة حتّى مع متوسّط جيّد، jitter كبير يعني عدم ثبات في التشغيل
deadline miss عدم انتهاء المعالجة بحلول الوقت المقرّر لا تُخفِه؛ عُدّه وأخرجه إلى السجلّ
p99 / p99.9 مؤشّر ينظر إلى ذيل الجانب البطيء p99 هو «الحدّ الذي يبدأ عنده ظهور المرّة الأبطأ من 100»
DPC / ISR معالجة جانب النواة حول برنامج التشغيل والمقاطعة إن طالت انتظر خيط user-mode
MMCSS آليّة Windows لتوزيع CPU على معالجة حسّاسة للوقت مثل الصوت / الصورة قوي حين لا تريد نضوب الـ buffer
QPC QueryPerformanceCounter أساس قياس الزمن المنقضي. عدّاد عالي الدقّة لا ساعة حائط
waitable timer (مؤقّت قابل للانتظار) كائن نواة يصبح signaled في وقت معيّن. إضافة CREATE_WAITABLE_TIMER_HIGH_RESOLUTION إلى CreateWaitableTimerExW تجعله نسخة عالية الدقّة أنسب كأساس لانتظار الدورة من Sleep (4.1)
EcoQoS حالة مصنَّفة «يجوز تفضيل توفير الطاقة». تُخفَّض تردّدات CPU أو يُزاح العمل إلى نوى أوفر طاقة تجنّبه في المعالجة الحسّاسة للوقت. إن لم تصرّح، خمّن نظام التشغيل تلقائيّاً (4.5)
IGNORE_TIMER_RESOLUTION تعيين يجيز تجاهل طلب دقّة مؤقّت العمليّة (PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION) إن فُعِّل اختفى أثر timeBeginPeriod. على Windows 11 قد يُطبَّق تلقائيّاً عند اختفاء النافذة (4.5)
CPU Sets آليّة تعيّن بلين أنّ الخيط أو العمليّة «يفضَّل تشغيلها على هذه المجموعة من النوى» جرّبها قبل التثبيت على نواة معيّنة (4.6)
ETW / WPR / WPA بنية التتبّع القياسيّة في Windows (ETW) وأداة التسجيل (WPR) وواجهة التحليل (WPA) تُستخدم عند حفر context switch و DPC / ISR و page fault (5.3)
LatencyMon أداة طرف ثالث لرؤية التأخير الآتي من برامج التشغيل لالتقاط أوّلي لزمن تنفيذ DPC / ISR حسب برنامج التشغيل (5.3)

3. الأسباب الرئيسة للتأخير والـ jitter

حين تتأخّر المعالجة الدوريّة على Windows العادي، تصل في الغالب إلى أحد فروع هذا المخطّط.

المعالجة الدوريّة تتأخّرالمجدول / الأولويّةDPC / ISR / برنامج التشغيلpage fault / الذاكرةدقّة المؤقّت / إدارة الطاقةانتقال النواة / الحرارة

الشكل 4: أسباب تأخير المعالجة الدوريّة تصل إلى خمسة مسارات: المجدول، DPC/ISR، الذاكرة، المؤقّت والطاقة، وانتقال النواة والحرارة.

3.1. المجدول والأولويّة

خيوط Windows يُحدَّد ترتيب تنفيذها بالأولويّة. بنفس الأولويّة تدور round-robin، وإذا صار خيط أعلى أولويّة قابلاً للتنفيذ أُزيح الخيط الأدنى.

أي أنّك حتّى إن كتبت خيط الدورة بعناية، من الشائع أن يسبقك:

  • خيط آخر
  • عمليّة أخرى
  • معالجة داخليّة لنظام التشغيل
  • منتج أمني
  • معالجة مساعدة للجهاز
  • مزامنة في الخلفيّة
الإزاحة بجدولة الأولويّةيبيّن أنّ الخيوط بنفس الأولويّة تدور round-robin بالترتيب، وإذا صار خيط أعلى أولويّة قابلاً للتنفيذ أُزيح الأدنى، لذا من الشائع أن تجري عمليّة أخرى أو معالجة داخليّة لنظام التشغيل قبل خيط الدورة.نفس الأولويّة فيما بينهاالدوران round-robin بالترتيبأولويّة أعلى تصبح قابلة للتنفيذالأولويّة الأدنى تُزاحعمليّة أخرى أو معالجة داخليّة لنظام التشغيل وغيرها

الشكل 5: حتّى إن كتبت خيط الدورة بعناية، من الشائع أن يجري عمل أعلى أولويّة أوّلاً.

3.2. DPC / ISR وبرامج التشغيل

هذا مهمّ جدّاً. حتّى إن رتّبت أولويّة التطبيق، إن طال DPC (Deferred Procedure Call) أو ISR (Interrupt Service Routine)، لا يستطيع خيط user-mode التنفيذ في تلك الأثناء.

الأجهزة وبرامج التشغيل التي يسهل أن تكون سبباً تقريباً هذه.

  • USB
  • Wi-Fi / Bluetooth
  • التخزين
  • الصوت
  • GPU
  • ACPI / محيط الطاقة

حتّى إن لم تكن شيفرة التطبيق سيّئة، قد تُوقَف لمقتضيات برنامج التشغيل أو العتاد. إن ظننت هنا أنّ «رفع أولويّة التطبيق أكثر سينتصر»، تأذّيت في الغالب.

كيف يوقف DPC و ISR تنفيذ user-modeيبيّن أنّ ISR و DPC، معالجة مقاطعة أجهزة وبرامج تشغيل مثل USB و Wi-Fi و GPU، إن طالت لا يستطيع خيط user-mode التنفيذ في تلك الأثناء، وأنّ رفع أولويّة التطبيق لا ينتصر.أجهزة مثل USB و Wi-Fi و GPUISR أو DPC يجري في جانب النواةفي تلك الأثناء لا ينفَّذ user-modeرفع الأولويّة لا ينتصر

الشكل 6: حتّى إن لم تكن شيفرة التطبيق سيّئة، يُوقَف user-mode لمقتضيات برنامج التشغيل أو العتاد.

3.3. page fault والذاكرة

إن وقع page fault في المسار الساخن (الصفحة اللازمة ليست في الذاكرة فيُذهَب لجلبها)، كبر التأخير دفعة واحدة.

أنماط يُفضَّل تجنّبها خصوصاً.

  • commit الصفحة عند أوّل وصول
  • التحميل الكسول
  • page-in لملفّ معيَّن في الذاكرة
  • تخصيص ديناميكي أكثر من اللازم
  • كائنات كبيرة أو كومة مجزّأة

في جسم المعالجة الدوريّة يكفي تقريباً أن تخصّص الذاكرة اللازمة مسبقاً وتلمسها مرّة عند البدء.

التأخير بـ page fault في المسار الساخنيبيّن أنّ لمس صفحة في المسار الساخن إن لم تكن في الذاكرة يؤدّي إلى جلبها بـ page fault فيكبر التأخير دفعة واحدة، لذا يحسن تخصيص الذاكرة مسبقاً ولمسها مرّة عند البدء.نعملالمس الذاكرة في المسار الساخنهل الصفحة في الذاكرة؟المضي كما هوالجلب بـ page faultالتأخير يكبر دفعة واحدةالتخصيص مسبقاً واللمس مرّة عند البدء

الشكل 7: التأخير يقفز بحسب وقوع page fault. الإجراء تخصيص مسبق وإحماء عند البدء.

3.4. دقّة المؤقّت وإدارة الطاقة

«أريد التشغيل كلّ 1ms لذا Sleep(1)» لا ينجح في معظم الحالات. دقّة الانتظار في Windows تتأثّر بدقّة المؤقّت والجدولة وحالة الطاقة.

ثمّ إنّ إعداد رفع دقّة المؤقّت قد يحسّن دقّة الانتظار قليلاً، لكن له آثاراً جانبيّة على استهلاك الطاقة وسلوك النظام بأكمله؛ هذا أيضاً لا يُغفَل.

3.5. انتقال النواة والحرارة

إذا انتقل الخيط بين النوى، لزم إعادة تسخين الذاكرة المؤقّتة. نظام التشغيل كثيراً ما يعالج هذا جيّداً، لكن في بيئة حمل عالٍ يصير سبباً للاهتزاز.

ثمّ إنّ الحرارة لا تُهمَل عند التشغيل الطويل. إن دخل thermal throttling، قد تنهار دورة كانت ثابتة.

مسار انهيار الدورة بانتقال النواة والحرارةيبيّن أنّ انتقال الخيط بين النوى يعيد تسخين الذاكرة المؤقّتة فيصير سبباً للاهتزاز في بيئة حمل عالٍ، وأنّ تراكم الحرارة في التشغيل الطويل يدخل thermal throttling فتنهار دورة كانت ثابتة.انتقال الخيط بين النوىإعادة تسخين الذاكرة المؤقّتةسبب اهتزاز في بيئة حمل عالٍتراكم الحرارة في تشغيل طويلthermal throttlingانهيار دورة كانت ثابتة

الشكل 8: انتقال النواة ينحت الثبات كـ jitter، والحرارة كـ throttling، في التشغيل الطويل.

4. قائمة فحص عمليّة لتقليل التأخير على Windows العادي

من هنا الجزء العملي. نرتّب مقابل الأسباب في الفقرات السابقة، في شكل قائمة فحص، ماذا تؤكّد على Windows العادي، وماذا تتجنّب، وماذا تقرّر أوّلاً.

4.1. الحلقة الدوريّة وطريقة الانتظار

النمط المضادّ النموذجي أوّلاً هو هذا.

while (running)
{
    Sleep(1);
    Step();
}

هذه ليست «دورة 1ms»، بل حلقة تنتظر نحو 1ms أو أكثر ثمّ تضيف فوق ذلك زمن تنفيذ Step(). ثمّ يتراكم تجاوز الانتظار كما هو.

على أساس أجل مطلقعلى أساس زمن نسبيWaitUntil(next - margin)next += periodspin قصير إن لزمFastStep()Step()Sleep(1)خطأ الانتظار وزمن التنفيذ يتراكمان تدريجيّاًيصعب تراكم الانحراف

الشكل 9: حلقة الزمن النسبي المعتمدة على Sleep(1) تراكم الخطأ، والحلقة المدارة بأجل مطلق يصعب عليها تراكم الانحراف.

قائمة فحص

  • الحلقة الدوريّة ليست مبنيّة على Sleep(1)
  • الدورة تُدار بأجل مطلق next += period
  • الانتظار يقدّم حدث الجهاز أو waitable timer (مؤقّت قابل للانتظار)
  • الضبط الأخير محصور في busy-spin قصير جدّاً (انتظار بإدارة فارغة)
  • timeBeginPeriod يُستخدم للمدّة اللازمة فقط ثمّ يُعاد
  • السلوك مؤكَّد أيضاً في حالة التصغير / الإخفاء / عدم الظهور

الحلقة الدوريّة أثبت حين تُدار بأجل مطلق لا بزمن نسبي.

int64_t next = QpcNow() + periodTicks;

while (running)
{
    WaitUntil(next - wakeMarginTicks);

    while (QpcNow() < next)
    {
        CpuRelax(); // 最後だけ短く spin
    }

    int64_t started = QpcNow();
    FastStep();
    int64_t finished = QpcNow();

    RecordTiming(next, started, finished);

    next += periodTicks;

    while (finished > next)
    {
        ++missedDeadlines;
        next += periodTicks;
    }
}

4.2. fast path / slow path وطابور ثابت الطول

أساس التكوين: ضع في fast path «العمل الحسّاس للأجل» فقط، وأخرج سواه إلى slow path.

الجهاز / حدث الحصولfast path: الحصول والتحكّم ونسخ أدنىطابور ثابت الطولslow path: الحفظ والإرسال وواجهة المستخدم والتجميعتسجيل lateness / miss / عمق الطابور

الشكل 10: التكوين الأساسي: عمل حسّاس للأجل فقط في fast path، وطابور ثابت الطول في الوسط، ثمّ الإخراج إلى slow path.

ضيّق ما يُفعل في fast path إلى هذا القدر.

  • الحصول على البيانات
  • حساب قيمة التحكّم
  • النسخ الأدنى اللازم
  • الطابع الزمني
  • الإدخال في الطابور
  • تسجيل miss / overrun

أسقط سواه إلى slow path.

قائمة فحص

  • المسار الساخن لا يكتب ملفّات ولا يرسل على الشبكة ولا يكتب قاعدة بيانات
  • المسار الساخن لا يخرج سجلاً ثقيلاً ولا Flush ولا RPC متزامناً
  • fast path / slow path مفصولان بوضوح بالخيط أو بالمسؤوليّة
  • الطابور ثابت الطول
  • سياسة امتلاء الطابور مقرّرة مسبقاً
  • عدد الـ miss وعدد الـ drop وعمق الطابور مرصودة
  • تحديث واجهة المستخدم وتجميع السجلّ مفصولان إلى دورة أدنى

عند امتلاء الطابور، أأمن ألّا تُبقِي السياسة غامضة.

القيمة الأحدث مهمّةكلّ العناصر مهمّةلغرض السجلّالطابور ممتلئماذا تحمي؟ارمِ القديم وأبقِ الأحدثتنبيه / إيقاف / تحكّم في المنبعأسقط القديم وسجّل عدد الـ drop فقط

الشكل 11: ماذا تحمي عند امتلاء الطابور يُقرَّر مسبقاً حسب الغرض.

4.3. الأولويّة / MMCSS / background mode

أساس الأولويّة: لا ترفع الكلّ. على Windows العادي ينجح أكثر أن «ترفع الخيط المهمّ فقط، وتخفض عمل الخلف بوضوح». background mode آليّة تعامل لا CPU وحده بل موارد مثل I/O أيضاً بميل إلى أولويّة أدنى.

فصل العملخيط حسّاس للأجلالحفظ / الإرسال / الضغط / التجميعواجهة المستخدمأولويّة أعلى إن لزم أو MMCSSbackground mode / أولويّة أدنىأولويّة عاديّةلا تبدأ من REALTIME_PRIORITY_CLASS

الشكل 12: طريقة توزيع الأولويّة: ارفع الخيط الحسّاس للأجل فقط، واخفض عمل الخلف بوضوح.

قائمة فحص

  • ليست كلّ الخيوط مرتفعة الأولويّة
  • الرفع للخيط الصارم زمنيّاً حقّاً فقط
  • عمل الخلف مثل الحفظ والإرسال والضغط والمزامنة مُسقَط إلى background mode
  • في معالجة buffer مستمرّة مثل الصوت والصورة والالتقاط والتشغيل يُنظَر في MMCSS
  • التفكير بوحدة الخيط أوّلاً لا بالعمليّة بأكملها
  • REALTIME_PRIORITY_CLASS لا يُستخدم حتّى تتّضح الضرورة

MMCSS (Multimedia Class Scheduler Service) ينفع خصوصاً في معالجة مثل الصوت / الصورة «تريد ملء الـ buffer خلال زمن معيّن». أوفق لتصميم Windows من إدارة خيط عالي الأولويّة باستمرار.

طابع الشيفرة كهذا.

DWORD taskIndex = 0;
HANDLE avrt = AvSetMmThreadCharacteristicsW(L"Pro Audio", &taskIndex);
if (!avrt)
{
    throw std::runtime_error("AvSetMmThreadCharacteristicsW failed");
}

// 時間に敏感なループを回す

if (!AvRevertMmThreadCharacteristics(avrt))
{
    throw std::runtime_error("AvRevertMmThreadCharacteristics failed");
}
تسجيل الخيط في MMCSS وإلغاؤهيبيّن التدفّق: التسجيل في MMCSS بـ AvSetMmThreadCharacteristicsW قبل الحلقة الحسّاسة للوقت، ثمّ الإعادة بـ AvRevertMmThreadCharacteristics بعد انتهائها، وأنّ MMCSS يوزّع CPU تفضيليّاً على المعالجة الحسّاسة للوقت.AvSetMmThreadCharacteristicsWإدارة الحلقة الحسّاسة للوقتAvRevertMmThreadCharacteristicsMMCSS يوزّع CPU تفضيليّاً

الشكل 13: MMCSS يُستخدم كزوج تسجيل وإلغاء. في معالجة buffer مستمرّة أوفق لتصميم Windows من الإدارة المستمرّة بأولويّة عالية.

4.4. الذاكرة / GC / تكلفة المرّة الأولى

إن استخدمت في المسار الساخن كلّ دورة new / malloc / List<T>.Add / ربط سلاسل / LINQ، ظهرت مقتضيات الجمع وإعادة الترتيب يوماً ما. GC (تجميع البيانات المهملة) نفسه ليس سيّئاً، لكن إن كتبت شيفرة كثيرة التخصيص ظهر أثر ذلك كـ jitter.

البدءتخصيص الـ buffers اللازمةلمسها مرّة لتسخين الصفحاتإنهاء JIT / تحميل DLL / I/O المرّة الأولىبعد ذلك القياس الفعلي / التشغيل الفعلي

الشكل 14: عند البدء أنهِ تخصيص الـ buffer وتسخين الصفحات وتكلفة المرّة الأولى، ثمّ ادخل القياس والتشغيل الفعليّين.

قائمة فحص

  • المسار الساخن لا يخصّص / يحرّر ذاكرة كلّ دورة
  • الـ buffers اللازمة مخصَّصة مسبقاً عند البدء
  • لمسها مرّة عند البدء لتسخين الصفحات
  • JIT المرّة الأولى وتحميل DLL المرّة الأولى و I/O المرّة الأولى ليست مخلوطة في القياس الفعلي
  • لا تُربَّى في الحلقة بنى ضخمة أو سجلّ متغيّر الطول
  • حتّى إن استُخدم VirtualLock فللمنطقة الحرجة الصغيرة جدّاً فقط

فحص جانب .NET

  • قياس الوقت بـ Stopwatch / Stopwatch.GetTimestamp()
  • المسار الساخن بلا LINQ ولا ربط سلاسل ولا ToString() ولا توليد سجلّ ضخم
  • async/await غير مُدخَل إلى hot path
  • التقييم مفصول قبل الإحماء وبعده

4.5. إعدادات الطاقة / EcoQoS / timer resolution

هذا متواضع المظهر لكنّه ينفع. حتّى إن ضغطت الشيفرة، إن قوي ضبط الطاقة الأعلى لم تستقرّ النتائج.

محيط الطاقة في Windows العاديالتشغيل على تيار متردّدوضع الطاقة: أقرب إلى أفضل أداءخطّة طاقة مخصّصة للإنتاج إن لزمتجنّب EcoQoS للعمليّة الحسّاسة للوقتتأكيد التعامل مع طلب دقّة المؤقّت

الشكل 15: نقاط التأكيد في محيط الطاقة. التغذية، وضع الطاقة، EcoQoS، والتعامل مع طلب دقّة المؤقّت.

قائمة فحص

  • تقييم الإنتاج يُجرى أوّلاً على تيار متردّد
  • [الإعدادات] > [النظام] > [الطاقة والبطارية] > [وضع الطاقة] أقرب إلى أفضل أداء
  • battery saver / وضع تفضيل التوفير غير مستخدم أثناء التشغيل
  • أوضاع الهدوء / eco / تفضيل البطارية في أدوات البائع مُراجَعة
  • العمليّة الحسّاسة للوقت ليست EcoQoS (QoS يميل إلى التوفير) عن غير قصد
  • IGNORE_TIMER_RESOLUTION غير مفعَّل في جانب العمليّة الحسّاسة للوقت
  • تأكيد أنّ أثر طلب دقّة المؤقّت لا يتغيّر عند التصغير / الإخفاء
  • إعدادات الطاقة مفصولة بين الاستخدام اليومي والإنتاج / القياس / العرض

timeBeginPeriod ينفع إن استُخدم بترتيب، لكنّه ليس علاجاً لكلّ شيء.

  • استدعِه قبيل الحاجة
  • بعد الانتهاء أعد بـ timeEndPeriod
  • من Windows 10 version 2004 فصاعداً لم يعد السلوك عالميّاً تماماً كما كان قديماً
  • على Windows 11، إن اختفت عمليّة ذات نافذة تماماً / صُغِّرت / لم تُرَ / لم تُسمَع، قد لا تُضمَن الدقّة العالية
  • رفع الدقّة لا يرفع دقّة QPC نفسها

إن اشتبهت بأثر الطاقة أو QoS، أكّد حالة power throttling بـ SetProcessInformation.

PROCESS_POWER_THROTTLING_STATE state{};
state.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION;
state.ControlMask =
    PROCESS_POWER_THROTTLING_EXECUTION_SPEED |
    PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION;
state.StateMask = 0; // HighQoS(性能優先寄り) + タイマ分解能要求を尊重

if (!SetProcessInformation(
        GetCurrentProcess(),
        ProcessPowerThrottling,
        &state,
        sizeof(state)))
{
    throw std::runtime_error("SetProcessInformation failed");
}

ControlMask هو «أيّ آليّة تتحكّم فيها بنفسك»، و StateMask هو «تشغيل تلك الآليّة أو إيقافها». المثال أعلاه اختار آليّتين للتحكّم ثمّ أوقف كلتيهما. أي أنّه تصريح ألّا تُسقَط إلى EcoQoS (ميل HighQoS) وألّا يُتجاهَل طلب دقّة المؤقّت. بالمقابل إن جعلت ControlMask يساوي 0 عادت كلتاهما إلى نظام التشغيل (السلوك الافتراضي).

دور القناعين في إعداد power throttlingيبيّن أنّ اختيار الآليّة التي تتحكّم فيها بـ ControlMask ثمّ تقرير تشغيلها أو إيقافها بـ StateMask يصرّح بعدم الإسقاط إلى EcoQoS وبعدم تجاهل طلب دقّة المؤقّت.اختيار موضوع التحكّم بـ ControlMaskتقرير التشغيل والإيقاف بـ StateMaskتصريح بعدم الإسقاط إلى EcoQoSعدم تجاهل طلب دقّة المؤقّتControlMask بصفر يعيد الأمر إلى نظام التشغيل

الشكل 16: دور قناعي SetProcessInformation. اختر موضوع التحكّم ثمّ صرّح بالتشغيل / الإيقاف.

عند الاستدعاء من C#

لإنجاز الأمر نفسه من C#، يكون تصريح P/Invoke هكذا.

// C# / .NET 8
using System.Runtime.InteropServices;

internal static class PowerQos
{
    [StructLayout(LayoutKind.Sequential)]
    private struct PROCESS_POWER_THROTTLING_STATE
    {
        public uint Version;
        public uint ControlMask;
        public uint StateMask;
    }

    private const uint PROCESS_POWER_THROTTLING_CURRENT_VERSION = 1;
    private const uint PROCESS_POWER_THROTTLING_EXECUTION_SPEED = 0x1;
    private const uint PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION = 0x4;

    // PROCESS_INFORMATION_CLASS の 5 番目(0 起算で 4)が ProcessPowerThrottling
    private const int ProcessPowerThrottling = 4;

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetProcessInformation(
        IntPtr hProcess,
        int processInformationClass,
        ref PROCESS_POWER_THROTTLING_STATE processInformation,
        uint processInformationSize);

    [DllImport("kernel32.dll")]
    private static extern IntPtr GetCurrentProcess();

    /// <summary>省電力寄りの扱いと、タイマ分解能要求の無視を、どちらも解除します。</summary>
    public static void OptOutOfPowerThrottling()
    {
        var state = new PROCESS_POWER_THROTTLING_STATE
        {
            Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION,
            ControlMask =
                PROCESS_POWER_THROTTLING_EXECUTION_SPEED |
                PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION,
            StateMask = 0,
        };

        if (!SetProcessInformation(
                GetCurrentProcess(),
                ProcessPowerThrottling,
                ref state,
                (uint)Marshal.SizeOf<PROCESS_POWER_THROTTLING_STATE>()))
        {
            throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
        }
    }
}

الاستدعاء: نفّذ PowerQos.OptOutOfPowerThrottling(); مرّة واحدة قبل بدء الحلقة الحسّاسة للوقت. مقبض العمليّة يحتاج حقّ وصول PROCESS_SET_INFORMATION، لكنّ المقبض الزائف للعمليّة ذاتها الذي يرجعه GetCurrentProcess() لا مشكلة فيه.

4.6. توزيع CPU / انتقال النواة / الحرارة

توزيع CPU ينجح في الغالب إن بدأت من تعيين قريب من soft affinity بمعنى «يفضَّل التشغيل على هذه المجموعة من النوى»، لا من تثبيت على نواة معيّنة فوراً (hard affinity / CPU pinning).

نعملاالقياس أوّلاًSetThreadIdealProcessor / CPU Setsهل تحسّن بما يكفي؟توقّف هناكأخيراً انظر في SetThreadAffinityMaskوفي الوقت نفسه أكّد الحرارة / الساعة / التشغيل الطويل

الشكل 17: توزيع CPU يبدأ من القياس، ويتوقّف إن كفى التعيين الليّن، والتثبيت على نواة معيّنة آخر الوسائل.

قائمة فحص

  • توزيع CPU يُعدَّل بعد القياس أوّلاً
  • لا تثبيت فوري على نواة معيّنة
  • تجربة SetThreadIdealProcessor أو CPU Sets أوّلاً
  • SetThreadAffinityMask يُعامَل كآخر وسيلة
  • تأكيد الحرارة والساعة و thermal throttling في التشغيل الطويل
  • تأكيد وضع الهدوء أو خفض الضوضاء على الحاسوب المحمول

الترتيب الآمن هو هذا التدفّق.

  1. قِس أوّلاً
  2. إن لزم ideal processor / CPU Sets
  3. إن بقي التحسين لازماً فالتثبيت على نواة معيّنة

التثبيت على نواة معيّنة يبدو نافعاً، لكنّه يضيّق مخارج نظام التشغيل، فإن استُخدم باستسهال فقدت المرونة بالعكس.

4.7. برامج التشغيل / DPC / ISR / فصل الاضطراب الخارجي

حين «ينفجر max أحياناً فقط» أو «المتوسّط جيّد و p99.9 سيّئ»، يحسن الاشتباه أيضاً باضطراب خارج شيفرة التطبيق.

نعملانعملانعملانعملاظهر late / miss / قفزة maxأزمن معالجتك أيضاً طويل؟تقصير المسار الساخن / تقليل التخصيص / إزالة I/Oهل ثمّة قفزة DPC / ISR؟تأكيد USB / Wi-Fi / Bluetooth / GPU / Audio / Storage / ACPI / تحديث برنامج التشغيلهل ثمّة page fault / GC / تكلفة المرّة الأولى؟تخصيص مسبق / إحماء / تقليل حمل الكومةهل ثمّة أثر بطارية / توفير / حرارة؟تيار متردّد / إعدادات الطاقة / تبريد / اختبار طويلحفر أعمق بـ ETW / WPA / LatencyMon

الشكل 18: ترتيب الفصل عند ظهور قفزة. اشتبه بمعالجتك، ثمّ DPC/ISR، ثمّ الذاكرة، ثمّ الطاقة والحرارة.

قائمة فحص

  • تأكيد برامج تشغيل محيط Wi-Fi / Bluetooth / USB / التخزين / GPU / الصوت
  • المقارنة بعد إيقاف مزامنة سحابيّة غير لازمة والفهرسة والتحديث التلقائي
  • تجربة الانهيار عند التصغير أو إطفاء الشاشة أيضاً
  • النظر في ميل DPC / ISR بـ LatencyMon أو ETW
  • الفصل بين «معالجتك ثقيلة» و«توقيف من الخارج»

5. القياس والتقييم

5.1. ماذا تسجّل

كحدّ أدنى، هذه يستحقّ أخذها.

  • الوقت المقرّر للدورة
  • وقت البدء الفعلي
  • وقت الانتهاء الفعلي
  • lateness (كم تأخّر البدء عن البدء المقرّر)
  • زمن التنفيذ
  • عدد missed deadline
  • عدد missed deadline المتتالية
  • عمق الطابور
  • عدد الـ drop
  • استخدام CPU
  • الانحياز حسب النواة
  • قفزات DPC / ISR
  • page fault
  • تغيّر الحرارة / الساعة

المتوسّط وحده يصعب معه التقاط الجوهر. ما يضايق في الإنتاج قفزة تأخير كبيرة تظهر أحياناً.

5.2. قراءة p99 / p99.9 / max

مؤشّرات مثل p99 للنظر إلى ذيل الجانب البطيء. المتوسّط وحده يخفي تأخيراً كبيراً يظهر أحياناً.

المؤشّر المعنى صورة عند القياس 10,000 مرّة
المتوسّط قيمة التسوية للكلّ يسهل دفن القفزات
p50 القيمة الوسطى قريبة من الإحساس المعتاد
p95 الحدّ الذي يبدأ عنده ظهور أبطأ 5% الحدّ بعد استبعاد أبطأ 500 مرّة
p99 الحدّ الذي يبدأ عنده ظهور أبطأ 1% الحدّ بعد استبعاد أبطأ 100 مرّة
p99.9 الحدّ الذي يبدأ عنده ظهور أبطأ 0.1% الحدّ بعد استبعاد أبطأ 10 مرّات
max أسوأ قيمة المرّة الأبطأ واحدة

مثلاً، لنفرض ترتيباً كهذا (مثال لشرح قراءة المؤشّر، وليس قياساً فعليّاً على عتاد معيّن).

  • المتوسّط: 0.8ms
  • p99: 1.2ms
  • p99.9: 3.5ms
  • max: 28ms

هذه حالة سريعة عادة، وفيها قفزة كبيرة أحياناً. على Windows العادي تظهر المشكلة الحقيقيّة تقريباً في ذيل p99 إلى max.

الفرق بين المتوسّط ومؤشّرات الذيليبيّن أنّ النظر إلى المتوسّط وحده يخفي تأخيراً كبيراً يظهر أحياناً، في حين أنّ النظر إلى p99 و p99.9 و max يُظهر ذيل الجانب البطيء، وأنّ المشكلة الحقيقيّة على Windows العادي تظهر هناك.النظر إلى المتوسّط وحدهتأخير كبير عابر يُخفىالنظر إلى p99 و p99.9 و maxذيل الجانب البطيء يظهرالمشكلة الحقيقيّة تظهر من p99 إلى max

الشكل 19: إن كان المتوسّط جيّداً و max يقفز فالحالة «سريعة عادة وتقفز أحياناً». التقطها بمؤشّرات الذيل.

لاحظ أنّ هذا المقال لا يعرض أثر التكوين الموصى به بأرقام. التأخير والـ jitter يتغيّران بسهولة حسب CPU وبرامج التشغيل والبرامج المقيمة وإعدادات الطاقة وطريقة الحمل، لذا أرقام بيئة غيرك ليست حجّة لبيئتك كما هي. بدلاً من ذلك نضع خطوات لصنع جدول بالشكل نفسه في بيئتك.

أدنى خطوات لإخراج p99 في بيئتك

  1. في المسار الساخن سجّل فقط. خذ lateness وزمن التنفيذ بـ Stopwatch.GetTimestamp() (في C++ QueryPerformanceCounter) واكتبهما في مصفوفة مخصَّصة مسبقاً. لا تحسب هنا متوسّطاً ولا ترتيباً
  2. أوقف القياس ثمّ جمّع. رتّب واستخرج القيمة عند موضع المئين
  3. كرّر نفس الخطوات مع تغيير الشرط. قبل الإحماء وبعده، تيار متردّد / بطارية، واجهة أماميّة / تصغير، حمل عمليّات أخرى موجود / غير موجود (5.4)
  4. كلّما أدخلت تغييراً واحداً، أعد الأخذ بنفس الشرط وقارن
// C# / .NET 8。集計は計測を止めたあとに行う
using System.Diagnostics;

// ホットパスでは配列へ書くだけ(割り当てゼロ)
long[] latenessTicks = new long[100_000];
int count = 0;

// 例: 周期ループの中
// latenessTicks[count++] = Stopwatch.GetTimestamp() - scheduledTimestamp;

static double PercentileMs(long[] ticks, int count, double percentile)
{
    long[] sorted = ticks.AsSpan(0, count).ToArray();
    Array.Sort(sorted);

    int index = (int)Math.Ceiling(percentile / 100.0 * count) - 1;
    index = Math.Clamp(index, 0, count - 1);

    return sorted[index] * 1000.0 / Stopwatch.Frequency;
}

// 使い方
// Console.WriteLine($"p50={PercentileMs(latenessTicks, count, 50):F3}ms");
// Console.WriteLine($"p99={PercentileMs(latenessTicks, count, 99):F3}ms");
// Console.WriteLine($"p99.9={PercentileMs(latenessTicks, count, 99.9):F3}ms");
// Console.WriteLine($"max={PercentileMs(latenessTicks, count, 100):F3}ms");

Stopwatch.Frequency عدد العدّات في الثانية، فالقسمة ثمّ الضرب في 1000 تعطي ملّي ثانية. إن قلّ عدد العيّنات فقد p99.9 معناه. إن تحدّثت عن p99.9 فاجمع 10,000 عيّنة على الأقلّ (ويُفضَّل 100 ألف).

5.3. بماذا تنظر

عدّة الأدوات محدّدة تقريباً.

  • قياس داخل التطبيق خذ أوّلاً بنفسك period / lateness / execution time / queue depth / drop
  • ETW / WPR / WPA احفر CPU و context switch و DPC / ISR و page fault
  • LatencyMon التقط أوّليّاً اهتزازاً آتياً من برنامج تشغيل
  • مراقبة الحرارة / الساعة انظر أثر الحرارة
قياس داخل التطبيقp50 / p95 / p99 / p99.9 / maxmiss / drop / عمق الطابورETW / WPR / WPAcontext switch / DPC / ISR / page faultمراقبة الحرارة / الساعةتقرير أولويّة التحسين

الشكل 20: قابل نتائج القياس داخل التطبيق و ETW ومراقبة الحرارة، ثمّ قرّر أولويّة التحسين.

الوصول إلى WPA فيه بعض العناء، لكنّه نافع جدّاً للفصل بين كون السبب DPC / ISR وكون معالجتك نفسها ثقيلة.

طريقة الحصول وأدنى استخدام

الأداة طريقة الحصول أدنى خطوات
WPR / WPA (Windows Performance Toolkit) عند تثبيت Windows ADK (Windows Assessment and Deployment Kit) اختر «Windows Performance Toolkit» فيدخل. الموضع الافتراضي C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit افتح موجه أوامر كمسؤول، (1) ابدأ التسجيل بـ wpr -start CPU، (2) شغّل المعالجة المشكلة عشرات الثواني، (3) احفظ بـ wpr -stop trace.etl "周期遅延の調査". ثمّ افتح trace.etl في WPA. أسماء الملفّات الشخصيّة المتاحة تؤكَّد بـ wpr -profiles
LatencyMon نزّله من موقع Resplendence Software. Home Edition الموجَّه للأفراد نسخة مجّانيّة ابدأ القياس واترك المعالجة المستهدفة تعمل دقائق. يُجمَّع أقصى تأخير لمؤقّت النواة وزمن تنفيذ ISR / DPC حسب برنامج التشغيل و hard pagefault، فسجّل برنامج التشغيل البارز زمن تنفيذه

ما تنظر إليه أوّلاً في WPA من رسوم CPU هو زمن تنفيذ DPC / ISR و context switch. يصطفّ «أيّ برنامج تشغيل كان يمسك CPU في الفترات التي لم يستطع خيطك الحركة فيها»، فقابله بأوقات ظهور التأخير المسجّلة في 5.1.

لاحظ أنّ هذا المقال لا يحمل لقطات شاشة. المظهر يتغيّر بسهولة حسب الإصدار، فاعمل وفق الخطوات أعلاه وأكّد على الشاشة الفعليّة.

5.4. أسلوب الاختبار

الاختبار في بيئة قياس هادئة وحده لا يكفي. على الأقلّ هذه الشروط يستحقّ النظر إليها مفصولة.

  • قبل الإحماء بعد البدء مباشرة
  • بعد الإحماء
  • تشغيل مستمرّ طويل
  • واجهة المستخدم في المقدّمة
  • حالة قريبة من تصغير / إخفاء واجهة المستخدم
  • تيار متردّد
  • تشغيل على البطارية
  • حالة حمل على الشبكة أو القرص

التقييم في بيئة القياس وحدها يسهّل إغفال مشكلات التشغيل الفعلي. Windows العادي يُسحَب سلوكه بسهولة حسب «طريقة الاستخدام»، لذا المهمّ التأكيد مقترباً من شروط الاستخدام الفعلي.

فكرة اختبار مفصول الشروطيبيّن أنّ التقييم في بيئة قياس هادئة وحدها يغفل مشكلات التشغيل الفعلي، لذا يُؤكَّد مفصولاً شروط مثل قبل الإحماء وبعده والتشغيل الطويل وواجهة المستخدم في المقدّمة والتصغير والتيار المتردّد والبطارية ووجود الحمل.تقييم بيئة قياس هادئة وحدهاإغفال مشكلات التشغيل الفعليالتقييم بفصل الشروطالإحماء والتشغيل الطويلواجهة المستخدم في المقدّمة والتصغيرشروط التغذية والحمل

الشكل 21: Windows العادي يُسحَب سلوكه حسب طريقة الاستخدام. قيّم مقترباً من شروط الاستخدام الفعلي.

6. تقسيم تقريبي للاستخدام

جدول نطاق الدورة السريع نُقل إلى 1.1 لتعود إليه أثناء القراءة. هنا نكمّل حكمين لا يحسمهما ذلك الجدول وحده.

أين تحكم أنّ «Windows العادي لا يكفي»

إذا ظهر لزوم الالتزام بأقل من 1ms في تشغيل طويل وحمل عالٍ، أسرع في الغالب أن تخرج الجزء الصارم زمنيّاً فقط من أن تواصل الضبط. مرشّحو الإخراج: برمجيّة الجهاز، متحكّم مخصّص، FPGA، RTOS. مادّة الحكم ليست الانطباع بل أرقام الفصل 5.

  • لم يعد المسار الساخن قابلاً للتقصير، و p99.9 و max ما زالا يتجاوزان المتطلّب
  • السبب اضطراب خارجي (DPC / ISR، برنامج تشغيل، عمليّة أخرى)، وإجراءات جانب التطبيق لا تبلغ (أكّد بفصل 4.7)
  • المتطلّب لم يعد «إن فات أحياناً لا ينكسر» بل «لا يجوز الفوات ولو مرّة»

حين تريد إيواء الكلّ في عمليّة واحدة

إن احتضنت واجهة المستخدم والسجلّ والاتّصال وقاعدة البيانات في الحلقة نفسها من العمليّة نفسها، مقتضيات المرحلة اللاحقة تفسد أجل المرحلة السابقة. انتظار تفريغ الملفّ، وإعادة الاتّصال بقاعدة البيانات، وإعادة رسم الواجهة، كلّها قد تمتدّ بوحدات عشرات الملّي ثانية. توسيع فصل fast path / slow path (4.2) إلى وحدة العمليّة أيضاً خيار. بفصل العمليّات تظلّ دورة المرحلة السابقة تدور حتّى إن تجمّدت المرحلة اللاحقة.

مقابلة تكوين الإيواء وفصل العمليّاتيبيّن أنّ احتضان واجهة المستخدم والسجلّ والاتّصال وقاعدة البيانات في حلقة واحدة لعمليّة واحدة يجعل مقتضيات المرحلة اللاحقة تفسد أجل المرحلة السابقة، وأنّ توسيع فصل fast path و slow path إلى وحدة العمليّة يبقي دورة المرحلة السابقة دائرة حتّى إن تجمّدت اللاحقة.احتضان الكلّ في عمليّة واحدة وحلقة واحدةمقتضيات اللاحقة تفسد أجل السابقةانتظار التفريغ وإعادة الاتّصال وإعادة الرسمفصل السابقة واللاحقة بالعمليّةحتّى إن تجمّدت اللاحقة تظلّ السابقة تدور

الشكل 22: إن لزم الإيواء حتماً، ثمّة خيار توسيع فصل fast path / slow path إلى وحدة العمليّة.

7. الخلاصة

افتراضان يجدر ضبطهما.

  • ما يُستهدف على Windows العادي ليس ضمان hard real-time، بل تكوين soft real-time يصغّر التأخير والـ jitter ولا ينكسر إن وقعت مخالفة للأجل
  • أكبر أثر ترتيب المسار الساخن، لا ضبط الأولويّة

ما ينفع في التنفيذ تقريباً هذا.

  • فصل fast path / slow path
  • طابور ثابت الطول، وتقرير سياسة الامتلاء مسبقاً
  • القياس بـ QPC، والانتظار بحدث / waitable timer (مؤقّت قابل للانتظار)
  • تجنّب التخصيص و I/O الحاجب والقفل الثقيل في المسار الساخن

تشغيليّاً ينفع هذا.

  • التشغيل على تيار متردّد
  • فصل إعدادات الطاقة للإنتاج
  • تقليل الحمل غير اللازم في الخلفيّة
  • التقييم بـ p99 / p99.9 / max وعدد الـ miss

soft real-time على Windows العادي لا يُحسَم بإعداد الأولويّة وحده؛ إن فصلت التصميم والتنفيذ وإعدادات الطاقة والقياس والتشغيل وأحكمتها، أمكنك صنع نظام ثابت إلى حدّ بعيد.

8. مراجع

أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.

الأسئلة الشائعة

أسئلة شائعة حول موضوع هذه المقالة.

هل يمكن تنفيذ معالجة في الوقت الحقيقي على Windows؟
لا يمكن ضمان hard real-time (صفر مخالفات للأجل)، لكن إن أحكمت التصميم والتنفيذ والقياس والتشغيل وصلت إلى حالة عمليّة جدّاً كـ soft real-time. معالجة دوريّة بفترة من بضعة ملّي ثانية إلى عشرات الملّي ثانية، وتحريك الصوت/الصورة بالـ buffer، وحلقة الحصول على بيانات حسّاس والتحكّم، كلّها واقعيّة على Windows 10/11 العادي. بالمقابل، إن احتجت ضمان صفر مخالفات للأجل أو ثباتاً طويلاً دون مئات الميكروثانية، فانظر في RTOS أو متحكّم مخصّص أو FPGA أو معالجة في جانب الجهاز.
لماذا لا ينبغي استخدام Sleep(1) في الحلقة الدوريّة؟
لأنّ Sleep(1) ليس «دورة 1ms»، بل «انتظر نحو 1ms أو أكثر ثمّ أضف زمن التنفيذ»، فيتراكم تجاوز الانتظار كما هو. أدِر الحلقة الدوريّة بأجل مطلق next += period، وقدّم انتظار حدث الجهاز أو waitable timer عالي الدقّة، واحصر الضبط الأخير في busy-spin قصير جدّاً. استخدم timeBeginPeriod للمدّة اللازمة فقط، ثمّ أعده.
ما أكثر ما ينفع لتقليل التأخير والـ jitter؟
أقوى من رفع الأولويّة أن تجعل المسار الساخن قصيراً وثابت الطول وغير حاجب. افصل fast path (الحصول والتحكّم) عن slow path (الحفظ والاتّصال وواجهة المستخدم) وصِلهما بطابور ثابت الطول، وتجنّب في المسار الساخن كتابة الملفّات وإرسال الشبكة والسجلّ الثقيل وتخصيص الذاكرة في كلّ دورة. تشغيليّاً ينفع التشغيل على تيار متردّد، ومراجعة وضع الطاقة، والتحقّق من EcoQoS، وترتيب الحمل في الخلفيّة.
بأيّ مؤشّرات تقيّم ثبات الحلقة الدوريّة؟
لا تنظر إلى المتوسّط وحده، بل إلى p99 و p99.9 و max وعدد missed deadline. مثلاً إن كان المتوسّط 0.8ms و max 28ms، فالحالة «سريع عادة، وفيه قفزة كبيرة أحياناً»، وعلى Windows العادي تظهر المشكلة الحقيقيّة في ذيل p99 إلى max. سجّل أيضاً قفزات DPC/ISR و page fault وعمق الطابور وتغيّر الحرارة والساعة، وقِيّم الشروط مفصولة: قبل الإحماء وبعده، والتشغيل الطويل، وحالة التصغير، والتشغيل على البطارية.

الملف الشخصي للمؤلف

صفحة الملف الشخصي لمؤلف المقالة.

غو كومورا

مؤسّس شركة كومورا سوفت ذ.م.م.

يركّز على تطوير برامج ويندوز، والاستشارات التقنية، والتحقيق في الأخطاء، ويتميّز في المشاريع التي تبقى فيها الأصول القديمة ناشطة، وفي تشخيص الأعطال التي يصعب تحديد سببها.

العودة إلى المدونة