Cerita rakyat programmer dan insinyur (bagian 1)

Cerita rakyat programmer dan insinyur (bagian 1)

Ini adalah kumpulan cerita dari Internet tentang bagaimana bug terkadang memiliki manifestasi yang sangat luar biasa. Mungkin Anda juga ingin menceritakan sesuatu.

Alergi mobil terhadap es krim vanilla

Sebuah cerita untuk para insinyur yang memahami bahwa hal yang sudah jelas tidak selalu merupakan jawabannya, dan betapapun tidak masuk akalnya fakta tersebut, hal tersebut tetaplah fakta. Divisi Pontiac General Motors Corporation menerima keluhan:

Ini kedua kalinya saya menulis surat kepada Anda, dan saya tidak menyalahkan Anda karena tidak menjawab, karena kedengarannya gila. Keluarga kami memiliki tradisi makan es krim setiap malam setelah makan malam. Jenis es krim berubah setiap saat, dan setelah makan malam, seluruh keluarga memilih es krim mana yang akan dibeli, setelah itu saya pergi ke toko. Saya baru saja membeli Pontiac baru dan sejak itu perjalanan saya untuk membeli es krim menjadi masalah. Soalnya, setiap kali saya membeli es krim vanilla dan kembali dari toko, mobil tidak mau hidup. Jika saya membawa es krim lain, mobil dapat menyala tanpa masalah. Saya ingin mengajukan pertanyaan yang serius, betapapun bodohnya kedengarannya: “Ada apa dengan Pontiac yang membuatnya tidak menyala saat saya membawakan es krim vanilla, tetapi mulai dengan mudah saat saya membawakan es krim rasa lain?”

Seperti yang dapat Anda bayangkan, presiden divisi merasa skeptis terhadap surat tersebut. Namun, untuk berjaga-jaga, saya mengirim seorang insinyur untuk memeriksanya. Ia terkejut karena ia bertemu dengan seorang pria kaya dan terpelajar yang tinggal di daerah yang indah. Mereka sepakat untuk bertemu segera setelah makan malam agar mereka berdua bisa pergi ke toko untuk membeli es krim. Malam itu vanilla, dan ketika mereka kembali ke mobil, mobil tidak mau menyala.

Insinyur itu datang tiga malam lagi. Pertama kali es krimnya coklat. Mobil menyala. Kedua kalinya ada es krim stroberi. Mobil menyala. Pada malam ketiga dia meminta untuk mengambil vanilla. Mobil tidak menyala.

Dengan alasan rasional, sang insinyur menolak untuk percaya bahwa mobil tersebut alergi terhadap es krim vanilla. Oleh karena itu, saya sepakat dengan pemilik mobil tersebut bahwa dia akan melanjutkan kunjungannya sampai dia menemukan solusi atas masalahnya. Dan dalam perjalanannya, dia mulai mencatat: dia menuliskan semua informasi, waktu, jenis bensin, waktu kedatangan dan kepulangan dari toko, dll.

Insinyur tersebut segera menyadari bahwa pemilik mobil menghabiskan lebih sedikit waktu untuk membeli es krim vanilla. Alasannya adalah tata letak barang di toko. Es krim vanilla adalah yang paling populer dan disimpan dalam freezer terpisah di depan toko agar lebih mudah ditemukan. Dan semua varietas lainnya ada di bagian belakang toko, dan butuh lebih banyak waktu untuk menemukan varietas yang tepat dan membayar.

Sekarang pertanyaannya adalah untuk sang insinyur: mengapa mobil tidak dapat dihidupkan jika waktu telah berlalu lebih sedikit sejak mesin dimatikan? Karena masalahnya adalah waktu, bukan es krim vanilla, sang insinyur dengan cepat menemukan jawabannya: itu adalah kunci gas. Hal ini terjadi setiap malam, namun ketika pemilik mobil menghabiskan lebih banyak waktu untuk mencari es krim, mesin berhasil menjadi cukup dingin dan dapat dihidupkan dengan mudah. Dan ketika pria tersebut membeli es krim vanilla, mesin masih terlalu panas dan kunci gas tidak sempat larut.

Moral: Bahkan masalah yang benar-benar gila pun terkadang nyata.

Crash Bandicoot

Sungguh menyakitkan untuk mengalami hal ini. Sebagai seorang programmer, Anda terbiasa menyalahkan kode Anda terlebih dahulu, kedua, ketiga... dan di urutan kesepuluh ribu Anda menyalahkan kompiler. Dan di bagian bawah daftar Anda sudah menyalahkan peralatannya.

Inilah cerita saya tentang bug perangkat keras.

Untuk game Crash Bandicoot, saya menulis kode untuk dimuat dan disimpan ke kartu memori. Bagi pengembang game yang sombong, ini seperti berjalan-jalan di taman: Saya pikir pengerjaannya akan memakan waktu beberapa hari. Namun, saya akhirnya men-debug kode tersebut selama enam minggu. Sepanjang jalan, saya memecahkan masalah lain, tetapi setiap beberapa hari saya kembali ke kode ini selama beberapa jam. Itu adalah penderitaan.

Gejalanya terlihat seperti ini: saat Anda menyimpan permainan saat ini dan mengakses kartu memori, semuanya hampir selalu berjalan baik-baik saja... Namun terkadang operasi baca atau tulis habis tanpa alasan yang jelas. Rekaman singkat seringkali merusak kartu memori. Ketika seorang pemain mencoba menyelamatkan, dia tidak hanya gagal menyelamatkan, tetapi juga menghancurkan peta. Omong kosong.

Beberapa saat kemudian, produser kami di Sony, Connie Bus, mulai panik. Kami tidak dapat mengirimkan game dengan bug ini, dan enam minggu kemudian saya tidak mengerti apa yang menyebabkan masalah tersebut. Melalui Connie, kami menghubungi pengembang PS1 lainnya: adakah yang mengalami hal serupa? TIDAK. Tidak ada yang punya masalah dengan kartu memori.

Ketika Anda tidak punya ide untuk melakukan debug, satu-satunya pendekatan yang tersisa adalah “membagi dan menaklukkan”: menghapus lebih banyak kode dari program yang salah hingga ada bagian yang relatif kecil tersisa yang masih menyebabkan masalah. Artinya, Anda memotong program itu sepotong demi sepotong hingga bagian yang mengandung bug itu tetap ada.

Namun masalahnya, sangat sulit untuk memotong bagian-bagian dari sebuah video game. Bagaimana cara menjalankannya jika Anda menghapus kode yang mengemulasi gravitasi? Atau menggambar karakter?

Oleh karena itu, kita harus mengganti seluruh modul dengan stub yang berpura-pura melakukan sesuatu yang berguna, namun sebenarnya melakukan sesuatu yang sangat sederhana yang tidak boleh mengandung kesalahan. Kita harus menulis kruk seperti itu agar game ini setidaknya berfungsi. Ini adalah proses yang lambat dan menyakitkan.

Singkatnya, saya berhasil. Saya menghapus semakin banyak potongan kode hingga tersisa kode awal yang mengonfigurasi sistem untuk menjalankan game, menginisialisasi perangkat keras rendering, dll. Tentu saja pada tahap ini saya tidak dapat membuat menu simpan dan muat, karena saya harus membuat stub untuk semua kode grafis. Tapi saya bisa berpura-pura menjadi pengguna menggunakan layar simpan dan muat (tidak terlihat) dan meminta untuk menyimpan dan kemudian menulis ke kartu memori.

Ini meninggalkan saya dengan sepotong kecil kode yang masih memiliki masalah di atas - tapi itu masih terjadi secara acak! Seringkali semuanya berfungsi dengan baik, tetapi terkadang ada gangguan. Saya menghapus hampir semua kode permainan, tetapi bug masih ada. Ini membingungkan: kode yang tersisa tidak melakukan apa pun.

Pada titik tertentu, mungkin sekitar jam tiga pagi, sebuah pemikiran muncul di benak saya. Operasi baca dan tulis (input/output) melibatkan waktu eksekusi yang tepat. Saat Anda bekerja dengan hard drive, kartu memori, atau modul Bluetooth, kode tingkat rendah yang bertanggung jawab untuk membaca dan menulis melakukannya sesuai dengan pulsa jam.

Dengan bantuan jam, perangkat yang tidak terhubung langsung ke prosesor disinkronkan dengan kode yang dijalankan pada prosesor. Jam menentukan baud rate—kecepatan transfer data. Jika ada kebingungan dengan pengaturan waktu, maka perangkat keras atau perangkat lunaknya, atau keduanya, juga akan bingung. Dan ini sangat buruk, karena datanya bisa rusak.

Bagaimana jika ada sesuatu dalam kode kita yang mengacaukan pengaturan waktunya? Saya memeriksa segala sesuatu yang berhubungan dengan ini dalam kode program pengujian dan memperhatikan bahwa kami menyetel pengatur waktu yang dapat diprogram di PS1 ke 1 kHz (1000 tick per detik). Ini cukup banyak; secara default, ketika konsol dimulai, ia berjalan pada 100 Hz. Dan sebagian besar game menggunakan frekuensi ini.

Andy, sang pengembang game, mengatur timer ke 1 kHz agar pergerakan dapat dihitung lebih akurat. Andy cenderung berlebihan, dan jika kita meniru gravitasi, kita melakukannya seakurat mungkin!

Namun bagaimana jika mempercepat pengatur waktu mempengaruhi waktu program secara keseluruhan, dan juga jam yang mengatur baud rate untuk kartu memori?

Saya mengomentari kode pengatur waktu. Kesalahan tersebut tidak terjadi lagi. Namun bukan berarti kami memperbaikinya, karena kegagalan terjadi secara acak. Bagaimana jika saya hanya beruntung?

Beberapa hari kemudian saya bereksperimen lagi dengan program tes. Bug tidak terulang kembali. Saya kembali ke basis kode permainan lengkap dan memodifikasi kode simpan dan muat sehingga pengatur waktu yang dapat diprogram akan diatur ulang ke nilai aslinya (100Hz) sebelum mengakses kartu memori, dan kemudian mengatur ulang kembali ke 1kHz. Tidak ada lagi kecelakaan.

Tapi mengapa ini terjadi?

Saya kembali ke program tes lagi. Saya mencoba mencari beberapa pola terjadinya error dengan timer 1 kHz. Akhirnya saya menyadari bahwa kesalahan terjadi ketika seseorang bermain dengan pengontrol PS1. Karena saya jarang melakukan ini sendiri - mengapa saya memerlukan pengontrol saat menguji kode simpan dan muat? - Saya bahkan tidak menyadari ketergantungan ini. Namun suatu hari salah satu artis kami sedang menunggu saya menyelesaikan pengujian - saya mungkin sedang mengumpat saat itu - dan dengan gugup memutar pengontrol di tangannya. Sebuah kesalahan telah terjadi. "Tunggu apa?!" Baiklah, lakukan lagi!”

Ketika saya menyadari bahwa kedua peristiwa ini saling berhubungan, saya dapat dengan mudah mereproduksi kesalahan tersebut: Saya mulai merekam ke kartu memori, memindahkan pengontrol, dan merusak kartu memori. Bagi saya itu tampak seperti bug perangkat keras.

Saya datang ke Connie dan menceritakan kepadanya tentang penemuan saya. Dia menyampaikan informasi tersebut kepada salah satu insinyur yang merancang PS1. “Tidak mungkin,” jawabnya, “Ini bukan masalah perangkat keras.” Saya meminta Connie untuk mengatur percakapan untuk kami.

Insinyur itu menelepon saya dan kami berdebat dalam bahasa Inggrisnya yang terpatah-patah dan bahasa Jepang saya (yang sangat) terpatah-patah. Akhirnya saya berkata, “Biarkan saya mengirimkan program pengujian 30 baris saya di mana memindahkan pengontrol menyebabkan bug.” Dia setuju. Mengatakan itu hanya membuang-buang waktu dan dia sangat sibuk mengerjakan proyek baru, namun menyerah karena kami adalah pengembang yang sangat penting bagi Sony. Saya membersihkan program pengujian saya dan mengirimkannya kepadanya.

Malam berikutnya (kami berada di Los Angeles dan dia di Tokyo) dia menelepon saya dan dengan malu-malu meminta maaf. Itu adalah masalah perangkat keras.

Saya tidak tahu apa sebenarnya bug tersebut, namun dari apa yang saya dengar di kantor pusat Sony, jika Anda menyetel timer ke nilai yang cukup tinggi, maka akan mengganggu komponen pada motherboard yang berada di sekitar kristal pengatur waktu. Salah satunya adalah pengontrol baud rate untuk kartu memori, yang juga mengatur baud rate untuk pengontrolnya. Saya bukan seorang insinyur, jadi saya mungkin telah mengacaukan sesuatu.

Namun intinya terjadi gangguan antar komponen pada motherboard. Dan ketika data ditransmisikan secara bersamaan melalui port pengontrol dan port kartu memori dengan timer berjalan pada 1 kHz, bit hilang, data hilang, dan kartu rusak.

Sapi yang buruk

Pada 1980-an, mentor saya Sergei menulis perangkat lunak untuk SM-1800, tiruan PDP-11 dari Soviet. Komputer mikro ini baru saja dipasang di stasiun kereta api dekat Sverdlovsk, pusat transportasi penting di Uni Soviet. Sistem baru ini dirancang untuk mengarahkan gerbong dan lalu lintas barang. Tapi itu berisi bug yang mengganggu yang menyebabkan crash dan crash secara acak. Jatuh selalu terjadi ketika seseorang hendak pulang pada malam hari. Namun meskipun dilakukan penyelidikan menyeluruh pada hari berikutnya, komputer berfungsi dengan benar dalam semua pengujian manual dan otomatis. Ini biasanya menunjukkan kondisi balapan atau bug kompetitif lainnya yang terjadi dalam kondisi tertentu. Bosan dengan panggilan larut malam, Sergei memutuskan untuk menyelesaikannya, dan pertama-tama, memahami kondisi apa di halaman marshalling yang menyebabkan kerusakan komputer.

Pertama, dia mengumpulkan statistik dari semua kejadian jatuh yang tidak dapat dijelaskan dan membuat grafik berdasarkan tanggal dan waktu. Polanya terlihat jelas. Setelah mengamati selama beberapa hari, Sergei menyadari bahwa dia dapat dengan mudah memprediksi waktu kegagalan sistem di masa depan.

Dia segera mengetahui bahwa gangguan hanya terjadi ketika stasiun tersebut sedang menyortir muatan ternak dari Ukraina utara dan Rusia barat menuju ke rumah jagal terdekat. Hal ini memang aneh, karena rumah jagal dipasok oleh peternakan yang berlokasi lebih dekat, di Kazakhstan.

Pembangkit listrik tenaga nuklir Chernobyl meledak pada tahun 1986, dan dampak radioaktif membuat daerah sekitarnya tidak dapat dihuni. Wilayah luas di Ukraina utara, Belarusia, dan Rusia barat terkontaminasi. Mencurigai tingkat radiasi yang tinggi di gerbong yang datang, Sergei mengembangkan metode untuk menguji teori ini. Penduduk dilarang memiliki dosimeter, jadi Sergei mendaftarkan dirinya pada beberapa orang militer di stasiun kereta api. Setelah beberapa kali minum vodka, dia berhasil meyakinkan seorang tentara untuk mengukur tingkat radiasi di salah satu gerbong yang mencurigakan. Ternyata kadarnya beberapa kali lebih tinggi dari nilai normal.

Tidak hanya ternak yang mengeluarkan banyak radiasi, tingkat radiasinya juga sangat tinggi sehingga menyebabkan hilangnya bit secara acak dalam memori SM-1800, yang terletak di gedung sebelah stasiun.

Terjadi kekurangan pangan di Uni Soviet, dan pihak berwenang memutuskan untuk mencampur daging Chernobyl dengan daging dari daerah lain di negara tersebut. Hal ini memungkinkan pengurangan tingkat radioaktivitas secara keseluruhan tanpa kehilangan sumber daya yang berharga. Mengetahui hal tersebut, Sergei segera mengisi dokumen emigrasi. Dan kerusakan komputer berhenti dengan sendirinya ketika tingkat radiasi menurun seiring waktu.

Melalui pipa

Suatu ketika, Movietech Solutions menciptakan perangkat lunak untuk bioskop, dirancang untuk akuntansi, penjualan tiket, dan manajemen umum. Versi DOS dari aplikasi andalan ini cukup populer di kalangan jaringan bioskop kecil dan menengah di Amerika Utara. Jadi tidak mengherankan ketika versi Windows 95 diumumkan, terintegrasi dengan layar sentuh terbaru dan kios layanan mandiri, dan dilengkapi dengan segala macam alat pelaporan, dengan cepat menjadi populer juga. Seringkali pembaruan berjalan tanpa masalah. Staf TI lokal memasang peralatan baru, memigrasikan data, dan bisnis dilanjutkan. Kecuali ketika itu tidak bertahan lama. Jika ini terjadi, perusahaan akan mengirimkan James, yang dijuluki "Si Pembersih".

Meskipun julukannya menunjukkan tipe yang jahat, pembersih hanyalah kombinasi dari instruktur, pemasang, dan ahli dalam segala hal. James akan menghabiskan beberapa hari di lokasi klien untuk menyatukan semua komponen, dan kemudian menghabiskan beberapa hari lagi untuk mengajari staf cara menggunakan sistem baru, memecahkan masalah perangkat keras yang muncul, dan pada dasarnya membantu perangkat lunak hingga tahap awal.

Oleh karena itu, tidak mengherankan jika di tengah kesibukan tersebut, James tiba di kantor pada pagi hari, dan sebelum sempat mencapai mejanya, ia disambut oleh sang manajer, dipenuhi kafein yang melebihi biasanya.

“Saya khawatir Anda harus pergi ke Annapolis, Nova Scotia, sesegera mungkin.” Seluruh sistem mereka mati, dan setelah semalaman bekerja dengan teknisi mereka, kami tidak tahu apa yang terjadi. Sepertinya jaringan telah gagal di server. Namun hanya setelah sistem berjalan selama beberapa menit.

— Mereka tidak kembali ke sistem lama? - James menjawab dengan sangat serius, meskipun secara mental dia melebarkan matanya karena terkejut.

— Tepatnya: spesialis TI mereka “mengubah prioritas” dan memutuskan untuk meninggalkan server lama mereka. James, mereka memasang sistem di enam lokasi dan hanya membayar untuk dukungan premium, dan bisnis mereka kini berjalan seperti pada tahun 1950-an.

James menegakkan tubuh sedikit.

- Itu masalah lain. Oke, mari kita mulai.

Ketika dia tiba di Annapolis, hal pertama yang dia lakukan adalah menemukan teater pertama pelanggan yang bermasalah. Pada peta yang diambil di bandara, semuanya tampak baik-baik saja, tetapi area di sekitar alamat yang diinginkan tampak mencurigakan. Bukan ghetto, tapi mengingatkan pada film noir. Saat James parkir di tepi jalan pusat kota, seorang pelacur mendekatinya. Mengingat luasnya Annapolis, kemungkinan besar itu adalah satu-satunya di seluruh kota. Kemunculannya langsung mengingatkan kita pada tokoh terkenal yang menawarkan seks demi uang di layar lebar. Bukan, bukan tentang Julia Roberts, tapi tentang Jon Voight [singgungan pada film "Midnight Cowboy" - kira-kira. jalur].

Setelah mengirim pelacur itu dalam perjalanannya, James pergi ke bioskop. Kawasan sekitar sudah membaik, namun masih memberikan kesan kumuh. Bukan berarti James terlalu khawatir. Dia pernah ke tempat-tempat buruk sebelumnya. Dan di Kanada, bahkan para perampok pun cukup sopan untuk mengucapkan “terima kasih” setelah mengambil dompet Anda.

Pintu samping bioskop berada di gang yang lembap. James berjalan ke pintu dan mengetuk. Segera itu berderit dan terbuka sedikit.

-Apakah kamu seorang pembersih? - terdengar suara serak dari dalam.

- Ya, ini aku... Aku datang untuk memperbaiki semuanya.

James berjalan ke lobi bioskop. Tampaknya tidak punya pilihan lain, staf mulai membagikan tiket kertas kepada pengunjung. Hal ini membuat pelaporan keuangan menjadi sulit, apalagi detailnya menjadi lebih menarik. Namun para staf menyambut James dengan lega dan segera membawanya ke ruang server.

Sekilas, semuanya baik-baik saja. James masuk ke server dan memeriksa tempat-tempat mencurigakan yang biasa. Tidak masalah. Namun, karena sangat berhati-hati, James mematikan server, mengganti kartu jaringan, dan mengembalikan sistem. Dia segera mulai bekerja secara penuh. Staf mulai menjual tiket lagi.

James menelepon Mark dan memberitahunya tentang situasinya. Tidak sulit membayangkan James ingin bertahan dan melihat apakah terjadi sesuatu yang tidak terduga. Dia menuruni tangga dan mulai bertanya kepada karyawan apa yang terjadi. Jelas sistem telah berhenti bekerja. Mereka mematikan dan menghidupkannya, semuanya berfungsi. Namun setelah 10 menit, sistemnya mati.

Tepat pada saat ini, hal serupa terjadi. Tiba-tiba, sistem tiket mulai menimbulkan kesalahan. Staf menghela nafas dan mengambil tiket kertas, dan James bergegas ke ruang server. Semuanya tampak baik dengan server.

Kemudian salah satu karyawan masuk.

— Sistem berfungsi kembali.

James bingung karena dia tidak melakukan apa pun. Lebih tepatnya, tidak ada yang membuat sistem berfungsi. Dia logout, mengangkat teleponnya, dan menelepon saluran dukungan perusahaannya. Tak lama kemudian karyawan yang sama memasuki ruang server.

- Sistem sedang down.

James melirik ke server. Pola bentuk warna-warni yang menarik dan familiar menari-nari di layar - pipa-pipa yang menggeliat dan terjalin secara kacau. Kita semua pernah melihat screensaver ini di beberapa titik. Itu ditampilkan dengan indah dan benar-benar menghipnotis.


James menekan sebuah tombol dan polanya menghilang. Dia bergegas ke loket tiket dan dalam perjalanan bertemu dengan seorang karyawan yang kembali kepadanya.

— Sistem berfungsi kembali.

Jika Anda dapat melakukan mental facepalm, itulah yang dilakukan James. Screen saver. Ini menggunakan OpenGL. Oleh karena itu, selama pengoperasian, ini menghabiskan semua sumber daya prosesor server. Akibatnya, setiap panggilan ke server berakhir dengan batas waktu.

James kembali ke ruang server, login, dan mengganti screensaver dengan pipa cantik dengan layar kosong. Artinya, alih-alih screensaver yang menghabiskan 100% sumber daya prosesor, saya memasang screensaver lain yang tidak menghabiskan sumber daya. Kemudian saya menunggu 10 menit untuk memeriksa tebakan saya.

Ketika James tiba di bioskop berikutnya, dia bertanya-tanya bagaimana menjelaskan kepada manajernya bahwa dia baru saja terbang sejauh 800 km untuk mematikan screen saver.

Jatuh pada fase bulan tertentu

Kisah nyata. Suatu hari muncul bug perangkat lunak yang bergantung pada fase bulan. Ada sedikit rutinitas yang biasa digunakan di berbagai program MIT untuk menghitung perkiraan fase Bulan yang sebenarnya. GLS membangun rutinitas ini ke dalam program LISP yang, ketika menulis file, akan menghasilkan baris dengan stempel waktu sepanjang hampir 80 karakter. Sangat jarang baris pertama pesan menjadi terlalu panjang dan mengarah ke baris berikutnya. Dan ketika program kemudian membaca file ini, program tersebut terkutuk. Panjang baris pertama bergantung pada tanggal dan waktu pastinya, serta panjang spesifikasi fase pada saat stempel waktu dicetak. Artinya, bug tersebut benar-benar bergantung pada fase bulan!

Edisi kertas pertama Berkas Jargon (Steele-1983) berisi contoh baris yang menyebabkan bug yang dijelaskan, tetapi penata huruf “memperbaikinya”. Hal ini kemudian digambarkan sebagai "bug fase bulan".

Namun hati-hati dengan asumsi. Beberapa tahun yang lalu, para insinyur dari CERN (Pusat Penelitian Nuklir Eropa) mengalami kesalahan dalam eksperimen yang dilakukan di Large Electron-Positron Collider. Karena komputer secara aktif memproses sejumlah besar data yang dihasilkan oleh perangkat ini sebelum menunjukkan hasilnya kepada para ilmuwan, banyak yang berspekulasi bahwa perangkat lunak tersebut sensitif terhadap fase bulan. Beberapa insinyur yang putus asa berhasil mengungkap kebenarannya. Kesalahan tersebut muncul karena adanya sedikit perubahan geometri cincin sepanjang 27 km tersebut akibat deformasi Bumi saat melintasnya Bulan! Kisah ini telah memasuki cerita rakyat fisika sebagai “Pembalasan Newton terhadap Fisika Partikel” dan merupakan contoh hubungan antara hukum fisika paling sederhana dan tertua serta konsep ilmiah paling maju.

Membilas toilet menghentikan kereta

Bug perangkat keras terbaik yang pernah saya dengar terjadi di kereta berkecepatan tinggi di Prancis. Bug tersebut menyebabkan pengereman darurat pada kereta, tetapi hanya jika ada penumpang di dalamnya. Dalam setiap kasus tersebut, kereta dikeluarkan dari layanan, diperiksa, tetapi tidak ada yang ditemukan. Kemudian dia dikirim kembali ke barisan, dan dia segera berhenti.

Dalam salah satu pemeriksaan, seorang insinyur yang bepergian dengan kereta pergi ke toilet. Dia segera terhanyut, BOOM! Pemberhentian darurat.

Insinyur menghubungi pengemudi dan bertanya:

— Apa yang kamu lakukan sebelum mengerem?

- Yah, aku melambat saat turun...

Ini aneh, karena selama pengoperasian normal, kereta melambat puluhan kali lipat. Kereta terus berjalan, dan pada turunan berikutnya pengemudinya memperingatkan:

- Aku akan memperlambatnya.

Tidak terjadi apa-apa.

— Apa yang kamu lakukan pada pengereman terakhir? - tanya pengemudi.

- Yah... aku sedang di toilet...

- Baiklah, pergilah ke toilet dan lakukan apa yang kamu lakukan saat kita turun lagi!

Insinyur tersebut pergi ke toilet, dan ketika pengemudinya memperingatkan: “Saya melambat,” dia menyiram air tersebut. Tentu saja keretanya langsung berhenti.

Sekarang mereka dapat mereproduksi masalah tersebut dan perlu menemukan penyebabnya.

Setelah dua menit, mereka memperhatikan bahwa kabel kendali jarak jauh rem mesin (kereta memiliki satu mesin di setiap ujungnya) terputus dari dinding kabinet listrik dan tergeletak di atas relai yang mengendalikan solenoid steker toilet... Saat relai dihidupkan, hal ini menimbulkan gangguan pada kabel rem, dan perlindungan sistem terhadap kegagalan hanya mencakup pengereman darurat.

Gerbang yang membenci FORTRAN

Beberapa bulan yang lalu kami memperhatikan bahwa koneksi jaringan di daratan [di Hawaii] menjadi sangat, sangat lambat. Ini bisa berlangsung selama 10-15 menit dan kemudian terjadi lagi secara tiba-tiba. Setelah beberapa waktu, rekan saya mengeluh kepada saya bahwa koneksi jaringan berada di daratan secara umum tidak bekerja. Dia mempunyai beberapa kode FORTRAN yang perlu disalin ke mesin di daratan, namun tidak bisa karena "jaringan tidak bertahan cukup lama untuk menyelesaikan pengunggahan FTP."

Ya, ternyata kegagalan jaringan terjadi ketika seorang rekan mencoba melakukan FTP file dengan kode sumber di FORTRAN ke mesin di daratan. Kami mencoba mengarsipkan file: kemudian disalin dengan lancar (tetapi mesin target tidak memiliki unpacker, jadi masalahnya tidak terpecahkan). Akhirnya kami “membagi” kode FORTRAN menjadi potongan-potongan yang sangat kecil dan mengirimkannya satu per satu. Sebagian besar fragmen disalin tanpa masalah, tetapi beberapa bagian tidak lolos, atau lolos setelahnya banyak upaya.

Ketika kami memeriksa bagian-bagian yang bermasalah, kami menemukan bahwa mereka memiliki kesamaan: semuanya berisi blok komentar yang dimulai dan diakhiri dengan baris yang terdiri dari huruf kapital C (seperti yang disukai rekan kerja untuk berkomentar di FORTRAN). Kami mengirim email kepada pakar jaringan di daratan dan meminta bantuan. Tentu saja, mereka ingin melihat contoh file kami yang tidak dapat ditransfer melalui FTP... tetapi surat kami tidak sampai kepada mereka. Akhirnya kami menemukan yang sederhana menggambarkanseperti apa file yang tidak dapat dipindahtangankan. Berhasil :) [Beranikah saya menambahkan contoh salah satu komentar FORTRAN yang bermasalah di sini? Mungkin tidak sepadan!]

Pada akhirnya kami berhasil mengetahuinya. Sebuah gerbang baru baru-baru ini dipasang antara bagian kampus kami dan jaringan daratan. Ia mengalami kesulitan BESAR dalam mentransmisikan paket yang berisi bit huruf besar C yang berulang! Hanya beberapa dari paket ini yang dapat menghabiskan semua sumber daya gateway dan mencegah sebagian besar paket lainnya untuk melewatinya. Kami mengeluh kepada produsen gateway... dan mereka menjawab: “Oh, ya, Anda dihadapkan pada bug C yang berulang! Kami sudah tahu tentang dia.” Kami akhirnya memecahkan masalah ini dengan membeli gateway baru dari pabrikan lain (sebagai pembelaan pabrikan lain, ketidakmampuan untuk mentransfer program FORTRAN mungkin merupakan keuntungan bagi sebagian orang!).

Masa-masa sulit

Beberapa tahun yang lalu, saat berupaya menciptakan sistem ETL di Perl untuk mengurangi biaya uji klinis fase 40, saya perlu memproses sekitar 000 tanggal. Dua di antaranya tidak lulus ujian. Hal ini tidak terlalu mengganggu saya karena tanggal-tanggal ini diambil dari data yang disediakan klien, yang sering kali mengejutkan. Namun ketika saya cek data aslinya, ternyata tanggal tersebut adalah 1 Januari 2011 dan 1 Januari 2007. Saya kira bug tersebut terdapat pada program yang baru saya tulis, namun ternyata sudah 30 tahun. tua. Ini mungkin terdengar misterius bagi mereka yang tidak terbiasa dengan ekosistem perangkat lunak. Karena keputusan lama perusahaan lain untuk menghasilkan uang, klien saya membayar saya untuk memperbaiki bug yang disebabkan oleh satu perusahaan secara tidak sengaja dan perusahaan lainnya sengaja dibuat. Agar Anda memahami apa yang saya bicarakan, saya perlu berbicara tentang perusahaan yang menambahkan fitur yang akhirnya menjadi bug, serta beberapa peristiwa menarik lainnya yang berkontribusi pada bug misterius yang saya perbaiki.

Di masa lalu, komputer Apple terkadang secara spontan mengatur ulang tanggalnya menjadi 1 Januari 1904. Alasannya sederhana: ia menggunakan “jam sistem” bertenaga baterai untuk melacak tanggal dan waktu. Apa yang terjadi jika baterainya mati? Komputer mulai melacak tanggal berdasarkan jumlah detik sejak awal suatu zaman. Yang kami maksud dengan zaman adalah tanggal referensi asli, dan untuk Macintosh adalah 1 Januari 1904. Dan setelah baterai mati, tanggal saat ini diatur ulang ke tanggal yang ditentukan. Namun mengapa hal ini bisa terjadi?

Sebelumnya, Apple menggunakan 32 bit untuk menyimpan jumlah detik sejak tanggal aslinya. Satu bit dapat menyimpan salah satu dari dua nilai - 1 atau 0. Dua bit dapat menyimpan salah satu dari empat nilai: 00, 01, 10, 11. Tiga bit - satu nilai dari delapan: 000, 001, 010, 011, 100 , 101, 110, 111, dst. Dan 32 dapat menyimpan salah satu dari 232 nilai, yaitu 4 detik. Untuk tanggal Apple, ini setara dengan sekitar 294 tahun, sehingga Mac lama tidak dapat menangani tanggal setelah tahun 967. Dan jika baterai sistem mati, tanggal akan diatur ulang ke 296 detik sejak awal zaman, dan Anda harus mengatur tanggal secara manual setiap kali Anda menyalakan komputer (atau hingga Anda membeli baterai baru).

Namun, keputusan Apple untuk menyimpan tanggal sebagai detik sejak epoch berarti bahwa kami tidak dapat menangani tanggal sebelum epoch, yang memiliki konsekuensi luas, seperti yang akan kita lihat nanti. Apple memperkenalkan fitur, bukan bug. Hal ini antara lain berarti sistem operasi Macintosh kebal terhadap “bug milenium” (hal ini tidak berlaku pada banyak aplikasi Mac yang memiliki sistem tanggal sendiri untuk menghindari pembatasan).

Teruskan. Kami menggunakan Lotus 1-2-3, "aplikasi mematikan" IBM yang membantu meluncurkan revolusi PC, meskipun komputer Apple memiliki VisiCalc, yang membuat komputer pribadi sukses. Sejujurnya, jika 1-2-3 tidak muncul, PC tidak akan berkembang pesat, dan sejarah komputer pribadi bisa berkembang dengan sangat berbeda. Lotus 1-2-3 salah memperlakukan tahun 1900 sebagai tahun kabisat. Ketika Microsoft merilis spreadsheet pertamanya, Multiplan, Microsoft hanya menguasai sebagian kecil pasar. Dan ketika mereka meluncurkan proyek Excel, mereka memutuskan tidak hanya untuk menyalin skema penamaan baris dan kolom dari Lotus 1-2-3, tetapi juga untuk memastikan kompatibilitas bug dengan sengaja memperlakukan tahun 1900 sebagai tahun kabisat. Masalah ini masih ada sampai sekarang. Artinya, di 1-2-3 ini adalah bug, tapi di Excel itu adalah keputusan sadar yang memastikan bahwa semua pengguna 1-2-3 bisa mengimpor tabel mereka ke Excel tanpa mengubah data, meskipun itu salah.

Tapi ada masalah lain. Pertama, Microsoft merilis Excel untuk Macintosh, yang tidak mengenal tanggal sebelum 1 Januari 1904. Dan di Excel, 1 Januari 1900 dianggap sebagai awal era. Oleh karena itu, para pengembang melakukan perubahan agar programnya mengenali jenis zaman dan menyimpan data di dalamnya sesuai dengan zaman yang diinginkan. Microsoft bahkan menulis artikel penjelasan tentang ini. Dan keputusan ini menyebabkan kesalahan saya.

Sistem ETL saya menerima spreadsheet Excel dari pelanggan yang dibuat di Windows, namun juga dapat dibuat di Mac. Oleh karena itu, permulaan era dalam tabel tersebut dapat berupa 1 Januari 1900, atau 1 Januari 1904. Bagaimana cara mengetahuinya? Format file Excel menunjukkan informasi yang diperlukan, tetapi parser yang saya gunakan tidak menunjukkannya (sekarang menunjukkannya), dan berasumsi bahwa Anda mengetahui zaman untuk tabel tertentu. Saya mungkin bisa menghabiskan lebih banyak waktu untuk memahami format biner Excel dan mengirimkan patch ke penulis parser, tapi masih banyak yang harus saya lakukan untuk klien, jadi saya segera menulis heuristik untuk menentukan zaman. Dia sederhana.

Di Excel, tanggal 5 Juli 1998 dapat direpresentasikan dalam format "07-05-98" (sistem Amerika tidak berguna), "5 Juli 98", "5 Juli 1998", "5-Jul-98" atau beberapa format lain, format lain yang tidak berguna (ironisnya, salah satu format yang versi Excel saya tidak tawarkan adalah ISO 8601). Namun, dalam tabel, tanggal yang belum diformat disimpan sebagai "35981" untuk epoch-1900 atau "34519" untuk epoch-1904 (angka mewakili jumlah hari sejak epoch tersebut). Saya hanya menggunakan parser sederhana untuk mengekstrak tahun dari tanggal yang diformat, dan kemudian menggunakan parser Excel untuk mengekstrak tahun dari tanggal yang tidak diformat. Jika kedua nilainya berbeda 4 tahun, maka saya tahu bahwa saya menggunakan sistem dengan epoch-1904.

Mengapa saya tidak menggunakan tanggal yang diformat saja? Karena tanggal 5 Juli 1998 dapat diformat menjadi "Juli 98" dengan hari pada bulan tersebut hilang. Kami menerima tabel dari begitu banyak perusahaan yang membuatnya dengan berbagai cara sehingga kami (dalam hal ini, saya) yang menentukan tanggalnya. Selain itu, jika Excel melakukannya dengan benar, kita juga harus melakukannya!

Pada saat yang sama saya menemukan 39082. Izinkan saya mengingatkan Anda bahwa Lotus 1-2-3 menganggap tahun 1900 sebagai tahun kabisat, dan ini diulangi dengan tepat di Excel. Dan karena ini menambah satu hari pada tahun 1900, banyak fungsi penghitungan tanggal yang mungkin salah pada hari itu juga. Artinya, 39082 bisa saja tanggal 1 Januari 2011 (di Mac) atau 31 Desember 2006 (di Windows). Jika “pengurai tahun” saya mengekstrak tahun 2011 dari nilai yang diformat, maka semuanya baik-baik saja. Namun karena parser Excel tidak mengetahui epoch apa yang digunakan, maka defaultnya adalah epoch-1900, yang mengembalikan tahun 2006. Aplikasi saya melihat perbedaannya adalah 5 tahun, menganggapnya sebagai kesalahan, mencatatnya, dan mengembalikan nilai yang belum diformat.

Untuk menyiasatinya, saya menulis ini (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

Dan kemudian 40 tanggal diurai dengan benar.

Di tengah pekerjaan cetak yang besar

Pada awal tahun 1980-an, ayah saya bekerja di Storage Technology, sebuah divisi yang sekarang sudah tidak beroperasi lagi, yang memproduksi tape drive dan sistem pneumatik untuk pengumpanan tape berkecepatan tinggi.

Mereka mendesain ulang drive tersebut sehingga mereka dapat memiliki satu drive pusat “A” yang terhubung ke tujuh drive “B”, dan OS kecil dalam RAM yang mengontrol drive “A” dapat mendelegasikan operasi baca dan tulis ke semua drive “B”.

Setiap kali drive "A" dimulai, floppy disk harus dimasukkan ke dalam drive periferal yang terhubung ke "A" untuk memuat sistem operasi ke dalam memorinya. Itu sangat primitif: daya komputasi disediakan oleh mikrokontroler 8-bit.

Target audiens untuk peralatan tersebut adalah perusahaan dengan gudang data yang sangat besar - bank, jaringan ritel, dll. - yang perlu mencetak banyak label alamat atau laporan bank.

Salah satu klien mempunyai masalah. Di tengah-tengah pekerjaan pencetakan, salah satu drive “A” mungkin berhenti bekerja, menyebabkan seluruh pekerjaan terhenti. Untuk memulihkan pengoperasian drive, staf harus me-reboot semuanya. Dan jika ini terjadi di tengah-tengah tugas enam jam, maka sejumlah besar waktu komputer yang mahal akan hilang dan jadwal seluruh operasi terganggu.

Teknisi dikirim dari Storage Technologies. Namun terlepas dari upaya terbaik mereka, mereka tidak dapat mereproduksi bug tersebut dalam kondisi pengujian: bug tersebut tampaknya terjadi di tengah-tengah pekerjaan pencetakan besar. Masalahnya bukan pada perangkat kerasnya, mereka mengganti semua yang mereka bisa: RAM, mikrokontroler, floppy drive, setiap bagian tape drive - masalahnya tetap ada.

Kemudian teknisi menelpon kantor pusat dan menelpon Expert.

Pakar tersebut mengambil kursi dan secangkir kopi, duduk di ruang komputer—pada masa itu terdapat ruangan khusus untuk komputer—dan mengamati para staf mengantri untuk mencetak pekerjaan dalam jumlah besar. Pakar sedang menunggu terjadinya kegagalan - dan hal itu terjadi. Semua orang melihat ke arah Pakar, tapi dia tidak tahu mengapa ini terjadi. Maka dia memerintahkan pekerjaan itu diantri lagi, dan semua staf serta teknisi kembali bekerja.

Pakar itu kembali duduk di kursi dan mulai menunggu kegagalan. Sekitar enam jam berlalu dan kegagalan terjadi. Sang Pakar lagi-lagi tidak punya ide, kecuali bahwa semuanya terjadi di ruangan yang dipenuhi orang. Dia memerintahkan misi untuk dimulai kembali, duduk kembali dan menunggu.

Pada kegagalan ketiga, Pakar menyadari sesuatu. Kegagalan terjadi ketika personel mengganti kaset di drive asing. Selain itu, kegagalan terjadi ketika salah satu karyawan berjalan melewati ubin tertentu di lantai.

Lantai yang ditinggikan terbuat dari ubin aluminium yang dipasang pada ketinggian 6 hingga 8 inci. Banyak kabel dari komputer dipasang di bawah lantai yang ditinggikan untuk mencegah siapa pun secara tidak sengaja menginjak kabel penting. Ubin dipasang sangat rapat untuk mencegah serpihan masuk ke bawah lantai yang ditinggikan.

Pakar tersebut menyadari bahwa salah satu ubin telah berubah bentuk. Ketika seorang pekerja menginjak sudutnya, ujung-ujung ubin bergesekan dengan ubin yang berdekatan. Bagian plastik yang menghubungkan ubin juga bergesekan dengannya, yang menyebabkan pelepasan muatan mikro statis yang menimbulkan interferensi frekuensi radio.

Saat ini, RAM jauh lebih terlindungi dari interferensi frekuensi radio. Namun pada tahun-tahun itu tidak demikian. Pakar menyadari bahwa gangguan ini mengganggu memori, dan juga pengoperasian sistem operasi. Dia menelepon layanan dukungan, memesan ubin baru, memasangnya sendiri, dan masalahnya hilang.

Ini air pasang!

Ceritanya terjadi di ruang server, di lantai empat atau lima sebuah kantor di Portsmouth (menurut saya), di area dermaga.

Suatu hari server Unix dengan database utama mengalami crash. Mereka me-reboot dia, tapi dia dengan senang hati terus terjatuh lagi dan lagi. Kami memutuskan untuk menghubungi seseorang dari layanan dukungan.

Orang pendukungnya... Saya pikir namanya Mark, tapi itu tidak masalah... Saya rasa saya tidak mengenalnya. Tidak masalah, sungguh. Mari kita tetap bersama Mark, oke? Besar.

Jadi, beberapa jam kemudian Mark tiba (tidak jauh dari Leeds ke Portsmouth lho), menyalakan server dan semuanya berjalan tanpa masalah. Biasanya dukungan sialan, klien menjadi sangat kesal tentang hal ini. Mark memeriksa file log dan tidak menemukan apa pun yang tidak diinginkan. Jadi Mark kembali ke kereta (atau moda transportasi apa pun yang dia gunakan, sejauh yang saya tahu, itu mungkin sapi yang lumpuh... lagipula, tidak masalah, oke?) dan kembali ke Leeds, setelah membuang-buang waktu hari itu.

Malam itu juga server crash lagi. Ceritanya sama..servernya gak naik. Mark mencoba membantu dari jarak jauh, tetapi klien tidak dapat memulai server.

Kereta lagi, bus, lemon meringue, atau omong kosong lainnya, dan Mark kembali ke Portsmouth. Lihat, server melakukan booting tanpa masalah! Keajaiban. Mark menghabiskan beberapa jam untuk memeriksa apakah semuanya baik-baik saja dengan sistem operasi atau perangkat lunak dan berangkat ke Leeds.

Sekitar tengah hari server crash (tenang saja!). Kali ini tampaknya masuk akal untuk mendatangkan orang-orang pendukung perangkat keras untuk menggantikan server. Tapi tidak, setelah sekitar 10 jam juga jatuh.

Situasi ini berulang selama beberapa hari. Server berfungsi, mogok setelah sekitar 10 jam dan tidak dimulai selama 2 jam berikutnya. Mereka memeriksa pendinginan, kebocoran memori, mereka memeriksa semuanya, tetapi tidak menemukan apa pun. Kemudian tabrakan berhenti.

Seminggu berlalu tanpa beban... semua orang bahagia. Senang sampai semuanya dimulai lagi. Gambarnya sama. 10 jam kerja, 2-3 jam waktu henti...

Dan kemudian seseorang (saya pikir mereka mengatakan kepada saya bahwa orang ini tidak ada hubungannya dengan IT) berkata:

"Ini air pasang!"

Seruan itu disambut dengan tatapan kosong, dan tangan seseorang mungkin ragu-ragu pada tombol panggilan keamanan.

“Ia berhenti bekerja mengikuti arus.”

Hal ini tampaknya merupakan konsep yang sangat asing bagi para pekerja pendukung TI, yang kemungkinan besar tidak akan membaca Buku Tahunan Tide sambil duduk untuk minum kopi. Mereka menjelaskan bahwa hal ini tidak ada hubungannya dengan air pasang, karena server telah bekerja selama seminggu tanpa kegagalan.

“Minggu lalu air pasangnya surut, tapi minggu ini airnya tinggi.”

Sedikit terminologi bagi yang belum memiliki lisensi kapal pesiar. Pasang surut bergantung pada siklus bulan. Dan saat Bumi berputar, setiap 12,5 jam tarikan gravitasi Matahari dan Bulan menimbulkan gelombang pasang. Pada awal siklus 12,5 jam terjadi air pasang, pada pertengahan siklus terjadi pasang surut, dan pada akhir siklus terjadi air pasang kembali. Namun seiring dengan perubahan orbit bulan, perbedaan antara air surut dan air pasang juga ikut berubah. Ketika Bulan berada di antara Matahari dan Bumi atau di sisi berlawanan dari Bumi (bulan purnama atau tidak ada bulan), kita mengalami pasang surut Syzygyn - pasang surut tertinggi dan pasang surut terendah. Pada bulan sabit kita mendapatkan pasang surut kuadratur - pasang surut terendah. Perbedaan antara kedua ekstrem tersebut sangat berkurang. Siklus bulan berlangsung selama 28 hari: syzygian - quadrature - syzygian - quadrature.

Ketika para teknisi dijelaskan tentang inti dari gaya pasang surut, mereka langsung berpikir bahwa mereka perlu memanggil polisi. Dan cukup logis. Namun ternyata pria itu benar. Dua minggu sebelumnya, sebuah kapal perusak ditambatkan tidak jauh dari kantor. Setiap kali air pasang menaikkannya ke ketinggian tertentu, pos radar kapal berakhir di lantai ruang server. Dan radar (atau peralatan peperangan elektronik, atau mainan militer lainnya) menciptakan kekacauan di komputer.

Misi penerbangan untuk roket

Saya ditugaskan untuk mem-porting sistem kendali dan pemantauan peluncuran roket yang besar (sekitar 400 ribu baris) ke versi baru dari sistem operasi, kompiler, dan bahasa. Lebih tepatnya, dari Solaris 2.5.1 hingga Solaris 7, dan dari Verdix Ada Development System (VADS), yang ditulis dalam Ada 83, hingga sistem Rational Apex Ada, yang ditulis dalam Ada 95. VADS dibeli oleh Rational, dan produknya dibeli usang, meskipun Rational mencoba mengimplementasikan versi paket khusus VADS yang kompatibel untuk memudahkan transisi ke kompiler Apex.

Tiga orang membantu saya mengkompilasi kode dengan rapi. Butuh waktu dua minggu. Dan kemudian saya bekerja sendiri untuk membuat sistem berfungsi. Singkatnya, ini adalah arsitektur dan implementasi sistem perangkat lunak terburuk yang pernah saya temui, jadi perlu waktu dua bulan lagi untuk menyelesaikan port tersebut. Sistem tersebut kemudian diserahkan untuk pengujian, yang memakan waktu beberapa bulan lagi. Saya segera memperbaiki bug yang ditemukan selama pengujian, tetapi jumlahnya dengan cepat berkurang (kode sumbernya adalah sistem produksi, jadi fungsinya bekerja cukup andal, saya hanya perlu menghapus bug yang muncul selama adaptasi ke kompiler baru). Akhirnya, ketika semuanya berjalan sebagaimana mestinya, saya dipindahkan ke proyek lain.

Dan pada hari Jumat sebelum Thanksgiving, telepon berdering.

Peluncuran roket seharusnya diuji dalam waktu sekitar tiga minggu, dan selama uji hitungan mundur di laboratorium, urutan perintah diblokir. Dalam kehidupan nyata, hal ini akan membatalkan pengujian, dan jika penyumbatan terjadi dalam beberapa detik setelah mesin dihidupkan, beberapa tindakan yang tidak dapat diubah akan terjadi pada sistem tambahan, yang memerlukan kesiapan roket yang lama dan mahal. Ini tidak akan dimulai, tapi banyak orang akan sangat kecewa karena kehilangan waktu dan banyak uang. Jangan biarkan siapa pun memberi tahu Anda bahwa Departemen Pertahanan membelanjakan uang secara sembarangan—saya belum pernah bertemu manajer kontrak yang tidak mengutamakan anggaran, diikuti dengan jadwal.

Pada bulan-bulan sebelumnya, tantangan hitung mundur ini telah dijalankan ratusan kali dalam berbagai variasi, dengan hanya sedikit gangguan kecil. Jadi kemungkinan terjadinya hal ini sangat rendah, namun konsekuensinya sangat signifikan. Lipat gandakan kedua faktor ini, dan Anda akan memahami bahwa berita tersebut meramalkan minggu liburan yang buruk bagi saya dan lusinan insinyur dan manajer.

Dan perhatian diberikan kepada saya sebagai orang yang melakukan porting sistem.

Seperti kebanyakan sistem yang sangat penting bagi keamanan, banyak parameter yang dicatat, sehingga cukup mudah untuk mengidentifikasi beberapa baris kode yang dijalankan sebelum sistem mogok. Dan tentu saja, tidak ada yang aneh pada mereka; ekspresi yang sama telah berhasil dieksekusi ribuan kali dalam jangka waktu yang sama.

Kami memanggil orang-orang dari Apex ke Rasional karena merekalah yang mengembangkan kompiler dan beberapa rutinitas yang mereka kembangkan dipanggil dalam kode yang mencurigakan. Mereka (dan semua orang) terkesan bahwa ada kebutuhan untuk menemukan akar permasalahan yang sebenarnya merupakan kepentingan nasional.

Karena tidak ada hal menarik di jurnal tersebut, kami memutuskan untuk mencoba mereproduksi masalah tersebut di laboratorium lokal. Ini bukanlah tugas yang mudah karena kejadian tersebut terjadi kira-kira sekali setiap 1000 kali lari. Salah satu alasan yang diduga adalah panggilan ke fungsi mutex yang dikembangkan vendor (bagian dari paket migrasi VADS) Unlock tidak mengarah pada pembukaan kunci. Thread pemrosesan yang memanggil fungsi tersebut memproses pesan detak jantung, yang secara nominal tiba setiap detik. Kami menaikkan frekuensi menjadi 10 Hz, yaitu 10 kali per detik, dan mulai berlari. Sekitar satu jam kemudian sistem terkunci sendiri. Di log, kami melihat bahwa urutan pesan yang direkam sama seperti saat pengujian gagal. Kami melakukan beberapa kali proses lagi, sistem secara konsisten diblokir 45-90 menit setelah permulaan, dan setiap kali log berisi rute yang sama. Meskipun secara teknis kami menjalankan kode yang berbeda - frekuensi pesannya berbeda - perilaku sistemnya sama, jadi kami yakin bahwa skenario pemuatan ini menyebabkan masalah yang sama.

Sekarang kami perlu mencari tahu di mana tepatnya pemblokiran terjadi dalam rangkaian ekspresi.

Implementasi sistem ini menggunakan sistem tugas Ada, dan penggunaannya sangat buruk. Tugas adalah konstruksi tingkat tinggi yang dapat dieksekusi secara bersamaan di Ada, seperti rangkaian eksekusi, hanya dibangun ke dalam bahasa itu sendiri. Ketika dua tugas perlu dikomunikasikan, mereka "mengatur pertemuan", bertukar data yang diperlukan, dan kemudian menghentikan pertemuan dan kembali ke eksekusi independennya. Namun, sistem yang diterapkan berbeda. Setelah tugas target bertemu, tugas target tersebut bertemu dengan tugas lain, yang kemudian bertemu dengan tugas ketiga, dan seterusnya hingga beberapa pemrosesan selesai. Setelah ini, semua pertemuan ini selesai dan setiap tugas harus kembali dilaksanakan. Artinya, kita berhadapan dengan sistem pemanggilan fungsi termahal di dunia, yang menghentikan seluruh proses “multitasking” saat memproses sebagian data masukan. Dan sebelumnya tidak menimbulkan masalah hanya karena throughputnya sangat rendah.

Saya menjelaskan mekanisme tugas ini karena ketika pertemuan diminta atau diharapkan selesai, "peralihan tugas" dapat terjadi. Artinya, prosesor bisa mulai memproses tugas lain yang siap dijalankan. Ternyata ketika satu tugas siap untuk bertemu dengan tugas lain, tugas yang sama sekali berbeda dapat mulai dijalankan, dan pada akhirnya kendali kembali ke pertemuan pertama. Dan kejadian lain mungkin terjadi yang menyebabkan tugas berpindah; salah satu kejadian tersebut adalah panggilan ke fungsi sistem, seperti mencetak atau mengeksekusi mutex.

Untuk memahami baris kode mana yang menyebabkan masalah, saya perlu menemukan cara untuk mencatat kemajuan melalui serangkaian pernyataan tanpa memicu peralihan tugas, yang akan mencegah terjadinya crash. Jadi saya tidak bisa mengambil keuntungan Put_Line()untuk menghindari melakukan operasi I/O. Saya dapat menyetel variabel penghitung atau yang serupa, tetapi bagaimana saya dapat melihat nilainya jika saya tidak dapat menampilkannya di layar?

Selain itu, saat memeriksa log, ternyata, meskipun terjadi pembekuan dalam pemrosesan pesan detak jantung, yang memblokir semua operasi I/O dari proses dan mencegah dilakukannya pemrosesan lain, tugas independen lainnya terus dijalankan. Artinya, pekerjaan tersebut tidak diblokir seluruhnya, hanya rangkaian tugas (kritis).

Ini adalah petunjuk yang diperlukan untuk mengevaluasi ekspresi pemblokiran.

Saya membuat paket Ada yang berisi tugas, tipe enumerasi, dan variabel global tipe tersebut. Literal yang dapat dihitung terikat pada ekspresi spesifik dari rangkaian masalah (mis. Incrementing_Buffer_Index, Locking_Mutex, Mutex_Unlocked), dan kemudian memasukkan ekspresi penugasan ke dalamnya yang menetapkan enumerasi yang sesuai ke variabel global. Karena kode objek dari semua ini hanya menyimpan konstanta dalam memori, peralihan tugas sebagai akibat dari pelaksanaannya sangat kecil kemungkinannya. Kami terutama curiga terhadap ekspresi yang dapat mengalihkan tugas, karena pemblokiran terjadi saat eksekusi, bukan kembali saat mengalihkan tugas kembali (karena beberapa alasan).

Tugas pelacakan hanya dijalankan dalam satu lingkaran dan diperiksa secara berkala untuk melihat apakah nilai variabel global telah berubah. Dengan setiap perubahan, nilainya disimpan ke file. Kemudian menunggu sebentar dan cek baru. Saya menulis variabel ke file karena tugas dijalankan hanya ketika sistem memilihnya untuk dieksekusi ketika mengalihkan tugas di area masalah. Apa pun yang terjadi dalam tugas ini tidak akan memengaruhi tugas lain yang diblokir dan tidak terkait.

Diharapkan ketika sistem mencapai titik mengeksekusi kode yang bermasalah, variabel global akan diatur ulang ketika berpindah ke setiap ekspresi berikutnya. Kemudian akan terjadi sesuatu yang menyebabkan tugas tersebut beralih, dan karena frekuensi eksekusinya (10 Hz) lebih rendah daripada frekuensi tugas pemantauan, monitor dapat menangkap nilai variabel global dan menuliskannya. Dalam situasi normal, saya bisa mendapatkan urutan berulang dari subset enumerasi: nilai terakhir variabel pada saat peralihan tugas. Saat digantung, variabel global seharusnya tidak berubah lagi, dan nilai terakhir yang ditulis akan menunjukkan ekspresi mana yang tidak selesai.

Saya menjalankan kode dengan pelacakan. Dia membeku. Dan pemantauannya bekerja seperti jarum jam.

Log berisi urutan yang diharapkan, yang diinterupsi oleh nilai yang menunjukkan bahwa mutex telah dipanggil Unlock, dan tugas tersebut belum selesai - seperti halnya ribuan panggilan sebelumnya.

Insinyur Apex saat ini dengan tergesa-gesa menganalisis kode mereka dan menemukan tempat di mutex di mana, secara teoritis, kunci dapat terjadi. Namun kemungkinannya sangat rendah, karena hanya rangkaian peristiwa tertentu yang terjadi pada waktu tertentu yang dapat menyebabkan pemblokiran. Hukum Murphy kawan, itu Hukum Murphy.

Untuk melindungi bagian kode yang saya perlukan, saya mengganti panggilan fungsi mutex (dibangun di atas fungsionalitas mutex OS) dengan paket mutex asli kecil untuk mengontrol akses mutex ke bagian itu.

Saya memasukkannya ke dalam kode dan menjalankan tes. Tujuh jam kemudian kode itu masih berfungsi.

Kode saya diserahkan ke Rational, di mana mereka mengkompilasinya, membongkarnya, dan memeriksa apakah kode tersebut tidak menggunakan pendekatan yang sama seperti yang digunakan dalam fungsi mutex yang bermasalah.

Ini adalah tinjauan kode yang paling ramai dalam karier saya 🙂 Ada sekitar sepuluh insinyur dan manajer di ruangan bersama saya, sepuluh orang lainnya sedang melakukan panggilan konferensi - dan mereka semua memeriksa sekitar 20 baris kode.

Kode telah ditinjau, file baru yang dapat dieksekusi dikumpulkan dan diserahkan untuk pengujian regresi formal. Beberapa minggu kemudian, uji hitung mundur berhasil dan roket lepas landas.

Oke, semuanya baik-baik saja, tapi apa gunanya ceritanya?

Itu adalah masalah yang sangat menjijikkan. Ratusan ribu baris kode, eksekusi paralel, lebih dari selusin proses yang saling berinteraksi, arsitektur yang buruk dan implementasi yang buruk, antarmuka untuk sistem tertanam dan jutaan dolar yang dihabiskan. Tidak ada tekanan, kan.

Saya bukan satu-satunya yang menangani masalah ini, meskipun saya menjadi sorotan saat melakukan porting. Namun meskipun saya melakukannya, itu tidak berarti saya memahami ratusan ribu baris kode, atau bahkan membacanya sekilas. Kode dan log dianalisis oleh para insinyur di seluruh negeri, tetapi ketika mereka memberi tahu saya hipotesis mereka tentang penyebab kegagalan, saya hanya butuh setengah menit untuk membantahnya. Dan ketika saya diminta menganalisis teori, saya akan meneruskannya kepada orang lain, karena jelas bagi saya bahwa para insinyur ini mengambil jalan yang salah. Terdengar lancang? Ya, ini benar, tetapi saya menolak hipotesis dan permintaan karena alasan lain.

Saya memahami sifat masalahnya. Saya tidak tahu persis di mana hal itu terjadi atau mengapa, tapi saya tahu apa yang sedang terjadi.

Selama bertahun-tahun, saya telah mengumpulkan banyak pengetahuan dan pengalaman. Saya adalah salah satu pionir penggunaan Ada dan memahami kelebihan dan kekurangannya. Saya tahu bagaimana perpustakaan runtime Ada menangani tugas dan menangani eksekusi paralel. Dan saya memahami pemrograman tingkat rendah pada level memori, register dan assembler. Dengan kata lain, saya memiliki pengetahuan yang mendalam di bidang saya. Dan saya menggunakannya untuk menemukan penyebab masalahnya. Saya tidak hanya mengatasi bug tersebut, saya juga memahami cara menemukannya di lingkungan runtime yang sangat sensitif.

Kisah-kisah perjuangan dengan kode seperti itu tidak terlalu menarik bagi mereka yang tidak terbiasa dengan fitur dan kondisi perjuangan tersebut. Namun kisah-kisah ini membantu kita memahami apa yang diperlukan untuk memecahkan masalah yang sangat sulit.

Untuk memecahkan masalah yang sangat sulit, Anda harus menjadi lebih dari sekedar seorang programmer. Anda perlu memahami “nasib” kode, cara kode berinteraksi dengan lingkungannya, dan cara kerja lingkungan itu sendiri.

Dan kemudian Anda akan mengalami minggu liburan Anda sendiri yang hancur.

Untuk dilanjutkan.

Sumber: www.habr.com

Tambah komentar