فولکلور برنامه نویسان و مهندسان (قسمت اول)

فولکلور برنامه نویسان و مهندسان (قسمت اول)

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

حساسیت ماشین به بستنی وانیلی

داستانی برای مهندسانی که می‌دانند چیزهای بدیهی همیشه جواب نمی‌دهند و مهم نیست که واقعیت‌ها چقدر دور از ذهن به نظر می‌رسند، باز هم حقایق هستند. بخش پونتیاک شرکت جنرال موتورز شکایتی دریافت کرد:

این دومین بار است که برای شما می نویسم و ​​شما را برای پاسخ ندادن سرزنش نمی کنم، زیرا دیوانه به نظر می رسد. خانواده ما رسم این است که هر شب بعد از شام بستنی می خورند. انواع بستنی ها هر بار تغییر می کنند و بعد از شام همه خانواده انتخاب می کنند که کدام بستنی را بخرند و بعد از آن به فروشگاه می روم. من اخیرا یک پونتیاک جدید خریدم و از آن زمان سفرهای من برای تهیه بستنی مشکل ساز شده است. ببینید هر وقت بستنی وانیلی می خرم و از مغازه برمی گردم ماشین روشن نمی شود. اگر بستنی دیگری بیاورم ماشین بدون مشکل روشن می شود. می‌خواهم یک سوال جدی بپرسم، مهم نیست که چقدر احمقانه به نظر می‌رسد: "چه چیزی در پونتیاک است که باعث می‌شود وقتی بستنی وانیلی می‌آورم شروع به کار نمی‌کند، اما وقتی طعم دیگری از بستنی می‌آورم به راحتی شروع می‌شود؟"

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

مهندس سه عصر دیگر آمد. اولین بار بستنی شکلاتی بود. ماشین راه افتاد. بار دوم بستنی توت فرنگی بود. ماشین راه افتاد. عصر سوم او خواست وانیل بخورد. ماشین روشن نشد

با استدلال منطقی، مهندس باور نکرد که ماشین به بستنی وانیلی حساسیت دارد. از این رو با مالک خودرو موافقت کردم که تا زمانی که مشکل را حل نکند به بازدیدهای خود ادامه دهد. و در طول مسیر شروع به یادداشت برداری کرد: تمام اطلاعات، ساعت روز، نوع بنزین، زمان ورود و بازگشت از فروشگاه و غیره را یادداشت کرد.

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

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

اخلاقی: حتی مشکلات کاملاً دیوانه کننده نیز گاهی واقعی هستند.

سقوط Bandicoot

تجربه این موضوع دردناک است. به عنوان یک برنامه نویس، شما عادت می کنید که ابتدا، دوم، سوم، کد خود را مقصر بدانید و جایی در ده هزارم کامپایلر را مقصر بدانید. و در پایین‌تر از فهرست، تجهیزات را مقصر می‌دانید.

در اینجا داستان من در مورد اشکال سخت افزاری است.

برای بازی Crash Bandicoot کدی نوشتم که روی کارت حافظه بارگذاری و ذخیره شود. برای چنین توسعه‌دهنده بازی‌های راضی، مانند قدم زدن در پارک بود: فکر می‌کردم کار چند روز طول می‌کشد. با این حال، من در نهایت کد را به مدت شش هفته اشکال زدایی کردم. در طول مسیر مشکلات دیگری را حل کردم اما هر چند روز یک بار چند ساعت به این کد باز می گشتم. عذاب بود

این علامت به این صورت بود: زمانی که شما پخش فعلی بازی را ذخیره می‌کنید و به کارت حافظه دسترسی پیدا می‌کنید، تقریباً همیشه همه چیز خوب پیش می‌رود... اما گاهی اوقات عملیات خواندن یا نوشتن بدون هیچ دلیل واضحی متوقف می‌شود. یک ضبط کوتاه اغلب به کارت حافظه آسیب می رساند. زمانی که یک بازیکن سعی می کند سیو کند، نه تنها موفق به سیو نمی شود، بلکه نقشه را نیز از بین می برد. چرندیات.

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

وقتی هیچ ایده ای برای اشکال زدایی ندارید، تنها روش باقی مانده «تقسیم کن و غلبه کن» است: کدهای بیشتری را از برنامه معیوب حذف کنید تا زمانی که قطعه نسبتاً کوچکی باقی بماند که همچنان باعث ایجاد مشکل می شود. یعنی قطعه قطعه برنامه را قطع می کنید تا قسمتی که حاوی باگ است باقی بماند.

اما نکته اینجاست که بریدن تکه‌های یک بازی ویدیویی بسیار دشوار است. اگر کدی را که گرانش را شبیه سازی می کند حذف کرده اید، چگونه آن را اجرا کنیم؟ یا طراحی شخصیت ها؟

بنابراین، ما باید کل ماژول‌ها را با خرده‌هایی جایگزین کنیم که وانمود می‌کنند کار مفیدی انجام می‌دهند، اما در واقع کاری بسیار ساده انجام می‌دهند که حاوی خطا نیست. باید چنین عصاهایی بنویسیم تا بازی حداقل کار کند. این یک روند آهسته و دردناک است.

خلاصه انجامش دادم من تعداد بیشتری از کدها را حذف کردم تا زمانی که کد اولیه ای که سیستم را برای اجرای بازی پیکربندی می کند، سخت افزار رندرینگ را مقداردهی اولیه می کند و غیره باقی می ماند. البته در این مرحله نتوانستم منوی ذخیره و بارگذاری ایجاد کنم، زیرا باید برای تمام کدهای گرافیکی یک خرد ایجاد کنم. اما می‌توانم با استفاده از صفحه ذخیره و بارگذاری (نامرئی) وانمود کنم که یک کاربر هستم و درخواست ذخیره‌سازی کنم و سپس روی کارت حافظه بنویسم.

این باعث شد که من با یک قطعه کد کوچک مواجه شوم که هنوز مشکل فوق را داشت - اما هنوز به صورت تصادفی اتفاق می افتاد! اغلب همه چیز خوب کار می کرد، اما گاهی اوقات اشکالاتی وجود داشت. تقریباً همه کدهای بازی را حذف کردم، اما باگ هنوز زنده بود. این گیج کننده بود: کد باقی مانده در واقع هیچ کاری انجام نداد.

در یک نقطه، احتمالا حدود سه بامداد، فکری به ذهنم رسید. عملیات خواندن و نوشتن (ورودی/خروجی) شامل زمان اجرای دقیق است. هنگامی که با هارد دیسک، کارت حافظه یا ماژول بلوتوث کار می کنید، کد سطح پایین مسئول خواندن و نوشتن این کار را مطابق با پالس های ساعت انجام می دهد.

با کمک یک ساعت، دستگاهی که مستقیماً به پردازنده متصل نیست، با کدی که روی پردازنده اجرا می شود، همگام می شود. ساعت نرخ باود را تعیین می کند - سرعت انتقال داده ها. اگر با زمان‌بندی اشتباه باشد، سخت‌افزار یا نرم‌افزار یا هر دو نیز اشتباه می‌شوند. و این بسیار بد است، زیرا داده ها ممکن است آسیب ببینند.

اگر چیزی در کد ما زمان‌بندی‌ها را اشتباه بگیرد چه؟ من همه چیز مربوط به این را در کد برنامه آزمایشی بررسی کردم و متوجه شدم که تایمر قابل برنامه ریزی را در PS1 روی 1 کیلوهرتز (1000 تیک در ثانیه) تنظیم کردیم. این مقدار بسیار زیاد است؛ به طور پیش فرض، زمانی که کنسول شروع به کار می کند، با فرکانس 100 هرتز کار می کند. و اکثر بازی ها از این فرکانس استفاده می کنند.

اندی، سازنده بازی، تایمر را روی ۱ کیلوهرتز تنظیم کرد تا حرکات با دقت بیشتری محاسبه شوند. اندی تمایل دارد از مرز عبور کند، و اگر ما از جاذبه تقلید کنیم، آن را تا حد امکان دقیق انجام می دهیم!

اما اگر افزایش سرعت تایمر به نحوی بر زمان بندی کلی برنامه و در نتیجه ساعتی که نرخ باود را برای کارت حافظه تنظیم می کند تأثیر بگذارد، چه؟

من کد تایمر را کامنت کردم. خطا دوباره رخ نداد. اما این بدان معنا نیست که ما آن را تعمیر کردیم، زیرا شکست به طور تصادفی رخ داد. اگر من فقط خوش شانس بودم چه؟

چند روز بعد دوباره با برنامه آزمایشی آزمایش کردم. اشکال تکرار نشد. من به پایگاه کد کامل بازی برگشتم و کد ذخیره و بارگذاری را تغییر دادم تا تایمر قابل برنامه ریزی قبل از دسترسی به کارت حافظه به مقدار اولیه خود (100 هرتز) بازنشانی شود و سپس به 1 کیلوهرتز بازنشانی شود. دیگر هیچ تصادفی وجود نداشت.

اما چرا این اتفاق افتاد؟

دوباره به برنامه تست برگشتم. سعی کردم با تایمر 1 کیلوهرتز الگویی در بروز خطا پیدا کنم. در نهایت متوجه شدم که این خطا زمانی رخ می دهد که شخصی با یک کنترلر PS1 بازی می کند. از آنجایی که من خودم به ندرت این کار را انجام می دهم - چرا هنگام تست ذخیره و بارگذاری کد به یک کنترلر نیاز دارم؟ - من حتی متوجه این وابستگی نشدم. اما یک روز یکی از هنرمندان ما منتظر بود تا من تست را تمام کنم - احتمالاً در آن لحظه فحش می دادم - و با عصبانیت کنترل را در دستانش چرخاند. خطایی رخ داده است. "صبر کن، چی؟!" خوب، دوباره انجامش بده!»

وقتی متوجه شدم که این دو رویداد به هم مرتبط هستند، توانستم به راحتی خطا را بازتولید کنم: شروع به ضبط در کارت حافظه کردم، کنترلر را حرکت دادم و کارت حافظه را خراب کردم. به نظر من یک باگ سخت افزاری به نظر می رسید.

من پیش کانی آمدم و در مورد کشفم به او گفتم. او اطلاعات را به یکی از مهندسانی که PS1 را طراحی کرده بود منتقل کرد. او پاسخ داد: غیرممکن است، این نمی تواند یک مشکل سخت افزاری باشد. از کانی خواستم تا یک گفتگو برای ما ترتیب دهد.

مهندس با من تماس گرفت و با انگلیسی شکسته او و ژاپنی من (به شدت) شکسته با هم دعوا کردیم. در نهایت گفتم: "اجازه دهید فقط برنامه آزمایشی 30 خطی خود را بفرستم که جابجایی کنترلر باعث ایجاد باگ می شود." او موافقت کرد. گفت که این اتلاف وقت است و او به طرز وحشتناکی مشغول کار روی یک پروژه جدید است، اما تسلیم خواهد شد زیرا ما یک توسعه دهنده بسیار مهم برای سونی بودیم. برنامه تستم رو پاک کردم و براش فرستادم.

عصر روز بعد (ما در لس آنجلس بودیم و او در توکیو) او با من تماس گرفت و با لجبازی عذرخواهی کرد. مشکل سخت افزاری بود

من نمی‌دانم دقیقاً باگ چیست، اما طبق آنچه در دفتر مرکزی سونی شنیدم، اگر تایمر را روی مقدار کافی تنظیم کنید، با اجزای روی مادربرد در مجاورت کریستال تایمر تداخل ایجاد می‌کند. یکی از آنها یک کنترلر Baud Rate برای کارت حافظه بود که نرخ باود را برای کنترلرها نیز تعیین می کرد. من مهندس نیستم، بنابراین ممکن است چیزی را به هم ریخته باشم.

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

گاوهای بد

در دهه 1980، مربی من، سرگئی، نرم افزاری برای SM-1800، شبیه سازی شوروی PDP-11، نوشت. این میکروکامپیوتر به تازگی در یک ایستگاه راه آهن در نزدیکی Sverdlovsk، یک مرکز حمل و نقل مهم در اتحاد جماهیر شوروی نصب شده است. سیستم جدید برای هدایت واگن ها و ترافیک بار طراحی شده است. اما حاوی یک باگ آزاردهنده بود که منجر به خرابی ها و خرابی های تصادفی می شد. سقوط همیشه زمانی اتفاق می‌افتد که شخصی عصر به خانه می‌رفت. اما علیرغم بررسی کامل روز بعد، کامپیوتر در تمام تست های دستی و اتوماتیک به درستی کار کرد. این معمولاً یک وضعیت مسابقه یا برخی از اشکالات رقابتی دیگر را نشان می دهد که تحت شرایط خاصی رخ می دهد. سرگئی که از تماس های اواخر شب خسته شده بود، تصمیم گرفت تا به ته آن بپردازد و اول از همه بفهمد که چه شرایطی در محوطه مارشالینگ منجر به خرابی رایانه شده است.

ابتدا، او آمار تمام سقوط‌های غیرقابل توضیح را جمع‌آوری کرد و یک نمودار بر اساس تاریخ و زمان ایجاد کرد. الگو مشخص بود. پس از مشاهده چند روز دیگر، سرگئی متوجه شد که به راحتی می تواند زمان خرابی سیستم در آینده را پیش بینی کند.

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

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

گاوها نه تنها تشعشعات زیادی از خود ساطع می کردند، بلکه سطح آن به قدری بالا بود که منجر به از دست دادن تصادفی قطعات در حافظه SM-1800 شد که در ساختمانی در کنار ایستگاه قرار داشت.

در اتحاد جماهیر شوروی کمبود مواد غذایی وجود داشت و مقامات تصمیم گرفتند گوشت چرنوبیل را با گوشت سایر مناطق کشور مخلوط کنند. این امر امکان کاهش سطح کلی رادیواکتیویته را بدون از دست دادن منابع ارزشمند فراهم کرد. با اطلاع از این موضوع ، سرگئی بلافاصله اسناد مهاجرت را پر کرد. و هنگامی که سطح تشعشع در طول زمان کاهش یافت، خرابی رایانه خود به خود متوقف شد.

از طریق لوله ها

روزی روزگاری، Movietech Solutions نرم افزاری را برای سینماها ایجاد کرد که برای حسابداری، فروش بلیط و مدیریت عمومی طراحی شده بود. نسخه DOS این برنامه پرچمدار در میان سینماهای زنجیره ای کوچک و متوسط ​​در آمریکای شمالی بسیار محبوب بود. بنابراین جای تعجب نیست که زمانی که نسخه ویندوز 95 معرفی شد، با جدیدترین صفحه نمایش های لمسی و کیوسک های سلف سرویس یکپارچه شد و به انواع ابزارهای گزارش دهی مجهز شد، به سرعت نیز محبوب شد. اغلب به روز رسانی بدون مشکل انجام شد. کارکنان محلی IT تجهیزات جدید نصب کردند، داده ها را انتقال دادند و تجارت ادامه یافت. مگر زمانی که دوام نیاورد. وقتی این اتفاق افتاد، شرکت جیمز را با نام مستعار «پاک کننده» فرستاد.

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

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

می ترسم هر چه زودتر به آناپولیس، نوا اسکوشیا بروید. کل سیستم آنها خراب شد و پس از یک شب کار با مهندسان آنها، نمی توانیم بفهمیم چه اتفاقی افتاده است. به نظر می رسد شبکه روی سرور از کار افتاده است. اما فقط پس از اینکه سیستم برای چند دقیقه کار کرد.

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

- دقیقاً: متخصص فناوری اطلاعات آنها "اولویت ها را تغییر داد" و تصمیم گرفتند با سرور قدیمی خود آنجا را ترک کنند. جیمز، آنها این سیستم را در شش سایت نصب کردند و فقط برای پشتیبانی پریمیوم پرداخت کردند، و تجارت آنها اکنون مانند دهه 1950 اداره می شود.

جیمز کمی راست شد.

- این یه چیز دیگه است. خوب، بیایید شروع کنیم.

وقتی به آناپولیس رسید، اولین کاری که کرد این بود که اولین تئاتر مشتری را پیدا کرد که مشکل داشت. در نقشه ای که در فرودگاه گرفته شد، همه چیز مناسب به نظر می رسید، اما منطقه اطراف آدرس مورد نظر مشکوک به نظر می رسید. گتو نیست، اما یادآور فیلم نوآر است. وقتی جیمز در حاشیه شهر پارک می کرد، یک فاحشه به او نزدیک شد. با توجه به اندازه آناپولیس، به احتمال زیاد تنها در کل شهر بوده است. ظاهر او بلافاصله شخصیت مشهوری را به ذهن متبادر کرد که برای پول در صفحه نمایش بزرگ پیشنهاد سکس می داد. نه، نه در مورد جولیا رابرتز، بلکه در مورد جان وویت [کنایه از فیلم "کابوی نیمه شب" - تقریبا. مسیر].

جیمز با فرستادن فاحشه به راه خود به سینما رفت. منطقه اطراف بهتر شده بود، اما هنوز این تصور را به وجود می آورد که فرسوده شده است. نه اینکه جیمز خیلی نگران بود. او قبلاً در مکان های بدبختی بوده است. و اینجا کانادا بود، جایی که حتی دزدگیرها آنقدر مودب هستند که بعد از گرفتن کیف پول شما بگویند «متشکرم».

ورودی فرعی سینما در یک کوچه پر آب بود. جیمز به سمت در رفت و در زد. به زودی جیر جیر زد و کمی باز شد.

-شما نظافتچی هستید؟ - صدای خشن از داخل آمد.

- آره منم... اومدم همه چی رو درست کنم.

جیمز وارد لابی سینما شد. ظاهراً چاره دیگری نداشت، کارکنان شروع به توزیع بلیط های کاغذی به بازدیدکنندگان کردند. این امر گزارشگری مالی را دشوار می کرد، چه رسد به جزئیات جالب تر. اما کارکنان با آسودگی خاطر از جیمز استقبال کردند و بلافاصله او را به اتاق سرور بردند.

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

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

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

سپس یکی از کارمندان وارد شد.

- سیستم دوباره کار می کند.

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

- سیستم خراب است.

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


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

- سیستم دوباره کار می کند.

اگر می توانید یک کف دست ذهنی انجام دهید، این دقیقاً همان کاری است که جیمز انجام داد. محافظ صفحه نمایش از OpenGL استفاده می کند. و بنابراین، در حین کار، تمام منابع پردازنده سرور را مصرف می کند. در نتیجه، هر تماس با سرور با یک تایم اوت به پایان می رسد.

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

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

سقوط در مرحله خاصی از ماه

داستان واقعی. یک روز یک باگ نرم افزاری به وجود آمد که به فاز ماه بستگی داشت. روال کوچکی وجود داشت که معمولاً در برنامه های مختلف MIT برای محاسبه تقریب فاز واقعی ماه استفاده می شد. GLS این روال را در یک برنامه LISP ایجاد کرد که هنگام نوشتن یک فایل، خطی را با مهر زمانی نزدیک به 80 کاراکتر خروجی می داد. بسیار نادر بود که خط اول یک پیام خیلی طولانی باشد و به خط بعدی منتهی شود. و وقتی برنامه بعداً این فایل را خواند، نفرین کرد. طول خط اول به تاریخ و زمان دقیق و همچنین طول مشخصات فاز در زمان چاپ مهر زمانی بستگی داشت. یعنی اشکال به معنای واقعی کلمه به فاز ماه بستگی داشت!

چاپ اول کاغذی فایل صنفی (Steele-1983) حاوی نمونه ای از چنین خطی بود که به اشکال توصیف شده منتهی شد، اما حروفچین آن را "رفع" کرد. از آن زمان به عنوان "اشکال فاز ماه" توصیف شده است.

با این حال، مراقب فرضیات باشید. چند سال پیش، مهندسان سرن (مرکز تحقیقات هسته ای اروپا) در آزمایشات انجام شده در برخورد دهنده بزرگ الکترون-پوزیترون با خطاهایی مواجه شدند. از آنجایی که کامپیوترها قبل از اینکه نتیجه را به دانشمندان نشان دهند، به طور فعال حجم عظیمی از داده های تولید شده توسط این دستگاه را پردازش می کنند، بسیاری حدس می زنند که این نرم افزار به نوعی به فاز ماه حساس است. چندین مهندس ناامید به ته حقیقت رسیدند. این خطا به دلیل تغییر جزئی در هندسه حلقه 27 کیلومتری به دلیل تغییر شکل زمین در هنگام عبور از ماه به وجود آمد! این داستان با عنوان «انتقام نیوتن از فیزیک ذرات» و نمونه‌ای از ارتباط بین ساده‌ترین و قدیمی‌ترین قوانین فیزیک و پیشرفته‌ترین مفاهیم علمی وارد فولکلور فیزیک شده است.

شستشوی توالت باعث توقف قطار می شود

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

در یکی از بررسی‌ها، یک مهندس که در قطار سفر می‌کرد به توالت رفت. او به زودی دور شد، بوم! توقف اضطراری.

مهندس با راننده تماس گرفت و پرسید:

- درست قبل از ترمز چه کار می کردی؟

-خب تو سرازیری سرعتمو کم کردم...

این عجیب بود، زیرا در طول عملیات عادی قطار ده ها بار سرعت خود را کاهش می دهد. قطار حرکت کرد و در فرود بعدی راننده هشدار داد:

- میرم سرعتمو کم کنم.

هیچ اتفاقی نیفتاد.

- در آخرین ترمز چه کردی؟ - از راننده پرسید.

-خب...تو توالت بودم...

-خب پس برو توالت و کاری که کردی بکن که دوباره پایین رفتیم!

مهندس به توالت رفت و وقتی راننده هشدار داد: «دارم کم می‌کنم»، آب را بیرون کشید. البته قطار بلافاصله متوقف شد.

حالا آنها می توانستند مشکل را بازتولید کنند و باید علت را پیدا کنند.

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

دروازه ای که از فرترن متنفر بود

چند ماه پیش متوجه شدیم که اتصالات شبکه در سرزمین اصلی [این در هاوایی بود] بسیار بسیار کند می شود. این می تواند 10-15 دقیقه طول بکشد و سپس به طور ناگهانی دوباره رخ دهد. پس از مدتی، همکارم به من شکایت کرد که اتصالات شبکه در سرزمین اصلی است به طور کلی کار نمی کند. او مقداری کد FORTRAN داشت که باید در دستگاهی در سرزمین اصلی کپی می‌شد، اما نمی‌توانست زیرا "شبکه به اندازه کافی نگه نداشت تا بارگذاری FTP کامل شود."

بله، مشخص شد که خرابی شبکه زمانی رخ می دهد که یکی از همکاران سعی می کند فایلی را با کد منبع در FORTRAN به یک ماشین در سرزمین اصلی FTP کند. ما سعی کردیم فایل را بایگانی کنیم: سپس به آرامی کپی شد (اما دستگاه مقصد بسته‌کننده نداشت، بنابراین مشکل حل نشد). در نهایت کد FORTRAN را به قطعات بسیار کوچک تقسیم کردیم و آنها را یکی یکی ارسال کردیم. اکثر قطعات بدون مشکل کپی شدند، اما چند قطعه از آن عبور نکردند یا بعد از آن گذشتند تعداد زیادی تلاش می کند.

هنگامی که ما بخش های مشکل ساز را بررسی کردیم، متوجه شدیم که آنها چیزی مشترک دارند: همه آنها حاوی بلوک های نظر بودند که با خطوطی از C بزرگ شروع و پایان می یافتند (همانطور که یکی از همکاران ترجیح داد در FORTRAN نظر بدهد). ما به کارشناسان شبکه در سرزمین اصلی ایمیل زدیم و درخواست کمک کردیم. البته می خواستند نمونه فایل های ما را ببینند که از طریق FTP قابل انتقال نبود... اما نامه های ما به دستشان نرسید. در نهایت ما به یک ساده رسیدیم توصیف کردنفایل های غیرقابل انتقال چگونه به نظر می رسند کار کرد :) [به جرات می توانم نمونه ای از یکی از نظرات مشکل ساز FORTRAN را اینجا اضافه کنم؟ احتمالاً ارزشش را ندارد!]

در نهایت ما موفق شدیم آن را کشف کنیم. اخیراً یک دروازه جدید بین بخش دانشگاه ما و شبکه اصلی نصب شده است. در انتقال بسته هایی که حاوی بیت های مکرر حروف بزرگ C بودند، مشکل بسیار زیادی داشت! فقط تعداد کمی از این بسته ها می توانند تمام منابع دروازه را اشغال کنند و از عبور بیشتر بسته های دیگر جلوگیری کنند. از سازنده گیت‌وی شکایت کردیم و آنها پاسخ دادند: «اوه، بله، شما با یک باگ C مکرر مواجه هستید! ما قبلاً درباره او می دانیم.» ما در نهایت مشکل را با خرید یک دروازه جدید از یک سازنده دیگر حل کردیم (در دفاع از اولی، عدم توانایی انتقال برنامه های FORTRAN ممکن است برای برخی یک مزیت باشد!).

دوران سخت

چند سال پیش، در حالی که در حال کار بر روی ایجاد یک سیستم ETL در پرل برای کاهش هزینه‌های آزمایش‌های بالینی فاز 40 بودم، نیاز به پردازش حدود 000 خرما داشتم. دو نفر از آنها در آزمون موفق نشدند. این خیلی من را آزار نداد، زیرا این تاریخ‌ها از داده‌های ارائه‌شده توسط مشتری گرفته شده‌اند که اغلب، باید بگوییم، شگفت‌انگیز بود. اما وقتی داده های اصلی را بررسی کردم، معلوم شد که این تاریخ ها 1 ژانویه 2011 و 1 ژانویه 2007 هستند. فکر می کردم که این اشکال در برنامه ای که به تازگی نوشته بودم وجود دارد، اما معلوم شد که 30 سال گذشته است. قدیمی این ممکن است برای کسانی که با اکوسیستم نرم افزاری آشنا نیستند مرموز به نظر برسد. به دلیل تصمیم طولانی مدت یک شرکت دیگر برای کسب درآمد، مشتری من به من پول داد تا اشکالی را که یک شرکت به طور تصادفی و دیگری عمدا معرفی کرده بود، برطرف کنم. برای اینکه متوجه شوید در مورد چه چیزی صحبت می کنم، باید در مورد شرکتی صحبت کنم که ویژگی را اضافه کرد که در نهایت به یک باگ تبدیل شد، و همچنین چند رویداد جالب دیگر که در ایجاد باگ مرموزی که من برطرف کردم، صحبت کنم.

در روزهای خوب قدیمی، کامپیوترهای اپل گاهی اوقات به طور خود به خود تاریخ خود را به اول ژانویه 1 بازنشانی می کردند. دلیل آن ساده بود: از یک "ساعت سیستم" با باتری برای پیگیری تاریخ و زمان استفاده می کرد. وقتی باتری از بین رفت چه اتفاقی افتاد؟ کامپیوترها شروع به ردیابی تاریخ با تعداد ثانیه از آغاز یک دوره کردند. منظور ما از دوره، تاریخ اصلی مرجع بود، و برای مکینتاش ها این تاریخ 1904 ژانویه 1 بود. و پس از اتمام باتری، تاریخ فعلی به تاریخ مشخص شده بازنشانی شد. اما چرا این اتفاق افتاد؟

پیش از این، اپل از 32 بیت برای ذخیره تعداد ثانیه از تاریخ اولیه استفاده می کرد. یک بیت می تواند یکی از دو مقدار را ذخیره کند - 1 یا 0. دو بیت می تواند یکی از چهار مقدار را ذخیره کند: 00، 01، 10، 11. سه بیت - یک مقدار از هشت: 000، 001، 010، 011، 100 ، 101، 110، 111، و غیره و 32 می تواند یکی از 232 مقدار را ذخیره کند، یعنی 4 ثانیه. برای تاریخ های اپل، این برابر با 294 سال است، بنابراین مک های قدیمی تر نمی توانند تاریخ های بعد از 967 را مدیریت کنند. و اگر باتری سیستم از بین برود، تاریخ از ابتدای دوره به 296 ثانیه بازنشانی می‌شود و شما باید هر بار که کامپیوتر را روشن می‌کنید (یا تا زمانی که باتری جدید بخرید) تاریخ را به صورت دستی تنظیم کنید.

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

برو جلو. ما از Lotus 1-2-3 استفاده کردیم، "برنامه قاتل" IBM که به راه اندازی انقلاب رایانه شخصی کمک کرد، اگرچه رایانه های اپل VisiCalc داشتند که باعث موفقیت رایانه شخصی شد. انصافاً، اگر 1-2-3 ظاهر نمی شد، رایانه های شخصی به سختی شروع به کار می کردند، و تاریخ رایانه های شخصی می توانست به طور بسیار متفاوتی توسعه یابد. لوتوس 1-2-3 به اشتباه سال 1900 را به عنوان یک سال کبیسه در نظر گرفت. هنگامی که مایکروسافت اولین صفحه گسترده خود، Multiplan را منتشر کرد، سهم کمی از بازار را به خود اختصاص داد. و هنگامی که پروژه اکسل را راه اندازی کردند، تصمیم گرفتند نه تنها طرح نامگذاری ردیف و ستون را از Lotus 1-2-3 کپی کنند، بلکه با در نظر گرفتن عمدی سال 1900 به عنوان یک سال کبیسه، سازگاری باگ را تضمین کنند. این مشکل امروز هم وجود دارد. یعنی در 1-2-3 این یک باگ بود، اما در اکسل این یک تصمیم آگاهانه بود که تضمین می‌کرد همه کاربران 1-2-3 می‌توانند جداول خود را بدون تغییر داده وارد اکسل کنند، حتی اگر نادرست باشد.

اما مشکل دیگری وجود داشت. ابتدا، مایکروسافت اکسل را برای مکینتاش منتشر کرد که تاریخ های قبل از 1 ژانویه 1904 را تشخیص نمی داد. و در اکسل، 1 ژانویه 1900 آغاز دوران در نظر گرفته شد. بنابراین توسعه دهندگان تغییری ایجاد کردند به طوری که برنامه آنها نوع دوران را تشخیص داد و داده ها را مطابق با دوران مورد نظر در درون خود ذخیره کرد. مایکروسافت حتی یک مقاله توضیحی در این باره نوشت. و این تصمیم منجر به باگ من شد.

سیستم ETL من صفحات گسترده اکسل را از مشتریان دریافت کرد که در ویندوز ایجاد شده بودند، اما می توانستند در مک نیز ایجاد شوند. بنابراین، آغاز دوران در جدول می تواند یا 1 ژانویه 1900 یا 1 ژانویه 1904 باشد. چگونه متوجه شویم؟ فرمت فایل اکسل اطلاعات لازم را نشان می دهد، اما تجزیه کننده ای که من استفاده کردم آن را نشان نمی دهد (اکنون نشان می دهد) و فرض می کند که شما دوره جدول خاصی را می دانید. احتمالاً می‌توانستم زمان بیشتری را صرف درک قالب باینری اکسل و ارسال یک وصله به نویسنده تجزیه‌کننده کنم، اما کارهای بیشتری برای انجام دادن برای مشتری داشتم، بنابراین به سرعت یک اکتشافی برای تعیین دوره نوشتم. او ساده بود.

در اکسل، تاریخ 5 ژوئیه 1998 را می توان در قالب "07-05-98" (سیستم آمریکایی بی فایده)، "5 جولای 98"، "5 جولای 1998"، "5-ژوئیه-98" یا فرمت دیگری، فرمت بی فایده دیگری (از قضا، یکی از فرمت هایی که نسخه اکسل من ارائه نمی داد ISO 8601 بود). با این حال، در جدول، تاریخ بدون قالب به عنوان "35981" برای دوره 1900 یا "34519" برای دوره 1904 ذخیره شده است (اعداد نشان دهنده تعداد روزهای پس از دوره است). من به سادگی از یک تجزیه کننده ساده برای استخراج سال از تاریخ فرمت شده استفاده کردم و سپس از تجزیه کننده اکسل برای استخراج سال از تاریخ فرمت نشده استفاده کردم. اگر هر دو مقدار 4 سال متفاوت بود، می دانستم که از سیستمی با epoch-1904 استفاده می کنم.

چرا فقط از تاریخ های قالب بندی شده استفاده نکردم؟ زیرا 5 ژوئیه 1998 می تواند به عنوان "ژوئیه 98" با روز از دست رفته ماه قالب بندی شود. ما جدول‌هایی را از شرکت‌های زیادی دریافت کردیم که آنها را به روش‌های مختلف ایجاد کردند که تعیین تاریخ‌ها به عهده ما (در این مورد، من) بود. علاوه بر این، اگر اکسل آن را به درستی دریافت کند، ما نیز باید همینطور باشیم!

در همان زمان با 39082 روبرو شدم. بگذارید به شما یادآوری کنم که Lotus 1-2-3 سال 1900 را یک سال کبیسه در نظر گرفت و این صادقانه در Excel تکرار شد. و از آنجایی که این یک روز به سال 1900 اضافه شد، بسیاری از توابع محاسبه تاریخ ممکن است برای آن روز اشتباه باشد. یعنی 39082 می توانست 1 ژانویه 2011 (در مک) یا 31 دسامبر 2006 (در ویندوز) باشد. اگر "تجزیه کننده سال" من سال 2011 را از مقدار قالب بندی شده استخراج کند، پس همه چیز خوب است. اما از آنجایی که تجزیه کننده اکسل نمی داند از چه دوره ای استفاده می شود، به طور پیش فرض epoch-1900 را انتخاب می کند و سال 2006 را برمی گرداند. برنامه من دید که تفاوت 5 سال است، آن را یک خطا در نظر گرفت، آن را ثبت کرد و یک مقدار فرمت نشده را برگرداند.

برای دور زدن این موضوع، این را نوشتم (شبه کد):

diff = formatted_year - parsed_year
if 0 == diff
    assume 1900 date system
if 4 == diff
    assume 1904 date system
if 5 == diff and month is December and day is 31
    assume 1904 date system

و سپس تمام 40 خرما به درستی تجزیه شد.

در وسط کارهای چاپ بزرگ

در اوایل دهه 1980، پدرم در Storage Technology کار می‌کرد، یک بخش منقرض شده که درایوهای نوار و سیستم‌های پنوماتیکی برای تغذیه نوار با سرعت بالا ایجاد می‌کرد.

آنها درایوها را دوباره طراحی کردند تا بتوانند یک درایو مرکزی "A" متصل به هفت درایو "B" داشته باشند، و سیستم عامل کوچک در RAM که درایو "A" را کنترل می کند می تواند عملیات خواندن و نوشتن را به همه درایوهای "B" واگذار کند.

هر بار که درایو "A" راه اندازی می شد، لازم بود یک فلاپی دیسک را در درایو جانبی متصل به "A" وارد کنید تا سیستم عامل در حافظه آن بارگذاری شود. بسیار ابتدایی بود: قدرت محاسباتی توسط یک میکروکنترلر 8 بیتی ارائه می شد.

مخاطبان چنین تجهیزاتی شرکت هایی با انبارهای داده بسیار بزرگ - بانک ها، زنجیره های خرده فروشی و غیره - بودند که نیاز به چاپ تعداد زیادی برچسب آدرس یا صورت حساب بانکی داشتند.

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

تکنسین ها از Storage Technologies فرستاده شدند. اما علی‌رغم تمام تلاش‌هایشان، آن‌ها نتوانستند این اشکال را در شرایط آزمایشی بازتولید کنند: به نظر می‌رسید که در وسط کارهای چاپی بزرگ رخ می‌دهد. مشکل سخت افزار نبود، آنها هر چیزی را که می توانستند جایگزین کردند: رم، میکروکنترلر، درایو فلاپی، هر قسمت قابل تصور درایو نوار - مشکل همچنان ادامه داشت.

سپس تکنسین ها با ستاد تماس گرفتند و با کارشناس تماس گرفتند.

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

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

با شکست سوم، کارشناس متوجه چیزی شد. این شکست زمانی رخ داد که پرسنل نوارها را در یک درایو خارجی تغییر دادند. علاوه بر این، به محض اینکه یکی از کارمندان از کاشی خاصی روی زمین عبور کرد، شکست رخ داد.

کف برجسته از کاشی های آلومینیومی ساخته شده بود که در ارتفاع 6 تا 8 اینچ گذاشته شده بودند. سیم‌های زیادی از رایانه‌ها از زیر زمین بلند شده عبور می‌کردند تا از پا گذاشتن تصادفی روی یک کابل مهم جلوگیری کنند. کاشی ها بسیار محکم چیده شده بودند تا از ورود آوار به زیر زمین بلند شده جلوگیری شود.

کارشناس متوجه شد که یکی از کاشی ها تغییر شکل داده است. هنگامی که یک کارمند روی گوشه آن پا می گذاشت، لبه های کاشی به کاشی های مجاور می سایید. قطعات پلاستیکی که کاشی‌ها را به هم متصل می‌کردند نیز با آن‌ها مالش می‌دادند که باعث ایجاد ریز تخلیه‌های ساکن می‌شد که تداخل فرکانس رادیویی ایجاد می‌کرد.

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

جزر و مد است!

داستان در یک اتاق سرور، در طبقه چهارم یا پنجم یک دفتر در پورتسموث (فکر می‌کنم)، در محوطه اسکله اتفاق افتاد.

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

مرد پشتیبانی... فکر کنم اسمش مارک بود، اما مهم نیست... فکر نمی کنم او را بشناسم. مهم نیست، واقعا. بیایید به مارک بمانیم، باشه؟ عالی.

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

همان شب سرور دوباره خراب می شود. داستان همینه... سرور بالا نمیاد. مارک سعی می کند از راه دور کمک کند، اما مشتری نمی تواند سرور را راه اندازی کند.

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

تقریباً در اواسط روز سرور از کار می افتد (آرامش کنید!). این بار منطقی به نظر می رسد که افراد پشتیبانی سخت افزاری را برای جایگزینی سرور وارد کنید. اما نه، بعد از حدود 10 ساعت هم می افتد.

این وضعیت چندین روز تکرار شد. سرور کار می کند، پس از حدود 10 ساعت از کار می افتد و تا 2 ساعت آینده روشن نمی شود. آنها خنک کننده، نشت حافظه را بررسی کردند، همه چیز را بررسی کردند، اما چیزی پیدا نکردند. سپس تصادفات متوقف شد.

هفته بی خیال گذشت... همه خوشحال بودند. خوشحال باش تا همه چیز دوباره شروع شود. عکس هم همینطوره 10 ساعت کار، 2 تا 3 ساعت استراحت ...

و بعد یکی (فکر می کنم به من گفت که این شخص ربطی به فناوری اطلاعات ندارد) گفت:

"این جزر و مد است!"

این تعجب با نگاه‌های خالی مواجه شد و احتمالاً دست کسی روی دکمه تماس امنیتی تردید داشت.

"با جزر و مد کار نمی کند."

به نظر می رسد این یک مفهوم کاملاً خارجی برای کارکنان پشتیبانی IT است، که بعید است در حالی که برای قهوه نشسته اند، کتاب سال Tide را بخوانند. آنها توضیح دادند که این به هیچ وجه نمی تواند با جزر و مد مرتبط باشد، زیرا سرور یک هفته بدون خرابی کار کرده است.

"هفته گذشته جزر و مد کم بود، اما این هفته زیاد است."

اصطلاحات مختصری برای کسانی که مجوز قایق رانی ندارند. جزر و مد به چرخه ماه بستگی دارد. و همانطور که زمین می چرخد، هر 12,5 ساعت نیروی گرانشی خورشید و ماه یک موج جزر و مدی ایجاد می کند. در ابتدای سیکل 12,5 ساعته جزر و مد، در وسط چرخه جزر و مد و در پایان دوباره جزر و مد وجود دارد. اما با تغییر مدار ماه، تفاوت بین جزر و مد کم و زیاد نیز تغییر می کند. زمانی که ماه بین خورشید و زمین یا در طرف مقابل زمین قرار دارد (ماه کامل یا بدون ماه)، جزر و مد Syzygyn را دریافت می کنیم - بالاترین جزر و مد و کمترین جزر و مد. در نیمه ماه، جزر و مد مربعی داریم - کمترین جزر و مد. تفاوت بین دو افراط به شدت کاهش می یابد. چرخه قمری 28 روز طول می کشد: سیزیجین - ربع - سیزیجین - ربع.

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

ماموریت پرواز برای موشک

من وظیفه داشتم یک سیستم کنترل و نظارت پرتاب موشک بزرگ (حدود 400 هزار خط) را به نسخه های جدید سیستم عامل، کامپایلر و زبان منتقل کنم. به طور دقیق تر، از Solaris 2.5.1 تا Solaris 7، و از Verdix Ada Development System (VADS)، نوشته شده در Ada 83، به سیستم Rational Apex Ada، نوشته شده در Ada 95. VADS توسط Rational خریداری شد و محصول آن منسوخ شده بود، اگرچه Rational سعی کرد نسخه های سازگار بسته های ویژه VADS را پیاده سازی کند تا انتقال به کامپایلر Apex را آسان کند.

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

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

قرار بود پرتاب موشک در حدود سه هفته دیگر آزمایش شود و طی آزمایشات آزمایشگاهی شمارش معکوس، توالی دستورات مسدود شد. در زندگی واقعی، این آزمایش را متوقف می‌کند و اگر انسداد در عرض چند ثانیه پس از راه‌اندازی موتور رخ می‌دهد، چندین عمل غیرقابل برگشت در سیستم‌های کمکی رخ می‌دهد که مستلزم آمادگی طولانی - و گران قیمت - موشک است. شروع نمی شد، اما بسیاری از مردم به خاطر از دست دادن زمان و پول زیاد، بسیار ناراحت می شدند. اجازه ندهید کسی به شما بگوید که وزارت دفاع بی‌احتیاطی پول خرج می‌کند—من هرگز مدیر قراردادی را ندیده‌ام که بودجه را اول یا دوم و پس از آن برنامه‌ریزی نکرده باشد.

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

و به من به عنوان شخصی که سیستم را پورت کردم توجه شد.

مانند بسیاری از سیستم‌های حیاتی امنیتی، پارامترهای زیادی ثبت شد، بنابراین شناسایی چند خط کدی که قبل از از کار افتادن سیستم اجرا می‌شدند نسبتاً آسان بود. و البته، مطلقاً هیچ چیز غیرعادی در مورد آنها وجود نداشت؛ همان عبارات به معنای واقعی کلمه هزاران بار در طول یک اجرا با موفقیت اجرا شده بودند.

ما افراد را از Apex به Rational فراخوانی کردیم زیرا آنها کسانی بودند که کامپایلر را توسعه دادند و برخی از روتین هایی که آنها توسعه دادند در کد مشکوک فراخوانی شدند. آنها (و بقیه) تحت تأثیر قرار گرفتند که نیاز به ریشه یابی مشکلی با اهمیت واقعی ملی وجود دارد.

از آنجایی که هیچ چیز جالبی در مجلات وجود نداشت، تصمیم گرفتیم این مشکل را در یک آزمایشگاه محلی بازتولید کنیم. این کار آسانی نبود زیرا این رویداد تقریباً یک بار در هر 1000 اجرا رخ می داد. یکی از دلایل مشکوک تماس با یک تابع mutex توسعه یافته توسط فروشنده (بخشی از بسته مهاجرت VADS) بود. Unlock منجر به باز کردن قفل نشد. رشته پردازشی که تابع نامیده می شد، پیام های ضربان قلب را پردازش می کرد که به طور اسمی هر ثانیه می رسید. فرکانس را به 10 هرتز یعنی 10 بار در ثانیه رساندیم و شروع به اجرا کردیم. حدود یک ساعت بعد سیستم قفل شد. در لاگ دیدیم که ترتیب پیغام های ضبط شده مانند تست شکست خورده است. ما چندین بار دیگر را اجرا کردیم، سیستم به طور مداوم 45-90 دقیقه پس از شروع مسدود شد، و هر بار گزارش شامل همان مسیر بود. حتی اگر از لحاظ فنی کدهای متفاوتی را اجرا می کردیم - فرکانس پیام متفاوت بود - رفتار سیستم یکسان بود، بنابراین مطمئن بودیم که این سناریوی بارگذاری همان مشکل را ایجاد می کند.

اکنون باید بفهمیم که مسدودسازی دقیقاً در کجای توالی عبارات رخ داده است.

این پیاده سازی سیستم از سیستم وظیفه Ada استفاده می کرد و از آن به طرز باورنکردنی ضعیفی استفاده می کرد. Tasks یک ساختار همزمان قابل اجرا در سطح بالا در Ada است، چیزی شبیه به رشته‌های اجرا که فقط در خود زبان تعبیه شده است. هنگامی که دو وظیفه نیاز به ارتباط دارند، آنها "قرار ملاقات" می گذارند، داده های لازم را مبادله می کنند و سپس قرار ملاقات را متوقف می کنند و به اجرای مستقل خود باز می گردند. با این حال، این سیستم به طور متفاوتی اجرا شد. پس از قرار ملاقات یک کار هدف، آن کار هدف با کار دیگری قرار می‌گیرد، که سپس با یک کار سوم قرار می‌گیرد و به همین ترتیب تا زمانی که برخی از پردازش‌ها تکمیل شود. پس از این، همه این قرار ملاقات ها تکمیل شد و هر کار باید به اجرای خود باز می گشت. یعنی ما با گران‌ترین سیستم فراخوانی تابع در جهان سر و کار داشتیم که در حالی که بخشی از داده‌های ورودی را پردازش می‌کرد، کل فرآیند «چند وظیفه‌ای» را متوقف کرد. و قبل از این تنها به این دلیل که توان عملیاتی بسیار کم بود به مشکلاتی منجر نشد.

من این مکانیسم وظیفه را توضیح دادم زیرا زمانی که یک قرار ملاقات درخواست می‌شود یا انتظار می‌رود تکمیل شود، ممکن است یک "تکلیف سوئیچ" رخ دهد. یعنی پردازنده می تواند کار دیگری را که آماده اجراست شروع به پردازش کند. معلوم می‌شود که وقتی یک وظیفه برای قرار ملاقات با کار دیگر آماده است، یک کار کاملاً متفاوت می‌تواند شروع به اجرا کند و در نهایت کنترل به اولین قرار ملاقات باز می‌گردد. و رویدادهای دیگری ممکن است رخ دهد که باعث تغییر کار شود. یکی از این رویدادها فراخوانی یک تابع سیستم است، مانند چاپ یا اجرای mutex.

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

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

این سرنخ مورد نیاز برای ارزیابی عبارت مسدودکننده بود.

من یک بسته Ada ساختم که حاوی یک وظیفه، یک نوع شمارش شده و یک متغیر جهانی از آن نوع بود. لفظ های شمارش شونده به عبارات خاصی از توالی مشکل ساز (مثلاً Incrementing_Buffer_Index, Locking_Mutex, Mutex_Unlocked، و سپس عبارات انتساب را در آن درج می کند که شمارش مربوطه را به یک متغیر سراسری اختصاص می دهد. از آنجایی که کد شی همه اینها به سادگی یک ثابت را در حافظه ذخیره می کرد، تغییر وظیفه در نتیجه اجرای آن بسیار بعید بود. ما اساساً به عباراتی که می‌توانستند کار را تغییر دهند مشکوک بودیم، زیرا مسدود کردن در هنگام اجرا به جای بازگشت به هنگام تعویض کار (به دلایل متعدد) اتفاق افتاد.

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

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

من کد را با ردیابی اجرا کردم. یخ کرد. و نظارت مانند ساعت کار می کرد.

گزارش حاوی دنباله مورد انتظار بود که با مقداری قطع شد که نشان می‌دهد یک mutex فراخوانی شده است. Unlock، و کار تکمیل نشده است - همانطور که در مورد هزاران تماس قبلی وجود دارد.

مهندسان Apex با تب و تاب در حال تجزیه و تحلیل کد خود در این زمان بودند و مکانی را در mutex پیدا کردند که از نظر تئوری، یک قفل ممکن است رخ دهد. اما احتمال آن بسیار کم بود، زیرا فقط توالی خاصی از رویدادها که در یک زمان خاص اتفاق می‌افتند می‌تواند منجر به مسدود شدن شود. بچه ها، قانون مورفی، این قانون مورفی است.

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

من آن را در کد وارد کردم و تست را انجام دادم. هفت ساعت بعد کد همچنان کار می کرد.

کد من به Rational ارسال شد، جایی که آن‌ها آن را کامپایل کردند، آن را جدا کردند و بررسی کردند که از همان رویکردی که در توابع mutex مشکل‌ساز استفاده می‌شد استفاده نمی‌کند.

این شلوغ‌ترین بررسی کد شغلی من بود 🙂 حدود ده مهندس و مدیر در اتاق با من بودند، ده نفر دیگر در یک کنفرانس تلفنی بودند - و همه آنها حدود 20 خط کد را بررسی کردند.

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

خوب، همه چیز خوب است، اما نکته داستان چیست؟

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

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

من ماهیت مشکل را درک کردم. من دقیقا نمی دانستم کجا و چرا اتفاق می افتد، اما می دانستم چه اتفاقی می افتد.

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

چنین داستان هایی از مبارزه با کد برای کسانی که با ویژگی ها و شرایط چنین مبارزه ای آشنا نیستند چندان جالب نیست. اما این داستان ها به ما کمک می کنند تا بفهمیم برای حل مشکلات واقعاً دشوار چه چیزی لازم است.

برای حل مشکلات واقعا سخت، باید چیزی بیش از یک برنامه نویس باشید. شما باید "سرنوشت" کد، نحوه تعامل آن با محیط خود و نحوه عملکرد خود محیط را درک کنید.

و سپس شما هفته تعطیلات ویران شده خود را خواهید داشت.

ادامه دارد

منبع: www.habr.com

اضافه کردن نظر