Фальклор праграмістаў і інжынераў (частка 1)

Фальклор праграмістаў і інжынераў (частка 1)

Гэта падборка гісторый з інтэрнэту аб тым, як у багаў часам бываюць зусім неверагодныя праявы. Магчыма, вам таксама ёсць што расказаць.

Алергія аўтамабіля на ванільнае марожанае

Гісторыя для інжынераў, якія разумеюць, што відавочнае не заўсёды з'яўляецца рашэннем, і што наколькі б факты ні здаваліся непраўдападобнымі, гэта ўсё роўна факты. У падраздзяленне Pontiac Division карпарацыі General Motors паступіла скарга:

Пішу вам другі раз, і не вінавачу вас у тым, што вы не адказваеце, бо гэта гучыць вар'яцка. У нашай сям'і ёсць традыцыя: кожны вечар пасля вячэры ёсць марожанае. Гатункі марожанага кожны раз мяняюцца, і павячэраўшы, уся сям'я выбірае, якое марожанае трэба купіць, пасля чаго я еду ў краму. Нядаўна я купіў новы Pontiac, і з тых часоў мае паездкі за марожаным ператварыліся ў праблему. Ці бачыце, кожны раз, калі я купляю ванільнае марозіва і вяртаюся з крамы, машына не заводзіцца. Калі я прыношу любое іншае марожанае, машына заводзіцца без праблем. Хачу задаць сур'ёзнае пытанне, незалежна ад таго, наколькі глупства гэта прагучыць: «Што такога ёсць у Pontiac, з-за чаго яно не заводзіцца, калі я прыношу ванільнае марожанае, але пры гэтым лёгка заводзіцца, калі я прыношу марожанае з іншым густам? ».

Як вы разумееце, прэзідэнт падраздзяленні паставіўся да ліста скептычна. Аднак на ўсялякі выпадак адправіў інжынера праверыць. Той быў здзіўлены, што яго сустрэў забяспечаны, добра адукаваны мужчына, які жыве ў цудоўным раёне. Яны дамовіліся сустрэцца адразу пасля вячэры, каб удваіх з'ездзіць у краму па марожанае. У той вечар было ванільнае, і калі яны вярнуліся ў машыну, тая не завялася.

Інжынер прыязджаў яшчэ тры вечары. Упершыню марожанае было шакаладным. Машына завялася. Другі раз было клубнічнае марожанае. Машына завялася. На трэці вечар ён папрасіў узяць ванільнае. Машына не завялася.

Разумна разважыўшы, інжынер адмовіўся верыць у алергію аўтамабіля на ванільнае марозіва. Таму дамовіўся з уладальнікам машыны, што ён працягне свае візіты, пакуль не знойдзе рашэння праблемы. І адначасна пачаў рабіць нататкі: запісваў усю інфармацыю, час сутак, гатунак бензіну, час прыезду і вяртанні з крамы, і т.д.

Неўзабаве інжынер здагадаўся: уладальнік машыны марнаваў на куплю ванільнага марожанага менш часу. Чыннік была ў раскладцы тавара ў краме. Ванільнае марожанае было самым папулярным і ляжала ў асобным маразільніку ў пярэдняй частцы крамы, каб яго было лягчэй знайсці. А ўсе астатнія гатункі знаходзіліся ў задняй частцы крамы, і на пошук патрэбнага гатунку і аплату ішло значна больш часу.

Цяпер пытанне было да інжынера: чаму машына не заводзілася, калі з таго моманту, калі заглушылі рухавік, праходзіла менш чакай? Паколькі праблемай стаў час, а не ванільнае марозіва, інжынер хутка знайшоў адказ: справа была ў газавым корку. Яна ўзнікала кожны вечар, але калі ўладальнік машыны марнаваў на пошук марожанага больш часу, рухавік паспяваў дастаткова астудзіцца і спакойна заводзіўся. А калі мужчына купляў ванільнае марожанае, рухавік яшчэ заставаўся занадта гарачым і газавы корак не паспявала рассмактацца.

Мараль: нават зусім шалёныя праблемы часам бываюць рэальнымі.

Crash Bandicoot

Перажываць такое балюча. Як праграміст, ты прывыкаеш абвінавачваць свой код у першую чаргу, у другую, у трэцюю… і недзе ў дзесяцітысячную чаргу вінаваціш кампілятар. І яшчэ ніжэй па спісе ўжо абвінавачваеш абсталяванне.

Вось мая гісторыя пра бага жалеза.

Для гульні Crash Bandicoot я напісаў код для загрузкі і захаванні на карту памяці. Для такога самазадаволенага распрацоўшчыка гульняў гэта было нібы прагуляцца па парку: я лічыў, што праца зойме некалькі дзён. Аднак у выніку адладжваў код шэсць тыдняў. Адначасна я вырашаў і іншыя задачы, але кожныя некалькі дзён на некалькі гадзін вяртаўся да гэтага кода. Гэта была агонія.

Сімптом выглядаў так: калі захоўваеш бягучае праходжанне гульні і звяртаешся да карты памяці, амаль заўсёды ўсё праходзіць нармальна… Але часам аперацыя чытання ці запісы завяршаецца па таймаўце без якой-небудзь відавочнай прычыны. Кароткі запіс часцяком пашкоджвае карту памяці. Калі гулец спрабуе захавацца, ён не толькі не захоўваецца, але яшчэ і разбурае карту. Блін.

Праз некаторы час наш прадзюсар у Sony, Коні Бус, пачала панікаваць. Мы не маглі адгрузіць гульню з такім багам, і праз шэсць тыдняў я не разумеў, у чым прычына гэтай праблемы. Праз Коні мы звязаліся з іншымі распрацоўшчыкамі PS1: хто-небудзь сутыкаўся з падобным? Не. Ні ў кога не было праблем з картай памяці.

Калі ў цябе няма ідэй па адладцы, то практычна адзіным падыходам застаецца "падзеляць і панаваць": прыбіраеш усё больш і больш кода з памылковай праграмы, пакуль не застаецца параўнальна невялікі фрагмент, пры працы якога да гэтага часу ўзнікае праблема. Гэта значыць адразаеш ад праграмы па кавалку, пакуль не застаецца тая частка, што змяшчае баг.

Але справа ў тым, што вельмі цяжка выразаць кавалкі з відэагульні. Як яе запускаць, калі ты прыбраў код, які эмулюе гравітацыю? Або які адмалёўвае персанажаў?

Таму даводзіцца замяняць цэлыя модулі заглушкамі, якія прыкідваюцца, што робяць нешта карыснае, а насамрэч выконваюць нешта вельмі простае, што не можа змяшчаць памылак. Даводзіцца пісаць такія мыліцы, каб гульня хаця б працавала. Гэта павольны і балючы працэс.

Карацей, я гэта зрабіў. Выдаляў усё новыя і новыя кавалкі кода, пакуль не застаўся пачатковы код, які настройвае сістэму для запуску гульні, ініцыялізуе абсталяванне для адмалёўкі і г.д. Вядома, на гэтай стадыі я не мог зрабіць меню захавання і загрузкі, таму што прыйшлося б рабіць заглушку для ўсяго кода, які адказвае за графіку. Але я мог прыкінуцца карыстачом, які выкарыстоўвае (нябачны) экран захавання і загрузкі і просіць захаваць, а потым запісаць на карту памяці.

У выніку ў мяне застаўся невялікі фрагмент кода, з якім усё яшчэ ўзнікала вышэйзгаданая праблема - але да гэтага часу гэта адбывалася выпадковым чынам! Часцей за ўсё працавала нармальна, але зрэдку ўзнікалі збоі. Я прыбраў амаль увесь код гульні, але баг усё яшчэ жыў. Гэта бянтэжыла: пакінуты код насамрэч нічога не рабіў.

У нейкі момант, верагодна, у тры раніцы, мне ў галаву прыйшла думка. Аперацыі чытання і запісы (уводу-высновы) маюць на ўвазе дакладны час выканання. Калі працуеш з цвёрдай кружэлкай, картай памяці або Bluetooth-модулем, нізкаўзроўневы код, які адказвае за чытанне і запіс, робіць гэта ў адпаведнасці з тактавымі імпульсамі.

З дапамогай гадзінніка прылада, якое не злучана напроста з працэсарам, сінхранізуецца з выкананым у працэсары кодам. Гадзіны вызначаюць частату бадоў - хуткасць перадачы дадзеных. Калі з таймінгамі ўзнікае блытаніна, тое таксама блытаецца альбо абсталяванне, альбо ПА, альбо яны абодва. І гэта вельмі дрэнна, бо дадзеныя могуць пашкодзіцца.

А раптам нешта ў нашым кодзе блытае таймінгі? Я праверыў усё, што з гэтым злучана, у кодзе тэставай праграмы, і заўважыў, што мы задалі праграмуемаму таймеру ў PS1 частату 1 кгц (1000 тактаў у секунду). Гэта даволі шмат, па змаўчанні пры запуску прыстаўкі ён працуе з частатой 100 Гц. І большасць гульняў выкарыстоўвае менавіта гэтую частату.

Эндзі, распрацоўшчык гульні, задаў таймеру частату 1 кгц каб рухі вылічаліся дакладней. Эндзі схільны да празмернасці, і калі мы эмулюем гравітацыю, то які робіцца гэта настолькі сапраўды, наколькі магчыма!

Але што калі паскарэнне таймера неяк паўплывала на агульны таймінг праграмы, а значыць і на гадзіннік, які рэгулюе частату бадоў для карты памяці?

Я закаментаваў код з таймерам. Памылка больш не паўтаралася. Але гэта не азначае, што мы яе выправілі, бо збой узнікаў выпадковым чынам. А раптам мне проста павезла?

Праз некалькі дзён я зноў эксперыментаваў з тэставай праграмай. Баг не паўтараўся. Я вярнуўся да поўнай кодавай базы гульні і змяніў код захавання і загрузкі так, каб праграмуемы таймер скідаўся ў зыходнае значэнне (100 Гц) перад зваротам да карты памяці, а затым зноў вяртаўся да 1 кгц. Збояў больш не ўзнікала.

Але чаму так здарылася?

Я зноў вярнуўся да тэставай праграмы. Паспрабаваў знайсці нейкую заканамернасць ва ўзнікненні памылкі пры таймеры ў 1 кгц. У рэшце рэшт я заўважыў, што памылка ўзнікае, калі нехта гуляе з кантролерам PS1. Паколькі сам я рэдка гэта рабіў бы - навошта мне кантролер пры тэставанні кода захавання і загрузкі? - то я і не заўважаў гэтай залежнасці. Але аднойчы адзін з нашых мастакоў чакаў, калі я скончу тэставанне, - напэўна ў той момант я лаяўся, - і нервова круціў кантролер у руках. Узнікла памылка. «Пачакай, што?! Ану зрабі так зноў!».

Калі я зразумеў, што гэтыя дзве падзеі ўзаемазвязаны, то змог лёгка прайграць памылку: пачаў запісваць на карту памяці, паварушыў кантролер, сапсаваў карту памяці. Для мяне гэта выглядала як апаратны баг.

Я прыйшоў да Коні і расказаў пра сваё адкрыццё. Яна перадала інфармацыю аднаму з інжынераў, які праектаваў PS1. "Немагчыма, – адказаў ён, – гэта не можа быць апаратнай праблемай". Я папрасіў Коні зрабіць нам размову.

Інжынер патэлефанаваў мне, і мы паспрачаліся з ім на яго ламанай ангельскай і маёй (вельмі) ламанай японскай. Нарэшце я сказаў: "Давайце я проста дашлю сваю тэставую праграму ў 30 радкоў, пры якой рух кантролера прыводзіць да бага". Ён пагадзіўся. Заявіў, што гэта страта часу, і што ён жудасна заняты працай над новым праектам, але саступіць, таму што мы вельмі важны распрацоўшчык для Sony. Я падчысціў сваю тэставую праграму і адправіў яму.

На наступны вечар (мы былі ў Лос-Анджэлесе, а ён у Токіо) ён патэлефанаваў мне і збянтэжана папрасіў прабачэння. Гэта была апаратная праблема.

Я не ведаю, у чым менавіта складаўся баг, але, наколькі я чуў у штаб-кватэры Sony, калі задаць таймеру досыць высокае значэнне, тое гэта замінала кампанентам на матчынай плаце паблізу ад крышталя таймера. Адным з іх быў кантролер частаты бадоў для карты памяці, які таксама задаваў частату бадоў для кантролераў. Я не інжынер, таму мог нешта наблытаць.

Але сутнасць у тым, што паміж кампанентамі на матчынай плаце ўзнікалі перашкоды. І пры адначасовай перадачы дадзеных праз порт кантролера і порт карты памяці пры таймеры, які працуе з частатой 1 кгц, біты знікалі, дадзеныя губляліся, а карта пашкоджвалася.

Збойныя каровы

У 1980-х мой ментар Сяргей пісаў ПЗ для СМ-1800, савецкага клона PDP-11. Гэты мікракампутар толькі што ўсталявалі на ЖД-станцыі пад Свярдлоўскам, важным транспартным вузлом СССР. Новая сістэма была спраектавана для маршрутызацыі вагонаў і грузапатокаў. Але ў ёй аказаўся прыкры баг, які прыводзіў да выпадковых збояў і падзенняў. Падзенні ўзнікалі заўсёды, калі хтосьці сыходзіў увечар дадому. Але нягледзячы на ​​??дбайнае расследаванне на наступны дзень, пры ўсіх ручных і аўтаматычных тэстах кампутар працаваў карэктна. Звычайна гэта сведчыць аб стане гонкі або нейкім іншым багу канкурэнтнасці, які праяўляецца пры пэўных умовах. Стаміўшыся ад званкоў позняй ноччу, Сяргей вырашыў дакапацца да сутнасці, і перш за ўсё зразумець, якія ўмовы на сартавальнай станцыі прыводзілі да паломкі кампутара.

Спачатку ён сабраў статыстыку ўсіх невытлумачальных падзенняў і пабудаваў графік па датах і часе. Патэрн быў відавочны. Паназіраўшы яшчэ некалькі дзён, Сяргей зразумеў, што лёгка можа спрагназаваць час будучых сістэмных збояў.

Неўзабаве ён высветліў, што збоі ўзнікалі толькі тады, калі на станцыі сартавалі вагоны з буйной рагатай жывёлай з паўночнай Украіны і заходняй Расіі, якія накіроўваліся на найбліжэйшую бойню. Гэта само па сабе было дзіўна, бо жывёлагадоўлю забяспечвалі гаспадаркі, якія знаходзіліся значна бліжэй, у Казахстане.

Чарнобыльская АЭС узарвалася ў 1986-м, і радыеактыўныя ападкі зрабілі непрыдатнымі да пражывання прылеглыя тэрыторыі. Забруджванню падвергліся шырокія тэрыторыі ў паўночнай Украіне, Беларусі і заходняй Расіі. Западозрыўшы высокі ўзровень радыяцыі ў вагонах, Сяргей распрацаваў метад праверкі гэтай тэорыі. Насельніцтву мець дазіметры забаранялася, таму Сяргей праставіўся некалькім вайскоўцам на ЖД-станцыі. Пасля некалькіх порцый гарэлкі яму ўдалося пераканаць салдата вымераць узровень радыяцыі ў адным з падазроных вагонаў. Аказалася, што ўзровень у разы перавышае звычайныя значэнні.

Мала таго, што быдла моцна фаніла радыяцыяй, яе ўзровень быў настолькі вялікі, што гэта прыводзіла да выпадковага выпадзення бітаў у памяці СМ-1800, якая стаяла ў будынку побач са станцыяй.

У СССР узнікала недахоп прадуктаў харчавання, і ўлады вырашылі змешваць "чарнобыльскае" мяса з мясам з іншых абласцей краіны. Гэта дазваляла знізіць агульны ўзровень радыеактыўнасці без страты каштоўных рэсурсаў. Даведаўшыся пра гэта, Сяргей адразу ж запоўніў дакументы на эміграцыю. А падзенні камп'ютара спыніліся самі сабой, калі ўзровень радыяцыі знізіўся з часам.

Па трубах

Калісьці кампанія Movietech Solutions стварыла ПЗ для кінатэатраў, прызначанае для ўліку і продажу квіткоў і агульнага кіравання. DOS-версія флагманскага дадатку была даволі папулярная сярод невялікіх і сярэдніх сетак кінатэатраў у Паўночнай Амерыцы. Таму не дзіўна, што калі анансавалі версію пад Windows 95, інтэграваную з найноўшымі сэнсарнымі экранамі і кіёскамі самаабслугоўвання, а таксама абсталяваную разнастайнымі сродкамі справаздачнасці, яна таксама хутка стала папулярнай. Часцей за ўсё абнаўленне праходзіла без праблем. ІТ-адмыслоўцы на месцах усталёўвалі новае абсталяванне, мігравалі дадзеныя, і бізнэс працягваўся. За выключэннем выпадкаў, калі не працягваўся. Калі такое адбывалася, кампанія адпраўляла Джэймса па мянушцы "Чысцільшчык".

Хоць гэта мянушка намякае на гнюснага тыпу, аднак чысцільшчык - гэта толькі спалучэнне інструктара, усталёўшчыка і майстра на ўсе рукі. Джэймс мог правесці некалькі дзён у кліента, збіраючы ўсе кампаненты разам, а затым яшчэ пару дзён вучыў персанал карыстацца новай сістэмай, вырашаючы любыя праблемы з абсталяваннем і фактычна дапамагаючы праграмнаму забеспячэнню прайсці перыяд станаўлення.

Таму не дзіўна, што ў гэты сумятлівы час Джэймс прыйшоў раніцай у офіс, і не паспеў дайсці да свайго стала, як яго сустрэў кіраўнік, напоўнены кафеінам звыш звычайнага.

- Баюся, табе трэба як мага хутчэй адправіцца ў Аннаполiс у Новай Шатландыі. У іх легла ўся сістэма, і пасля ночы супольнай працы з іх інжынерамі мы не можам зразумець, што адбылося. Падобна, на серверы адмовіла сетка. Але толькі пасля таго, як сістэма прапрацавала некалькі хвілін.

- Яны не вярнуліся да старой сістэмы? - зусім сур'ёзна адказаў Джэймс, хоць у думках ён вылупіў вочы ад здзіўлення.

- Менавіта: у іх айцішніка "змяніліся прыярытэты" і ён вырашыў сысці з іх старым серверам. Джэймс, яны ўсталявалі сістэму на шасці пляцоўках і толькі што заплацілі за прэміяльную падтрымку, а іх бізнэс зараз вядзецца як у 1950-х.

Джэймс злёгку выпрастаўся.

- Гэта іншая справа. Добра, прыступаю.

Калі ён прыбыў у Аннаполiс, то перш за ўсё знайшоў першы кінатэатр кліента, у якім узнікла праблема. На ўзятай у аэрапорце мапе ўсё выглядала прыстойна, але наваколлі патрэбнага адрасу выглядалі падазрона. Не гета, але нагадвалі фільмы ў жанры "нуар". Калі Джэймс прыпаркаваўся каля абочыны ў цэнтры, да яго наблізілася прастытутка. Улічваючы памер Анаполіса, яна, хутчэй за ўсё, была адзіная на ўвесь горад. Яе з'яўленне адразу ж нагадала аб знакамітым персанажу, які на вялікім экране прапаноўваў сэкс за грошы. Не, не пра Джулію Робертс, а пра Джона Войце [намёк на фільм «Паўночны каўбой» - заўв. зав.].

Адправіўшы прастытутку дадому, Джэймс адправіўся да кінатэатра. Наваколлі сталі лепей, але ўсё роўна стваралася ўражанне занядбанасці. Не тое каб Джэймс занадта турбаваўся. Ён ужо бываў ва ўбогіх месцах. А гэта была Канада, у якой нават рабаўнікі дастаткова ветлівыя, каб сказаць «дзякуй» пасля таго, як адабралі ваш кашалёк.

Бакавы ўваход у кінатэатр знаходзіўся ў золкай алеі. Джэймс падышоў да дзвярэй і пастукаў. Неўзабаве яна зарыпела і прыадчынілася.

- Вы чысцільшчык? - раздаўся знутры хрыплы голас.

- Так, гэта я... я прыехаў, каб усё выправіць.

Джэймс прайшоў у фае кінатэатра. Верагодна, не маючы іншага выйсця, персанал пачаў выдаваць наведвальнікам папяровыя білеты. Гэта абцяжарвала фінансавую справаздачнасць, не кажучы ўжо пра цікавейшыя падрабязнасці. Але супрацоўнікі сустрэлі Джэймса з палёгкай і неадкладна завялі ў серверную.

На першы погляд усё было ў парадку. Джэймс залагініўся на сервер і праверыў звычайныя падазроныя месцы. Ніякіх праблем. Аднак з засцярогі Джэймс выключыў сервер, замяніў сеткавую карту і адкаціў сістэму. Яна маментальна зарабіла ў поўным аб'ёме. Персанал зноў пачаў прадаваць білеты.

Джэймс патэлефанаваў Марку і паведаміў аб сітуацыі. Няцяжка выказаць здагадку, што Джэймс можа захацець затрымацца тут і паглядзець, ці не адбудзецца што-небудзь нечаканае. Ён спусціўся па лесвіцы і пачаў распытваць супрацоўнікаў і тым, што адбылося. Відавочна, што сістэма перастала працаваць. Яны яе выключылі і ўключылі, усё зарабіла. Але праз 10 хвілін сістэма адвалілася.

Якраз у гэты момант адбылося нешта падобнае. Раптам сістэма для продажу білетаў пачала выдаваць памылкі. Супрацоўнікі ўздыхнулі і згрэблі папяровыя білеты, а Джэймс паспяшаўся ў серверную. З серверам усё выглядала добра.

Потым увайшоў адзін з супрацоўнікаў.

- Сістэма зноў працуе.

Джэймс быў збянтэжаны, бо ён нічога не зрабіў. Дакладней, нічога такога, што прымусіла б сыстэму працаваць. Ён разлагініўся, узяў тэлефон і патэлефанаваў у службу падтрымкі сваёй кампаніі. Неўзабаве ў серверную ўвайшоў той жа супрацоўнік.

- Сістэма ляжыць.

Джэймс зірнуў на сервер. На экране танцаваў цікавы і знаёмы ўзор з рознакаляровых формаў — трубы, якія хаатычна выгіналіся і перапляталіся. Усе мы некалі бачылі гэты скрынсэйвер. Ён быў выдатна адмаляваны і літаральна гіпнатызаваў.


Джэймс націснуў кнопку і ўзор знік. Ён паспяшаўся да білетнай касы і па шляху сустрэў які вяртаўся да яго супрацоўніка.

- Сістэма зноў працуе.

Калі можна ў думках зрабіць фэйспалм, то менавіта гэта Джэймс і зрабіў. Скрынсэйвер. Ён выкарыстоўвае OpenGL. І таму падчас працы спажывае ўсе рэсурсы сервернага працэсара. У выніку кожны зварот да сервера завяршаецца па таймаўце.

Джэймс вярнуўся ў серверную, залагініўся і замяніў скрынсэйвер з выдатнымі трубамі на пусты экран. Гэта значыць замест скрынсэйвера, паглынальнага 100% рэсурсаў працэсара, паставіў іншы, які не спажывае рэсурсы. Затым пачакаў 10 хвілін, каб праверыць сваю здагадку.

Калі Джэймс прыехаў у наступны кінатэатр, ён задумаўся аб тым, як растлумачыць свайму кіраўніку, што ён толькі што праляцеў 800 км, каб адключыць скрынсэйвер.

Збой у пэўную фазу Месяца

Праўдзівая гісторыя. Аднойчы ўзнік праграмны баг, які залежаў ад фазы Месяца. Там была маленькая падпраграма, якая звычайна выкарыстоўвалася ў розных праграмах MIT для вылічэння набліжэння да сапраўднай фазы Месяца. GLS убудавала гэтую падпраграму ў праграму на LISP, якая пры запісе файла выводзіла радок з часавай пазнакай даўжынёй амаль 80 знакаў. Вельмі рэдка першы радок паведамлення атрымліваўся занадта доўгім і пераходзіў на наступны радок. І калі праграма потым чытала гэты файл, яна лаялася. Даўжыня першага радка залежала ад дакладнай даты і чакай, а таксама ад даўжыні спецыфікацыі фазы ў момант друку часавай пазнакі. Гэта значыць баг у літаральным сэнсе залежаў ад фазы Месяца!

Першае папяровае выданне Jargon File (Steele-1983) утрымоўвала ўзор такога радка, які прыводзіў да апісанага бага, аднак наборшчык "выправіў" яе. З таго часу гэта апісваюць як «баг фазы Месяца».

Аднак будзьце асцярожныя са здагадкамі. Некалькі гадоў таму інжынеры з CERN (European Center for Nuclear Research) сутыкнуліся з памылкамі ў эксперыментах, якія праводзіліся на Вялікім электрон-пазітронным калайдэры. Паколькі кампутары актыўна апрацоўваюць гіганцкую колькасць дадзеных, якія генерыруюцца гэтай прыладай, перш чым паказаць вынік навукоўцам, многія меркавалі, што ПЗ нейкім чынам адчувальна да фазы Месяца. Некалькі адчайных інжынераў дакапаліся да ісціны. Памылка ўзнікала з-за невялікай змены геаметрыі кольца даўжынёй 27 км у сувязі з дэфармацыяй Зямлі пры праходзе Месяца! Гэтая гісторыя ўвайшла ў фальклор фізікаў як "Ньютонаўская помста фізіцы часціц" і прыклад сувязі найпростых і найстарэйшых фізічных законаў з найбольш перадавымі навуковымі канцэпцыямі.

Змыванне ў туалеце спыняе цягнік

Лепшы апаратны баг, аб якім я чуў, быў у хуткасным цягніку ў Францыі. Баг прыводзіў да аварыйнага тармажэння саставу, але толькі калі на борце былі пасажыры. Пры кожным такім выпадку поезд выводзілі з эксплуатацыі, правяралі, але нічога не знаходзілі. Пасля яго зноў адпраўлялі на лінію, і ён маментальна аварыйна спыняўся.

Падчас адной з праверак інжынер, які ехаў у цягніку, пайшоў у прыбіральню. Неўзабаве ён змыў за сабой, БУМ! Аварыйны прыпынак.

Інжынер звязаўся з машыністам і спытаў:

- Што ты рабіў перад самым тармажэннем?

- Ну, я прытармажваў на спуску...

Гэта было дзіўна, таму што пры звычайным курсаванні цягнік прытармажвае на спусках дзясяткі разоў. Састаў адправіўся далей, і на наступным спуску машыніст папярэдзіў:

- Я збіраюся прытармажваць.

Нічога не здарылася.

- Што ты рабіў пры апошнім тармажэнні? - спытаў машыніст.

- Ну… я быў у туалеце…

- Ну, тады ідзі ў туалет і зрабі тое, што рабіў, калі будзем спускацца зноў!

Інжынер адправіўся ў прыбіральню, і калі машыніст папярэдзіў: «Я тармажу», ён спусціў ваду. Вядома ж, цягнік тут жа спыніўся.

Цяпер яны маглі прайграць праблему і трэба было знайсці прычыну.

Праз дзве хвіліны яны заўважылі, што кабель дыстанцыйнага кіравання тармажэннем рухавіка (у цягніка было па адным рухавіку ў абодвух канцах) адлучаны ад сценкі электрашафы і ляжыць на рэле, які кіруе саленоідам туалетнай заглушкі… Калі рэле ўключалася, яно стварала перашкоды ў тармазным кабелі, і сістэма абароны ад збояў проста ўключала аварыйнае тармажэнне.

Шлюз, які ненавідзеў FORTRAN

Некалькі месяцаў таму мы заўважылі, што сеткавыя падлучэнні да сеткі на мацерыку [справа было на Гаваях] станавіліся вельмі-вельмі павольнымі. Гэта магло доўжыцца 10-15 хвілін, а потым нечакана ўзнікала зноў. Праз некаторы час мой калега пажаліўся мне, што падключэння да сеткі на мацерыку наогул не працуюць. У яго быў нейкі код на FORTRAN, які трэба было скапіяваць на машыну на мацерыку, але гэта не атрымлівалася, таму што "сетка не трымалася дастаткова доўга, каб завяршылася загрузка па FTP".

Так, атрымлівалася так, што адмовы сеткі ўзнікалі тады, калі калега спрабаваў перадаць па FTP файл з зыходным кодам на FORTRAN на машыну на мацерыку. Мы паспрабавалі архіваваць файл: тады ён спакойна капіяваўся (але на мэтавай машыне не было распакоўшчыка, так што праблема не была вырашана). Нарэшце мы падзялілі код на FORTRAN на вельмі маленькія фрагменты і адправілі іх па чарзе. Большасць фрагментаў скапіявалася без праблем, але некалькі штук не прайшлі, альбо прайшлі пасля шматлікіх спроб.

Вывучыўшы праблемныя фрагменты, мы выявілі, што ў іх ёсць сёе-тое агульнае: усе яны ўтрымоўваюць блокі каментароў, якія пачынаюцца і сканчаюцца радкамі, якія складаюцца з вялікіх літар З (так калега аддаваў перавагу каментаваць на FORTRAN). Мы адправілі на мацярык электронныя лісты спецыялістам па сетках і папрасілі аб дапамозе. Вядома, ім захацелася ўбачыць узоры нашых файлаў, якія не паддаюцца перасылцы па FTP… але нашы лісты да іх не дайшлі. Нарэшце мы прыдумалі проста апісаць, як выглядаюць неперасыланыя файлы. Гэта спрацавала 🙂 [Ці адважуся я дадаць сюды прыклад аднаго з праблемных каментароў на FORTRAN? Напэўна, не варта!]

У рэшце рэшт нам удалося разабрацца. Паміж нашай часткай кампуса і выхадам у сетку на мацерыку нядаўна ўсталявалі новы шлюз. У яго былі ВЯЛІКІЯ цяжкасці з перадачай пакетаў, якія ўтрымоўвалі паўтараюцца фрагменты з вялікіх З! Усяго некалькі такіх пакетаў маглі заняць усе рэсурсы шлюза і не дазвалялі прабіцца большасці іншых пакетаў. Мы пажаліліся вытворцу шлюза… і нам адказалі: «А, так, вы сутыкнуліся з багам паўтаральных С! Мы пра яго ўжо ведаем». У выніку мы вырашылі праблему, купіўшы новы шлюз іншага вытворцы (у абарону першага скажу, што няздольнасць перадаваць праграмы на FORTRAN для кагосьці можа апынуцца перавагай!).

Цяжкія часы

Некалькі гадоў таму, працуючы над стварэннем ETL-сістэмы на Perl, прызначанай для зніжэння выдаткаў на трэці этап клінічных выпрабаванняў, мне запатрабавалася апрацаваць каля 40 000 дат. Дзве з іх не прайшлі праверку. Мяне гэта не занадта занепакоіла, таму што гэтыя даты былі ўзяты з прадстаўленых кліентам дадзеных, якія часта, скажам так, дзівілі. Але калі я праверыў зыходныя дадзеныя, аказалася, што гэтымі датамі былі 1 студзеня 2011 і 1 студзеня 2007. Я падумаў, што баг змяшчаецца ў толькі што напісанай мной праграме, але аказалася, яму ўжо 30 гадоў. Гэта можа гучаць таямніча для тых, хто не знаёмы з экасістэмай праграмнага забеспячэння. З-за даўняга рашэння іншай кампаніі, прынятага дзеля заробку грошай, мой кліент заплаціў мне за выпраўленне бага, які адна кампанія занесла выпадкова, а іншая наўмысна. Каб вы зразумелі, пра што гаворка, мне трэба распавесці пра кампанію, якая дадала фічу, у выніку якая стала багам, а таксама яшчэ аб некалькіх цікаўных падзеях, якія ўнеслі фундуш у выпраўлены мной таямнічы баг.

У старыя добрыя часы кампутары Apple часам спантанна скідалі сваю дату на 1 студзеня 1904 гады. Прычына была простай: для адсочвання даты і часу выкарыстоўваліся якія працуюць ад батарэйкі «сістэмны гадзіннік». Што адбывалася, калі батарэйка садзілася? Кампутары пачыналі адсочваць дату па колькасці секунд ад пачатку эпохі. Пад эпохай мелася на ўвазе рэферэнсная зыходная дата, і для Macintosh'ей гэта было 1 студзеня 1904. І пасля памірання батарэйкі бягучая дата скідалася на паказаную. Але чаму так адбывалася?

Раней для захоўвання колькасці секунд з зыходнай даты Apple выкарыстоўвала 32 біта. Адзін біт можа захоўваць адно з двух значэнняў - 1 або 0. Два біты могуць захоўваць адно з чатырох значэнняў: 00, 01, 10, 11. Тры біта - адно значэнне з васьмі: 000, 001, 010, 011, 100, 101, 110, 111, і г.д. А 32 маглі захоўваць адно з 232 значэнняў, гэта значыць 4 секунд. Для дат па версіі Apple гэта было роўнае прыкладна 294 гадам, таму старыя Макі не могуць апрацоўваць даты пасля 967 года. І калі сістэмная батарэйка садзіцца, дата скідаецца на 296 секунд з пачатку эпохі, і даводзіцца ўручную выстаўляць дату пры кожным уключэнні кампутара (ці пакуль вы не купіце новую батарэйку).

Аднак рашэнне Apple захоўваць даты ў выглядзе секунд з пачатку эпохі азначала, што мы не можам апрацоўваць даты да пачатку эпохі, што мела далёка ідучыя наступствы, як мы ўбачым. Apple увяла фічу, а не баг. Апроч іншага гэта азначала, што аперацыйная сістэма Macintosh была непаражальная для «бага миллениума» (чаго не скажаш пра шматлікія прыкладанні для Мака, якія мелі ўласныя сістэмы вылічэння дат для абыходу абмежаванняў).

Ідзем далей. Мы выкарыстоўвалі Lotus 1-2-3, распрацаванае IBM "кілер-дадатак", якое дапамагло запусціць PC-рэвалюцыю, хоць на Apple-кампутарах была VisiCalc, якая забяспечыла поспех персанальным кампутарам. Дзеля справядлівасці, калі б 1-2-3 не з'явілася, PC наўрад ці ўзляцелі б, а гісторыя персанальных кампутараў магла развівацца б зусім інакш. Lotus 1-2-3 некарэктна апрацоўвала 1900-й як высакосны год. Калі Microsoft выпусціла сваю першую электронную табліцу Multiplan, тая заняла невялікую дзель рынка. І калі запусцілі праект Excel, вырашылі не толькі скапіяваць у Lotus 1-2-3 схему наймення радкоў і калонак, але і забяспечыць сумяшчальнасць па багах, свядома апрацоўваючы 1900-й як высакосны год. Гэтая праблема існуе дагэтуль. Гэта значыць у 1-2-3 гэта было багам, а ў Excel - свядомым рашэннем, якое гарантавала, што ўсе карыстачы 1-2-3 могуць імпартаваць свае табліцы ў Excel без змены дадзеных, нават калі яны памылковыя.

Але тут была яшчэ адна праблема. Спачатку Microsoft выпусціла Excel для Macintosh, які не прызнаваў даты да 1 студзеня 1904 года. А ў Excel пачаткам эпохі лічылася 1 студзеня 1900 гады. Таму распрацоўнікі занеслі змену, каб іх праграма распазнавала выгляд эпохі і захоўвала ў сабе дадзеныя ў адпаведнасці з патрэбнай эпохай. Microsoft нават напісала аб гэтым які тлумачыць артыкул. І гэтае рашэнне прывяло да майго бага.

Мая ETL-сістэма атрымлівала ад пакупнікоў Excel-табліцы, якія ствараліся пад Windows, але маглі быць створаны і на Маку. Таму пачаткам эпохі ў табліцы магло быць як 1 студзеня 1900 г., так і 1 студзеня 1904 года. Як гэта даведацца? Фармат файла Excel паказвае патрэбную інфармацыю, а парсер які я ўжываў, не паказваў (зараз паказвае), і меркаваў, што вы ведаеце эпоху для пэўнай табліцы. Мусіць, можна было выдаткаваць больш часу на тое, каб разабрацца ў двайковым фармаце Excel і даслаць патч аўтару парсера, але мне трэба было зрабіць для кліента шмат іншага, таму я хутка напісаў эўрыстыку для вызначэння эпохі. Яна была простай.

У Excel дата 5 ліпеня 1998 г. можа быць прадстаўлена ў фармаце «07-05-98» (бескарысная амерыканская сістэма), «Jul 5, 98», «July 5, 1998», «5-Jul-98» або ў якім-небудзь іншым бескарысным фармаце (па іроніі лёсу, адным з фарматаў, які не прапаноўвала мая версія Excel, быў стандарт ISO 8601). Аднак усярэдзіне табліц нефарматаваная дата захоўвалася альбо як «35981» для эпохі-1900, альбо як «34519» для эпохі-1904 (лікі ўяўляюць колькасць дзён з пачатку эпохі). Я проста з дапамогай простага парсера здабываў год з адфарматаванай даты, а затым з дапамогай парсера Excel здабываў год з неадфарматаванай даты. Калі абодва значэнні адрозніваліся на 4 гады, ад я разумеў, што выкарыстоўваю сістэму з эпохай-1904.

Чаму я не выкарыстоўваў проста адфарматаваныя даты? Таму што 5 ліпеня 1998 г. можа быць адфарматавана як «July, 98» са стратай дня месяца. Мы атрымлівалі табліцы ад такой колькасці кампаній, якія стваралі іх такімі рознымі спосабамі, што разбірацца з датамі павінны былі мы (у дадзеным выпадку я). Акрамя таго, калі Excel разумее правільна, дык і мы павінны!

Тады ж я сутыкнуўся з 39082. Нагадаю, што Lotus 1-2-3 лічыў 1900-й высакосным, і гэта добрасумленна паўтарылі ў Excel. А паколькі гэта дадавала да 1900-га адзін дзень, многія функцыі вылічэння дат маглі памыляцца на гэты самы дзень. Гэта значыць 39082 магло быць 1 студзеня 2011 г. (на Маках) або 31 снежня 2006 (у Windows). Калі мой "парсер гадоў" здабываў з адфарматаванага значэння 2011-ы год, то ўсё добра. Але паколькі парсер Excel не ведае, якая выкарыстоўваецца эпоха, ён па змаўчанні прымяняе эпоху-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, у не існуючым цяпер падраздзяленні, якое стварала істужачныя назапашвальнікі і пнеўматычныя сістэмы для высакахуткаснай падачы стужак.

Яны так перараблялі назапашвальнікі, каб тыя маглі мець адзін цэнтральны прывад "А", злучаны з сямю прывадамі "Бы", а маленькая АС у аператыўнай памяці, якая кіравала прывадам "А", магла дэлегаваць аперацыі чытання і запісы па ўсіх прывадах "Бы".

Пры кожным запуску прывада "А" трэба было ўстаўляць дыскету ў перыферыйны дыскавод, падлучаны да "А", каб загрузіць у яго памяць аперацыйную сістэму. Яна была вельмі прымітыўнай: вылічальная магутнасць забяспечвалася 8-бітным мікракантролерам.

Мэтавы аўдыторыяй такога абсталявання былі кампаніі з вельмі вялікімі сховішчамі дадзеных - банкі, рознічныя сеткі і г.д., - якім трэба было друкаваць шмат ярлыкоў з адрасамі або банкаўскіх выпісак.

У аднаго кліента была праблема. Пасярод задання на друк адзін канкрэтны прывад "А" мог перастаць працаваць, з-за чаго ўставала ўсё заданне. Каб аднавіць працу прывада, персаналу даводзілася ўсё перазагружаць. І калі гэта адбывалася пасярод шасцігадзіннага задання, то гублялася велізарная колькасць дарагога кампутарнага часу і зрываўся расклад усёй аперацыі.

З Storage Technologies адправілі тэхнікаў. Але нягледзячы на ​​ўсе спробы, яны не змаглі прайграць баг у тэставых умовах: падобна, збой узнікаў сярод вялікіх заданняў на друк. Праблема была не ў абсталяванні, яны замянілі ўсё, што маглі: аператыўную памяць, мікракантролер, дыскавод, усе мажлівыя часткі істужачнага прывада – праблема захоўвалася.

Тады тэхнікі патэлефанавалі ў штаб-кватэру і паклікалі эксперта.

Эксперт узяў крэсла і кубак кавы, сеў у кампутарнай зале - у тыя часы былі пакоі, спецыяльна выдзеленыя пад кампутары - і глядзеў, як персанал ставіць у чаргу вялікае заданне на друк. Эксперт чакаў, каб адбыўся збой - і той адбыўся. Усе паглядзелі на Эксперта - а ў таго не было ніякіх ідэй, чаму так адбылося. Таму ён загадаў зноўку паставіць заданне ў чаргу, і ўсе супрацоўнікі з тэхнікамі вярнуліся да працы.

Эксперт зноў сеў у крэсла і стаў чакаць збою. Прайшло каля шасці гадзін, і збой адбыўся. У Эксперта зноў не было ідэй, не лічачы таго, што ўсё здарылася ў запоўненым людзьмі памяшканні. Ён загадаў перазапусціць заданне, зноў сеў і пачаў чакаць.

Да трэцяга збою Эксперт сёе-тое заўважыў. Збой адбываўся тады, калі персанал мяняў стужкі ў староннім прывадзе. Больш за тое, збой узнікаў, як толькі адзін з супрацоўнікаў праходзіў праз пэўную плітку на падлозе.

Фальшпол быў зроблены з алюмініевых плітак, выкладзеных на вышыні 6-8 цаляў. Пад фальшпалам праходзілі шматлікія правады ад кампутараў, каб хто-небудзь выпадкова не наступіў на важны кабель. Пліткі былі выкладзеныя вельмі шчыльна, каб пад фальшпол не пападала смецце.

Эксперт зразумеў, што адна з плітак была дэфармаваная. Калі супрацоўнік наступаў на яе кут, плітка церлася бакамі аб суседнія пліткі. З імі церліся і пластмасавыя дэталі, якія злучалі пліткі, з-за чаго ўзнікалі статычныя мікраразрады, якія стваралі радыёчастотныя перашкоды.

Сёння аператыўная памяць значна лепш абаронена ад радыёчастотных перашкод. Але ў тыя гады гэта было ня так. Эксперт зразумеў, што гэтыя перашкоды парушалі працу памяці, а з ёй і працу аперацыйнай сістэмы. Ён патэлефанаваў у службу суправаджэння, замовіў новую плітку, сам яе ўстанавіў, і праблема знікла.

Гэта прыліў!

Гісторыя адбылася ў серверным пакоі, на чацвёртым ці пятым паверсе офіса ў Портсмуце (здаецца), у раёне докаў.

Аднойчы зваліўся Unix-сервер з асноўнай базай дадзеных. Яго перазагружалі, але ён радасна працягваў штораз падаць. Вырашылі паклікаць каго-небудзь са службы падтрымкі.

Чувак з падтрымкі… здаецца, яго звалі Марк, але гэта не важна… ці наўрад я з ім знакам. Гэта не важна, праўда. Спынімся на «Марку», добра? Выдатна.

Такім чынам, праз некалькі гадзін прыбыў Марк (ад Лідса да Портсмута шлях не блізкі, ці ведаеце), уключыў сервер і ўсё зарабіла без праблем. Тыповая чортава падтрымка, кліент з-за гэтага вельмі хвалюецца. Марк праглядае файлы часопіса і не знаходзіць нічога заганнага. Тады Марк вяртаецца на цягнік (ці на якім тамака выглядзе транспарта ён прыехаў, гэта магла быць і кульгавая карова, наколькі я ведаю… карацей, гэта не важна, добра?) і адпраўляецца зваротна ў Лідс, марна выдаткаваўшы дзень.

Тым жа ўвечар сервер падае зноў. Гісторыя тая ж… сервер не паднімаецца. Марка выдалена спрабуе дапамагчы, але кліент не можа запусціць сервер.

Зноў цягнік, аўтобус, цытрынавае безэ ці яшчэ нейкая херня, і Марк зноў у Портсмуце. Зірні, сервер загружаецца без праблем! Цуд. Марка некалькі гадзін правярае, што з аперацыёнкай ці ПА усё ў парадку, і адпраўляецца ў Лідс.

Прыкладна ў сярэдзіне дня сервер падае (лягчэй!). На гэты раз здаецца разумным прыцягнуць людзей з апаратнай падтрымкі, каб яны замянілі сэрвер. Але не, прыкладна праз 10 гадзін ён таксама падае.

Сітуацыя паўтаралася некалькі дзён. Сервер працуе прыкладна праз 10 гадзін падае і не запускаецца на працягу наступных 2 гадзін. Яны праверылі астуджэнне, уцечкі памяці, яны праверылі ўсё, але нічога не знайшлі. Затым збоі спыніліся.

Тыдзень прайшоў бесклапотна... усе былі шчаслівыя. Шчаслівыя, пакуль усё не пачалося зноў. Карціна тая ж. 10 гадзін працы, 2-3 гадзіны прастою…

А потым нехта (здаецца, мне казалі, што гэты чалавек не меў дачынення да ІТ) сказаў:

"Гэта прыліў!"

Выгук сустрэлі пустымі поглядамі, і, верагодна, нечая рука павагалася ля кнопкі выкліку аховы.

"Ён перастае працаваць з прылівам".

Здавалася б, гэта зусім чужая канцэпцыя для супрацоўнікаў ІТ-падтрымкі, якія ці наўрад чытаюць «штогоднік прыліваў», седзячы за каву. Яны патлумачылі, што гэта ніяк не можа быць звязана з прылівам, таму што сервер працаваў тыдзень без збояў.

"На мінулым тыдні прыліў быў нізкім, а на гэтым высокім".

Трохі тэрміналогіі для тых, у каго няма ліцэнзіі на кіраванне яхтай. Прылівы залежаць ад месяцовага цыклу. І па меры кручэння Зямлі, кожныя 12,5 гадзіны гравітацыйнае прыцягненне Сонца і Месяца стварае прыліўную хвалю. У пачатку 12,5-гадзіннага цыклу ўзнікае прыліў, у сярэдзіне цыкла - адліў, а ў канцы зноў прыліў. Але паколькі арбіта Месяцы змяняецца, мяняецца і розніца паміж адлівам і прылівам. Калі Месяц знаходзіцца паміж Сонцам і Зямлёй або з процілеглага боку ад Зямлі (паўнютка або адсутнасць Месяца), мы атрымліваем сізігійскія прылівы - самыя высокія прылівы і самыя нізкія адлівы. У поўню мы атрымліваем квадратурныя прылівы - самыя нізкія прылівы. Розніца паміж двума экстрэмумамі моцна памяншаецца. Месяцовы цыкл доўжыцца 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.

Тры чалавекі дапамагалі мне проста атрымаць чыста скампіляваны код. На гэта спатрэбілася два тыдні. А потым я самастойна працаваў над тым, каб прымусіць сістэму працаваць. Карацей, гэта былі горшыя архітэктура і рэалізацыя праграмнай сістэмы, што мне сустракаліся, таму на завяршэнне партавання пайшло яшчэ два месяцы. Затым сістэму перадалі на тэсціраванне, што заняло яшчэ некалькі месяцаў. Я адразу выпраўляў багі, якія знаходзілі пры тэставанні, але іх колькасць хутка знізілася (зыходны код быў production-сістэмай, таму яго функцыянальнасць працавала досыць надзейна, мне толькі прыйшлося прыбраць багі, якія ўзніклі пры адаптацыі пад новы кампілятар). У рэшце рэшт, калі ўсё працавала так, як і павінна было, мяне перавялі на іншы праект.

А ў пятніцу перад Днём падзякі раздаўся тэлефонны званок.

Прыкладна праз тры тыдні павінны былі пратэставаць запуск ракеты, і падчас лабараторных выпрабаванняў зваротнага адліку паслядоўнасць каманд аказалася заблакаванай. У рэальным жыцці гэта прывяло б да перапынення выпрабаванняў, а калі блакіроўка ўзнікла б на працягу некалькіх секунд пасля запуску рухавіка, то ў дапаможных сістэмах адбылося б некалькі незваротных дзеянняў, з-за якіх прыйшлося б доўга і дорага зноўку рыхтаваць ракету. Яна не стартавала б, але вельмі шмат людзей моцна знервавалася б з-за страты часу і вельмі, вельмі вялікіх грошай. Не дазваляйце нікому казаць вам, што міністэрства абароны бесцырымонна расходуе грошы - я яшчэ не сустракаў ніводнага мэнэджара па кантрактнай дзейнасці, для якога бюджэт не быў бы на першым ці другім месцы, а следам за ім графік.

У папярэднія месяцы гэтае выпрабаванне зваротнага адліку праганялася сотні разоў у шматлікіх варыянтах, і было толькі некалькі дробных замінак. Таму верагоднасць узнікнення гэтай была вельмі нізкай, аднак яе наступствы былі вельмі значныя. Памножце абодва гэтых фактару, і зразумееце, што навіна прадказвала мне і дзясяткам інжынераў і менеджэраў сапсаваны святочны тыдзень.

І ўвага была звернута на мяне, як на чалавека, які партаваў сістэму.

Як і ў большасці сістэм, для якіх крытычна важная бяспека, тут часопісавалася мноства параметраў, так што атрымалася даволі лёгка вызначыць некалькі радкоў кода, выкананых перад завісаннем сістэмы. І вядома ж, у іх не было абсалютна нічога незвычайнага, тыя ж самыя выразы паспяхова выконваліся літаральна тысячы разоў падчас таго ж прагону.

Мы паклікалі ў Rational людзей з Apex, паколькі гэта яны распрацавалі кампілятар і ў падазроным кодзе выклікаліся некаторыя распрацаваныя імі падпраграмы. На іх (і ўсіх іншых) зрабіла ўражанне, што трэба высветліць прычыну праблемы літаральна нацыянальнага значэння.

Паколькі ў часопісах не было нічога цікавага, вырашылі паспрабаваць прайграць праблему ў мясцовай лабараторыі. Гэта была няпростая задача, паколькі падзея ўзнікала прыкладна адзін раз на 1000 прагонаў. Адной з меркаваных прычын было тое, што выклік распрацаванай пастаўшчыком м'ютэкс-функцыі (частка пакета міграцыі VADS) Unlock не прыводзіў да разблакавання. Струмень апрацоўкі, які выклікаў функцыю, апрацоўваў heartbeat-паведамленні, якія намінальна прыходзілі кожную секунду. Мы паднялі частату да 10 Гц, гэта значыць 10 раз у секунду, і пачалі прагон. Прыкладна праз гадзіну сістэма заблакавалася. У часопісе мы ўбачылі, што паслядоўнасць запісаных паведамленняў была такой жа, як падчас збойнага выпрабавання. Зрабілі яшчэ некалькі прагонаў, сістэма стабільна блакавалася праз 45-90 хвілін пасля пачатку, і кожны раз у часопісе была адна і тая ж траса. Нягледзячы на ​​тое, што тэхнічна мы зараз выконвалі іншы код – частата паведамленняў была іншай – паводзіны сістэмы паўтараліся, таму мы пераканаліся, што гэты нагрузачны сцэнар прыводзіў да той жа праблемы.

Цяпер трэба было высветліць, дзе менавіта ў паслядоўнасці выразаў узнікала блакіроўка.

У гэтай рэалізацыі сістэмы выкарыстоўвалася сістэма задач Ada, і выкарыстоўвалася неверагодна дрэнна. Задачы - гэта высокаўзроўневая раўналежна выкананая канструкцыя ў Ada, нешта накшталт струменяў выканання, толькі ўбудаваная ў саму мову. Калі дзвюм задачам трэба ўзаемадзейнічаць, яны «прызначаюць рандэву» (rendezvous), абменьваюцца патрэбнымі дадзенымі, а затым спыняюць рандэву і вяртаюцца да сваіх незалежных выкананняў. Аднак сістэма была рэалізавана інакш. Пасля таго, як з мэтавай задачай праводзілася рандэву, гэтая мэтавая задача праводзіла рандэву з іншай задачай, якая потым праводзіла рандэву з трэцяй, і гэтак далей, пакуль не завяршалася нейкая апрацоўка. Пасля гэтага ўсе гэтыя рандэву завяршаліся і кожная задача павінна была вярнуцца да свайго выканання. Гэта значыць, мы мелі справу з самай дарагой у свеце сістэмай выкліку функцый, якая стопарыла ўвесь «шматзадачнай» працэс, пакуль апрацоўвала частка ўваходных дадзеных. І раней гэта не прыводзіла да праблем толькі таму, што прапускная здольнасць была вельмі нізкай.

Я апісаў гэты механізм задач таму, што калі запытвалася рандэву ці чакалася яго завяршэнне, магло адбывацца "пераключэнне задач". Гэта значыць працэсар мог пачаць апрацоўку іншай задачы, гатовай да выканання. Атрымліваецца, што калі адна задача гатова да рандэва з іншай задачай, можа пачацца выкананне зусім іншай задачы, і ў выніку кіраванне вяртаецца першаму рандэву. І могуць узнікаць іншыя падзеі, якія прыводзяць да пераключэння задачы; адна з такіх падзей - выклік сістэмнай функцыі, напрыклад, друк або выкананне м'ютэкса.

Каб зразумець, які радок кода прыводзіў да праблемы, мне трэба было знайсці спосаб запісваць прагрэс праходжання паслядоўнасці выразаў, пры гэтым не ініцыюючы пераключэнне задачы, што можа перашкодзіць узнікненню збою. Таму я не мог скарыстацца Put_Line(), Каб не выконваць аперацый уводу-вываду. Можна было задаць зменную-лічыльнік ці нешта падобнае, але як мне паглядзець яе значэнне, калі я не магу выводзіць яе на экран?

Таксама пры вывучэнні часопіса высветлілася, што, нягледзячы на ​​завісанне апрацоўкі heartbeat-паведамленняў, якое блакавала ўсе аперацыі ўводу-вываду працэсу і не давала выконваць іншыя апрацоўкі, іншыя незалежныя задачы працягвалі выконвацца. Гэта значыць праца блакавалася не цалкам, толькі (крытычны) ланцужок задач.

Гэта была зачэпка, неабходная для вылічэння блакіруючага выразы.

Я зрабіў Ada-пакет, які змяшчаў задачу, які пералічваецца тып і глабальную зменную гэтага тыпу. Пералічаныя літаралы былі прывязаныя да пэўных выразаў праблемнай паслядоўнасці (напрыклад, Incrementing_Buffer_Index, Locking_Mutex, Mutex_Unlocked), а затым уставіў у яе выразы прысвойвання, якія прысвойвалі адпаведны пералік глабальнай зменнай. Паколькі аб'ектны код усяго гэтага проста захоўваў сталую ў памяці, пераключэнне задачы ў выніку яго выканання было вельмі малаверагодна. У першую чаргу мы падазравалі выразы, якія маглі пераключыць задачу, паколькі блакіроўка ўзнікала пры выкананні, а не вяртанні пры зваротным пераключэнні задачы (па некалькіх прычынах).

Якая адсочвае задача проста выконвалася ў цыкле і перыядычна правярала, ці змянілася значэнне глабальнай зменнай. Пры кожнай змене значэнне захоўвалася ў файл. Затым нядоўгае чаканне і новая праверка. Я запісваў зменную ў файл таму, што задача выконвалася толькі тады, калі сістэма выбірала яе для выканання пры пераключэнні задачы ў праблемнай вобласці. Што б ні адбывалася ў гэтай задачы, гэта не ўплывала б на іншыя, не злучаныя з ёй заблакаваныя задачы.

Чакалася, што калі сістэма дойдзе да выканання праблемнага кода, глабальная пераменная будзе скідацца пры пераходзе да кожнага наступнага выразы. Затым адбудзецца нешта, якое прыводзіць да пераключэння задачы, і паколькі частата яго выканання (10 Гц) ніжэй, чым у маніторнай задачы, манітор мог зафіксаваць значэнне глабальнай зменнай і запісаць яго. У нармальнай сітуацыі я мог бы атрымаць паўтаральную паслядоўнасць падмноства пералічэнняў: апошнія значэнні зменнай на момант пераключэння задачы. Пры завісанні глабальная пераменная не павінна больш мяняцца, і апошняе запісанае значэнне пакажа, выкананне якога выразу не завяршылася.

Запусціў код з адсочваннем. Ён завіс. А маніторынг спрацаваў як па алеі.

У часопісе апынулася чаканая паслядоўнасць, якая перарывалася значэннем, якое паказвае, што быў выкліканы м'ютэкс. Unlock, а задача не завершана - як і ў выпадку з тысячамі папярэдніх выклікаў.

Інжынеры з Apex тым часам ліхаманкава аналізавалі свой код і знайшлі ў мьютэксе месца, дзе, тэарэтычна, магла ўзнікаць блакіроўка. Але яе верагоднасць была вельмі малая, паколькі да блакіроўкі магла прывесці толькі пэўная паслядоўнасць падзей, якія адбываюцца ў пэўны час. Закон Мерфі, хлопцы, гэта закон Мерфі.

Каб абараніць патрэбны фрагмент кода, я замяніў выклікі м'ютэкс-функцый (пабудаваных на аснове м'ютэкс-функцыянальнасці АС) маленькім натыўным м'ютэкс-пакетам Ada, каб з яго дапамогай кіраваць доступам мьютэксаў да гэтага фрагмента.

Уставіў у код і запусціў тэст. Сем гадзін праз код працягваў працаваць.

Мой код перадалі ў Rational, там яго скампілявалі, дызасэмблявалі і праверылі, што ў ім не выкарыстоўваецца той жа падыход, які ўжываўся ў праблемных м'ютэкс-функцыях.

Гэта была самая шматлюдная праверка кода ў маёй кар'еры 🙂 У пакоі са мной было каля дзесяці інжынераў і менеджэраў, яшчэ дзясятак людзей падключыліся па канферэнц-званку - і ўсе яны даследавалі каля 20 радкоў кода.

Код прайшоў праверку, сабралі новыя выкананыя файлы і перадалі на фармальнае рэгрэсійнае тэсціраванне. Праз пару тыдняў праз выпрабаванні зваротнага адліку прайшлі паспяхова, і ракета ўзляцела.

Добра, гэта ўсё добра і цудоўна, але ў чым сутнасць гэтай гісторыі?

Гэта была зусім агідная праблема. Сотні тысяч радкоў кода, паралельнае выкананне, звыш дзясятка якія ўзаемадзейнічаюць працэсаў, дрэнная архітэктура і дрэнная рэалізацыя, інтэрфейсы для ўбудаваных сістэмы і мільёны выдаткаваных даляраў. Ніякага ціску, праўда.

Я быў не адзіным, хто працаваў над гэтай праблемай, хаця і знаходзіўся ў цэнтры ўвагі, бо рабіў партаванне. Але хоць я і рабіў яго, гэта не азначае, што я разбіраўся з усімі сотнямі тысяч радкоў кода, ці хаця б бегла прагледзеў іх. Код і часопісы аналізавалі інжынеры па ўсёй краіне, але калі яны казалі мне свае гіпотэзы аб прычынах збою, мне хапала паўхвіліны, каб абвергнуць іх. І калі мяне прасілі прааналізаваць тэорыі, я перакладаў гэта на каго-небудзь іншага, таму што мне было відавочна, што гэтыя інжынеры ідуць не тым шляхам. Гучыць саманадзейна? Так, гэта так, але я адхіліў гіпотэзы і запыты па іншай прычыне.

Я разумеў прыроду праблемы. Я не ведаў дакладна, дзе яна ўзнікае і чаму, але я ведаў, што менавіта адбываецца.

За гады працы я назапасіў шмат ведаў і досведу. Я быў адным з піянераў выкарыстання Ada, разумеў яе добрыя якасці і недахопы. Я ведаю, як runtime-бібліятэкі Ada апрацоўваюць задачы і працуюць з паралельным выкананнем. І я разбіраюся ў нізкаўзроўневым праграмаванні на ўзроўні памяці, рэгістраў і асэмблера. Іншымі словамі, у мяне глыбокія спазнанні ў сваёй сферы. І я выкарыстоўваў іх для пошуку прычыны праблемы. Я не проста абышоў баг, а разумеў, як знайсці яго ва ўмовах вельмі адчувальнага асяроддзя выканання.

Такія гісторыі барацьбы з кодам не занадта цікавыя для тых, хто не знаёмы з асаблівасцямі і ўмовамі такой барацьбы. Але гэтыя гісторыі дапамагаюць зразумець, што патрабуецца для вырашэння сапраўды цяжкіх праблем.

Для вырашэння сапраўды цяжкіх праблем вам трэба быць не проста праграмістам. Вам трэба разумець "лёс" кода, як ён узаемадзейнічае са сваім асяроддзем і як працуе само асяроддзе.

І тады ў вас будзе свой сапсаваны святочны тыдзень.

Працяг будзе.

Крыніца: habr.com

Дадаць каментар