يكتب Bursty إلى SD/USB لإيقاف تطبيقاتي ذات الأهمية الزمنية على Linux المدمج

StackOverflow https://stackoverflow.com/questions/78157

سؤال

أنا أعمل على مشروع Linux مضمن يربط ARM9 بشريحة تشفير فيديو للجهاز، ويكتب الفيديو على بطاقة SD أو وحدة USB.تشتمل بنية البرنامج على برنامج تشغيل kernel يقرأ البيانات في مجموعة من المخازن المؤقتة، وتطبيق userland الذي يكتب البيانات إلى ملف على الجهاز القابل للإزالة المثبت.

أجد أنه فوق معدل بيانات معين (حوالي 750 كيلو بايت / ثانية) أبدأ في رؤية تطبيق كتابة الفيديو الخاص بـ userland يتوقف لمدة نصف ثانية تقريبًا، كل 5 ثوانٍ تقريبًا.وهذا يكفي للتسبب في نفاد المخازن المؤقتة في برنامج تشغيل kernel - وحتى لو تمكنت من زيادة عدد المخازن المؤقتة، فيجب مزامنة بيانات الفيديو (من الأفضل خلال 40 مللي ثانية) مع أشياء أخرى تحدث في الوقت الفعلي.بين هذه "الارتفاعات المتأخرة" الخمس ثواني، تكتمل عمليات الكتابة بشكل جيد في غضون 40 مللي ثانية (فيما يتعلق بالتطبيق - أقدر أن نظام التشغيل قد قام بتخزينها مؤقتًا)

أعتقد أن هذا الارتفاع في التأخر يتعلق بالطريقة التي يقوم بها نظام التشغيل Linux بإخراج البيانات إلى القرص - وألاحظ أن pdflush مصمم ليستيقظ كل 5 ثوانٍ، وما أفهمه هو أن هذا سيكون هو ما تفعله الكتابة.بمجرد انتهاء المماطلة، يصبح تطبيق userland قادرًا على الخدمة بسرعة وكتابة تراكم المخازن المؤقتة (التي لم تتجاوز السعة).

أعتقد أن الجهاز الذي أكتب إليه يتمتع بإنتاجية نهائية معقولة:لقد أعطاني نسخ ملف بحجم 15 ميجابايت من وحدة الذاكرة وانتظار اكتمال المزامنة (وتوقف ضوء فلاش USB عن الوميض) سرعة كتابة تبلغ حوالي 2.7 ميجابايت / ثانية.

أبحث عن نوعين من القرائن:

  1. كيف يمكنني إيقاف الكتابة المتقطعة من إيقاف تطبيقي - ربما معالجة الأولويات، أو تصحيحات الوقت الفعلي، أو ضبط كود نظام الملفات للكتابة بشكل مستمر بدلاً من الكتابة المتقطعة؟

  2. كيف يمكنني جعل تطبيقي (تطبيقاتي) على علم بما يحدث في نظام الملفات فيما يتعلق بتراكم الكتابة والإنتاجية على البطاقة/العصا؟لدي القدرة على تغيير معدل البت للفيديو في برنامج ترميز الأجهزة بسرعة وهو ما سيكون أفضل بكثير من إسقاط الإطارات، أو فرض حد اصطناعي على الحد الأقصى لمعدل البت المسموح به.

بعض المعلومات الإضافية:هذا هو 200 ميجا هرتز ARM9 يشغل حاليًا نواة تعتمد على Montavista 2.6.10.

التحديثات:

  • يؤدي تثبيت نظام الملفات SYNC إلى أن تكون الإنتاجية رديئة للغاية.
  • الوسائط القابلة للإزالة بتنسيق FAT/FAT32 ويجب أن تكون لأن الغرض من التصميم هو إمكانية توصيل الوسائط بأي جهاز كمبيوتر يعمل بنظام Windows وقراءتها.
  • على سبيل المثال، يتم الاتصال بانتظام بـ sync() أو fsync()، حيث تتسبب كل ثانية في حدوث توقفات منتظمة وإنتاجية سيئة بشكل غير مقبول
  • أنا أستخدم write() وopen(O_WRONLY | O_CREAT | O_TRUNC) بدلاً من fopen() وما إلى ذلك.
  • لا يمكنني العثور على أي شيء عبر الإنترنت على الفور حول "أنظمة ملفات Linux في الوقت الفعلي" المذكورة.الروابط؟

آمل أن يكون هذا الأمر يبدو معقولا تماما.أول سؤال Linux مضمن حول تدفق المكدس؟:)

هل كانت مفيدة؟

المحلول

للعلم، تبين أن هناك جانبين رئيسيين يبدو أنهما قد قضوا على المشكلة في جميع الحالات باستثناء الحالات القصوى.هذا النظام لا يزال قيد التطوير ولم يتم اختباره بشكل كامل بعد ولكنه يعمل بشكل جيد إلى حد ما (لمس الخشب).

جاء الفوز الكبير من جعل تطبيق userland للكاتب متعدد الخيوط.إن الاستدعاءات للكتابة () هي التي تمنع أحيانًا:لا تزال العمليات والمواضيع الأخرى قيد التشغيل.طالما أن لدي سلسلة رسائل لخدمة برنامج تشغيل الجهاز وتحديث عدد الإطارات والبيانات الأخرى للمزامنة مع التطبيقات الأخرى قيد التشغيل، يمكن تخزين البيانات مؤقتًا وكتابتها بعد بضع ثوانٍ دون انتهاك أي مواعيد نهائية.لقد جربت لعبة بينج بونج مزدوجة بسيطة أولًا، لكن ذلك لم يكن كافيًا؛سيتم إرهاق المخازن المؤقتة الصغيرة وتسبب المخازن المؤقتة الكبيرة في توقف مؤقت أكبر أثناء استيعاب نظام الملفات لعمليات الكتابة.تعمل مجموعة مكونة من 10 مخازن مؤقتة سعة 1 ميجا بايت في قائمة الانتظار بين سلاسل العمليات بشكل جيد الآن.

الجانب الآخر هو مراقبة إنتاجية الكتابة النهائية للوسائط المادية.لهذا أنا أراقب الإحصائيات القذرة:تم الإبلاغ عنها بواسطة /proc/meminfo.لدي بعض التعليمات البرمجية التقريبية والجاهزة لخنق برنامج التشفير إذا كان متسخًا:يتسلق فوق عتبة معينة، ويبدو أن العمل غامض.هناك حاجة إلى مزيد من الاختبار والضبط لاحقًا.لحسن الحظ، لدي الكثير من ذاكرة الوصول العشوائي (128 ميجا) لألعب بها، مما يمنحني بضع ثوانٍ لرؤية تراكم الأعمال المتراكمة لدي والانخفاض بسلاسة.

سأحاول أن أتذكر الرجوع إلى هذه الإجابة وتحديثها إذا وجدت أنني بحاجة إلى القيام بأي شيء آخر للتعامل مع هذه المشكلة.شكرا للمجيبين الآخرين.

نصائح أخرى

سأطرح بعض الاقتراحات، فالمشورة رخيصة الثمن.

  • تأكد من أنك تستخدم واجهة برمجة التطبيقات ذات المستوى الأدنى للكتابة على القرص، ولا تستخدم وظائف التخزين المؤقت لوضع المستخدم مثل fopen, fread, fwrite استخدم وظائف المستوى الأدنى open, read, write.
  • مرر ال O_SYNC عند فتح الملف، سيؤدي ذلك إلى حظر كل عملية كتابة حتى تتم كتابتها على القرص، مما سيؤدي إلى إزالة السلوك المتقطع لكتاباتك... مع أن تكون كل عملية كتابة أبطأ.
  • إذا كنت تقوم بعمليات قراءة/ioctls من جهاز للحصول على جزء من بيانات الفيديو، فقد ترغب في التفكير في تخصيص منطقة ذاكرة مشتركة بين التطبيق والنواة، وإلا فسوف تتعرض لمجموعة من الأخطاء copy_to_user المكالمات عند نقل المخازن المؤقتة لبيانات الفيديو من مساحة kernel إلى مساحة المستخدم.
  • قد تحتاج إلى التحقق من أن جهاز فلاش USB الخاص بك سريع بما يكفي مع عمليات النقل المستمرة لكتابة البيانات.

مجرد أفكارين، آمل أن يساعد هذا.

هنا هذه بعض المعلومات حول ضبط pdflush للعمليات كثيفة الكتابة.

يبدو أنك تبحث عن أنظمة ملفات Linux في الوقت الفعلي.تأكد من البحث في Google et al عن ذلك.

لدى XFS خيار الوقت الفعلي، على الرغم من أنني لم ألعب به.

قد يتيح لك hdparm إيقاف تشغيل التخزين المؤقت تمامًا.

قد يؤدي ضبط خيارات نظام الملفات (إيقاف تشغيل كافة سمات الملف الإضافية غير الضرورية) إلى تقليل ما تحتاج إلى مسحه، وبالتالي تسريع عملية التدفق.أشك في أن هذا سيساعد كثيرًا.

لكن اقتراحي هو تجنب استخدام العصا كنظام ملفات على الإطلاق وبدلاً من ذلك استخدامها كجهاز خام.قم بتعبئة البيانات عليه كما لو كنت تستخدم "dd".ثم اقرأ تلك البيانات الأولية في مكان آخر واكتبها بعد الخبز.

بالطبع، لا أعرف إذا كان هذا خيارًا بالنسبة لك.

يحتوي على أداة مساعدة لتصحيح الأخطاء، ويمكنك استخدام strace لمعرفة العمليات التي تستغرق وقتًا.قد يكون هناك بعض الأشياء المدهشة مع FAT/FAT32.

هل تكتب في ملف واحد أم في عدة ملفات؟

يمكنك إنشاء سلسلة قراءة، والتي ستحافظ على مجموعة من المخزن المؤقت للفيديو جاهزة للكتابة في قائمة الانتظار.عند استلام إطار، تتم إضافته إلى قائمة الانتظار، ويتم الإشارة إلى خيط الكتابة

البيانات المشتركة

empty_buffer_queue
ready_buffer_queue
video_data_ready_semaphore

موضوع القراءة:

buf=get_buffer()
bufer_to_write = buf_dequeue(empty_buffer_queue)
memcpy(bufer_to_write, buf)
buf_enqueue(bufer_to_write, ready_buffer_queue)
sem_post(video_data_ready_semaphore)

خيط الكتابة

sem_wait(vido_data_ready_semaphore)
bufer_to_write = buf_dequeue(ready_buffer_queue)
write_buffer
buf_enqueue(bufer_to_write, empty_buffer_queue)

إذا تم حظر خيط الكتابة الخاص بك في انتظار النواة، فقد ينجح هذا.ومع ذلك، إذا تم حظرك داخل مساحة النواة، فليس هناك الكثير مما يمكنك فعله، باستثناء البحث عن نواة أحدث من 2.6.10

وبدون معرفة المزيد عن ظروفك الخاصة، لا يمكنني إلا أن أقدم التخمينات التالية:

حاول استخدام fsync()/sync() لإجبار النواة على تدفق البيانات إلى جهاز التخزين بشكل متكرر.يبدو أن النواة تقوم بتخزين جميع كتاباتك مؤقتًا ثم تقوم بربط الناقل أو إيقاف نظامك بطريقة أخرى أثناء إجراء الكتابة الفعلية.من خلال الاستدعاءات الدقيقة إلى fsync()، يمكنك محاولة جدولة عمليات الكتابة عبر ناقل النظام بطريقة أكثر دقة.

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

الشيء الوحيد الذي يبدو مريبًا هو أنك لا ترى هذه المشكلة إلا عند معدل بيانات معين - إذا كانت هذه مشكلة تخزين مؤقت بالفعل، كنت أتوقع أن تحدث المشكلة بشكل أقل تكرارًا عند معدلات بيانات أقل، لكنني ما زلت أتوقع رؤية هذا مشكلة.

على أية حال، قد يكون المزيد من المعلومات مفيدًا.ما هي بنية النظام الخاص بك؟(بعبارات عامة جدًا.)

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

إحدى وظائف Linux المفيدة والبديلة للمزامنة أو fsync هي sync_file_range.يتيح لك ذلك جدولة البيانات للكتابة دون انتظار نظام المخزن المؤقت داخل النواة للوصول إليها.

لتجنب التوقف المؤقت لفترة طويلة، تأكد من قائمة انتظار الإدخال/الإخراج (على سبيل المثال:/sys/block/hda/queue/nr_requests) كبير بدرجة كافية.قائمة الانتظار هذه هي المكان الذي تنتقل فيه البيانات بين مسحها من الذاكرة ووصولها إلى القرص.

لاحظ أن sync_file_range ليس محمولاً، وهو متاح فقط في النواة 2.6.17 والإصدارات الأحدث.

لقد قيل لي أنه بعد أن يرسل المضيف أمرًا، يجب أن تستجيب بطاقات MMC وSD "في غضون 0 إلى 8 بايت".

ومع ذلك، تسمح المواصفات لهذه البطاقات بالرد بكلمة "مشغولة" حتى تنتهي من العملية، ويبدو أنه لا يوجد حد للمدة التي يمكن للبطاقة أن تدعي أنها مشغولة (من فضلك، من فضلك أخبرني إذا كان هناك مثل هذا الحد).

أرى أن بعض شرائح الفلاش منخفضة التكلفة مثل M25P80 تتمتع بـ "أقصى وقت لمحو القطاع الواحد" مضمون يبلغ 3 ثوانٍ، على الرغم من أن ذلك يتطلب عادةً "فقط" 0.6 ثانية.

تبدو تلك الـ 0.6 ثانية مشابهة بشكل مثير للريبة لـ "المماطلة ربما لمدة نصف ثانية".

أظن أن المقايضة بين شرائح الفلاش الرخيصة والبطيئة وشرائح الفلاش السريعة باهظة الثمن لها علاقة بالتنوع الكبير في نتائج محرك أقراص فلاش USB:

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

لذلك، إذا كان لديك تطبيق مهم للوقت، فقد تحتاج إلى (أ) اختبار بطاقات SD ووحدات تخزين USB للتأكد من أنها تلبي الحد الأدنى من زمن الوصول وعرض النطاق الترددي وما إلى ذلك.يتطلبها تطبيقك، و(ب) إعادة اختبار أجهزة الذاكرة هذه بشكل دوري أو استبدالها بشكل استباقي.

حسنًا أولاً، هل حاولت إخبار الملف بوضوح بالتدفق؟أعتقد أيضًا أنه قد يكون هناك بعض ioctl الذي يمكنك استخدامه للقيام بذلك، لكنني بصراحة لم أقم بالكثير من برمجة ملفات C/POSIX.

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


فحص سريع في صفحات الرجل الخاصة بي يجد هذا:

SYNC(2)                    Linux Programmer’s Manual                   SYNC(2)

NAME
       sync - commit buffer cache to disk

SYNOPSIS
       #include <unistd.h>

       void sync(void);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       sync(): _BSD_SOURCE || _XOPEN_SOURCE >= 500

DESCRIPTION
       sync() first commits inodes to buffers, and then buffers to disk.

ERRORS
       This function is always successful.

إن القيام بعملية الدفق () الخاصة بك يبدو أمرًا صحيحًا بالنسبة لي - فأنت تريد أن تكون مسيطرًا، ولا تترك الأمر لتقلبات الطبقة العازلة العامة.

قد يكون هذا واضحًا، ولكن تأكد من أنك لا تتصل بـ write() كثيرًا - تأكد من أن كل write() لديها ما يكفي من البيانات ليتم كتابتها لجعل حمل syscall يستحق كل هذا العناء.وفي الاتجاه الآخر أيضًا، لا تتصل به نادرًا جدًا، وإلا فسيتم حظره لفترة كافية لتسبب مشكلة.

في مسار أكثر صعوبة في إعادة التنفيذ، هل حاولت التبديل إلى الإدخال/الإخراج غير المتزامن؟باستخدام aio، يمكنك إطلاق عملية الكتابة وتسليمها مجموعة واحدة من المخازن المؤقتة بينما تقوم بامتصاص بيانات الفيديو إلى المجموعة الأخرى، وعندما تنتهي الكتابة يمكنك تبديل مجموعات المخازن المؤقتة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top