Folklore van programmeurs en ingenieurs (deel 1)

Folklore van programmeurs en ingenieurs (deel 1)

Dit is een selectie verhalen van internet over hoe bugs soms volkomen ongelooflijke manifestaties hebben. Misschien heeft u ook iets te vertellen.

Auto-allergie voor vanille-ijs

Een verhaal voor ingenieurs die begrijpen dat het voor de hand liggende niet altijd het antwoord is, en dat, hoe vergezocht de feiten ook lijken, het nog steeds de feiten zijn. De Pontiac-divisie van General Motors Corporation ontving een klacht:

Dit is de tweede keer dat ik je schrijf, en ik neem het je niet kwalijk dat je niet antwoordt, want het klinkt gek. Onze familie heeft de traditie om elke avond na het eten een ijsje te eten. De soorten ijs veranderen elke keer en na het eten kiest het hele gezin welk ijs ze kopen, waarna ik naar de winkel ga. Ik heb onlangs een nieuwe Pontiac gekocht en sindsdien zijn mijn uitstapjes om ijs te halen een probleem geworden. Zie je, elke keer als ik vanille-ijs koop en terugkom van de winkel, start de auto niet. Als ik nog een ander ijsje meeneem, start de auto zonder problemen. Ik wil een serieuze vraag stellen, hoe stom het ook klinkt: “Wat is er met de Pontiac dat hij niet start als ik vanille-ijs meeneem, maar wel makkelijk start als ik een andere smaak ijs meeneem?”

Zoals u zich kunt voorstellen, was de divisiepresident sceptisch over de brief. Maar voor het geval dat, heb ik een ingenieur gestuurd om het te controleren. Hij was verrast dat hij werd opgewacht door een rijke, goed opgeleide man die in een prachtige omgeving woonde. Ze spraken af ​​elkaar onmiddellijk na het eten te ontmoeten, zodat ze samen naar de winkel konden gaan om een ​​ijsje te halen. Die avond was het vanille, en toen ze terugkwamen bij de auto, wilde hij niet starten.

De ingenieur kwam nog drie avonden. De eerste keer was het ijs chocolade. De auto startte. De tweede keer was er aardbeienijs. De auto startte. Op de derde avond vroeg hij om vanille. De auto startte niet.

Rationeel redenerend weigerde de ingenieur te geloven dat de auto allergisch was voor vanille-ijs. Daarom heb ik met de eigenaar van de auto afgesproken dat hij zijn bezoeken zou voortzetten totdat hij een oplossing voor het probleem had gevonden. En gaandeweg begon hij aantekeningen te maken: hij noteerde alle informatie, het tijdstip van de dag, het type benzine, het tijdstip van aankomst en terugkomst uit de winkel, enz.

De ingenieur realiseerde zich al snel dat de eigenaar van de auto minder tijd besteedde aan het kopen van vanille-ijs. De reden was de indeling van de goederen in de winkel. Vanille-ijs was het populairst en werd in een aparte vriezer aan de voorkant van de winkel bewaard, zodat het gemakkelijker te vinden was. En alle andere soorten stonden achter in de winkel, en het kostte veel meer tijd om de juiste soort te vinden en te betalen.

Nu was de vraag aan de ingenieur: waarom startte de auto niet als er minder tijd was verstreken sinds het moment dat de motor werd afgezet? Omdat het probleem tijd was en niet vanille-ijs, vond de machinist snel het antwoord: het was een gassluis. Het gebeurde elke avond, maar toen de autobezitter meer tijd besteedde aan het zoeken naar ijs, slaagde de motor erin voldoende af te koelen en startte hij gemakkelijk. En toen de man vanille-ijs kocht, was de motor nog steeds te heet en had het gasslot geen tijd om op te lossen.

Moraal: zelfs volkomen gekke problemen zijn soms reëel.

Crash Bandicoot

Het is pijnlijk om dit te ervaren. Als programmeur raak je eraan gewend om eerst, ten tweede, ten derde de schuld te geven aan je code... en ergens op de tienduizendste plaats geef je de compiler de schuld. En verderop in de lijst geeft u de apparatuur al de schuld.

Hier is mijn verhaal over de hardwarebug.

Voor het spel Crash Bandicoot heb ik code geschreven om te laden en op te slaan op een geheugenkaart. Voor zo'n zelfvoldane game-ontwikkelaar was het een wandeling door het park: ik dacht dat het werk meerdere dagen zou duren. Uiteindelijk heb ik echter zes weken lang de code gedebugd. Gaandeweg heb ik andere problemen opgelost, maar om de paar dagen keerde ik een paar uur terug naar deze code. Het was pijn.

Het symptoom zag er als volgt uit: wanneer je de huidige speelwijze van het spel opslaat en toegang krijgt tot de geheugenkaart, gaat alles bijna altijd goed... Maar soms worden de lees- of schrijfbewerkingen zonder duidelijke reden onderbroken. Een korte opname beschadigt vaak de geheugenkaart. Wanneer een speler probeert te redden, slaagt hij er niet alleen niet in om op te slaan, maar vernietigt hij ook de kaart. Stront.

Na een tijdje begon onze producer bij Sony, Connie Bus, in paniek te raken. We konden de game met deze bug niet verzenden en zes weken later begreep ik niet wat de oorzaak van het probleem was. Via Connie hebben we contact opgenomen met andere PS1-ontwikkelaars: is iemand iets soortgelijks tegengekomen? Nee. Niemand had problemen met de geheugenkaart.

Als je geen ideeën hebt voor het debuggen, is de enige aanpak die overblijft ‘verdeel en heers’: verwijder steeds meer code uit het defecte programma totdat er een relatief klein fragment overblijft dat nog steeds het probleem veroorzaakt. Dat wil zeggen dat u het programma stukje bij beetje afsnijdt totdat het gedeelte met de bug overblijft.

Maar het punt is dat het erg moeilijk is om stukjes uit een videogame te knippen. Hoe moet je het uitvoeren als je de code hebt verwijderd die de zwaartekracht emuleert? Of karakters tekenen?

Daarom moeten we hele modules vervangen door stubs die doen alsof ze iets nuttigs doen, maar in feite iets heel eenvoudigs doen dat geen fouten kan bevatten. We moeten zulke krukken schrijven om het spel tenminste te laten werken. Dit is een langzaam en pijnlijk proces.

Kortom, ik heb het gedaan. Ik verwijderde steeds meer stukjes code totdat ik de initiële code overhield die het systeem configureert om het spel uit te voeren, de renderinghardware initialiseert, enz. Natuurlijk kon ik in dit stadium geen menu voor opslaan en laden maken, omdat ik dan een stub zou moeten maken voor alle grafische code. Maar ik zou kunnen doen alsof ik een gebruiker ben via het (onzichtbare) opslag- en laadscherm en vragen om op te slaan en vervolgens naar de geheugenkaart te schrijven.

Hierdoor hield ik een klein stukje code over dat nog steeds het bovenstaande probleem had, maar het gebeurde nog steeds willekeurig! Meestal werkte alles prima, maar af en toe waren er problemen. Ik heb bijna alle spelcode verwijderd, maar de bug leefde nog steeds. Dit was een raadsel: de resterende code deed eigenlijk niets.

Op een gegeven moment, waarschijnlijk rond drie uur in de ochtend, kwam er een gedachte bij me op. Bij lees- en schrijfbewerkingen (invoer/uitvoer) zijn nauwkeurige uitvoeringstijden vereist. Wanneer je met een harde schijf, geheugenkaart of Bluetooth-module werkt, doet de low-level code die verantwoordelijk is voor het lezen en schrijven dit volgens klokpulsen.

Met behulp van een klok wordt een apparaat dat niet rechtstreeks op de processor is aangesloten, gesynchroniseerd met de code die op de processor wordt uitgevoerd. De klok bepaalt de baudrate: de snelheid waarmee gegevens worden overgedragen. Als er verwarring bestaat over de timing, dan is de hardware of de software, of beide, ook verward. En dit is erg slecht, omdat de gegevens beschadigd kunnen raken.

Wat als iets in onze code de timings verwart? Ik controleerde alles wat hiermee samenhangt in de testprogrammacode en merkte dat we de programmeerbare timer in PS1 op 1 kHz (1000 ticks per seconde) hadden ingesteld. Dit is behoorlijk veel; als de console start, draait deze standaard op 100 Hz. En de meeste games gebruiken deze frequentie.

Andy, de game-ontwikkelaar, zette de timer op 1 kHz zodat bewegingen nauwkeuriger zouden worden berekend. Andy heeft de neiging om overboord te gaan, en als we de zwaartekracht nabootsen, doen we dat zo nauwkeurig mogelijk!

Maar wat als het versnellen van de timer op de een of andere manier de algehele timing van het programma zou beïnvloeden, en dus de klok die de baudsnelheid voor de geheugenkaart regelt?

Ik heb commentaar gegeven op de timercode. De fout heeft zich niet opnieuw voorgedaan. Maar dit betekent niet dat we het probleem hebben opgelost, omdat de fout willekeurig is opgetreden. Wat als ik gewoon geluk had?

Een paar dagen later experimenteerde ik opnieuw met het testprogramma. De bug heeft zich niet herhaald. Ik ging terug naar de volledige codebasis van het spel en paste de code voor opslaan en laden aan, zodat de programmeerbare timer werd gereset naar de oorspronkelijke waarde (100 Hz) voordat hij toegang kreeg tot de geheugenkaart, en vervolgens weer werd teruggezet naar 1 kHz. Er waren geen crashes meer.

Maar waarom is dit gebeurd?

Ik keerde weer terug naar het testprogramma. Ik heb geprobeerd een patroon te vinden in het optreden van een fout met een 1 kHz-timer. Uiteindelijk merkte ik dat de fout optreedt wanneer iemand met een PS1-controller speelt. Aangezien ik dit zelf zelden zou doen, waarom zou ik dan een controller nodig hebben bij het testen van de opslag- en laadcode? - Ik merkte deze afhankelijkheid niet eens op. Maar op een dag wachtte een van onze artiesten tot ik klaar was met testen - ik was op dat moment waarschijnlijk aan het vloeken - en draaide zenuwachtig de controller in zijn handen. Er is een fout opgetreden. "Wacht wat?!" Nou, doe het nog een keer!”

Toen ik besefte dat deze twee gebeurtenissen met elkaar verbonden waren, kon ik de fout gemakkelijk reproduceren: ik begon met opnemen op de geheugenkaart, verplaatste de controller en vernielde de geheugenkaart. Voor mij leek het op een hardwarefout.

Ik kwam naar Connie en vertelde haar over mijn ontdekking. Ze gaf de informatie door aan een van de ingenieurs die de PS1 ontwierp. ‘Onmogelijk,’ antwoordde hij, ‘het kan geen hardwareprobleem zijn.’ Ik vroeg Connie om een ​​gesprek voor ons te regelen.

De ingenieur belde mij en we maakten ruzie in zijn gebroken Engels en mijn (extreem) gebroken Japans. Uiteindelijk zei ik: "Laat me mijn testprogramma van 30 regels sturen, waarbij het verplaatsen van de controller een bug veroorzaakt." Hij was het er mee eens. Hij zei dat het tijdverspilling was en dat hij het vreselijk druk had met een nieuw project, maar zou toegeven omdat we een heel belangrijke ontwikkelaar voor Sony waren. Ik heb mijn testprogramma opgeschoond en naar hem gestuurd.

De volgende avond (we waren in Los Angeles en hij was in Tokio) belde hij me en bood schaapachtig zijn excuses aan. Het was een hardwareprobleem.

Ik weet niet wat de bug precies was, maar van wat ik op het hoofdkantoor van Sony hoorde, bleek dat als je de timer op een voldoende hoge waarde instelde, er interferentie ontstond met componenten op het moederbord in de buurt van het timerkristal. Eén daarvan was een baudratecontroller voor de geheugenkaart, die ook de baudrate voor de controllers instelde. Ik ben geen ingenieur, dus het kan zijn dat ik iets verprutst heb.

Maar het komt erop neer dat er interferentie was tussen componenten op het moederbord. En bij het gelijktijdig verzenden van gegevens via de controllerpoort en de geheugenkaartpoort met een timer die op 1 kHz liep, gingen bits verloren, gingen gegevens verloren en raakte de kaart beschadigd.

Slechte koeien

In de jaren tachtig schreef mijn mentor Sergei software voor de SM-1980, een Sovjet-kloon van de PDP-1800. Deze microcomputer is zojuist geïnstalleerd op een treinstation in de buurt van Sverdlovsk, een belangrijk transportknooppunt in de USSR. Het nieuwe systeem is ontworpen om wagons en vrachtverkeer te routeren. Maar het bevatte een vervelende bug die tot willekeurige crashes en crashes leidde. Valpartijen kwamen altijd voor als iemand 's avonds naar huis ging. Maar ondanks een grondig onderzoek de volgende dag werkte de computer correct bij alle handmatige en automatische tests. Dit duidt meestal op een raceconditie of een andere competitieve bug die onder bepaalde omstandigheden optreedt. Sergei was de telefoontjes 's avonds laat beu en besloot het tot op de bodem uit te zoeken en allereerst te begrijpen welke omstandigheden op het rangeerterrein tot de computerstoring hadden geleid.

Eerst verzamelde hij statistieken van alle onverklaarde valpartijen en maakte hij een grafiek op datum en tijd. Het patroon was duidelijk. Na nog een paar dagen te hebben geobserveerd, realiseerde Sergei zich dat hij gemakkelijk het tijdstip van toekomstige systeemstoringen kon voorspellen.

Hij kwam er al snel achter dat verstoringen alleen plaatsvonden toen het station treinladingen vee uit Noord-Oekraïne en West-Rusland aan het sorteren was, op weg naar een nabijgelegen slachthuis. Dit was op zichzelf al vreemd, omdat het slachthuis werd bevoorraad door boerderijen die veel dichterbij gelegen waren, in Kazachstan.

De kerncentrale van Tsjernobyl ontplofte in 1986 en de radioactieve neerslag maakte de omliggende gebieden onbewoonbaar. Grote gebieden in Noord-Oekraïne, Wit-Rusland en West-Rusland raakten besmet. Sergei vermoedde hoge stralingsniveaus in de aankomende rijtuigen en ontwikkelde een methode om deze theorie te testen. Het was de bevolking verboden dosismeters te hebben, dus meldde Sergei zich bij verschillende militairen op het treinstation. Na enkele drankjes wodka wist hij een soldaat ervan te overtuigen het stralingsniveau in een van de verdachte rijtuigen te meten. Het bleek dat het niveau meerdere malen hoger was dan normale waarden.

Niet alleen zond het vee veel straling uit, het niveau was zo hoog dat dit leidde tot willekeurig verlies van bits in het geheugen van de SM-1800, die zich in een gebouw naast het station bevond.

Er was een voedseltekort in de USSR en de autoriteiten besloten Tsjernobyl-vlees te mengen met vlees uit andere regio's van het land. Dit maakte het mogelijk om het algehele niveau van radioactiviteit te verminderen zonder waardevolle hulpbronnen te verliezen. Toen Sergei hiervan hoorde, vulde hij onmiddellijk de documenten voor emigratie in. En de computercrashes stopten vanzelf toen het stralingsniveau in de loop van de tijd afnam.

Via de leidingen

Ooit creëerde Movietech Solutions software voor bioscopen, ontworpen voor boekhouding, kaartverkoop en algemeen beheer. De DOS-versie van de vlaggenschip-app was behoorlijk populair bij kleine en middelgrote bioscoopketens in Noord-Amerika. Het is dus niet verwonderlijk dat toen er een Windows 95-versie werd aangekondigd, geïntegreerd met de nieuwste touchscreens en zelfbedieningskiosken, en uitgerust met allerlei rapportagetools, deze ook snel populair werd. Meestal verliep de update zonder problemen. Het lokale IT-personeel installeerde nieuwe apparatuur, migreerde gegevens en de zaken gingen door. Behalve toen het niet duurde. Wanneer dit gebeurde, stuurde het bedrijf James op pad, bijgenaamd 'The Cleaner'.

Hoewel de bijnaam een ​​snode soort doet vermoeden, is de schoonmaker slechts een combinatie van instructeur, installateur en alleskunner. James bracht een paar dagen door bij de klant om alle componenten in elkaar te zetten, en bracht daarna nog een paar dagen door met het leren van het personeel hoe het nieuwe systeem moest worden gebruikt, het oplossen van eventuele hardwareproblemen die zich voordeden en het helpen van de software door de kinderschoenen heen.

Het is dan ook niet verwonderlijk dat James tijdens deze hectische tijden 's ochtends op kantoor aankwam en voordat hij zijn bureau kon bereiken, werd begroet door de manager, meer dan normaal gevuld met cafeïne.

'Ik ben bang dat je zo snel mogelijk naar Annapolis, Nova Scotia moet gaan.' Hun hele systeem viel uit en na een nacht werken met hun technici kunnen we niet achterhalen wat er is gebeurd. Het lijkt erop dat het netwerk op de server is uitgevallen. Maar pas nadat het systeem enkele minuten had gedraaid.

— Ze zijn niet teruggekeerd naar het oude systeem? - James antwoordde volkomen serieus, hoewel hij mentaal zijn ogen groot maakte van verbazing.

— Precies: hun IT-specialist “veranderde de prioriteiten” en besloot te vertrekken met hun oude server. James, ze hebben het systeem op zes locaties geïnstalleerd en betaalden alleen voor premiumondersteuning, en hun bedrijf wordt nu gerund zoals in de jaren vijftig.

James richtte zich een beetje op.

- Dat is een andere zaak. Oké, laten we beginnen.

Toen hij in Annapolis aankwam, was het eerste wat hij deed het vinden van de eerste bioscoop van de klant die een probleem had. Op de kaart die op de luchthaven werd genomen, zag alles er netjes uit, maar het gebied rond het gewenste adres zag er verdacht uit. Geen getto, maar doet denken aan film noir. Terwijl James op de stoep in het centrum parkeerde, kwam een ​​prostituee naar hem toe. Gezien de omvang van Annapolis was dit hoogstwaarschijnlijk de enige in de hele stad. Haar uiterlijk deed onmiddellijk denken aan het beroemde personage dat seks voor geld op het grote scherm aanbood. Nee, niet over Julia Roberts, maar over Jon Voight [toespeling op de film "Midnight Cowboy" - ca. rijbaan].

Nadat hij de prostituee op weg had gestuurd, ging James naar de bioscoop. De omgeving was beter geworden, maar gaf nog steeds de indruk van verwaarlozing. Niet dat James zich al te veel zorgen maakte. Hij is al eerder op ellendige plaatsen geweest. En dit was Canada, waar zelfs overvallers beleefd genoeg zijn om ‘bedankt’ te zeggen nadat ze je portemonnee hebben afgepakt.

De zij-ingang van de bioscoop bevond zich in een vochtig steegje. James liep naar de deur en klopte. Al snel kraakte het en ging het een beetje open.

-Ben jij een schoonmaker? - er kwam een ​​schorre stem van binnenuit.

- Ja, ik ben het... Ik kwam alles repareren.

James liep de bioscooplobby binnen. Omdat ze blijkbaar geen andere keuze hadden, begon het personeel papieren kaartjes uit te delen aan bezoekers. Dit maakte financiële verslaggeving lastig, laat staan ​​interessantere details. Maar het personeel begroette James opgelucht en nam hem onmiddellijk mee naar de serverruimte.

Op het eerste gezicht was alles in orde. James logde in op de server en controleerde de gebruikelijke verdachte plaatsen. Geen probleem. Uit grote voorzichtigheid schakelde James echter de server uit, verving de netwerkkaart en draaide het systeem terug. Ze ging meteen voluit aan de slag. Het personeel begon weer kaartjes te verkopen.

James belde Mark en informeerde hem over de situatie. Het is niet moeilijk voor te stellen dat James zou willen blijven om te kijken of er iets onverwachts gebeurt. Hij ging de trap af en begon de medewerkers te vragen wat er was gebeurd. Het is duidelijk dat het systeem niet meer werkt. Ze hebben het uit en weer aangezet, alles werkte. Maar na 10 minuten viel het systeem uit.

Precies op dit moment gebeurde er iets soortgelijks. Plots begon het ticketsysteem fouten te genereren. Het personeel zuchtte en pakte de papieren kaartjes, en James haastte zich naar de serverruimte. Alles zag er goed uit met de server.

Toen kwam een ​​van de medewerkers binnen.

— Het systeem werkt weer.

James was verbaasd omdat hij niets had gedaan. Om precies te zijn, niets dat het systeem zou laten werken. Hij logde uit, pakte zijn telefoon en belde de ondersteuningslijn van zijn bedrijf. Al snel kwam dezelfde medewerker de serverruimte binnen.

- Het systeem is defect.

James wierp een blik op de server. Een interessant en vertrouwd patroon van veelkleurige vormen danste op het scherm: chaotisch kronkelende en in elkaar verweven pijpen. We hebben deze screensaver allemaal wel eens gezien. Het was prachtig weergegeven en letterlijk hypnotiserend.


James drukte op een knop en het patroon verdween. Hij haastte zich naar het loket en ontmoette onderweg een medewerker die naar hem terugkeerde.

— Het systeem werkt weer.

Als je een mentale facepalm kunt doen, is dat precies wat James deed. Screensaver. Het maakt gebruik van OpenGL. En daarom verbruikt het tijdens bedrijf alle bronnen van de serverprocessor. Als gevolg hiervan eindigt elke oproep naar de server met een time-out.

James keerde terug naar de serverruimte, logde in en verving de screensaver door de prachtige pijpen met een leeg scherm. Dat wil zeggen, in plaats van een screensaver die 100% van de processorbronnen verbruikt, heb ik een andere geïnstalleerd die geen bronnen verbruikt. Daarna wachtte ik 10 minuten om mijn gok te controleren.

Toen James bij de volgende bioscoop aankwam, vroeg hij zich af hoe hij aan zijn manager moest uitleggen dat hij net 800 km had gevlogen om de screensaver uit te zetten.

Crash tijdens een bepaalde fase van de maan

Waargebeurd verhaal. Op een dag ontstond er een softwarefout die afhankelijk was van de stand van de maan. Er was een kleine routine die vaak werd gebruikt in verschillende MIT-programma's om de benadering van de ware fase van de maan te berekenen. GLS bouwde deze routine in een LISP-programma dat, bij het schrijven van een bestand, een regel met een tijdstempel van bijna 80 tekens lang zou opleveren. Het kwam zeer zelden voor dat de eerste regel van een bericht te lang werd en naar de volgende regel leidde. En toen het programma dit bestand later las, vloekte het. De lengte van de eerste regel was afhankelijk van de exacte datum en tijd, evenals van de lengte van de fasespecificatie op het moment dat de tijdstempel werd afgedrukt. Dat wil zeggen, de bug was letterlijk afhankelijk van de fase van de maan!

Eerste papieren editie Jargon-bestand (Steele-1983) bevatte een voorbeeld van zo'n regel die tot de beschreven bug leidde, maar de zetter 'repareerde' deze. Dit wordt sindsdien beschreven als een "maanfase-bug".

Wees echter voorzichtig met aannames. Een paar jaar geleden kwamen ingenieurs van CERN (European Centre for Nuclear Research) fouten tegen in experimenten die werden uitgevoerd bij de Large Electron-Positron Collider. Omdat computers de enorme hoeveelheid gegevens die door dit apparaat worden gegenereerd actief verwerken voordat ze het resultaat aan wetenschappers laten zien, speculeerden velen dat de software op de een of andere manier gevoelig was voor de fase van de maan. Verschillende wanhopige ingenieurs hebben de waarheid tot op de bodem uitgezocht. De fout ontstond door een kleine verandering in de geometrie van de 27 km lange ring als gevolg van de vervorming van de aarde tijdens de passage van de maan! Dit verhaal is in de natuurkundefolklore terechtgekomen als ‘Newton’s Revenge on Particle Physics’ en is een voorbeeld van het verband tussen de eenvoudigste en oudste wetten van de natuurkunde en de meest geavanceerde wetenschappelijke concepten.

Door het toilet door te spoelen stopt de trein

De beste hardwarebug waar ik ooit van heb gehoord, deed zich voor in een hogesnelheidstrein in Frankrijk. De bug leidde tot een noodremming van de trein, maar alleen als er passagiers aan boord waren. In elk van deze gevallen werd de trein buiten dienst gesteld, gecontroleerd, maar er werd niets gevonden. Vervolgens werd hij teruggestuurd naar de lijn en kwam onmiddellijk tot stilstand.

Tijdens een van de controles ging een machinist die in de trein zat naar het toilet. Hij spoelde snel weg, BOOM! Noodstop.

De ingenieur nam contact op met de chauffeur en vroeg:

— Wat deed je vlak voordat je remde?

- Nou, ik ging langzamer rijden tijdens de afdaling...

Dat was vreemd, want tijdens normaal gebruik vertraagt ​​de trein bij afdalingen tientallen keren. De trein reed verder en bij de volgende afdaling waarschuwde de machinist:

- Ik ga langzamer rijden.

Er is niks gebeurd.

— Wat heb je gedaan tijdens de laatste keer remmen? - vroeg de chauffeur.

- Nou... ik was op het toilet...

- Nou, ga dan naar het toilet en doe wat je deed als we weer naar beneden gaan!

De machinist ging naar het toilet en toen de chauffeur waarschuwde: ‘Ik ga langzamer rijden’, spoelde hij het water door. Uiteraard stopte de trein onmiddellijk.

Nu konden ze het probleem reproduceren en moesten ze de oorzaak vinden.

Na twee minuten merkten ze dat de kabel van de afstandsbediening van de motorrem (de trein had één motor aan elk uiteinde) was losgekoppeld van de muur van de elektriciteitskast en op het relais lag dat de solenoïde van de toiletstekker aanstuurde... Toen het relais was ingeschakeld, veroorzaakte dit interferentie in de remkabel, en de systeembescherming tegen storingen omvatte eenvoudigweg een noodremming.

De poort die FORTRAN haatte

Een paar maanden geleden merkten we dat de netwerkverbindingen op het vasteland [dit was op Hawaï] heel erg traag werden. Dit kan 10-15 minuten duren en dan plotseling weer optreden. Na enige tijd klaagde mijn collega bij mij over de netwerkverbindingen op het vasteland in het algemeen werkt niet. Hij had wat FORTRAN-code die naar een machine op het vasteland moest worden gekopieerd, maar dat lukte niet omdat "het netwerk het niet lang genoeg volhield om de FTP-upload te voltooien."

Ja, het bleek dat er netwerkstoringen optraden toen een collega probeerde een bestand met broncode in FORTRAN te FTP-en naar een machine op het vasteland. We hebben geprobeerd het bestand te archiveren: daarna werd het probleemloos gekopieerd (maar de doelmachine had geen uitpakker, dus het probleem was niet opgelost). Ten slotte hebben we de FORTRAN-code in zeer kleine stukjes "gesplitst" en deze één voor één verzonden. De meeste fragmenten werden zonder problemen gekopieerd, maar een paar stukken kwamen niet of later voorbij talrijk pogingen.

Toen we de problematische passages onderzochten, ontdekten we dat ze iets gemeen hadden: ze bevatten allemaal commentaarblokken die begonnen en eindigden met regels bestaande uit een hoofdletter C (zoals een collega in FORTRAN liever commentaar gaf). We hebben netwerkexperts op het vasteland gemaild en om hulp gevraagd. Natuurlijk wilden ze voorbeelden zien van onze bestanden die niet via FTP konden worden overgedragen... maar onze brieven bereikten hen niet. Uiteindelijk kwamen we op een simpel idee beschrijvenhoe niet-overdraagbare bestanden eruitzien. Het werkte :) [Durf ik hier een voorbeeld toe te voegen van een van de problematische FORTRAN-opmerkingen? Waarschijnlijk niet de moeite waard!]

Uiteindelijk hebben we het kunnen achterhalen. Er is onlangs een nieuwe gateway geïnstalleerd tussen ons deel van de campus en het vastelandnetwerk. Het had ENORME moeite met het verzenden van pakketten die herhaalde bits van hoofdletters C bevatten! Slechts een paar van deze pakketten kunnen alle gatewaybronnen in beslag nemen en voorkomen dat de meeste andere pakketten erdoorheen komen. We hebben een klacht ingediend bij de fabrikant van de gateway... en zij antwoordden: “O ja, je wordt geconfronteerd met een bug van herhaalde C! Wij weten al van hem.” We hebben het probleem uiteindelijk opgelost door een nieuwe gateway van een andere fabrikant te kopen (ter verdediging van eerstgenoemde: het onvermogen om FORTRAN-programma's over te dragen kan voor sommigen een voordeel zijn!).

Moeilijke tijden

Een paar jaar geleden, toen ik werkte aan het creëren van een ETL-systeem in Perl om de kosten van fase 40 klinische onderzoeken te verlagen, moest ik ongeveer 000 dadels verwerken. Twee van hen slaagden niet voor de test. Dit stoorde mij niet zo erg, omdat deze data afkomstig waren uit door de klant verstrekte gegevens die vaak, laten we zeggen, verrassend waren. Maar toen ik de originele gegevens controleerde, bleek dat deze data 1 januari 2011 en 1 januari 2007 waren. Ik dacht dat de bug zat in het programma dat ik zojuist had geschreven, maar het bleek al 30 jaar geleden te zijn. oud. Dit klinkt misschien mysterieus voor degenen die niet bekend zijn met het software-ecosysteem. Vanwege de al lang bestaande beslissing van een ander bedrijf om geld te verdienen, betaalde mijn cliënt mij om een ​​bug te repareren die het ene bedrijf per ongeluk had geïntroduceerd en het andere met opzet. Om te begrijpen waar ik het over heb, moet ik het hebben over het bedrijf dat de functie heeft toegevoegd die uiteindelijk een bug werd, en over een paar andere interessante gebeurtenissen die hebben bijgedragen aan de mysterieuze bug die ik heb opgelost.

Vroeger zetten Apple-computers soms spontaan hun datum terug naar 1 januari 1904. De reden was simpel: er werd gebruik gemaakt van een “systeemklok” op batterijen om de datum en tijd bij te houden. Wat gebeurde er toen de batterij leeg was? Computers begonnen de datum bij te houden aan de hand van het aantal seconden sinds het begin van een tijdperk. Met tijdperk bedoelden we de oorspronkelijke referentiedatum, en voor Macintoshes was dat 1 januari 1904. En nadat de batterij leeg was, werd de huidige datum opnieuw ingesteld op de opgegeven datum. Maar waarom gebeurde dit?

Voorheen gebruikte Apple 32 bits om het aantal seconden sinds de oorspronkelijke datum op te slaan. Eén bit kan een van de twee waarden opslaan: 1 of 0. Twee bits kunnen een van de vier waarden opslaan: 00, 01, 10, 11. Drie bits - één waarde uit acht: 000, 001, 010, 011, 100 , 101, 110, 111, enz. En 32 zou één van de 232 waarden kunnen opslaan, dat wil zeggen 4 seconden. Voor Apple-datums komt dit neer op ongeveer 294 jaar, dus oudere Macs kunnen geen datums na 967 aan. En als de systeembatterij leeg raakt, wordt de datum opnieuw ingesteld op 296 seconden sinds het begin van het tijdperk, en moet u de datum handmatig instellen telkens wanneer u de computer aanzet (of totdat u een nieuwe batterij koopt).

Het besluit van Apple om datums op te slaan als seconden sinds het tijdperk betekende echter dat we datums vóór het tijdperk niet konden verwerken, wat verstrekkende gevolgen had, zoals we zullen zien. Apple heeft een functie geïntroduceerd, geen bug. Dit betekende onder meer dat het Macintosh-besturingssysteem immuun was voor de “millenniumbug” (wat niet gezegd kon worden over veel Mac-applicaties die hun eigen datumsystemen hadden om beperkingen te omzeilen).

Doe Maar. We gebruikten Lotus 1-2-3, IBM's 'killer-applicatie' die hielp bij het lanceren van de pc-revolutie, hoewel Apple-computers VisiCalc hadden, wat de personal computer tot een succes maakte. Eerlijk gezegd: als 1-2-3 niet was verschenen, zouden pc's nauwelijks van de grond zijn gekomen en had de geschiedenis van personal computers zich heel anders kunnen ontwikkelen. Lotus 1-2-3 behandelde 1900 ten onrechte als een schrikkeljaar. Toen Microsoft zijn eerste spreadsheet, Multiplan, uitbracht, veroverde het een klein marktaandeel. En toen ze het Excel-project lanceerden, besloten ze niet alleen het naamgevingsschema voor rijen en kolommen uit Lotus 1-2-3 te kopiëren, maar ook om compatibiliteit met bugs te garanderen door 1900 opzettelijk als een schrikkeljaar te beschouwen. Dit probleem bestaat nog steeds. Dat wil zeggen, in 1-2-3 was dit een bug, maar in Excel was het een bewuste beslissing die ervoor zorgde dat alle 1-2-3-gebruikers hun tabellen in Excel konden importeren zonder de gegevens te wijzigen, zelfs als deze onjuist waren.

Maar er was nog een probleem. Ten eerste bracht Microsoft Excel uit voor de Macintosh, die geen datums herkende vóór 1 januari 1904. En in Excel werd 1 januari 1900 beschouwd als het begin van het tijdperk. Daarom hebben de ontwikkelaars een wijziging aangebracht zodat hun programma het type tijdperk herkende en gegevens in zichzelf opsloeg in overeenstemming met het gewenste tijdperk. Microsoft schreef hier zelfs een verklarend artikel over. En deze beslissing leidde tot mijn bug.

Mijn ETL-systeem ontving Excel-spreadsheets van klanten die op Windows waren gemaakt, maar ook op een Mac konden worden gemaakt. Daarom kan het begin van de jaartelling in de tabel 1 januari 1900 of 1 januari 1904 zijn. Hoe kom je erachter? Het Excel-bestandsformaat toont de benodigde informatie, maar de parser die ik gebruikte liet deze niet zien (nu wel), en ging ervan uit dat je het tijdperk voor een specifieke tabel kent. Ik had waarschijnlijk meer tijd kunnen besteden aan het begrijpen van het binaire Excel-formaat en het sturen van een patch naar de auteur van de parser, maar ik had veel meer te doen voor de klant, dus schreef ik snel een heuristiek om het tijdperk te bepalen. Ze was eenvoudig.

In Excel kan de datum 5 juli 1998 worden weergegeven in het formaat "07-05-98" (nutteloos Amerikaans systeem), "5 juli 98", "5 juli 1998", "5-jul-98" of een ander formaat, nog een nutteloos formaat (ironisch genoeg was ISO 8601 een van de formaten die mijn versie van Excel niet bood). In de tabel werd de niet-opgemaakte datum echter opgeslagen als "35981" voor tijdperk-1900 of "34519" voor tijdperk-1904 (de cijfers vertegenwoordigen het aantal dagen sinds het tijdperk). Ik heb eenvoudigweg een eenvoudige parser gebruikt om het jaar uit de opgemaakte datum te extraheren, en vervolgens de Excel-parser gebruikt om het jaar uit de niet-opgemaakte datum te extraheren. Als beide waarden 4 jaar verschilden, wist ik dat ik een systeem met tijdperk-1904 gebruikte.

Waarom heb ik niet gewoon opgemaakte datums gebruikt? Omdat 5 juli 1998 kan worden opgemaakt als 'Juli 98', waarbij de dag van de maand verloren gaat. We ontvingen tabellen van zoveel bedrijven die ze op zoveel verschillende manieren maakten dat het aan ons (in dit geval aan mij) was om de data te achterhalen. Trouwens, als Excel het goed doet, dan moeten wij dat ook doen!

Tegelijkertijd kwam ik 39082 tegen. Ik wil u eraan herinneren dat Lotus 1-2-3 1900 als een schrikkeljaar beschouwde, en dit werd getrouw herhaald in Excel. En aangezien hierdoor één dag aan het jaar 1900 werd toegevoegd, kunnen veel datumberekeningsfuncties voor diezelfde dag verkeerd zijn. Dat wil zeggen: 39082 had 1 januari 2011 (op Macs) of 31 december 2006 (op Windows) kunnen zijn. Als mijn "jaarparser" het jaar 2011 uit de opgemaakte waarde heeft gehaald, dan is alles in orde. Maar omdat de Excel-parser niet weet welk tijdperk wordt gebruikt, wordt standaard tijdperk-1900 gebruikt, waarbij het jaar 2006 wordt geretourneerd. Mijn applicatie zag dat het verschil vijf jaar was, beschouwde het als een fout, registreerde het en retourneerde een niet-geformatteerde waarde.

Om dit te omzeilen, heb ik dit geschreven (pseudocode):

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

En toen werden alle 40 datums correct geparseerd.

Midden in grote printopdrachten

Begin jaren tachtig werkte mijn vader bij Storage Technology, een inmiddels ter ziele gegane divisie die tapedrives en pneumatische systemen maakte voor snelle tape-invoer.

Ze hebben de schijven opnieuw ontworpen, zodat ze één centrale ‘A’-schijf konden hebben, verbonden met zeven ‘B’-schijven, en het kleine besturingssysteem in het RAM dat de’ A’-schijf bestuurde, lees- en schrijfbewerkingen kon delegeren aan alle ‘B’-schijven.

Elke keer dat station “A” werd gestart, was het nodig om een ​​diskette in het randapparaat te plaatsen dat op “A” was aangesloten om het besturingssysteem in zijn geheugen te laden. Het was uiterst primitief: de rekenkracht werd geleverd door een 8-bit microcontroller.

De doelgroep voor dergelijke apparatuur waren bedrijven met zeer grote datawarehouses (banken, winkelketens, enz.) die veel adresetiketten of bankafschriften moesten afdrukken.

Eén klant had een probleem. Midden in een afdruktaak kan één bepaalde schijf “A” stoppen met werken, waardoor de hele taak vastloopt. Om de werking van de schijf te herstellen, moest het personeel alles opnieuw opstarten. En als dit midden in een taak van zes uur gebeurde, ging er enorm veel dure computertijd verloren en werd de planning van de hele operatie verstoord.

Technici werden gestuurd door Storage Technologies. Maar ondanks hun inspanningen waren ze niet in staat de bug onder testomstandigheden te reproduceren: de bug leek zich voor te doen tijdens grote printopdrachten. Het probleem was niet de hardware, ze hebben alles vervangen wat ze konden: RAM, microcontroller, diskettestation, elk denkbaar onderdeel van de tapedrive - het probleem bleef bestaan.

Toen belden de technici het hoofdkantoor en belden de expert.

De expert pakte een stoel en een kop koffie, ging in de computerkamer zitten (in die tijd waren er kamers voor computers) en keek toe hoe het personeel een grote printopdracht in de rij zette. De expert wachtte op een storing, en dat gebeurde ook. Iedereen keek naar de Expert, maar hij had geen idee waarom dit gebeurde. Daarom gaf hij opdracht om de klus opnieuw in de wachtrij te zetten en al het personeel en de technici gingen weer aan het werk.

De expert ging weer in de stoel zitten en begon te wachten op een mislukking. Ongeveer zes uur gingen voorbij en de storing vond plaats. De Expert had wederom geen idee, behalve dat alles gebeurde in een kamer vol mensen. Hij gaf opdracht de missie opnieuw te starten, ging weer zitten en wachtte.

Bij de derde mislukking merkte de Expert iets op. De storing deed zich voor toen personeel de banden op een buitenlandse schijf verwisselde. Bovendien ontstond de storing zodra een van de medewerkers door een bepaalde tegel op de vloer liep.

De verhoogde vloer was gemaakt van aluminium tegels die op een hoogte van 6 tot 8 centimeter waren gelegd. Onder de verhoogde vloer liepen talloze draden van computers om te voorkomen dat iemand per ongeluk op een belangrijke kabel zou stappen. De tegels werden zeer strak gelegd om te voorkomen dat er vuil onder de verhoogde vloer zou komen.

De deskundige realiseerde zich dat een van de tegels vervormd was. Wanneer een medewerker op de hoek stapte, schuurden de randen van de tegel tegen de aangrenzende tegels. De plastic onderdelen die de tegels met elkaar verbonden, schuurden er ook mee, wat statische micro-ontladingen veroorzaakte die radiofrequentie-interferentie veroorzaakten.

Tegenwoordig is RAM veel beter beschermd tegen radiofrequentie-interferentie. Maar dat was in die jaren niet het geval. De expert realiseerde zich dat deze interferentie het geheugen verstoorde, en daarmee de werking van het besturingssysteem. Hij belde de ondersteuningsdienst, bestelde nieuwe tegels, plaatste ze zelf en het probleem verdween.

Het is vloed!

Het verhaal speelde zich af in een serverruimte, op de vierde of vijfde verdieping van een kantoor in Portsmouth (denk ik), in het havengebied.

Op een dag crashte de Unix-server met de hoofddatabase. Ze startten hem opnieuw op, maar hij bleef gelukkig keer op keer vallen. We besloten iemand van de ondersteuningsdienst te bellen.

De supportman... Ik denk dat zijn naam Mark was, maar dat maakt niet uit... Ik denk niet dat ik hem ken. Het maakt eigenlijk niet uit. Laten we bij Mark blijven, oké? Geweldig.

Dus een paar uur later arriveerde Mark (het is niet ver van Leeds naar Portsmouth, weet je), zette de server aan en alles werkte zonder problemen. Typisch verdomde ondersteuning, de klant raakt hier erg boos over. Mark bladert door de logbestanden en vindt niets onaangenaams. Dus Mark stapt weer in de trein (of met welk vervoersmiddel hij ook aankwam, het had voor zover ik weet een lamme koe kunnen zijn... hoe dan ook, het maakt niet uit, oké?) en gaat terug naar Leeds, nadat hij verspilde tijd heeft verloren. de dag.

Diezelfde avond crasht de server opnieuw. Het verhaal is hetzelfde... de server komt niet omhoog. Mark probeert op afstand te helpen, maar de client kan de server niet starten.

Nog een trein, bus, citroenmeringue of iets anders, en Mark is terug in Portsmouth. Kijk, de server start zonder problemen op! Wonder. Mark besteedt enkele uren aan het controleren of alles in orde is met het besturingssysteem of de software en vertrekt naar Leeds.

Rond het midden van de dag crasht de server (doe rustig aan!). Deze keer lijkt het redelijk om hardwareondersteuningsmensen in te schakelen om de server te vervangen. Maar nee, na ongeveer 10 uur valt het ook.

De situatie herhaalde zich gedurende meerdere dagen. De server werkt, crasht na ongeveer 10 uur en start de volgende 2 uur niet op. Ze controleerden de koeling, geheugenlekken, ze controleerden alles, maar vonden niets. Toen stopten de crashes.

De week ging zorgeloos voorbij... iedereen was blij. Blij totdat het allemaal opnieuw begint. Het beeld is hetzelfde. 10 uur werk, 2-3 uur downtime...

En toen zei iemand (ik denk dat ze me vertelden dat deze persoon niets met IT te maken had):

"Het is het tij!"

De uitroep werd beantwoord met lege blikken, en iemands hand aarzelde waarschijnlijk bij de beveiligingsbelknop.

‘Het werkt niet meer met het getij mee.’

Dit lijkt een volkomen vreemd concept voor IT-ondersteuners, die het Tide Yearbook waarschijnlijk niet zullen lezen terwijl ze aan de koffie zitten. Ze legden uit dat dit op geen enkele manier met het getij te maken had, omdat de server al een week zonder storingen werkte.

“Vorige week was het tij laag, maar deze week is het hoog.”

Een beetje terminologie voor degenen die geen jachtlicentie hebben. De getijden zijn afhankelijk van de maancyclus. En terwijl de aarde ronddraait, creëert de zwaartekracht van de zon en de maan elke 12,5 uur een vloedgolf. Aan het begin van de cyclus van 12,5 uur is er hoogwater, in het midden van de cyclus is er eb en aan het einde is er weer hoogwater. Maar naarmate de baan van de maan verandert, verandert ook het verschil tussen eb en vloed. Wanneer de maan zich tussen de zon en de aarde bevindt, of aan de andere kant van de aarde (volle maan of geen maan), krijgen we Syzygyn-getijden - de hoogste vloed en de laagste eb. Bij halve maan krijgen we kwadratuurgetijden - de laagste getijden. Het verschil tussen de twee uitersten wordt sterk kleiner. De maancyclus duurt 28 dagen: syzygisch - kwadratuur - syzygisch - kwadratuur.

Toen de technici de essentie van getijdenkrachten werd uitgelegd, dachten ze meteen dat ze de politie moesten bellen. En best logisch. Maar het blijkt dat de man gelijk had. Twee weken eerder meerde een torpedobootjager niet ver van het kantoor af. Elke keer dat het tij het tot een bepaalde hoogte bracht, kwam de radarpost van het schip ter hoogte van de vloer van de serverruimte terecht. En de radar (of apparatuur voor elektronische oorlogsvoering, of een ander militair speelgoed) veroorzaakte chaos in de computers.

Vluchtmissie voor de raket

Ik kreeg de taak om een ​​groot (ongeveer 400 lijnen) raketlanceringscontrole- en monitoringsysteem over te zetten naar nieuwe versies van het besturingssysteem, de compiler en de taal. Om precies te zijn, van Solaris 2.5.1 tot Solaris 7, en van het Verdix Ada Development System (VADS), geschreven in Ada 83, tot het Rational Apex Ada-systeem, geschreven in Ada 95. VADS werd gekocht door Rational en het product ervan werd verouderd, hoewel Rational probeerde compatibele versies van VADS-specifieke pakketten te implementeren om de overgang naar de Apex-compiler te vergemakkelijken.

Drie mensen hebben me geholpen om de code netjes te compileren. Het duurde twee weken. En daarna heb ik er zelf aan gewerkt om het systeem te laten werken. Kortom, het was de slechtste architectuur en implementatie van een softwaresysteem die ik ben tegengekomen, dus het duurde nog eens twee maanden om de port te voltooien. Vervolgens werd het systeem ter test aangeboden, wat nog enkele maanden duurde. Ik corrigeerde onmiddellijk de bugs die tijdens het testen werden gevonden, maar hun aantal nam snel af (de broncode was een productiesysteem, dus de functionaliteit werkte redelijk betrouwbaar, ik hoefde alleen maar de bugs te verwijderen die ontstonden tijdens de aanpassing aan de nieuwe compiler). Uiteindelijk, toen alles naar behoren werkte, werd ik overgeplaatst naar een ander project.

En op de vrijdag vóór Thanksgiving ging de telefoon.

De raketlancering zou over ongeveer drie weken worden getest, en tijdens laboratoriumtests van het aftellen werd de reeks commando's geblokkeerd. In het echte leven zou dit de test afbreken, en als de blokkering binnen een paar seconden na het starten van de motor zou optreden, zouden er verschillende onomkeerbare acties plaatsvinden in de hulpsystemen, wat een lange – en dure – paraatheid van de raket zou vereisen. Het zou niet zijn begonnen, maar veel mensen zouden erg boos zijn geweest over het verlies van tijd en heel veel geld. Laat niemand je vertellen dat het ministerie van Defensie roekeloos geld uitgeeft. Ik heb nog nooit een contractmanager ontmoet die het budget niet op de eerste of tweede plaats zette, gevolgd door de planning.

In de voorgaande maanden was deze countdown-uitdaging honderden keren uitgevoerd in vele variaties, met slechts een paar kleine minpuntjes. De kans dat dit zou gebeuren was dus erg klein, maar de gevolgen waren zeer aanzienlijk. Vermenigvuldig beide factoren en je zult begrijpen dat het nieuws een verpest vakantieweek voorspelde voor mij en tientallen ingenieurs en managers.

En er werd aandacht besteed aan mij als de persoon die het systeem porteerde.

Zoals bij de meeste beveiligingskritieke systemen werden er veel parameters geregistreerd, dus het was vrij eenvoudig om de paar regels code te identificeren die werden uitgevoerd voordat het systeem crashte. En natuurlijk was er absoluut niets ongewoons aan; dezelfde uitdrukkingen waren tijdens dezelfde run letterlijk duizenden keren met succes uitgevoerd.

We hebben de mensen van Apex naar Rational geroepen omdat zij degenen waren die de compiler ontwikkelden en sommige van de routines die ze ontwikkelden werden aangeroepen in de verdachte code. Zij (en alle anderen) waren onder de indruk dat het nodig was om tot de kern van een probleem van letterlijk nationaal belang te komen.

Omdat er niets interessants in de tijdschriften stond, besloten we te proberen het probleem in een plaatselijk laboratorium te reproduceren. Dit was geen gemakkelijke taak, aangezien de gebeurtenis ongeveer één keer per 1000 runs plaatsvond. Eén vermoedelijke reden was dat een aanroep naar een door de leverancier ontwikkelde mutex-functie (onderdeel van het VADS-migratiepakket) Unlock heeft niet tot ontsluiting geleid. De verwerkingsthread die de functie aanriep, verwerkte hartslagberichten, die nominaal elke seconde binnenkwamen. We verhoogden de frequentie naar 10 Hz, dat wil zeggen 10 keer per seconde, en begonnen te rennen. Ongeveer een uur later vergrendelde het systeem zichzelf. In het log zagen we dat de volgorde van de opgenomen berichten dezelfde was als tijdens de mislukte test. We hebben nog een aantal runs gemaakt, het systeem werd 45-90 minuten na de start consequent geblokkeerd en elke keer bevatte het logboek dezelfde route. Ook al gebruikten we technisch gezien andere code (de berichtfrequentie was anders), het gedrag van het systeem was hetzelfde, dus we waren ervan overtuigd dat dit laadscenario hetzelfde probleem veroorzaakte.

Nu moesten we uitzoeken waar de blokkering precies plaatsvond in de reeks expressies.

Deze implementatie van het systeem maakte gebruik van het Ada-taaksysteem en gebruikte het ongelooflijk slecht. Taken zijn een gelijktijdig uitvoerbare constructie op hoog niveau in Ada, zoiets als uitvoeringsdraden, alleen ingebouwd in de taal zelf. Wanneer twee taken moeten communiceren, "zetten ze een afspraak", wisselen ze de nodige gegevens uit, stoppen vervolgens de afspraak en keren terug naar hun onafhankelijke executies. Het systeem werd echter anders geïmplementeerd. Nadat een doeltaak een ontmoeting had gehad, kwam die doeltaak samen met een andere taak, die vervolgens samenkwam met een derde taak, enzovoort totdat enige verwerking was voltooid. Hierna waren al deze rendez-vous voltooid en moest elke taak terugkeren naar de uitvoering ervan. Dat wil zeggen, we hadden te maken met het duurste functieaanroepsysteem ter wereld, dat het hele ‘multitasking’-proces stopte terwijl het een deel van de invoergegevens verwerkte. En voorheen leidde dit niet alleen tot problemen omdat de doorvoer erg laag was.

Ik heb dit taakmechanisme beschreven omdat wanneer een rendez-vous werd aangevraagd of naar verwachting zou worden voltooid, er een "taakwisseling" zou kunnen plaatsvinden. Dat wil zeggen dat de processor zou kunnen beginnen met het verwerken van een andere taak die gereed is om te worden uitgevoerd. Het blijkt dat wanneer een taak gereed is voor een ontmoeting met een andere taak, een compleet andere taak kan worden uitgevoerd, en dat uiteindelijk de controle terugkeert naar de eerste ontmoeting. En er kunnen zich andere gebeurtenissen voordoen die ervoor zorgen dat de taak verandert; Eén zo'n gebeurtenis is een aanroep van een systeemfunctie, zoals het afdrukken of uitvoeren van een mutex.

Om te begrijpen welke coderegel het probleem veroorzaakte, moest ik een manier vinden om de voortgang via een reeks instructies vast te leggen zonder een taakwisseling te activeren, waardoor een crash zou worden voorkomen. Ik kon er dus niet van profiteren Put_Line()om te voorkomen dat I/O-bewerkingen worden uitgevoerd. Ik zou een tellervariabele of iets dergelijks kunnen instellen, maar hoe kan ik de waarde ervan zien als ik deze niet op het scherm kan weergeven?

Bij onderzoek van het logboek bleek ook dat, ondanks dat de verwerking van hartslagberichten vastliep, waardoor alle I/O-bewerkingen van het proces werden geblokkeerd en andere verwerkingen niet konden worden uitgevoerd, andere onafhankelijke taken nog steeds werden uitgevoerd. Dat wil zeggen dat het werk niet volledig werd geblokkeerd, maar slechts een (kritieke) keten van taken.

Dit was de aanwijzing die nodig was om de blokkerende expressie te evalueren.

Ik heb een Ada-pakket gemaakt dat een taak, een opgesomd type en een globale variabele van dat type bevatte. Optelbare letterlijke waarden waren gebonden aan specifieke uitdrukkingen van de problematische reeks (bijv. Incrementing_Buffer_Index, Locking_Mutex, Mutex_Unlocked), en vervolgens toewijzingsexpressies erin ingevoegd die de corresponderende opsomming aan een globale variabele toewezen. Omdat de objectcode van dit alles eenvoudigweg een constante in het geheugen opsloeg, was het wisselen van taak als gevolg van de uitvoering ervan uiterst onwaarschijnlijk. We stonden vooral wantrouwend tegenover expressies die de taak konden omschakelen, omdat de blokkering plaatsvond bij de uitvoering en niet terugkeerde bij het terugschakelen van de taak (om verschillende redenen).

De trackingtaak liep eenvoudigweg in een lus en controleerde periodiek of de waarde van de globale variabele was veranderd. Bij elke wijziging werd de waarde opgeslagen in een bestand. Daarna even wachten en een nieuwe cheque. Ik heb de variabele naar het bestand geschreven omdat de taak alleen werd uitgevoerd toen het systeem deze selecteerde voor uitvoering toen de taak in het probleemgebied werd gewijzigd. Wat er ook tijdens deze taak gebeurde, zou geen invloed hebben op andere, niet-gerelateerde geblokkeerde taken.

Er werd verwacht dat wanneer het systeem het punt bereikte waarop de problematische code werd uitgevoerd, de globale variabele opnieuw zou worden ingesteld bij het overgaan naar elke volgende uitdrukking. Dan zal er iets gebeuren waardoor de taak verandert, en aangezien de uitvoeringsfrequentie (10 Hz) lager is dan die van de monitoringtaak, kan de monitor de waarde van de globale variabele vastleggen en deze schrijven. In een normale situatie zou ik een herhalende reeks van een subset van opsommingen kunnen krijgen: de laatste waarden van de variabele op het moment van de taakwisseling. Bij het ophangen zou de globale variabele niet langer moeten veranderen, en de laatst geschreven waarde zal aangeven welke expressie niet is voltooid.

Ik heb de code uitgevoerd met tracking. Hij verstijfde. En de monitoring werkte als een uurwerk.

Het logbestand bevatte de verwachte reeks, die werd onderbroken door een waarde die aangaf dat er een mutex was aangeroepen Unlock, en de taak is niet voltooid - zoals het geval is met duizenden eerdere oproepen.

Apex-ingenieurs waren op dat moment koortsachtig bezig met het analyseren van hun code en vonden een plek in de mutex waar theoretisch een vergrendeling zou kunnen optreden. Maar de waarschijnlijkheid ervan was zeer laag, omdat alleen een bepaalde reeks gebeurtenissen die op een bepaald tijdstip plaatsvonden tot blokkering kon leiden. De wet van Murphy, jongens, het is de wet van Murphy.

Om het stuk code dat ik nodig had te beschermen, heb ik de mutex-functieaanroepen (gebouwd bovenop de mutex-functionaliteit van het besturingssysteem) vervangen door een klein native Ada mutex-pakket om de mutex-toegang tot dat stuk te regelen.

Ik heb het in de code ingevoegd en de test uitgevoerd. Zeven uur later werkte de code nog steeds.

Mijn code werd ingediend bij Rational, waar ze deze compileerden, demonteerden en controleerden of deze niet dezelfde aanpak gebruikte als bij de problematische mutex-functies.

Dit was de drukste codereview uit mijn carrière 🙂 Er waren ongeveer tien ingenieurs en managers bij mij in de kamer, nog eens tien mensen waren in een telefonische vergadering - en ze onderzochten allemaal ongeveer twintig regels code.

De code werd beoordeeld, nieuwe uitvoerbare bestanden werden samengesteld en ingediend voor formele regressietests. Een paar weken later was de afteltest succesvol en vertrok de raket.

Oké, dat is allemaal goed en wel, maar wat is de zin van het verhaal?

Het was een absoluut walgelijk probleem. Honderdduizenden regels code, parallelle uitvoering, meer dan een dozijn op elkaar inwerkende processen, slechte architectuur en slechte implementatie, interfaces voor embedded systemen en miljoenen uitgegeven dollars. Geen druk, toch.

Ik was niet de enige die aan dit probleem werkte, ook al stond ik in de schijnwerpers tijdens het porten. Maar ook al deed ik het, dat betekent niet dat ik alle honderdduizenden regels code begreep, of ze zelfs maar doorbladerde. De code en logboeken werden geanalyseerd door ingenieurs uit het hele land, maar toen ze mij hun hypothesen vertelden over de oorzaken van de storing, kostte het me slechts een halve minuut om ze te weerleggen. En als mij werd gevraagd theorieën te analyseren, gaf ik dat door aan iemand anders, omdat het voor mij duidelijk was dat deze ingenieurs de verkeerde kant op gingen. Klinkt aanmatigend? Ja, dat is waar, maar ik heb de hypothesen en verzoeken om een ​​andere reden afgewezen.

Ik begreep de aard van het probleem. Ik wist niet precies waar het gebeurde en waarom, maar ik wist wel wat er gebeurde.

Door de jaren heen heb ik veel kennis en ervaring opgebouwd. Ik was een van de pioniers van het gebruik van Ada en begreep de voor- en nadelen ervan. Ik weet hoe de Ada-runtimebibliotheken taken afhandelen en omgaan met parallelle uitvoering. En ik begrijp programmeren op laag niveau op het niveau van geheugen, registers en assembler. Met andere woorden, ik heb diepgaande kennis in mijn vakgebied. En ik gebruikte ze om de oorzaak van het probleem te vinden. Ik heb niet alleen om de bug heen gewerkt, ik heb ook begrepen hoe ik deze kon vinden in een zeer gevoelige runtime-omgeving.

Dergelijke verhalen over de strijd met code zijn niet erg interessant voor degenen die niet bekend zijn met de kenmerken en omstandigheden van een dergelijke strijd. Maar deze verhalen helpen ons te begrijpen wat er nodig is om echt moeilijke problemen op te lossen.

Om echt moeilijke problemen op te lossen, moet je meer zijn dan alleen een programmeur. Je moet het ‘lot’ van de code begrijpen, hoe deze interageert met zijn omgeving en hoe de omgeving zelf werkt.

En dan heb je je eigen verpest vakantieweek.

Worden voortgezet.

Bron: www.habr.com

Voeg een reactie