Folklore des programmeurs et des ingénieurs (partie 1)





Il s'agit d'un recueil d'histoires sur Internet sur la façon dont les bogues se manifestent parfois d'incroyables. Peut-être avez-vous aussi une histoire à raconter.



Allergie automobile à la glace à la vanille



Une histoire pour les ingénieurs qui comprennent que l'évidence n'est pas toujours la solution et que, aussi invraisemblables soient-elles, ce sont des faits. La division Pontiac de General Motors Corporation a reçu une plainte:



, , , . : . , , , , . Pontiac, . , , , . , . , , : « Pontiac, - , , , ?».


Comme vous pouvez l'imaginer, le président de la division était sceptique quant à la lettre. Cependant, juste au cas où, j'ai envoyé un ingénieur pour vérifier. Il a été surpris d'avoir rencontré un homme riche et instruit vivant dans une belle région. Ils ont convenu de se rencontrer juste après le dîner pour aller ensemble au magasin de crème glacée. C'était de la vanille cette nuit-là, et quand ils sont remontés dans la voiture, ça n'a pas commencé.



L'ingénieur est venu trois autres soirs. La première fois que la glace était au chocolat. La voiture a démarré. La deuxième fois, il y avait de la glace à la fraise. La voiture a démarré. Le troisième soir, il a demandé de la vanille. La voiture n'a pas démarré.



Après avoir raisonné sagement, l'ingénieur a refusé de croire à l'allergie de la voiture à la glace à la vanille. Par conséquent, j'ai convenu avec le propriétaire de la voiture qu'il continuera ses visites jusqu'à ce qu'il trouve une solution au problème. Et en cours de route, il a commencé à prendre des notes: il a noté toutes les informations, l'heure de la journée, le type d'essence, l'heure d'arrivée et de retour du magasin, etc.



Bientôt, l'ingénieur s'est rendu compte que le propriétaire de la voiture passait moins de temps à acheter de la glace à la vanille. La raison était la disposition du produit dans le magasin. La crème glacée à la vanille était la plus populaire et était conservée dans un congélateur séparé à l'avant du magasin pour la rendre plus facile à trouver. Et toutes les autres variétés se trouvaient à l'arrière du magasin, et il a fallu beaucoup plus de temps pour trouver la bonne variété et payer.



Maintenant, la question était pour l'ingénieur: pourquoi la voiture n'a-t-elle pas démarré, si moins de temps s'est écoulé depuis le moment où le moteur a été coupé? Puisque le problème était le temps et non la glace à la vanille, l'ingénieur a rapidement trouvé la réponse: c'était une serrure à gaz. Cela se produisait tous les soirs, mais lorsque le propriétaire de la voiture passait plus de temps à chercher de la glace, le moteur avait le temps de se refroidir suffisamment et de démarrer tranquillement. Et quand l'homme a acheté de la glace à la vanille, le moteur était encore trop chaud et le bouchon d'essence n'a pas eu le temps de se dissoudre.



Morale: Même des problèmes complètement insensés peuvent parfois être réels.



Crash Bandicoot



C'est douloureux de vivre cela. En tant que programmeur, vous vous habituez à blâmer votre code en premier, deuxième, troisième ... et quelque part au dix-millième endroit vous blâmez le compilateur. Et même plus bas dans la liste, vous blâmez déjà l'équipement.



Voici mon histoire sur un bug matériel.



Pour le jeu Crash Bandicoot, j'ai écrit un code pour charger et enregistrer sur une carte mémoire. Pour un développeur de jeux aussi honnête, c'était comme marcher dans un parc: je pensais que le travail prendrait plusieurs jours. Cependant, en conséquence, j'ai débogué le code pendant six semaines. J'ai résolu d'autres problèmes en cours de route, mais tous les quelques jours, je suis revenu à ce code pendant plusieurs heures. C'était une agonie.



Le symptôme ressemblait à ceci: lorsque vous enregistrez la partie en cours du jeu et accédez à la carte mémoire, presque toujours tout se passe bien ... Mais parfois, l'opération de lecture ou d'écriture est terminée par timeout sans raison évidente. Les enregistrements courts endommagent souvent la carte mémoire. Lorsqu'un joueur essaie de sauvegarder, non seulement il échoue à sauvegarder, mais détruit également la carte. Crêpe.



Au bout d'un moment, notre productrice chez Sony, Connie Bus, a commencé à paniquer. Nous n'avons pas pu expédier le jeu avec ce bogue, et après six semaines, je n'ai pas compris quelle était la cause de ce problème. Grâce à Connie, nous avons contacté d'autres développeurs PS1: quelqu'un a-t-il rencontré un problème similaire? Non. Personne n'a eu de problèmes avec la carte mémoire.



Lorsque vous n’avez pas d’idées de débogage, la seule approche est quasiment la «division et la conquête»: vous supprimez de plus en plus de code du programme erroné jusqu’à ce qu’il y ait un fragment relativement petit, ce qui pose toujours un problème. Autrement dit, vous coupez du programme morceau par morceau, jusqu'à ce que la partie qui contient le bogue reste.



Mais le fait est qu'il est très difficile de découper des morceaux d'un jeu vidéo. Comment l'exécuter si vous avez supprimé le code d'émulation de gravité? Ou dessiner des personnages?



Par conséquent, vous devez remplacer des modules entiers par des stubs qui prétendent faire quelque chose d'utile, mais qui font en fait quelque chose de très simple qui ne peut pas contenir d'erreurs. Nous devons écrire de telles béquilles pour que le jeu fonctionne. C'est un processus lent et douloureux.



Bref, je l'ai fait. J'ai supprimé de plus en plus de morceaux de code jusqu'à ce qu'il y ait un code initial qui configure le système pour démarrer le jeu, initialise l'équipement pour le rendu, etc. Bien sûr, à ce stade, je ne pouvais pas créer le menu de sauvegarde et de chargement, car je devrais créer un stub pour tout le code graphique. Mais je pourrais prétendre être un utilisateur qui utilise l'écran (invisible) de sauvegarde et de chargement et demande à enregistrer puis à écrire sur la carte mémoire.



En conséquence, je me suis retrouvé avec un petit morceau de code qui avait toujours le problème susmentionné - mais jusqu'à présent, cela se produisait au hasard! La plupart du temps, tout fonctionnait bien, mais il y avait parfois des plantages. J'ai supprimé presque tout le code du jeu, mais le bogue persistait. C'était déroutant: le code restant n'a vraiment rien fait.



À un moment donné, probablement à trois heures du matin, une pensée m'est venue. Les opérations de lecture et d'écriture (E / S) supposent une synchronisation exacte. Lorsque vous travaillez avec un disque dur, une carte mémoire ou un module Bluetooth, le code de bas niveau responsable de la lecture et de l'écriture le fait conformément aux impulsions d'horloge.



À l'aide d'une horloge, un appareil qui n'est pas directement connecté au processeur est synchronisé avec le code exécutable dans le processeur. L'horloge détermine la vitesse de transmission - la vitesse de transmission. En cas de confusion avec les horaires, le matériel ou le logiciel, ou les deux, sont également confondus. Et c'est très mauvais, car les données peuvent être corrompues.



Et si quelque chose dans notre code confond les horaires? J'ai vérifié tout ce qui s'y rapporte dans le code du programme de test, et j'ai remarqué que nous réglions la minuterie programmable du PS1 sur une fréquence de 1 kHz (1000 cycles par seconde). C'est beaucoup, par défaut, lorsque le décodeur est démarré, il fonctionne à 100 Hz. Et la plupart des jeux utilisent cette fréquence.



Andy, le développeur du jeu, a réglé la minuterie sur 1 kHz afin que les mouvements soient calculés avec plus de précision. Andy est sujet à l'excès, et si nous imitons la gravité, nous le faisons aussi précisément que possible!



Mais que se passerait-il si l'accélération de la minuterie affectait d'une manière ou d'une autre la synchronisation globale du programme, et donc l'horloge qui ajuste le débit en bauds de la carte mémoire?



J'ai commenté le code de la minuterie. L'erreur ne s'est plus jamais produite. Mais cela ne signifie pas que nous l'avons corrigé, car le crash s'est produit au hasard. Et si j'avais de la chance?



Quelques jours plus tard, j'ai de nouveau expérimenté le programme de test. Le bogue ne s'est pas répété. Je suis retourné à la base de code du jeu complète et j'ai changé le code de sauvegarde et de chargement afin que le minuteur programmable soit réinitialisé à sa valeur d'origine (100 Hz) avant d'accéder à la carte mémoire, puis de nouveau à 1 kHz. Il n'y a plus eu de crash.



Mais pourquoi est-ce arrivé?



Je suis retourné au programme de test. J'ai essayé de trouver une certaine régularité dans l'apparition d'une erreur avec une minuterie de 1 kHz. Finalement, j'ai remarqué que l'erreur se produit lorsque quelqu'un joue avec le contrôleur PS1. Comme je le ferais rarement moi-même, pourquoi aurais-je besoin d'un contrôleur lors du test de sauvegarde et de chargement du code? - alors je n'ai pas remarqué cette dépendance. Mais un jour, l'un de nos artistes m'attendait pour terminer les tests - je jurais probablement à ce moment-là - et tordit nerveusement le contrôleur dans ses mains. Une erreur est survenue. "Attends quoi ?! Eh bien, recommencez! "



Quand j'ai réalisé que ces deux événements sont interconnectés, j'ai pu facilement reproduire l'erreur: j'ai commencé à écrire sur la carte mémoire, déplacé le contrôleur, endommagé la carte mémoire. Pour moi, cela ressemblait à un bug matériel.



Je suis allé voir Connie et j'ai raconté ma découverte. Elle a transmis l'information à l'un des ingénieurs qui ont conçu la PS1. "Impossible," répondit-il, "ça ne peut pas être un problème matériel." J'ai demandé à Connie de nous parler.



L'ingénieur m'a appelé et nous nous sommes disputés avec lui dans son anglais cassé et mon japonais (extrêmement) cassé. Enfin, j'ai dit: "Laissez-moi simplement envoyer mon programme de test de 30 lignes où le mouvement du contrôleur provoque un bogue." Il a accepté. Il a dit que c'était une perte de temps et qu'il était terriblement occupé à travailler sur un nouveau projet, mais il abandonnerait parce que nous sommes un développeur très important pour Sony. J'ai nettoyé mon programme de test et je le lui ai envoyé.



Le lendemain soir (nous étions à Los Angeles et il était à Tokyo), il m'a appelé et s'est excusé avec embarras. C'était un problème matériel.



Je ne sais pas exactement quel était le bogue, mais d'après ce que j'ai entendu au siège de Sony, régler la minuterie à une valeur suffisamment élevée interférerait avec les composants de la carte mère près du cristal de la minuterie. L'un de ceux-ci était le contrôleur de vitesse de transmission de la carte mémoire, qui définissait également la vitesse de transmission des contrôleurs. Je ne suis pas ingénieur, alors j'ai peut-être confondu quelque chose.



Mais le fait est qu'il y a eu des interférences entre les composants de la carte mère. Et lors de la transmission simultanée de données via le port du contrôleur et le port de la carte mémoire avec la minuterie fonctionnant à une fréquence de 1 kHz, les bits ont disparu, les données ont été perdues et la carte a été endommagée.



Mauvaises vaches



Dans les années 1980, mon mentor Sergei a écrit un logiciel pour le CM-1800, un clone soviétique du PDP-11. Ce micro-ordinateur vient d'être installé dans une gare près de Sverdlovsk, une importante plaque tournante des transports en URSS. Le nouveau système a été conçu pour l'acheminement des wagons et des flux de marchandises. Mais il s'est avéré être un bogue ennuyeux qui a conduit à des plantages aléatoires. Les chutes se produisaient toujours lorsque quelqu'un rentrait chez lui le soir. Mais malgré une enquête minutieuse le lendemain, l'ordinateur a fonctionné correctement avec tous les tests manuels et automatisés. Cela indique généralement une condition de concurrence ou un autre bogue de concurrence qui se manifeste sous certaines conditions. Fatigué des appels de fin de soirée, Sergei a décidé d'aller au fond des choses, et tout d'abord, de comprendre quelles conditions à la gare de triage ont conduit à une panne de l'ordinateur.



Premièrement, il a recueilli des statistiques sur toutes les chutes inexpliquées et a construit un graphique basé sur les dates et les heures. Le schéma était évident. Après avoir observé quelques jours de plus, Sergey s'est rendu compte qu'il pouvait facilement prédire l'heure des futures pannes du système.



Il a vite appris que les perturbations ne se produisaient que lorsque la station triait des wagons de bétail du nord de l'Ukraine et de l'ouest de la Russie vers un abattoir voisin. C'était étrange en soi, car l'abattoir était approvisionné par des fermes beaucoup plus proches du Kazakhstan.



La centrale nucléaire de Tchernobyl a explosé en 1986 et les retombées radioactives ont rendu la zone environnante inhabitable. De vastes zones du nord de l'Ukraine, de la Biélorussie et de l'ouest de la Russie ont été contaminées. Suspectant un niveau élevé de rayonnement dans les voitures à l'arrivée, Sergei a développé une méthode pour tester cette théorie. Il était interdit à la population d'avoir des dosimètres, alors Sergei a déposé plusieurs militaires à la gare. Après plusieurs verres de vodka, il a réussi à convaincre le soldat de mesurer le niveau de rayonnement dans l'une des voitures suspectes. Il s'est avéré que le niveau est plusieurs fois supérieur aux valeurs habituelles.



Non seulement le bétail émettait un fort rayonnement, mais son niveau était si élevé qu'il a entraîné la perte accidentelle de bits dans la mémoire du CM-1800, qui se trouvait dans le bâtiment à côté de la station.



Il y avait une pénurie de nourriture en URSS et les autorités ont décidé de mélanger de la viande «Tchernobyl» avec de la viande d'autres régions du pays. Cela a permis de réduire le niveau global de radioactivité sans perdre de précieuses ressources. En apprenant cela, Sergei a immédiatement rempli les documents d'émigration. Et les chutes de l'ordinateur se sont arrêtées d'elles-mêmes lorsque le niveau de rayonnement a diminué avec le temps.



À travers les tuyaux



Movietech Solutions a créé un logiciel pour les cinémas pour la billetterie, la billetterie et la gestion générale. La version DOS de l'application phare a été très populaire auprès des petites et moyennes chaînes de théâtre en Amérique du Nord. Il n’est donc pas surprenant que lorsque la version de Windows 95 a été annoncée, intégrée aux derniers écrans tactiles et bornes libre-service, et équipée de toutes sortes d’outils de création de rapports, elle est également rapidement devenue populaire. La plupart du temps, la mise à jour s'est bien déroulée. Les professionnels de l'informatique sur le terrain ont installé du nouveau matériel, migré les données et poursuivi leurs activités. Sauf quand ça n'a pas continué. Lorsque cela s'est produit, la société a envoyé James le nettoyeur.



Bien que ce surnom fasse allusion au type néfaste, le nettoyeur n'est qu'une combinaison d'instructeur, d'installateur et de touche-à-tout. James pourrait passer quelques jours chez le client à assembler tous les composants, puis pendant quelques jours supplémentaires, il a enseigné au personnel comment utiliser le nouveau système, résoudre tous les problèmes matériels qui surviennent et aider réellement le logiciel à traverser sa période de formation.



Par conséquent, il n'est pas étonnant qu'en cette période mouvementée, James soit venu au bureau le matin, et n'ait pas eu le temps de rejoindre son bureau, lorsqu'il a été accueilli par le patron, rempli de caféine au-dessus de la normale.



«J'ai bien peur que vous deviez vous rendre à Annapolis en Nouvelle-Écosse le plus tôt possible. Tout leur système est tombé en panne et après une nuit de travail avec leurs ingénieurs, nous ne pouvons pas comprendre ce qui s'est passé. Il semble que le serveur a une panne de réseau. Mais seulement après que le système a fonctionné pendant quelques minutes.



- Ils ne sont pas revenus à l'ancien système? - James a répondu assez sérieusement, même si dans son esprit ses yeux se sont écarquillés de surprise.



- Exactement: leur informaticien "a changé de priorités" et il a décidé de repartir avec leur ancien serveur. James, ils ont installé le système sur six sites et viennent de payer pour un support premium, et leur entreprise fait maintenant les années 1950.



James se redressa légèrement.



- Ceci est une autre affaire. D'accord, commençons.



Lorsqu'il est arrivé à Annapolis, la première chose qu'il a faite a été de trouver le premier cinéma du client qui avait un problème. Sur la carte prise à l'aéroport, tout avait l'air correct, mais les environs de l'adresse souhaitée paraissaient suspects. Pas un ghetto, mais qui rappelle le film noir. Alors que James se garait sur le trottoir au centre, une prostituée s'approcha de lui. Compte tenu de la taille d'Annapolis, c'était probablement le seul de toute la ville. Son apparence a immédiatement rappelé le célèbre personnage qui offrait du sexe contre de l'argent sur grand écran. Non, pas à propos de Julia Roberts, mais à propos de Jon Voight [un soupçon du film "Midnight Cowboy" - env. par. ].



Après avoir renvoyé la prostituée à la maison, James est allé au cinéma. L'environnement est devenu meilleur, mais l'impression est toujours médiocre. Non pas que James soit trop inquiet. Il était déjà allé dans des endroits sordides. Et c'était le Canada, où même les voleurs sont assez polis pour vous remercier après avoir pris votre portefeuille.



L'entrée latérale du cinéma se trouvait dans une ruelle humide. James est allé à la porte et a frappé. Bientôt, elle craqua et s'ouvrit un peu.



- Êtes-vous un nettoyeur? Une voix rauque venait de l'intérieur.



«Oui, c'est moi… je suis venu tout arranger.



James entra dans le hall du cinéma. Probablement sans autre choix, le personnel a commencé à délivrer des billets papier aux visiteurs. Cela a rendu la communication de l'information financière difficile, sans parler de détails plus intéressants. Mais le personnel accueillit James avec soulagement et l'emmena immédiatement dans la salle des serveurs.



À première vue, tout était en ordre. James s'est connecté au serveur et a vérifié les endroits suspects habituels. Aucun problème. Cependant, par mesure de précaution, James a arrêté le serveur, remplacé la carte réseau et annulé le système. Elle a immédiatement commencé à travailler pleinement. Le personnel a recommencé à vendre des billets.



James a appelé Mark et a signalé la situation. Il n'est pas difficile de supposer que James voudra peut-être s'attarder ici et voir si quelque chose d'inattendu se produit. Il descendit les escaliers et commença à interroger le personnel sur ce qui s'était passé. De toute évidence, le système a cessé de fonctionner. Ils l'ont éteint et rallumé, cela a fonctionné. Mais après 10 minutes, le système est tombé.



Juste à ce moment, quelque chose de similaire s'est produit. Tout à coup, le système de billetterie a commencé à donner des erreurs. Le personnel soupira et attrapa les billets papier, et James se précipita vers la salle des serveurs. Tout avait l'air bien avec le serveur.



Puis l'un des employés est entré.



- Le système fonctionne à nouveau.



James était perplexe car il n'avait rien fait. Plus précisément, rien qui ferait fonctionner le système. Il s'est déconnecté, a pris le téléphone et a appelé l'équipe d'assistance de son entreprise. Bientôt, le même employé entra dans la salle des serveurs.



- Le système ment.



James jeta un coup d'œil au serveur. Un motif intéressant et familier de formes multicolores dansait sur l'écran - des tuyaux de torsion et d'entrelacement chaotiques. Nous avons tous vu cet écran de veille une fois. C'était magnifiquement rendu et littéralement hypnotisé.





James a appuyé sur le bouton et le motif a disparu. Il s'est dépêché à la billetterie et en chemin a rencontré l'employé qui lui revenait.



- Le système fonctionne à nouveau.



Si vous pouvez faire mentalement une paume faciale, c'est exactement ce que James a fait. Économiseur d'écran. Il utilise OpenGL. Et donc, pendant le fonctionnement, il consomme toutes les ressources du processeur du serveur. En conséquence, chaque demande adressée au serveur est expirée.



James retourna dans la salle des serveurs, se connecta et remplaça le magnifique économiseur d'écran des tuyaux par un écran vide. Autrement dit, au lieu d'un économiseur d'écran qui consomme 100% des ressources du processeur, j'en ai installé un autre qui ne consomme pas de ressources. Ensuite, j'ai attendu 10 minutes pour vérifier ma supposition.



Lorsque James est arrivé au cinéma suivant, il s'est demandé comment expliquer à son superviseur qu'il venait de parcourir 800 km pour désactiver l'économiseur d'écran.



Crash à une phase de lune spécifique



Histoire vraie. Une fois, il y avait un bug logiciel qui dépendait de la phase de la lune. Il y avait un petit sous-programme qui était couramment utilisé dans divers programmes du MIT pour calculer l'approximation de la phase réelle de la lune. GLS a construit ce sous-programme dans un programme LISP qui produit une chaîne horodatée de près de 80 caractères lors de l'écriture d'un fichier. Il était très rare que la première ligne d'un message soit trop longue et continue jusqu'à la ligne suivante. Et quand le programme a ensuite lu ce fichier, il a maudit. La longueur de la première ligne dépendait de la date et de l'heure exactes ainsi que de la longueur de la spécification de phase au moment où l'horodatage était imprimé. Autrement dit, le bug dépendait littéralement de la phase de la lune!



Première édition papier du fichier Jargon(Steele-1983) contenait un échantillon d'une telle chaîne menant au bogue décrit, mais le compositeur l'a "corrigé". Il a depuis été décrit comme un "bug de phase de lune".



Cependant, soyez prudent avec les hypothèses. Il y a plusieurs années, des ingénieurs du CERN (Centre Européen de Recherche Nucléaire) ont rencontré des erreurs dans des expériences menées au Grand Collisionneur Electron-Positron. Étant donné que les ordinateurs traitent activement l'énorme quantité de données générées par cet appareil avant de montrer le résultat aux scientifiques, beaucoup ont supposé que le logiciel était en quelque sorte sensible à la phase de la lune. Plusieurs ingénieurs désespérés sont allés au fond de la vérité. L'erreur est survenue en raison d'un léger changement de la géométrie de l'anneau de 27 km de long dû à la déformation de la Terre lors du passage de la Lune! Cette histoire est entrée dans le folklore des physiciens comme "la revanche de Newton sur la physique des particules" et un exemple du lien entre les lois physiques les plus simples et les plus anciennes avec les concepts scientifiques les plus avancés.



La chasse d'eau arrête le train



Le meilleur bug matériel dont j'ai entendu parler concernait un train à grande vitesse en France. Le bug a conduit à un freinage d'urgence du train, mais uniquement s'il y avait des passagers à bord. Dans chaque cas, le train a été mis hors service, vérifié, mais rien n'a été trouvé. Puis il a été renvoyé sur la ligne, et il s'est immédiatement arrêté d'urgence.



Lors de l'un des contrôles, un ingénieur voyageant dans le train s'est rendu aux toilettes. Bientôt, il s'est emporté après lui-même, BOOM! Arrêt d'urgence.



L'ingénieur a contacté le conducteur et lui a demandé:



- Qu'as-tu fait juste avant de freiner?



- Eh bien, j'ai ralenti dans la descente ...



C'était étrange, car pendant la course normale le train ralentit sur les pentes des dizaines de fois. Le train a continué, et à la descente suivante, le chauffeur a averti:



- Je vais ralentir.



Rien ne s'est passé.



- Qu'as-tu fait du dernier freinage? - a demandé au chauffeur.



- Et bien… j'étais aux toilettes…



- Eh bien, alors va aux toilettes et fais ce que tu as fait quand on redescend!



L'ingénieur est allé aux toilettes, et lorsque le conducteur a averti: «Je freine», il a chassé l'eau. Bien sûr, le train s'est arrêté immédiatement.



Maintenant, ils pouvaient reproduire le problème et devaient en trouver la cause.



Deux minutes plus tard, ils ont remarqué que le câble de commande à distance du frein moteur (le train avait un moteur aux deux extrémités) était déconnecté de la paroi de l'armoire électrique et reposait sur le relais qui contrôlait le solénoïde de la prise des toilettes ... Lorsque le relais s'est activé, il a interféré dans le câble de frein et le système. la protection contre les collisions comprenait simplement le freinage d'urgence.



La passerelle qui détestait FORTRAN



Il y a quelques mois, nous avons remarqué que les connexions réseau sur le continent [c'était à Hawaï] devenaient très, très lentes. Cela pourrait durer 10 à 15 minutes, puis réapparaître soudainement. Après un certain temps, un de mes collègues me plaignit que les connexions réseau sur le continent ont été ne fonctionnent pas du tout. Il avait du code FORTRAN qui devait être copié sur une machine sur le continent, mais cela ne fonctionnait pas car «le réseau n’a pas duré assez longtemps pour terminer le téléchargement FTP».



Oui, il s'est avéré que des pannes de réseau se sont produites lorsqu'un collègue a tenté de transférer le fichier source FORTRAN par FTP sur une machine sur le continent. Nous avons essayé d'archiver le fichier: puis il a copié tranquillement (mais il n'y avait pas de décompresseur sur la machine cible, donc le problème n'a pas été résolu). Finalement, nous avons «divisé» le code FORTRAN en très petits morceaux et les avons expédiés un à la fois. La plupart des fragments ont été copiés sans problème, mais certains d'entre eux n'ont pas fonctionné, ou ils l'ont fait après de nombreuses tentatives.



Après avoir examiné les fragments de problème, nous avons constaté qu'ils ont quelque chose en commun: ils contiennent tous des blocs de commentaires qui commencent et se terminent par des lignes constituées de lettres C majuscules (comme un collègue a préféré commenter FORTRAN). Nous avons envoyé des courriels vers le continent aux spécialistes du réseau et avons demandé de l'aide. Bien sûr, ils voulaient voir des échantillons de nos fichiers qui ne pouvaient pas être envoyés via FTP ... mais nos lettres ne les ont pas atteints. Enfin, nous avons proposé une description simple de l' aspect des fichiers non transférés. Cela a fonctionné :) [Est-ce que j'ose ajouter ici un exemple d'un des commentaires problématiques sur FORTRAN? Ça ne vaut probablement pas la peine!]



En fin de compte, nous avons réussi à le comprendre. Une nouvelle passerelle a été récemment installée entre notre partie du campus et le réseau continental. Il avait d'énormes difficultés à transmettre des paquets contenant des C majuscules en double! Seuls quelques-uns de ces paquets pourraient prendre toutes les ressources de la passerelle et empêcher la plupart des autres paquets de percer. Nous nous sommes plaints au fabricant de la passerelle ... et ils nous ont dit: «Oh, oui, vous avez rencontré un bogue C en double! Nous savons déjà pour lui. " Au final, nous avons résolu le problème en achetant une nouvelle passerelle chez un autre constructeur (pour la défense du premier, je dirai que l'impossibilité de transférer des programmes vers FORTRAN pour quelqu'un peut être un avantage!).



Les temps difficiles



Il y a plusieurs années, alors que je travaillais sur un système Perl ETL conçu pour réduire le coût des essais cliniques de phase 3, je devais traiter environ 40 000 dates. Deux d'entre eux n'ont pas réussi le test. Cela ne m'a pas trop dérangé, car ces dates étaient tirées des données fournies par le client, ce qui était souvent, disons, surprenant. Mais quand j'ai vérifié les données initiales, il s'est avéré que ces dates étaient le 1er janvier 2011 et le 1er janvier 2007. Je pensais que le bogue était dans le programme que je viens d'écrire, mais il s'est avéré qu'il avait déjà 30 ans. Cela peut sembler mystérieux à ceux qui ne connaissent pas l'écosystème logiciel. En raison d'une décision de longue date prise par une autre entreprise de gagner de l'argent, mon client m'a payé pour corriger un bug qu'une entreprise a accidentellement introduit et une autre intentionnellement. Pour que vous compreniez de quoi il s'agit,Je dois vous parler de la société qui a ajouté la fonctionnalité qui est devenue un bogue en conséquence, ainsi que de quelques autres événements curieux qui ont contribué au mystérieux bug que j'ai corrigé.



Dans le bon vieux temps, les ordinateurs Apple réinitialisaient parfois spontanément leur date au 1er janvier 1904. La raison était simple: une «horloge système» alimentée par batterie était utilisée pour garder une trace de la date et de l'heure. Que s'est-il passé lorsque la batterie était épuisée? Les ordinateurs ont commencé à suivre la date par le nombre de secondes depuis le début de l'ère. L'époque signifiait la date d'origine de référence, et pour le Macintosh c'était le 1er janvier 1904. Et après que la batterie est morte, la date actuelle a été réinitialisée à celle spécifiée. Mais pourquoi est-ce arrivé?



Auparavant, Apple utilisait 32 bits pour stocker le nombre de secondes à partir de la date d'origine. Un bit peut stocker l'une des deux valeurs - 1 ou 0. Deux bits peuvent stocker l'une des quatre valeurs: 00, 01, 10, 11. Trois bits - une valeur sur huit: 000, 001, 010, 011, 100, 101, 110, 111, etc. Et 32 pourrait stocker l'une des 2 32 valeurs, soit 4 294 967 296 secondes. Pour les dates Apple, il avait environ 136 ans, de sorte que les anciens Mac ne peuvent pas gérer les dates après 2040. Et si la batterie du système est épuisée, la date est réinitialisée à 0 seconde à partir du début de l'époque et vous devez régler manuellement la date chaque fois que vous allumez l'ordinateur (ou jusqu'à ce que vous achetiez une nouvelle batterie).



Cependant, la décision d'Apple de stocker les dates en secondes à partir du début de l'époque signifiait que nous ne pouvions pas gérer les dates avant le début de l'époque, ce qui avait des implications profondes, comme nous le verrons. Apple a introduit une fonctionnalité, pas un bogue. Entre autres choses, cela signifiait que le système d'exploitation Macintosh était immunisé contre le «bogue du millénaire» (ce qui ne peut pas être dit à propos de nombreuses applications Mac qui avaient leurs propres systèmes de date pour contourner les restrictions).



Passez. Nous avons utilisé Lotus 1-2-3, l '«application tueur» développée par IBM qui a aidé à lancer la révolution PC, bien que les ordinateurs Apple aient VisiCalc, qui a fait le succès des ordinateurs personnels. Pour être honnête, si le 1-2-3 n'était pas apparu, les PC n'auraient guère décollé, et l'histoire des ordinateurs personnels aurait pu évoluer très différemment. Lotus 1-2-3 a traité à tort 1900 comme une année bissextile. Lorsque Microsoft a publié sa première feuille de calcul Multiplan, il avait une petite part de marché. Et lorsque nous avons lancé le projet Excel, nous avons décidé non seulement de copier le schéma de dénomination des lignes et des colonnes de Lotus 1-2-3, mais également d'assurer la compatibilité des bogues, en traitant délibérément 1900 comme une année bissextile. Ce problème persiste à ce jour. Autrement dit, dans 1-2-3 c'était un bogue, et dans Excel c'était une décision délibérée qui garantissaitque tous les utilisateurs 1-2-3 peuvent importer leurs feuilles de calcul dans Excel sans modifier les données, même s'ils se trompent.



Mais il y avait un autre problème. Microsoft a d'abord publié Excel pour Macintosh, qui ne reconnaissait les dates que le 1er janvier 1904. Et dans Excel, le début d'une ère était le 1er janvier 1900. Par conséquent, les développeurs ont fait un changement afin que leur programme reconnaisse le type d'époque et stocke les données à l'intérieur de lui-même conformément à l'époque souhaitée. Microsoft a même écrit un article explicatif à ce sujet. Et cette décision a conduit à mon bug.



Mon système ETL a reçu des feuilles de calcul Excel de clients créés sous Windows mais pouvant également être créés sur un Mac. Par conséquent, le début d'une époque dans le tableau pourrait être le 1er janvier 1900 ou le 1er janvier 1904. Comment le découvrir? Le format de fichier Excel affiche les informations nécessaires, mais l'analyseur que j'ai utilisé n'a pas montré (maintenant il le fait), et a supposé que vous connaissez l'époque pour une table particulière. Je pourrais probablement passer plus de temps à comprendre le binaire Excel et à soumettre le correctif à l'auteur de l'analyseur, mais j'avais beaucoup à faire pour le client, alors j'ai rapidement écrit une heuristique pour déterminer l'époque. C'était simple.



Dans Excel, la date du 5 juillet 1998 peut être représentée au format «07-05-98» (système américain inutile), «5 juillet 98», «5 juillet 1998», «5-juillet-98» ou dans certains un autre format inutile (ironiquement, l'un des formats que ma version d'Excel n'offrait pas était la norme ISO 8601). Cependant, dans le tableau, la date non formatée a été stockée sous la forme "35981" pour l'époque-1900 ou "34519" pour l'époque-1904 (les nombres représentent le nombre de jours depuis le début de l'époque). J'utilisais juste un analyseur simple pour extraire l'année de la date formatée, puis j'utilisais l'analyseur Excel pour extraire l'année de la date non formatée. Si les deux valeurs différaient de 4 ans, alors j'ai compris que j'utilisais le système avec l'ère-1904.



Pourquoi n'ai-je pas simplement utilisé des dates formatées? Parce que le 5 juillet 1998 peut être formaté comme "juillet 98" avec le jour du mois manquant. Nous avons reçu des tableaux de tant d'entreprises qui les ont créés de manière si différente que nous (dans ce cas, moi) avons dû gérer les dates. De plus, si Excel fait les choses correctement, nous devrions le faire aussi!



Ensuite, je suis tombé sur 39082. Permettez-moi de vous rappeler que Lotus 1-2-3 considérait 1900 comme une année bissextile, et cela a été fidèlement répété dans Excel. Et comme cela a ajouté un jour à 1900, de nombreuses fonctions de date pourraient être erronées pour ce jour-là. Autrement dit, 39082 aurait pu être le 1er janvier 2011 (sur Mac) ou le 31 décembre 2006 (sur Windows). Si mon "analyseur d'années" extrait 2011 de la valeur formatée, alors tout va bien. Mais comme l'analyseur Excel ne sait pas quelle époque utiliser, il est par défaut à l'époque-1900, retournant 2006. Mon application a vu qu'il y avait une différence de 5 ans, l'a considérée comme une erreur, enregistrée et a renvoyé une valeur non formatée.



Pour contourner cela, j'ai écrit ceci (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


Et puis les 40 000 dates ont été analysées correctement.



Au milieu des gros travaux d'impression



Au début des années 80, mon père travaillait à Storage Technology, une ancienne unité commerciale qui construisait des lecteurs de bande et des systèmes pneumatiques pour l'alimentation de bande à grande vitesse.



Ils ont repensé les disques afin qu'ils puissent avoir un disque central «A» connecté à sept disques «B», et le petit système d'exploitation dans la RAM qui contrôlait le disque «A» pouvait déléguer les opérations de lecture et d'écriture à tous les disques «B».



Chaque fois que le lecteur "A" était démarré, une disquette devait être insérée dans le lecteur périphérique connecté à "A" pour charger le système d'exploitation dans sa mémoire. C'était extrêmement primitif: la puissance de traitement était fournie par un microcontrôleur 8 bits.



Le public cible de ces équipements était les entreprises disposant de très grands magasins de données - banques, chaînes de vente au détail, etc. - qui devaient imprimer de nombreuses étiquettes d'adresse ou relevés bancaires.



Un client a eu un problème. Au milieu d'un travail d'impression, un lecteur "A" particulier peut cesser de fonctionner, provoquant la reprise de l'ensemble du travail. Pour remettre le disque en marche, le personnel a dû tout redémarrer. Et si cela se produisait au milieu d'une tâche de six heures, alors une énorme quantité de temps informatique coûteux était gaspillée et le calendrier de l'opération entière était perturbé.



Les technologies de stockage ont envoyé des techniciens. Malgré tous leurs efforts, ils n'ont pas pu reproduire le bogue dans des conditions de test: il semble que le crash se soit produit au milieu de gros travaux d'impression. Le problème n'était pas avec le matériel, ils ont remplacé tout ce qu'ils pouvaient: la RAM, le microcontrôleur, le lecteur de disquette, chaque partie imaginable d'un lecteur de bande - le problème persistait.



Ensuite, les techniciens ont appelé le siège et ont appelé l'expert.



L'examinateur a attrapé une chaise et une tasse de café, s'est assis dans la salle informatique - à l'époque, il y avait des salles dédiées aux ordinateurs - et a regardé le personnel faire la queue pour un gros travail d'impression. L'expert a attendu qu'un échec se produise - et c'est arrivé. Tout le monde a regardé l'expert - et il ne savait pas pourquoi cela s'était produit. Par conséquent, il a ordonné que la tâche soit à nouveau mise en file d'attente et tous les employés avec des techniciens sont retournés au travail.



L'expert se rassit sur sa chaise et attendit l'échec. Cela a pris environ six heures et l'échec s'est produit. L'expert n'avait encore aucune idée, sauf que tout se passait dans une salle remplie de monde. Il a ordonné de redémarrer la mission, s'est assis à nouveau et a attendu.



Au troisième problème, l'expert a remarqué quelque chose. L'échec s'est produit lorsque le personnel a changé les courroies d'un lecteur externe. De plus, l'accident s'est produit dès qu'un des employés a traversé une certaine tuile sur le sol.



Le plancher surélevé était fait de tuiles d'aluminium placées de 6 à 8 pouces de hauteur. De nombreux câbles informatiques passaient sous le plancher surélevé afin que quelqu'un ne marche pas accidentellement sur un câble important. Les carreaux ont été posés très étroitement afin qu'aucun débris ne puisse pénétrer sous le plancher surélevé.



L'expert s'est rendu compte que l'un des carreaux était déformé. Lorsqu'un employé marchait sur son coin, la tuile frottait ses bords contre les tuiles adjacentes. Ils ont également frotté les pièces en plastique qui reliaient les carreaux, ce qui a créé des micro-décharges statiques qui ont créé des interférences radio.



De nos jours, la RAM est bien mieux protégée contre les interférences radio. Mais à l'époque, ce n'était pas le cas. L'expert s'est rendu compte que ces interférences perturbaient la mémoire, et avec elle le fonctionnement du système d'exploitation. Il a appelé le service d'escorte, a commandé une nouvelle tuile, l'a installé lui-même et le problème a disparu.



C'est la marée!



L'histoire s'est déroulée dans une salle de serveurs, au quatrième ou cinquième étage d'un bureau à Portsmouth (je crois) dans la zone des quais.



Un jour, un serveur Unix avec la base de données principale s'est écrasé. Il a été redémarré, mais il a joyeusement continué à tomber encore et encore. Nous avons décidé d'appeler quelqu'un du service d'assistance.



Support mec ... Je pense que son nom était Mark, mais ce n'est pas grave ... Je ne pense pas que je le connais. Cela n'a pas d'importance, vraiment. Restons au Mark, d'accord? Excellent.



Ainsi, quelques heures plus tard, Mark est arrivé (de Leeds à Portsmouth, le chemin n'est pas proche, vous savez), a allumé le serveur et tout a fonctionné sans problème. Putain de support typique, le client est très contrarié à ce sujet. Mark parcourt les fichiers journaux et ne trouve rien de répréhensible. Puis Mark remonte dans le train (ou quel que soit le moyen de transport qu'il a pris, ça aurait pu être une vache boiteuse pour autant que je sache ... eh bien, ça n'a pas d'importance, d'accord?) Et retourne à Leeds, perdant la journée.



Le serveur plante à nouveau ce soir-là. L'histoire est la même ... le serveur ne monte pas. Mark essaie d'aider à distance, mais le client ne peut pas démarrer le serveur.



Un autre train, un bus, une meringue au citron ou une autre merde, et Mark est de retour à Portsmouth. Regardez, le serveur démarre sans aucun problème! Miracle. Mark vérifie pendant plusieurs heures que tout est en ordre avec le système d'exploitation ou le logiciel, et se rend à Leeds.



Vers le milieu de la journée, le serveur plante (allez-y doucement!). Cette fois, il semble judicieux de faire appel au support matériel pour remplacer le serveur. Mais non, après environ 10 heures, il tombe également.



La situation s'est répétée pendant plusieurs jours. Le serveur est en marche, plante après environ 10 heures et ne démarre pas pendant les 2 heures suivantes. Ils ont vérifié le refroidissement, les fuites de mémoire, ils ont tout vérifié, mais ils n'ont rien trouvé. Ensuite, les accidents se sont arrêtés.



La semaine s'est passée sans soucis ... tout le monde était heureux. Heureux jusqu'à ce que tout recommence. L'image est la même. 10 heures de travail, 2-3 heures d'arrêt ...



Et puis quelqu'un (je pense qu'ils m'ont dit que cette personne n'avait rien à voir avec l'informatique) a dit:



"C'est la marée!"



L'exclamation fut accueillie par des regards vides et, probablement, la main de quelqu'un vacilla sur le bouton pour appeler le garde.



"Il arrête de travailler avec la marée."



Cela semble être un concept complètement étranger pour le personnel de support informatique qui lit à peine le Tide Yearbook tout en prenant un café. Ils ont expliqué que cela n'avait rien à voir avec la marée car le serveur fonctionnait depuis une semaine sans accroc.



"La marée était basse la semaine dernière et haute cette semaine."



Un peu de terminologie pour ceux qui n'ont pas de licence pour exploiter un yacht. Les marées dépendent du cycle lunaire. Et pendant que la Terre tourne, toutes les 12,5 heures, l'attraction gravitationnelle du Soleil et de la Lune crée un raz-de-marée. Au début d'un cycle de 12,5 heures, il y a une marée haute, au milieu du cycle il y a une marée descendante, et à la fin d'une marée haute à nouveau. Mais à mesure que l'orbite de la lune change, la différence entre le flux et le reflux change également. Lorsque la Lune est entre le Soleil et la Terre ou sur le côté opposé de la Terre (pleine lune ou pas de lune), nous obtenons les marées Syzygy - les marées les plus hautes et les marées de reflux les plus basses. En demi-lune, nous obtenons des marées en quadrature - les marées les plus basses. La différence entre les deux extrêmes est considérablement réduite. Le cycle lunaire dure 28 jours: syzygie - quadrature - syzygie - quadrature.



Lorsque les forces de marée ont été expliquées aux techniciens, ils ont immédiatement pensé à appeler la police. Et c'est assez logique. Mais il s'est avéré que le mec avait raison. Deux semaines plus tôt, un destroyer avait accosté près du bureau. Chaque fois que la marée l'élevait à une certaine hauteur, le poste radar du navire se trouvait au niveau du plancher de la salle des serveurs. Et le radar (ou l'équipement de guerre électronique, ou un autre jouet de l'armée) a créé le chaos dans les ordinateurs.



Mission de vol pour une fusée



J'ai été chargé de porter un grand système de contrôle et de surveillance du lancement de missiles (environ 400 000 lignes) pour les nouvelles versions du système d'exploitation, du compilateur et du langage. Plus précisément, de Solaris 2.5.1 sur Solaris 7, et de Verdix Ada Development System (VADS) écrit en Ada 83 au système Rational Apex Ada écrit en Ada 95. VADS a été acheté par Rational et son produit est obsolète, bien que Rational a essayé d'implémenter des versions compatibles de packages spécifiques à VADS pour faciliter la transition vers le compilateur Apex.



Trois personnes m'ont aidé juste à obtenir un code compilé proprement. Cela a pris deux semaines. Et puis j'ai travaillé seul pour faire fonctionner le système. En bref, c'était la pire architecture et implémentation d'un système logiciel que j'aie jamais rencontrée, il a donc fallu encore deux mois pour terminer le portage. Ensuite, le système a été remis pour des tests, qui ont pris plusieurs mois de plus. J'ai immédiatement corrigé les bogues que j'avais trouvés lors des tests, mais leur nombre a rapidement diminué (le code source était un système de production, donc ses fonctionnalités fonctionnaient de manière assez fiable, il me suffisait de supprimer les bogues survenus lors de l'adaptation au nouveau compilateur). Au final, quand tout a fonctionné comme il se doit, j'ai été transféré vers un autre projet.



Et le vendredi avant Thanksgiving, le téléphone a sonné.



Environ trois semaines plus tard, un lancement de fusée devait être testé, et lors des tests en laboratoire du compte à rebours, la séquence de commandes a été bloquée. Dans la vraie vie, cela conduirait à l'interruption des tests, et si un blocage se produisait quelques secondes après le démarrage du moteur, alors plusieurs actions irréversibles se produiraient dans les systèmes auxiliaires, ce qui prendrait beaucoup de temps - et coûteux - pour préparer la fusée. Cela ne commencerait pas, mais beaucoup de gens seraient très contrariés par la perte de temps et de très, très gros argent. Ne laissez personne vous dire que le ministère de la Défense dépense de l'argent à l'improviste - je n'ai pas encore rencontré un seul gestionnaire de contrat qui n'a pas de budget en premier ou en second, suivi d'un calendrier.



Au cours des mois précédents, ce test de compte à rebours avait été exécuté des centaines de fois dans de nombreuses variantes, avec seulement quelques problèmes mineurs. La probabilité que cela se produise était donc très faible, mais ses conséquences étaient très importantes. Multipliez ces deux facteurs et vous comprendrez que la nouvelle prévoyait une semaine de vacances ruinée pour moi et des dizaines d'ingénieurs et de managers.



Et l'attention a été attirée sur moi en tant que personne qui portait le système.



Comme avec la plupart des systèmes critiques pour la sécurité, de nombreux paramètres étaient enregistrés ici, il était donc assez facile d'identifier les quelques lignes de code exécutées avant le crash du système. Et bien sûr, il n'y avait absolument rien d'extraordinaire à leur sujet, les mêmes expressions ont été exécutées avec succès des milliers de fois au cours de la même course.



Nous avons appelé les gens d'Apex vers Rational parce qu'ils avaient développé le compilateur et que certaines des routines qu'ils avaient développées étaient appelées dans le code suspect. Ils (et tout le monde) ont été impressionnés par la nécessité de découvrir la cause du problème de la signification nationale littérale.



Comme il n'y avait rien d'intéressant dans les logs, nous avons décidé d'essayer de reproduire le problème dans un laboratoire local. Ce n'était pas une tâche facile, car l'événement se produisait environ une fois toutes les 1000 exécutions. L'une des raisons supposées était que l'appel à une fonction mutex développée par le fournisseur (faisant partie du lot de migration VADS)Unlockn'a pas conduit au déverrouillage. Le thread appelant traitait les messages de pulsation, qui arrivaient nominalement toutes les secondes. Nous avons augmenté la fréquence à 10 Hz, soit 10 fois par seconde, et avons commencé à courir. Après environ une heure, le système était verrouillé. Dans le journal, nous avons vu que la séquence des messages enregistrés était la même que lors du test échoué. Nous avons fait quelques essais supplémentaires, le système s'est bloqué de manière stable 45 à 90 minutes après le départ, et à chaque fois le journal contenait la même trace. Même si nous exécutions techniquement un code différent maintenant - le débit des messages était différent - le comportement du système était répété, nous nous sommes donc assurés que ce scénario de charge conduisait au même problème.



Maintenant, il était nécessaire de déterminer exactement où dans la séquence d'expressions le blocage s'est produit.



Cette implémentation a utilisé le système de tâches Ada et a été incroyablement mal utilisée. Les tâches sont une construction de haut niveau exécutable simultanément dans Ada, un peu comme des threads d'exécution, juste intégrée au langage lui-même. Lorsque deux tâches doivent interagir, elles se «rencontrent», échangent les données nécessaires, puis arrêtent le rendez-vous et reviennent à leurs performances indépendantes. Cependant, le système a été mis en œuvre différemment. Une fois qu'une cible avait un rendez-vous, cette cible se retrouvait avec une autre, qui se rendrait ensuite avec une troisième, et ainsi de suite, jusqu'à ce qu'un certain traitement soit terminé. Après cela, tous ces rendez-vous ont pris fin et chaque tâche devait revenir à son exécution. Autrement dit, nous avions affaire au système d'appel de fonction le plus cher au monde,qui a interrompu tout le processus "multitâche" lors du traitement de certaines des données d'entrée. Et avant, cela ne posait pas de problèmes simplement parce que le débit était très faible.



J'ai décrit ce mécanisme de tâche parce que lorsqu'un rendez-vous était demandé ou prévu de se terminer, un «changement de tâche» pouvait se produire. Autrement dit, le processeur pourrait commencer à traiter une autre tâche prête à être exécutée. Il s'avère que lorsqu'une tâche est prête à se rendre avec une autre tâche, l'exécution d'une tâche complètement différente peut commencer, et finalement le contrôle revient au premier rendez-vous. Et d'autres événements peuvent se produire et conduire à un changement de tâche; l'un de ces événements est un appel de fonction système, comme l'impression ou l'exécution d'un mutex.



Pour comprendre quelle ligne de code causait le problème, je devais trouver un moyen d'enregistrer la progression de la séquence d'expressions sans déclencher un changement de tâche, ce qui pourrait empêcher le crash de se produire. Alors je n'ai pas pu en profiterPut_Line()pour ne pas effectuer d'opérations d'E / S. Vous pouvez définir une variable de compteur ou quelque chose comme ça, mais comment puis-je voir sa valeur si je ne peux pas l'afficher à l'écran?



De plus, lors de l'examen du journal, il s'est avéré que, malgré le gel du traitement des messages de pulsation, qui bloquait toutes les opérations d'E / S du processus et ne permettait pas d'effectuer d'autres traitements, d'autres tâches indépendantes continuaient d'être exécutées. Autrement dit, le travail n'a pas été entièrement bloqué, seulement la chaîne (critique) des tâches.



C'était le hook requis pour évaluer l'expression de blocage.



J'ai créé un package Ada contenant une tâche, un type énuméré et une variable globale de ce type. Littéraux énumérés ont été attachés à des expressions spécifiques des séquences problématiques (par exemple Incrementing_Buffer_Index, Locking_Mutex,Mutex_Unlocked), puis y insère des expressions d'affectation, qui attribuent l'énumération correspondante à une variable globale. Comme le code objet de tout cela gardait simplement une constante en mémoire, le changement de tâche à la suite de son exécution était extrêmement improbable. Tout d'abord, nous soupçonnons des expressions qui pourraient changer la tâche, puisque le blocage s'est produit pendant l'exécution, et ne reviennent pas lors du basculement de la tâche (pour plusieurs raisons).



La tâche de suivi s'est simplement exécutée en boucle et vérifiée périodiquement pour voir si la valeur de la variable globale avait changé. Chaque fois qu'elle était modifiée, la valeur était enregistrée dans un fichier. Puis une courte attente et un nouveau chèque. J'ai écrit la variable dans un fichier car la tâche n'était exécutée que lorsque le système la sélectionnait pour exécution lors du basculement de la tâche dans la zone à problème. Tout ce qui se passe dans cette tâche n'affectera pas les autres tâches verrouillées non liées.



Il était prévu que lorsque le système atteindra l'exécution du code problématique, la variable globale sera réinitialisée à chaque expression suivante. Puis quelque chose se produira, conduisant à un basculement de la tâche, et comme la fréquence de son exécution (10 Hz) est inférieure à celle de la tâche de surveillance, le moniteur pourrait fixer la valeur de la variable globale et l'écrire. Dans une situation normale, je pourrais obtenir une séquence répétée d'un sous-ensemble d'énumérations: les dernières valeurs de la variable au moment du changement de tâche. En cas de blocage, la variable globale ne devrait plus changer et la dernière valeur écrite indiquera quelle expression n'a pas terminé l'exécution.



Lancement du code de suivi. Il est gelé. Et la surveillance a fonctionné comme une horloge.



Le journal s'est terminé avec la séquence attendue, qui a été interrompue par une valeur indiquant que le mutex a été appelé Unlocket que la tâche était en attente - comme avec des milliers d'appels précédents.



À cette époque, les ingénieurs d'Apex analysaient frénétiquement leur code et trouvaient une place dans le mutex où, en théorie, un verrou pourrait se produire. Mais sa probabilité était très faible, car seule une certaine séquence d'événements se produisant à un certain moment pouvait conduire à un blocage. Les avocats de Murphy, c'est la loi de Murphy.



Pour protéger ce morceau de code, j'ai remplacé les appels aux fonctions mutex (construites au-dessus de la fonctionnalité mutex du système d'exploitation) par un petit package mutex Ada natif pour contrôler l'accès mutex à ce morceau.



Collez-le dans le code et exécutez le test. Sept heures plus tard, le code a continué à fonctionner.



Mon code a été remis à Rational, où il a été compilé, démonté et vérifié qu'il n'utilise pas la même approche que celle utilisée dans les fonctions mutex problématiques.



C'était la revue de code la plus encombrée de ma carrière :) Il y avait une dizaine d'ingénieurs et de managers dans la salle avec moi, une dizaine de personnes de plus connectées en conférence téléphonique - et ils ont tous examiné environ 20 lignes de code.



Le code a été revu, de nouveaux fichiers exécutables ont été construits et soumis à des tests de régression formels. Quelques semaines plus tard, les tests du compte à rebours ont réussi et la fusée a décollé.



D'accord, tout cela est beau et bon, mais à quoi sert cette histoire?



C'était un problème totalement dégoûtant. Des centaines de milliers de lignes de code, une exécution parallèle, plus d'une douzaine de processus en interaction, une architecture médiocre et une mise en œuvre médiocre, des interfaces pour les systèmes embarqués et des millions de dollars dépensés. Pas de pression, d'accord.



Je n'étais pas le seul à travailler sur cette question, même si j'étais sous les projecteurs pendant que je faisais le portage. Mais même si je l'ai fait, cela ne signifie pas que j'ai compris toutes les centaines de milliers de lignes de code, ou du moins les ai écrémées. Le code et les logs ont été analysés par des ingénieurs de tout le pays, mais lorsqu'ils m'ont fait part de leurs hypothèses sur les causes de l'échec, il m'a fallu une demi-minute pour les réfuter. Et quand on m'a demandé d'analyser des théories, je l'ai transmise à quelqu'un d'autre, car il était évident pour moi que ces ingénieurs allaient dans le mauvais sens. Cela semble arrogant? Oui, c'est vrai, mais j'ai rejeté les hypothèses et les demandes pour une raison différente.



J'ai compris la nature du problème. Je ne savais pas exactement où c'était ni pourquoi, mais je savais exactement ce qui se passait.



Au fil des ans, j'ai accumulé beaucoup de connaissances et d'expérience. J'ai été l'un des pionniers de l'utilisation d'Ada, j'ai compris ses avantages et ses inconvénients. Je sais comment les bibliothèques d'exécution Ada gèrent les tâches et gèrent l'exécution parallèle. Et je suis bon en programmation de bas niveau au niveau de la mémoire, des registres et de l'assembleur. En d'autres termes, j'ai une connaissance approfondie de mon domaine. Et je les ai utilisés pour trouver la cause du problème. Je n'ai pas seulement contourné le bogue, mais j'ai trouvé comment le trouver dans un environnement d'exécution très sensible.



De telles histoires de lutte avec le code ne sont pas très intéressantes pour ceux qui ne connaissent pas les particularités et les conditions d'une telle lutte. Mais ces histoires aident à comprendre ce qu'il faut pour résoudre des problèmes vraiment difficiles.



Vous devez être plus qu'un simple programmeur pour résoudre des problèmes vraiment difficiles. Vous devez comprendre le «destin» du code, comment il interagit avec son environnement et comment l'environnement lui-même fonctionne.



Et puis vous avez votre semaine de vacances gâtée.






À suivre.



All Articles