Folklor programera i inženjera (1. dio)

Folklor programera i inženjera (1. dio)

Ovo je izbor priča s interneta o tome kako bube ponekad imaju potpuno nevjerojatne manifestacije. Možda i vi imate nešto za reći.

Auto alergija na sladoled od vanilije

Priča za inženjere koji razumiju da očito nije uvijek odgovor i da koliko god činjenice izgledale nategnute, one su ipak činjenice. Pontiac Division of General Motors Corporation primio je pritužbu:

Ovo je drugi put da ti pišem i ne krivim te što se ne javljaš jer zvuči ludo. Naša obitelj ima tradiciju jedenja sladoleda svaku večer nakon večere. Vrste sladoleda se svaki put mijenjaju, a nakon večere cijela obitelj bira koji će sladoled kupiti, nakon čega odlazim u trgovinu. Nedavno sam kupio novi Pontiac i od tada mi odlasci na sladoled postaju problem. Vidite, svaki put kad kupim sladoled od vanilije i vratim se iz dućana, auto neće upaliti. Ako ponesem još koji sladoled, auto upali bez problema. Želim postaviti jedno ozbiljno pitanje, koliko god glupo zvučalo: “Što je to u Pontiacu da se ne pali kad donesem sladoled od vanilije, već lako pali kad donesem drugi okus sladoleda?”

Kao što možete zamisliti, predsjednik odjela bio je skeptičan u vezi s pismom. Međutim, za svaki slučaj poslao sam inženjera da provjeri. Bio je iznenađen što ga je sreo imućan, obrazovan čovjek koji živi u lijepom kraju. Dogovorili su se da će se naći odmah nakon večere kako bi njih dvoje otišli u dućan po sladoled. Te večeri bilo je vanile, a kad su se vratili do auta, nije htio upaliti.

Inženjer je dolazio još tri večeri. Prvi put je sladoled bio čokoladni. Auto je krenuo. Drugi put je bio sladoled od jagoda. Auto je krenuo. Treće večeri tražio je da uzme vaniliju. Auto nije upalio.

Racionalno razmišljajući, inženjer je odbio vjerovati da je automobil alergičan na sladoled od vanilije. Stoga sam se s vlasnikom automobila dogovorio da će nastaviti obilaziti dok ne nađe rješenje problema. I usput je počeo bilježiti: zapisivao je sve podatke, doba dana, vrstu benzina, vrijeme dolaska i povratka iz trgovine itd.

Inženjer je ubrzo shvatio da vlasnik automobila troši manje vremena kupujući sladoled od vanilije. Razlog je bio raspored robe u trgovini. Sladoled od vanilije bio je najpopularniji i držao se u zasebnom zamrzivaču ispred trgovine kako bi ga lakše pronašli. A sve druge sorte bile su u stražnjem dijelu trgovine i trebalo je mnogo više vremena da se pronađe prava sorta i plati.

Sada je pitanje bilo za inženjera: zašto auto nije upalio ako je prošlo manje vremena od trenutka kada je motor ugašen? Budući da je problem bilo vrijeme, a ne sladoled od vanilije, inženjer je brzo pronašao odgovor: bila je to plinska brava. Događalo se svake večeri, ali kada je vlasnik automobila više vremena proveo tražeći sladoled, motor se uspio dovoljno ohladiti i lako pokrenuti. A kad je čovjek kupio sladoled od vanilije, motor je još bio prevruć, a plinska brava se nije imala vremena otopiti.

Moral: Čak su i potpuno ludi problemi ponekad stvarni.

Crash Bandicoot

Bolno je ovo doživjeti. Kao programer, naviknete se kriviti svoj kod prvi, drugi, treći... i negdje na desettisućitom mjestu krivite kompajler. A niže na popisu već krivite opremu.

Evo moje priče o hardverskoj grešci.

Za igru ​​Crash Bandicoot napisao sam kod za učitavanje i spremanje na memorijsku karticu. Za tako samodopadnog programera igara, to je bilo poput šetnje parkom: mislio sam da će posao trajati nekoliko dana. Međutim, na kraju sam otklanjao pogreške koda šest tjedana. Usput sam rješavao i druge probleme, ali sam se svakih nekoliko dana vraćao na ovaj kod na nekoliko sati. Bila je to agonija.

Simptom je izgledao ovako: kada spremite trenutno igranje igre i pristupite memorijskoj kartici, sve gotovo uvijek ide u redu... Ali ponekad operacije čitanja ili pisanja isteknu bez očitog razloga. Kratka snimka često oštećuje memorijsku karticu. Kada igrač pokuša spasiti, ne samo da ne uspijeva spasiti, već i uništi mapu. Sranje.

Nakon nekog vremena, naša producentica u Sonyju, Connie Bus, počela je paničariti. Nismo mogli poslati igru ​​s ovom greškom, a šest tjedana kasnije nisam razumio što je uzrok problema. Preko Connie kontaktirali smo druge programere PS1: je li se netko susreo s nečim sličnim? Ne. Nitko nije imao problema s memorijskom karticom.

Kada nemate ideja za otklanjanje pogrešaka, jedini preostali pristup je "podijeli pa vladaj": uklonite sve više i više koda iz neispravnog programa dok ne ostane relativno mali fragment koji još uvijek uzrokuje problem. Odnosno, odsiječete program dio po dio dok ne ostane dio koji sadrži grešku.

Ali stvar je u tome što je vrlo teško izrezati dijelove video igre. Kako ga pokrenuti ako ste uklonili kod koji emulira gravitaciju? Ili crtanje likova?

Stoga cijele module moramo zamijeniti zaglavcima koji se pretvaraju da rade nešto korisno, ali zapravo rade nešto vrlo jednostavno što ne može sadržavati pogreške. Moramo napisati takve štake da igra barem funkcionira. Ovo je spor i bolan proces.

Ukratko, uspio sam. Uklanjao sam sve više i više dijelova koda dok mi nije ostao početni kod koji konfigurira sustav za pokretanje igre, inicijalizira hardver za renderiranje itd. Naravno, u ovoj fazi nisam mogao kreirati izbornik za spremanje i učitavanje, jer bih morao stvoriti stubić za sav grafički kod. Ali mogao bih se pretvarati da sam korisnik koji koristi (nevidljivi) zaslon za spremanje i učitavanje i zatražiti spremanje, a zatim pisati na memorijsku karticu.

Ovo mi je ostavilo mali dio koda koji je i dalje imao gornji problem - ali se i dalje događao nasumično! Najčešće je sve radilo dobro, ali povremeno je bilo kvarova. Uklonio sam gotovo sav kod igre, ali bug je i dalje bio živ. Ovo je bilo zbunjujuće: preostali kod zapravo nije učinio ništa.

U nekom trenutku, valjda oko tri ujutro, sinula mi je jedna misao. Operacije čitanja i pisanja (ulaz/izlaz) uključuju precizno vrijeme izvršenja. Kada radite s tvrdim diskom, memorijskom karticom ili Bluetooth modulom, kod niske razine odgovoran za čitanje i pisanje to čini u skladu s taktnim impulsima.

Uz pomoć sata se uređaj koji nije izravno povezan s procesorom sinkronizira s kodom koji se izvršava na procesoru. Sat određuje brzinu prijenosa podataka — brzinu prijenosa podataka. Ako postoji zabuna s vremenskim rasporedima, onda su ili hardver ili softver, ili oboje, također zbunjeni. A to je jako loše jer se podaci mogu oštetiti.

Što ako nešto u našem kodu zbuni vremena? Provjerio sam sve u vezi s tim u testnom programskom kodu i primijetio da smo programabilni timer u PS1 postavili na 1 kHz (1000 otkucaja u sekundi). To je dosta, po defaultu, kada se konzola pokrene, radi na 100 Hz. I većina igara koristi ovu frekvenciju.

Andy, programer igre, postavio je mjerač vremena na 1 kHz kako bi se pokreti izračunali točnije. Andy ima tendenciju pretjerati, a ako oponašamo gravitaciju, činimo to što je točnije moguće!

Ali što ako je ubrzavanje mjerača vremena na neki način utjecalo na ukupno vrijeme programa, a time i na sat koji regulira brzinu prijenosa podataka za memorijsku karticu?

Komentirao sam tajmer kod. Greška se više nije ponovila. Ali to ne znači da smo to popravili, jer se kvar dogodio slučajno. Što ako sam samo imao sreće?

Nekoliko dana kasnije ponovno sam eksperimentirao s testnim programom. Greška se nije ponovila. Vratio sam se na punu bazu kodova igre i izmijenio kod za spremanje i učitavanje tako da se programabilni mjerač vremena vrati na svoju izvornu vrijednost (100Hz) prije pristupa memorijskoj kartici, a zatim se vrati na 1kHz. Više nije bilo sudara.

Ali zašto se to dogodilo?

Opet sam se vratio na testni program. Pokušao sam pronaći neki obrazac u pojavi greške s timerom od 1 kHz. Na kraju sam primijetio da se greška javlja kada netko igra s PS1 kontrolerom. Budući da bih to rijetko sam radio - zašto bi mi trebao kontroler kada testiram kod za spremanje i učitavanje? - Nisam ni primijetio tu ovisnost. Ali jednog dana me je jedan od naših umjetnika čekao da završim testiranje - vjerojatno sam u tom trenutku psovao - i nervozno vrtio kontroler u rukama. Došlo je do pogreške. "Čekaj, što?!" Pa, ponovi to!”

Kad sam shvatio da su ta dva događaja međusobno povezana, uspio sam lako reproducirati pogrešku: počeo sam snimati na memorijsku karticu, pomaknuo kontroler i uništio memorijsku karticu. Meni je to izgledalo kao hardverski bug.

Došao sam do Connie i rekao joj za svoje otkriće. Prenijela je informacije jednom od inženjera koji su dizajnirali PS1. "Nemoguće", odgovorio je, "ne može biti hardverski problem." Zamolio sam Connie da nam organizira razgovor.

Inženjer me nazvao i raspravljali smo na njegovom pokvarenom engleskom i mom (iznimno) pokvarenom japanskom. Na kraju sam rekao: "Dopustite da pošaljem svoj testni program od 30 redaka gdje pomicanje kontrolera uzrokuje grešku." On se složio. Rekao je da je to gubljenje vremena i da je užasno zauzet radom na novom projektu, ali da će popustiti jer smo vrlo važan programer za Sony. Očistio sam svoj testni program i poslao mu ga.

Sljedeće večeri (mi smo bili u Los Angelesu, a on u Tokiju) nazvao me i posramljeno se ispričao. Bio je to hardverski problem.

Ne znam u čemu je točno bila pogreška, ali prema onome što sam čuo u sjedištu Sonya, ako mjerač vremena postavite na dovoljno visoku vrijednost, ometao je komponente na matičnoj ploči u blizini kristala mjerača vremena. Jedan od njih bio je regulator brzine prijenosa podataka za memorijsku karticu, koji je također postavljao brzinu prijenosa podataka za kontrolere. Nisam inženjer pa sam možda nešto zabrljao.

Ali bit je da je došlo do smetnji između komponenti na matičnoj ploči. A kod istovremenog prijenosa podataka kroz priključak kontrolera i priključak memorijske kartice s timerom koji radi na 1 kHz, bitovi su izgubljeni, podaci su izgubljeni, a kartica je oštećena.

Loše krave

U 1980-ima, moj mentor Sergej je napisao softver za SM-1800, sovjetski klon PDP-11. Ovo mikroračunalo upravo je instalirano na željezničkoj postaji u blizini Sverdlovska, važnog prometnog čvorišta u SSSR-u. Novi sustav dizajniran je za usmjeravanje vagonskog i teretnog prometa. Ali sadržavao je dosadnu pogrešku koja je dovela do nasumičnog rušenja i rušenja. Padovi su se uvijek događali kad bi netko odlazio kući navečer. Ali unatoč temeljitoj istrazi sljedećeg dana, računalo je radilo ispravno u svim ručnim i automatskim testovima. To obično ukazuje na stanje utrke ili neku drugu natjecateljsku pogrešku koja se javlja pod određenim uvjetima. Umoran od poziva u kasnim noćnim satima, Sergej je odlučio doći do dna stvari i prije svega shvatiti koji su uvjeti na ranžirnom kolodvoru doveli do kvara računala.

Prvo je prikupio statistiku svih neobjašnjivih padova i izradio grafikon po datumu i vremenu. Uzorak je bio očit. Nakon promatranja još nekoliko dana, Sergej je shvatio da može lako predvidjeti vrijeme budućih kvarova sustava.

Ubrzo je saznao da su se smetnje događale samo kad je postaja razvrstavala vlakove pune stoke iz sjeverne Ukrajine i zapadne Rusije koja je išla u obližnju klaonicu. To je samo po sebi bilo čudno, jer su klaonicu opskrbljivale farme koje su se nalazile mnogo bliže, u Kazahstanu.

Černobilska nuklearna elektrana eksplodirala je 1986., a radioaktivne padavine učinile su okolna područja nenastanjivim. Kontaminirana su ogromna područja u sjevernoj Ukrajini, Bjelorusiji i zapadnoj Rusiji. Sumnjajući na visoku razinu radijacije u pristiglim vagonima, Sergej je razvio metodu za provjeru ove teorije. Stanovništvu je bilo zabranjeno imati dozimetre, pa se Sergej prijavio kod nekoliko vojnih ljudi na željezničkom kolodvoru. Nakon nekoliko pića votke, uspio je uvjeriti jednog vojnika da izmjeri razinu radijacije u jednom od sumnjivih vagona. Pokazalo se da je razina nekoliko puta viša od normalnih vrijednosti.

Ne samo da je stoka emitirala puno zračenja, njegova je razina bila toliko visoka da je dovela do nasumičnog gubitka bitova u memoriji SM-1800, koji se nalazio u zgradi pokraj postaje.

U SSSR-u je vladala nestašica hrane, a vlasti su odlučile pomiješati černobilsko meso s mesom iz drugih dijelova zemlje. To je omogućilo smanjenje ukupne razine radioaktivnosti bez gubitka vrijednih resursa. Saznavši za to, Sergej je odmah popunio dokumente za emigraciju. A kvarovi računala prestali su sami od sebe kada se razina zračenja s vremenom smanjila.

Kroz cijevi

Nekada davno, Movietech Solutions stvorio je softver za kina, dizajniran za računovodstvo, prodaju ulaznica i općenito upravljanje. DOS verzija vodeće aplikacije bila je prilično popularna među malim i srednjim lancima kina u Sjevernoj Americi. Stoga ne čudi da je, kada je najavljena verzija sustava Windows 95, integrirana s najnovijim ekranima osjetljivim na dodir i samoposlužnim kioscima, te opremljena svim vrstama alata za izvješćivanje, brzo postala popularna. Ažuriranje je najčešće prošlo bez problema. Lokalno IT osoblje instaliralo je novu opremu, migriralo podatke i posao se nastavio. Osim kad nije potrajalo. Kad bi se to dogodilo, tvrtka bi poslala Jamesa, pod nadimkom "Čistač".

Iako nadimak sugerira opaku vrstu, čistač je samo kombinacija instruktora, instalatera i majstora za sve. James bi proveo nekoliko dana na mjestu klijenta spajajući sve komponente, a zatim bi proveo još nekoliko dana podučavajući osoblje kako koristiti novi sustav, rješavajući sve hardverske probleme koji bi se pojavili i u biti pomagao softveru u povojima.

Stoga ne čudi da je tijekom ovih užurbanih vremena James ujutro stigao u ured i prije nego što je stigao do svog stola, dočekao ga je menadžer, napunjen kofeinom iznad uobičajenog.

"Bojim se da moraš što prije otići u Annapolis, Nova Škotska." Cijeli im je sustav pao, a nakon noći rada s njihovim inženjerima, ne možemo shvatiti što se dogodilo. Čini se da mreža nije uspjela na poslužitelju. Ali tek nakon što je sustav radio nekoliko minuta.

— Nisu se vratili na stari sustav? – potpuno je ozbiljno odgovorio James, iako je mentalno razrogačio oči od iznenađenja.

— Točno: njihov informatičar je “promijenio prioritete” i odlučio otići sa svojim starim serverom. James, instalirali su sustav na šest lokacija i upravo su platili premium podršku, a njihov posao sada se vodi kao u 1950-ima.

James se lagano uspravio.

- To je druga stvar. U redu, počnimo.

Kad je stigao u Annapolis, prvo što je učinio bilo je pronaći prvo kino kupca koje je imalo problema. Na karti snimljenoj u zračnoj luci sve je izgledalo pristojno, ali područje oko željene adrese izgledalo je sumnjivo. Nije geto, ali podsjeća na film noir. Dok je James parkirao na pločniku u centru grada, prišla mu je prostitutka. S obzirom na veličinu Annapolisa, najvjerojatnije je bio jedini u cijelom gradu. Njezina pojava odmah je podsjetila na poznati lik koji je na velikom platnu nudio seks za novac. Ne, ne o Juliji Roberts, nego o Jonu Voightu [aluzija na film "Ponoćni kauboj" - cca. traka].

Isprativši prostitutku, James je otišao u kino. Okolica je postala bolja, ali je i dalje ostavljala dojam oronule. Nije da je James bio previše zabrinut. Već je bio na jadnim mjestima. A ovo je bila Kanada, gdje su čak i pljačkaši dovoljno pristojni da vam kažu "hvala" nakon što vam uzmu novčanik.

Sporedni ulaz u kino bio je u vlažnoj uličici. James je prišao vratima i pokucao. Ubrzo je zaškripalo i lagano se otvorilo.

- Jeste li čistačica? - začuo se iznutra promukli glas.

- Da, ja sam... Došao sam sve srediti.

James je ušao u predvorje kina. Očito nemajući drugog izbora, osoblje je počelo dijeliti papirnate ulaznice posjetiteljima. To je otežavalo financijsko izvješćivanje, a kamoli zanimljivije detalje. No, osoblje je Jamesa dočekalo s olakšanjem i odmah ga odvelo u sobu s poslužiteljima.

Na prvi pogled sve je bilo u redu. James se prijavio na server i provjerio uobičajena sumnjiva mjesta. Nema problema. Međutim, zbog pretjeranog opreza, James je isključio poslužitelj, zamijenio mrežnu karticu i vratio sustav u prethodno stanje. Odmah je počela raditi u punom obimu. Osoblje je ponovno počelo prodavati ulaznice.

James je nazvao Marka i obavijestio ga o situaciji. Nije teško zamisliti da bi James mogao ostati i vidjeti hoće li se dogoditi nešto neočekivano. Sišao je niz stepenice i počeo ispitivati ​​zaposlenike što se dogodilo. Očito je sustav prestao raditi. Ugasili su ga i uključili, sve je radilo. Ali nakon 10 minuta sustav je pao.

Upravo u ovom trenutku dogodilo se nešto slično. Odjednom je sustav za prodaju karata počeo iskazivati ​​pogreške. Osoblje je uzdahnulo i zgrabilo papirnate karte, a James je požurio u sobu s poslužiteljem. Sve je izgledalo dobro s poslužiteljem.

Zatim je ušao jedan od zaposlenika.

— Sustav ponovno radi.

James je bio zbunjen jer nije učinio ništa. Točnije, ništa što bi omogućilo funkcioniranje sustava. Odjavio se, uzeo telefon i nazvao podršku svoje tvrtke. Ubrzo je isti zaposlenik ušao u server sobu.

- Sustav je u kvaru.

James je pogledao poslužitelja. Na ekranu je plesao zanimljiv i poznat uzorak raznobojnih oblika - kaotično uvijajući se i ispreplićući cijevi. Svi smo u nekom trenutku vidjeli ovaj čuvar zaslona. Bilo je prekrasno izvedeno i doslovno hipnotizirajuće.


James je pritisnuo gumb i uzorak je nestao. Požurio je do blagajne i putem sreo djelatnicu koja se vraćala do njega.

— Sustav ponovno radi.

Ako možete napraviti mentalni facepalm, to je upravo ono što je James napravio. Čuvar zaslona. Koristi OpenGL. I stoga, tijekom rada, troši sve resurse poslužiteljskog procesora. Kao rezultat toga, svaki poziv poslužitelju završava vremenskim ograničenjem.

James se vratio u sobu s poslužiteljem, prijavio se i zamijenio čuvar zaslona s prekrasnim cijevima s praznim zaslonom. Odnosno, umjesto čuvara zaslona koji troši 100% resursa procesora, instalirao sam drugi koji ne troši resurse. Zatim sam čekao 10 minuta da provjerim svoju pretpostavku.

Kad je James stigao u sljedeće kino, pitao se kako objasniti svom menadžeru da je upravo preletio 800 km kako bi isključio čuvar zaslona.

Pad tijekom određene mjesečeve faze

Istinita priča. Jednog dana pojavio se programski bug koji je ovisio o fazi mjeseca. Postojala je mala rutina koja se obično koristila u raznim programima MIT-a za izračunavanje aproksimacije prave Mjesečeve faze. GLS je ugradio ovu rutinu u LISP program koji bi, prilikom pisanja datoteke, ispisao redak s vremenskom oznakom dugom gotovo 80 znakova. Bilo je vrlo rijetko da prvi redak poruke na kraju bude predug i vodi do sljedećeg retka. I kad je program kasnije pročitao ovu datoteku, opsovao je. Duljina prvog retka ovisila je o točnom datumu i vremenu, kao i o duljini specifikacije faze u trenutku ispisa vremenske oznake. Odnosno, buba je doslovno ovisila o fazi mjeseca!

Prvo papirnato izdanje Datoteka žargona (Steele-1983) sadržavao je primjer takvog retka koji je doveo do opisanog buga, ali ga je slovoslagač "popravio". To je od tada opisano kao "bug mjesečeve mijene".

Ipak, budite oprezni s pretpostavkama. Prije nekoliko godina inženjeri iz CERN-a (Europskog centra za nuklearna istraživanja) naišli su na pogreške u eksperimentima provedenim na Velikom elektron-pozitronskom sudaraču. Budući da računala aktivno obrađuju ogromnu količinu podataka koje generira ovaj uređaj prije nego pokažu rezultat znanstvenicima, mnogi su nagađali da je softver na neki način osjetljiv na mjesečeve mijene. Nekoliko očajnih inženjera došlo je do dna istine. Greška je nastala zbog male promjene geometrije prstena dugog 27 km uslijed deformacije Zemlje tijekom prolaska Mjeseca! Ova je priča ušla u folklor fizike kao “Newtonova osveta fizici čestica” i primjer povezanosti najjednostavnijih i najstarijih zakona fizike s najnaprednijim znanstvenim konceptima.

Ispiranje WC-a zaustavlja vlak

Najbolja hardverska greška za koju sam ikada čuo bila je na brzom vlaku u Francuskoj. Buba je dovela do hitnog kočenja vlaka, ali samo ako je u njemu bilo putnika. U svakom takvom slučaju vlak je isključen iz prometa, provjeravan, ali ništa nije pronađeno. Zatim je vraćen na liniju, a on se odmah srušio i zaustavio.

Tijekom jedne od provjera, strojar koji je putovao u vlaku otišao je na WC. Ubrzo se isprao, BUM! Hitno zaustavljanje.

Inženjer je kontaktirao vozača i upitao:

— Što ste radili neposredno prije kočenja?

- Pa usporio sam na spustu...

To je bilo čudno, jer tijekom normalnog rada vlak uspori na nizbrdicama nekoliko desetaka puta. Vlak je krenuo dalje, a na sljedećem spustu strojovođa je upozorio:

- Idem usporiti.

Ništa se nije dogodilo.

— Što ste radili tijekom zadnjeg kočenja? - upitao je vozač.

- Pa... bio sam u wc-u...

- Pa, onda idi na WC i radi ono što si radio kad opet siđemo!

Inženjer je otišao do WC-a, a kada ga je vozač upozorio: "Usporavam", pustio je vodu. Naravno, vlak je odmah stao.

Sada su mogli reproducirati problem i morali su pronaći uzrok.

Nakon dvije minute primijetili su da je kabel za daljinsko upravljanje motornom kočnicom (vlak je imao po jedan motor na svakom kraju) bio odvojen od zida električnog ormarića i da leži na releju koji je upravljao solenoidom WC čepa... Kad je relej bio uključen, stvarao je smetnje u sajli kočnice, a zaštita sustava od kvarova jednostavno je uključivala hitno kočenje.

Gateway koji je mrzio FORTRAN

Prije nekoliko mjeseci primijetili smo da su mrežne veze na kopnu [to je bilo na Havajima] postale vrlo, vrlo spore. To može trajati 10-15 minuta, a zatim se odjednom ponovi. Nakon nekog vremena kolega mi se požalio da mrežni priključci na kopnu općenito Ne radi. Imao je neki FORTRAN kod koji je trebalo kopirati na stroj na kopnu, ali nije mogao jer "mreža nije izdržala dovoljno dugo da se FTP učitavanje završi."

Da, pokazalo se da su se mrežni kvarovi dogodili kada je kolega pokušao FTP-om poslati datoteku s izvornim kodom u FORTRAN-u na stroj na kopnu. Pokušali smo arhivirati datoteku: tada je glatko kopirana (ali ciljni stroj nije imao program za raspakiranje, pa problem nije riješen). Na kraju smo "podijelili" FORTRAN kod na vrlo male dijelove i poslali ih jedan po jedan. Većina fragmenata je kopirana bez problema, ali nekoliko komada nije prošlo ili je prošlo kasnije brojan pokušaji.

Kad smo ispitali problematične odlomke, otkrili smo da imaju nešto zajedničko: svi su sadržavali blokove komentara koji su započinjali i završavali redovima koji se sastoje od velikog C (kao što je kolega radije komentirao u FORTRAN-u). Poslali smo e-poštu mrežnim stručnjacima na kopnu i zatražili pomoć. Naravno, htjeli su vidjeti uzorke naših datoteka koje se nisu mogle prenijeti FTP-om... ali naša pisma nisu stigla do njih. Napokon smo smislili jednostavan opisatikako izgledaju neprenosive datoteke. Uspjelo je :) [Usuđujem li se ovdje dodati primjer jednog od problematičnih FORTRAN komentara? Vjerojatno ne vrijedi!]

Na kraju smo uspjeli shvatiti. Nedavno je postavljen novi pristupnik između našeg dijela kampusa i kopnene mreže. Imao je VELIKIH poteškoća u slanju paketa koji su sadržavali ponovljene bitove velikih slova C! Samo nekoliko ovih paketa moglo bi zauzeti sve resurse pristupnika i spriječiti većinu drugih paketa da prođu. Žalili smo se proizvođaču gatewaya... a oni su odgovorili: “O, da, suočeni ste s greškom ponavljanja C! Već znamo za njega.” Na kraju smo riješili problem kupnjom novog gatewaya od drugog proizvođača (u obranu prvog, nemogućnost prijenosa FORTRAN programa za neke bi mogla biti prednost!).

Teška vremena

Prije nekoliko godina, dok sam radio na stvaranju ETL sustava u Perlu kako bih smanjio troškove kliničkih ispitivanja faze 40, trebao sam obraditi oko 000 1 datuma. Dvoje od njih nije prošlo test. To me nije previše zasmetalo jer su ti datumi preuzeti iz podataka koje je dostavio klijent, što je često, da tako kažemo, bilo iznenađujuće. Ali kad sam provjerio izvorne podatke, pokazalo se da su ti datumi 2011. siječnja 1. i 2007. siječnja 30. Mislio sam da je greška sadržana u programu koji sam upravo napisao, ali pokazalo se da je prošlo već XNUMX godina star. Ovo može zvučati misteriozno onima koji nisu upoznati sa softverskim ekosustavom. Zbog dugotrajne odluke druge tvrtke da zaradi novac, moj mi je klijent platio da popravim bug koji je jedna tvrtka uvela slučajno, a druga namjerno. Da biste razumjeli o čemu govorim, moram govoriti o tvrtki koja je dodala značajku koja je na kraju postala bug, kao i o nekoliko drugih zanimljivih događaja koji su pridonijeli misterioznom bugu koji sam popravio.

U dobra stara vremena, Appleova računala ponekad bi spontano vratila svoj datum na 1. siječnja 1904. godine. Razlog je bio jednostavan: koristio je "sat sustava" na baterije za praćenje datuma i vremena. Što se dogodilo kad se baterija ispraznila? Računala su počela pratiti datum prema broju sekundi od početka epohe. Pod epohom smo mislili na referentni izvorni datum, a za Macintoshee to je bio 1. siječnja 1904. A nakon što se baterija ispraznila, trenutni datum je resetiran na navedeni. Ali zašto se to dogodilo?

Prethodno je Apple koristio 32 bita za pohranu broja sekundi od izvornog datuma. Jedan bit može pohraniti jednu od dvije vrijednosti - 1 ili 0. Dva bita mogu pohraniti jednu od četiri vrijednosti: 00, 01, 10, 11. Tri bita - jedna vrijednost od osam: 000, 001, 010, 011, 100 , 101, 110, 111 itd. A 32 može pohraniti jednu od 232 vrijednosti, odnosno 4 sekundi. Za Appleove datume to je otprilike 294 godina, tako da stariji Macovi ne mogu podnijeti datume nakon 967. godine. A ako se baterija sustava isprazni, datum se resetira na 296 sekundi od početka epohe i morate ručno postaviti datum svaki put kada uključite računalo (ili dok ne kupite novu bateriju).

Međutim, Appleova odluka da pohranjuje datume kao sekunde od epohe značila je da nismo mogli rukovati datumima prije epohe, što je imalo dalekosežne posljedice, kao što ćemo vidjeti. Apple je predstavio značajku, a ne grešku. Između ostalog, to je značilo da je operativni sustav Macintosh bio imun na "milenijsku grešku" (što se ne bi moglo reći za mnoge Mac aplikacije koje su imale vlastite datumske sustave za zaobilaženje ograničenja).

Samo naprijed. Koristili smo Lotus 1-2-3, IBM-ovu "ubojitu aplikaciju" koja je pomogla u pokretanju PC revolucije, iako su Appleova računala imala VisiCalc, što je osobno računalo učinilo uspješnim. Iskreno govoreći, da se 1-2-3 nije pojavio, računala teško da bi uzela maha, a povijest osobnih računala mogla se razvijati vrlo drugačije. Lotus 1-2-3 pogrešno je tretirao 1900. kao prijestupnu godinu. Kada je Microsoft izdao svoju prvu proračunsku tablicu, Multiplan, zauzeo je mali udio na tržištu. A kada su pokrenuli Excel projekt, odlučili su ne samo kopirati shemu imenovanja redaka i stupaca iz Lotusa 1-2-3, već i osigurati kompatibilnost s greškama tako što su 1900. namjerno tretirali kao prijestupnu godinu. Taj problem postoji i danas. Odnosno, u 1-2-3 je to bio bug, ali u Excelu je to bila svjesna odluka koja je osigurala da svi 1-2-3 korisnici mogu uvesti svoje tablice u Excel bez promjene podataka, čak i ako su bili netočni.

Ali postojao je još jedan problem. Najprije je Microsoft izdao Excel za Macintosh, koji nije prepoznavao datume prije 1. siječnja 1904. A u Excelu se 1. siječnja 1900. smatrao početkom ere. Stoga su programeri napravili promjenu tako da je njihov program prepoznao vrstu ere i pohranio podatke u sebe u skladu sa željenom erom. Microsoft je čak napisao članak s objašnjenjem o tome. I ova odluka dovela je do moje greške.

Moj ETL sustav primio je Excel proračunske tablice od korisnika koje su izrađene u sustavu Windows, ali su se mogle izraditi i na Macu. Stoga bi početak ere u tablici mogao biti ili 1. siječnja 1900. ili 1. siječnja 1904. godine. Kako saznati? Format datoteke u Excelu prikazuje potrebne informacije, ali parser koji sam koristio nije ih prikazivao (sada pokazuje) i pretpostavljao je da znate epohu za određenu tablicu. Vjerojatno sam mogao potrošiti više vremena na razumijevanje binarnog formata programa Excel i slanje zakrpe autoru parsera, ali imao sam puno više za napraviti za klijenta, pa sam brzo napisao heuristiku za određivanje epohe. Bila je jednostavna.

U Excelu se datum 5. srpnja 1998. može prikazati u formatu "07-05-98" (beskoristan američki sustav), "5. srpnja 98.", "5. srpnja 1998.", "5. srpnja 98." ili neki drugi format.još jedan beskoristan format (ironično, jedan od formata koji moja verzija Excela nije nudila bio je ISO 8601). Međutim, unutar tablice, neformatirani datum je pohranjen ili kao "35981" za epohu-1900 ili kao "34519" za epohu-1904 (brojevi predstavljaju broj dana od epohe). Jednostavno sam upotrijebio jednostavan parser za izdvajanje godine iz formatiranog datuma, a zatim sam upotrijebio Excel parser za izdvajanje godine iz neformatiranog datuma. Ako su se obje vrijednosti razlikovale za 4 godine, tada sam znao da koristim sustav s epohom-1904.

Zašto jednostavno nisam upotrijebio formatirane datume? Zato što se 5. srpnja 1998. može formatirati kao "srpanj 98" s izgubljenim danom u mjesecu. Dobili smo tablice od toliko mnogo tvrtki koje su ih izradile na toliko različitih načina da je na nama (u ovom slučaju meni) bilo da odredimo datume. Osim toga, ako Excel dobro radi, trebali bismo i mi!

Istovremeno sam naišao na 39082. Da vas podsjetim da je Lotus 1-2-3 1900. smatrao prijestupnom godinom, a to je vjerno ponovljeno u Excelu. A budući da je ovo dodao jedan dan godini 1900., mnoge funkcije izračuna datuma mogle bi biti pogrešne za taj dan. To jest, 39082 je mogao biti 1. siječnja 2011. (na Macovima) ili 31. prosinca 2006. (na Windowsima). Ako je moj "parser godina" izdvojio godinu 2011. iz formatirane vrijednosti, onda je sve u redu. Ali budući da Excel parser ne zna koja se epoha koristi, zadana je epoha-1900, vraćajući 2006. godinu. Moja je aplikacija vidjela da je razlika 5 godina, smatrala je to pogreškom, zabilježila je i vratila neformatiranu vrijednost.

Da bih to zaobišao, napisao sam ovo (pseudokod):

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

I tada je svih 40 datuma ispravno raščlanjeno.

Usred velikih poslova ispisa

Početkom 1980-ih, moj otac je radio u Storage Technology, sada već nepostojećem odjelu koji je kreirao pogone trake i pneumatske sustave za uvlačenje trake velikom brzinom.

Redizajnirali su pogone tako da su mogli imati jedan središnji pogon "A" povezan sa sedam pogona "B", a mali OS u RAM-u koji je kontrolirao pogon "A" mogao je delegirati operacije čitanja i pisanja na sve pogone "B".

Pri svakom pokretanju pogona “A” bilo je potrebno umetnuti disketu u periferni pogon spojen na “A” kako bi se operativni sustav učitao u njegovu memoriju. Bio je krajnje primitivan: računalnu snagu osiguravao je 8-bitni mikrokontroler.

Ciljana publika za takvu opremu bile su tvrtke s vrlo velikim skladištima podataka - banke, trgovački lanci itd. - koje su trebale ispisati puno adresnih naljepnica ili bankovnih izvoda.

Jedan klijent je imao problem. Usred posla ispisa, jedan određeni pogon "A" mogao bi prestati raditi, uzrokujući zastoj cijelog posla. Kako bi vratili pogon u rad, osoblje je moralo sve ponovno pokrenuti. A ako se to dogodilo usred šestosatnog zadatka, izgubljena je ogromna količina skupog računalnog vremena i poremećen raspored cijele operacije.

Tehničari su poslani iz Storage Technologies. Ali usprkos njihovim najvećim naporima, nisu uspjeli reproducirati grešku u testnim uvjetima: činilo se da se pojavljuje usred velikih poslova ispisa. Problem nije bio hardver, zamijenili su sve što su mogli: RAM, mikrokontroler, disketnu jedinicu, svaki zamislivi dio trake - problem je i dalje postojao.

Tada su tehničari pozvali stožer i pozvali Stručnjaka.

Stručnjak je zgrabio stolicu i šalicu kave, sjeo u računalnu sobu - u to su vrijeme postojale sobe posvećene računalima - i gledao kako osoblje čeka veliki posao ispisa. Vještak je čekao da se dogodi kvar - i dogodio se. Svi su pogledali u Stručnjaka, ali on nije imao pojma zašto se to dogodilo. Stoga je naredio da se posao ponovno stavi u red čekanja, a svo osoblje i tehničari vratili su se na posao.

Stručnjak je ponovno sjeo u stolicu i počeo čekati neuspjeh. Prošlo je oko šest sati i dogodio se kvar. Stručnjak opet nije imao pojma, osim da se sve dogodilo u prostoriji punoj ljudi. Naredio je ponovno pokretanje misije, sjeo natrag i čekao.

Do trećeg kvara, Stručnjak je nešto primijetio. Kvar se dogodio kada je osoblje promijenilo trake u stranom pogonu. Štoviše, kvar se dogodio čim je netko od zaposlenika prošao kroz određenu pločicu na podu.

Povišeni pod bio je napravljen od aluminijskih pločica položenih na visinu od 6 do 8 inča. Ispod podignutog poda protezale su se brojne žice od računala kako netko slučajno ne bi stao na važan kabel. Pločice su postavljene vrlo čvrsto kako bi se spriječilo da krhotine dospiju ispod podignutog poda.

Vještak je utvrdio da je jedna od pločica deformirana. Kad je zaposlenik stao na njezin kut, rubovi pločice trljali su se o susjedne pločice. Plastični dijelovi koji su spajali pločice također su trljali o njih, što je uzrokovalo statička mikropražnjenja koja su stvarala radiofrekvencijske smetnje.

Danas je RAM puno bolje zaštićen od radiofrekventnih smetnji. Ali tih godina to nije bio slučaj. Stručnjak je shvatio da je ta smetnja poremetila memoriju, a s njom i rad operativnog sustava. Nazvao je podršku, naručio nove pločice, sam ih postavio i problem je nestao.

Plima je!

Priča se odvijala u server sobi, na četvrtom ili petom katu ureda u Portsmouthu (mislim), u području dokova.

Jednog dana Unix poslužitelj s glavnom bazom podataka se srušio. Ponovno su ga pokrenuli, ali on je sretno nastavio padati iznova i iznova. Odlučili smo nazvati nekoga iz službe podrške.

Tip iz podrške... Mislim da se zvao Mark, ali to nije važno... Mislim da ga ne poznajem. Nema veze, stvarno. Držimo se Marka, u redu? Sjajno.

Dakle, nekoliko sati kasnije stigao je Mark (nije daleko od Leedsa do Portsmoutha, znate), uključio server i sve je radilo bez problema. Tipična prokleta podrška, klijent se jako uzruja zbog toga. Mark pregledava zapisnike i ne nalazi ništa nepoželjno. Dakle, Mark se vraća na vlak (ili kojim god prijevoznim sredstvom je stigao, mogla je to biti jadna krava koliko ja znam... u svakom slučaju, nije važno, u redu?) i vraća se u Leeds, nakon što je potrošeno dan.

Iste večeri poslužitelj se ponovno ruši. Priča je ista... server se ne diže. Mark pokušava pomoći na daljinu, ali klijent ne može pokrenuti poslužitelj.

Još jedan vlak, autobus, meringue s limunom ili neko drugo sranje, i Mark se vraća u Portsmouth. Pogledajte, poslužitelj se pokreće bez ikakvih problema! Čudo. Mark provodi nekoliko sati provjeravajući je li sve u redu s operativnim sustavom ili softverom te kreće u Leeds.

Oko sredine dana poslužitelj se ruši (polako!). Ovaj put se čini razumnim dovesti ljude iz hardverske podrške da zamijene poslužitelj. Ali ne, nakon 10-ak sati i on pada.

Situacija se ponavljala nekoliko dana. Server radi, ruši se nakon 10-tak sati i ne pali iduća 2 sata. Provjerili su hlađenje, curenje memorije, sve su provjerili, ali ništa nisu našli. Tada su udari prestali.

Tjedan je prošao bezbrižno...svi su bili sretni. Sretan dok sve ne počne iznova. Slika je ista. 10 sati rada, 2-3 sata mirovanja...

A onda je netko (mislim da su mi rekli da ta osoba nema nikakve veze s IT-om) rekao:

"To je plima!"

Uzvik je dočekan praznim pogledima, a nečija je ruka vjerojatno oklijevala na sigurnosnom gumbu za poziv.

"Prestaje raditi s plimom."

Čini se da je ovo potpuno stran koncept radnicima IT podrške, koji vjerojatno neće čitati Tide Yearbook dok sjede na kavi. Objasnili su da se to ni na koji način ne može povezati s plimom jer je server radio tjedan dana bez kvarova.

"Prošli tjedan plima je bila niska, ali ovaj tjedan je visoka."

Malo terminologije za one koji nemaju dozvolu za jahtu. Plima i oseka ovise o mjesečevom ciklusu. A kako se Zemlja rotira, svakih 12,5 sati gravitacijska sila Sunca i Mjeseca stvara plimni val. Na početku ciklusa od 12,5 sati je plima, sredinom ciklusa oseka, a na kraju opet plima. Ali kako se Mjesečeva orbita mijenja, tako se mijenja i razlika između plime i oseke. Kada se Mjesec nalazi između Sunca i Zemlje ili na suprotnoj strani Zemlje (pun Mjesec ili bez Mjeseca), dobivamo Syzygyn plime - najveće plime i najniže oseke. U polumjesecu dobivamo kvadraturne plime - najniže oseke. Razlika između te dvije krajnosti znatno se smanjuje. Mjesečev ciklus traje 28 dana: sizigij – kvadratura – sizigija – kvadratura.

Kada je tehničarima objašnjena bit plimnih sila, odmah su pomislili da trebaju pozvati policiju. I sasvim logično. Ali pokazalo se da je tip bio u pravu. Dva tjedna ranije, nedaleko od ureda usidrio se razarač. Svaki put kad bi ga plima podigla na određenu visinu, brodski radarski stup bi završio u razini poda server sobe. A radar (ili oprema za elektroničko ratovanje, ili neka druga vojna igračka) napravio je kaos u računalima.

Misija leta za raketu

Dobio sam zadatak prenijeti veliki (oko 400 tisuća redaka) sustav za kontrolu i nadzor lansiranja raketa na nove verzije operativnog sustava, kompajlera i jezika. Točnije, od Solarisa 2.5.1 do Solarisa 7, te od Verdix Ada Development System (VADS), napisanog u Adi 83, do Rational Apex Ada sustava, napisanog u Adi 95. VADS je kupio Rational, a njegov proizvod je zastario, iako je Rational pokušao implementirati kompatibilne verzije paketa specifičnih za VADS kako bi olakšao prijelaz na Apex kompajler.

Troje ljudi pomoglo mi je samo da čisto kompajliram kod. Trajalo je dva tjedna. I onda sam sam radio na tome da sustav funkcionira. Ukratko, bila je to najgora arhitektura i implementacija softverskog sustava s kojom sam se susreo, pa su bila potrebna još dva mjeseca da se dovrši port. Sustav je zatim poslan na testiranje, koje je trajalo još nekoliko mjeseci. Odmah sam ispravio greške koje su pronađene tijekom testiranja, ali se njihov broj brzo smanjio (izvorni kod je bio produkcijski sustav, pa je njegova funkcionalnost radila prilično pouzdano, samo sam morao ukloniti greške koje su se pojavile tijekom prilagodbe novom prevoditelju). Na kraju, kada je sve funkcioniralo kako treba, prebačen sam na drugi projekt.

A u petak prije Dana zahvalnosti zazvonio je telefon.

Lansiranje rakete trebalo je isprobati za oko tri tjedna, a tijekom laboratorijskih ispitivanja odbrojavanja došlo je do blokade slijeda naredbi. U stvarnom životu to bi prekinulo test, a ako bi se blokada dogodila unutar nekoliko sekundi od paljenja motora, u pomoćnim bi se sustavima dogodilo nekoliko nepovratnih radnji, što bi zahtijevalo dugo - i skupo - spremanje rakete. Ne bi počelo, ali mnogi bi ljudi bili jako uzrujani zbog gubitka vremena i puno, puno novca. Ne dopustite da vam itko kaže da Ministarstvo obrane nemarno troši novac—nikada nisam sreo voditelja ugovora koji nije stavio proračun na prvo ili drugo mjesto, a zatim raspored.

Prethodnih mjeseci ovaj izazov odbrojavanja pokrenut je stotine puta u mnogim varijantama, uz samo nekoliko manjih zastoja. Dakle, vjerojatnost da se to dogodi bila je vrlo mala, ali su njegove posljedice bile vrlo značajne. Pomnožite oba ova faktora i shvatit ćete da su vijesti predviđale uništeni praznični tjedan za mene i desetke inženjera i menadžera.

I obratila se pozornost na mene kao osobu koja je portirala sustav.

Kao i kod većine sigurnosno kritičnih sustava, puno je parametara bilo zapisano, tako da je bilo prilično lako identificirati nekoliko redaka koda koji su bili izvršeni prije nego što se sustav srušio. I naravno, u njima nije bilo apsolutno ničeg neobičnog; isti su izrazi bili uspješno izvedeni doslovno tisuće puta tijekom iste vožnje.

Pozvali smo ljude iz Apexa u Rational jer su oni bili ti koji su razvili kompajler i neke od rutina koje su razvili pozvane su u sumnjivom kodu. Oni (i svi ostali) bili su impresionirani da postoji potreba da se dođe do korijena problema od doslovno nacionalne važnosti.

Budući da u časopisima nije bilo ničeg zanimljivog, odlučili smo pokušati reproducirati problem u lokalnom laboratoriju. Ovo nije bio lak zadatak jer se događaj dogodio otprilike jednom na 1000 pokretanja. Jedan od razloga za koje se sumnjalo je da je poziv mutex funkciji koju je razvio dobavljač (dio VADS paketa za migraciju) Unlock nije doveo do otključavanja. Nit za obradu koja je pozvala funkciju obradila je poruke otkucaja srca, koje su nominalno stizale svake sekunde. Podigli smo frekvenciju na 10 Hz, odnosno 10 puta u sekundi i krenuli trčati. Oko sat vremena kasnije sustav se sam zaključao. U zapisniku smo vidjeli da je redoslijed snimljenih poruka isti kao tijekom neuspjelog testa. Napravili smo još nekoliko vožnji, sustav je bio stalno blokiran 45-90 minuta nakon starta, i svaki put je dnevnik sadržavao istu rutu. Iako smo tehnički izvodili drugačiji kod - učestalost poruka bila je drugačija - ponašanje sustava bilo je isto, pa smo bili uvjereni da ovaj scenarij opterećenja uzrokuje isti problem.

Sada smo trebali otkriti gdje se točno dogodilo blokiranje u nizu izraza.

Ova implementacija sustava koristila je sustav zadataka Ada, i koristila ga je nevjerojatno loše. Zadaci su paralelno izvršna konstrukcija visoke razine u Adi, nešto poput niti izvršavanja, samo što je ugrađeno u sam jezik. Kada dva zadatka trebaju komunicirati, oni "postavljaju sastanak", razmjenjuju potrebne podatke, a zatim prekidaju sastanak i vraćaju se svojim neovisnim izvršenjima. Međutim, sustav je implementiran drugačije. Nakon što se ciljni zadatak sastao, taj se ciljni zadatak sastao s drugim zadatkom, koji se zatim sastao s trećim zadatkom, i tako dalje sve dok neka obrada nije dovršena. Nakon toga su svi ovi susreti bili završeni i svaki zadatak se morao vratiti na svoje izvršenje. Naime, imali smo posla s najskupljim sustavom za pozivanje funkcija na svijetu, koji je zaustavio cijeli “multitasking” proces dok je obrađivao dio ulaznih podataka. A prije to nije dovodilo do problema samo zato što je propusnost bila vrlo niska.

Opisao sam ovaj mehanizam zadatka jer kada je sastanak zatražen ili se očekuje da će završiti, može doći do "promjene zadatka". To jest, procesor bi mogao započeti s obradom drugog zadatka koji je spreman za izvršenje. Ispostavilo se da kada je jedan zadatak spreman za susret s drugim zadatkom, potpuno drugačiji zadatak može se početi izvršavati i na kraju se kontrola vraća na prvi sastanak. Mogu se dogoditi i drugi događaji koji uzrokuju promjenu zadatka; jedan takav događaj je poziv funkciji sustava, kao što je ispis ili izvođenje muteksa.

Da bih razumio koji redak koda uzrokuje problem, morao sam pronaći način za bilježenje napretka kroz niz izjava bez pokretanja promjene zadatka, što bi spriječilo pad programa. Tako da nisam mogao iskoristiti Put_Line()kako biste izbjegli izvođenje I/O operacija. Mogao bih postaviti varijablu brojača ili nešto slično, ali kako mogu vidjeti njegovu vrijednost ako je ne mogu prikazati na ekranu?

Također, pregledom dnevnika pokazalo se da su se, unatoč zamrzavanju obrade otkucaja poruka, koje je blokiralo sve I/O operacije procesa i spriječilo izvođenje drugih obrada, drugi neovisni zadaci nastavili izvršavati. Odnosno, rad nije blokiran u cijelosti, samo (kritični) lanac zadataka.

Ovo je bio trag potreban za procjenu blokirajućeg izraza.

Napravio sam Ada paket koji je sadržavao zadatak, nabrojani tip i globalnu varijablu tog tipa. Prebrojivi literali bili su vezani za specifične izraze problematičnog niza (npr. Incrementing_Buffer_Index, Locking_Mutex, Mutex_Unlocked), a zatim u nju umetnuo izraze dodjele koji su dodijelili odgovarajuću enumeraciju globalnoj varijabli. Budući da je objektni kod svega ovoga jednostavno pohranio konstantu u memoriju, prebacivanje zadataka kao rezultat njegovog izvršenja bilo je vrlo malo vjerojatno. Prvenstveno smo bili sumnjičavi prema izrazima koji bi mogli prebaciti zadatak, budući da se blokiranje dogodilo tijekom izvršenja, a ne vraćanja prilikom prebacivanja zadatka natrag (iz nekoliko razloga).

Zadatak praćenja jednostavno se izvodio u petlji i povremeno provjeravao je li se vrijednost globalne varijable promijenila. Sa svakom promjenom, vrijednost je spremljena u datoteku. Zatim kratko čekanje i nova provjera. Zapisao sam varijablu u datoteku jer se zadatak izvršavao samo kada ga je sustav odabrao za izvršenje prilikom prebacivanja zadatka u problematično područje. Što god se dogodilo u ovom zadatku neće utjecati na druge, nepovezane blokirane zadatke.

Očekivalo se da će se globalna varijabla resetirati kada sustav dođe do točke izvršavanja problematičnog koda pri prelasku na svaki sljedeći izraz. Tada će se dogoditi nešto što uzrokuje promjenu zadatka, a budući da je njegova frekvencija izvršavanja (10 Hz) niža od one zadatka nadzora, monitor bi mogao uhvatiti vrijednost globalne varijable i zapisati je. U normalnoj situaciji mogao bih dobiti ponavljajući slijed podskupa nabrajanja: posljednje vrijednosti varijable u trenutku promjene zadatka. Kada visi, globalna varijabla više se ne bi trebala mijenjati, a zadnja zapisana vrijednost pokazat će koji izraz nije dovršen.

Pokrenuo sam kod s praćenjem. Smrznuo se. A nadzor je radio kao sat.

Dnevnik je sadržavao očekivani niz koji je prekinut vrijednošću koja ukazuje da je pozvan mutex Unlock, a zadatak nije dovršen - kao što je slučaj s tisućama prethodnih poziva.

Apexovi inženjeri grozničavo su analizirali svoj kod u to vrijeme i pronašli mjesto u mutexu gdje bi, teoretski, moglo doći do zaključavanja. Ali njegova je vjerojatnost bila vrlo niska, budući da je samo određeni niz događaja koji se događaju u određeno vrijeme mogao dovesti do blokade. Murphyjev zakon, ljudi, to je Murphyjev zakon.

Kako bih zaštitio dio koda koji mi je trebao, zamijenio sam pozive mutex funkcije (izgrađene na vrhu OS mutex funkcionalnosti) s malim izvornim Ada mutex paketom za kontrolu mutex pristupa tom dijelu.

Umetnuo sam ga u kod i pokrenuo test. Sedam sati kasnije šifra je i dalje radila.

Moj kod je poslan Rationalu, gdje su ga kompajlirali, rastavili i provjerili da ne koristi isti pristup koji je korišten u problematičnim mutex funkcijama.

Ovo je bio najnapučeniji pregled koda u mojoj karijeri 🙂 Sa mnom je u sobi bilo desetak inženjera i menadžera, još deset ljudi je bilo na konferencijskom pozivu - i svi su pregledali oko 20 redaka koda.

Kod je pregledan, nove izvršne datoteke su sastavljene i poslane na formalno regresijsko testiranje. Nekoliko tjedana kasnije, test odbrojavanja bio je uspješan i raketa je poletjela.

Dobro, sve je to lijepo i u redu, ali koja je poanta priče?

Bio je to apsolutno odvratan problem. Stotine tisuća redaka koda, paralelno izvođenje, više od desetak međusobno povezanih procesa, loša arhitektura i loša implementacija, sučelja za ugrađene sustave i potrošeni milijuni dolara. Nema pritiska, zar ne.

Nisam bio jedini koji je radio na ovom problemu, iako sam bio u centru pažnje dok sam radio portiranje. Ali iako sam to učinio, to ne znači da sam razumio sve stotine tisuća redaka koda, pa čak ni da sam ih preletio. Kod i zapise analizirali su inženjeri diljem zemlje, ali kad su mi rekli svoje hipoteze o uzrocima kvara, trebalo mi je samo pola minute da ih opovrgnem. A kad su me zamolili da analiziram teorije, proslijedio bih to nekom drugom, jer mi je bilo očito da ti inženjeri idu krivim putem. Zvuči drsko? Da, to je istina, ali sam hipoteze i zahtjeve odbio iz drugog razloga.

Shvatio sam prirodu problema. Nisam točno znao gdje se to događa ni zašto, ali sam znao što se događa.

Tijekom godina skupio sam puno znanja i iskustva. Bio sam jedan od pionira korištenja Ade i razumio sam njezine prednosti i nedostatke. Znam kako Ada runtime biblioteke rješavaju zadatke i bave se paralelnim izvršavanjem. I razumijem programiranje niske razine na razini memorije, registara i asemblera. Drugim riječima, imam duboko znanje u svom području. I upotrijebio sam ih da pronađem uzrok problema. Nisam samo zaobišao grešku, već sam shvatio kako je pronaći u vrlo osjetljivom okruženju izvođenja.

Takve priče o borbi s kodom nisu previše zanimljive onima koji nisu upoznati sa značajkama i uvjetima takve borbe. Ali te nam priče pomažu razumjeti što je potrebno za rješavanje stvarno teških problema.

Da biste riješili stvarno teške probleme, morate biti više od običnog programera. Morate razumjeti "sudbinu" koda, kako on djeluje sa svojom okolinom i kako sama okolina funkcionira.

A onda ćete imati vlastiti uništeni praznični tjedan.

Nastaviti.

Izvor: www.habr.com

Dodajte komentar