最難調試修復的 bug 是怎樣的?
由Quora上的同名問題引過來What"s the hardest bug you"ve debugged?
放眼望去怎麼基本都是純軟體的bug。。。。。。。。廣大的硬體工程師固件工程師驅動工程師在哪裡?
來吧,我來分享一下硬體相關的bug吧(線路設計,固件,驅動,etc)。在以前的回答中,我曾經零零碎碎寫過一些,這裡先搬一點兒過來。如這個答案(怎樣讓別人明白學習或從事計算機專業的人不一定會修電腦?)里的我的回答。
本答案會繼續更新,有空就來寫點兒:
==============2014/8/20更新============================(搬過來的答案,懶得重新整理了) 不嚴謹的USB驅動撰寫者:
- 一個英國的驅動高手(56歲的老頭),有一次客戶報bug說在一家醫院裡他們的一個USB設備就是沒法在新一代電腦上用,而且是時好時壞,沒有規律可言。客戶派了硬體軟體BIOS幾個工程師過去解都沒解出來。我請到這位高手出馬,高手拿到USB設備和電腦後,花了一天的時間做初步驗證,然後花了一個晚上寫了個小程序模擬那個USB設備的驅動的掛起/卸載,然後花了2小時運行那個程序,發現USB設備的驅動在掛起/卸載很多次以後Windows就會有一定的幾率拒絕掛載這個設備,然後他在和微軟以及那個設備的廠商聯繫,花了一天時間確定USB設備的驅動里的一個bug,第三天,USB設備的廠商出了一個測試驅動,問題完美解決。
粗心的硬體工程師
- 某台式機機型,出廠後大約一年後,開始出現大批量的返廠。返廠的現象驚人一致:主板掛了無法開機,掛掉的是主板上的晶元組。 由於該機型晶元組損壞率遠高於其他機型,我們一開始懷疑是客戶使用不當(因為最早返回的都是某一特定大客戶的在某國工廠退回來的機器),但隨著時間的推移,全世界各地都有返廠的現象。於是目標轉向懷疑該主板設計有問題。但是,妖異的來了,從工廠抽調數百台該機型進行壓力測試(沒日沒夜跑高壓程序,進烤箱,各種設備插拔),就是沒有一台機器掛掉。前前後後折騰了一個月,大家都喪氣了。最後,好不容易,從客戶手中拿到一些壞掉的機器,我們把晶元組拆下,重新植球,檢測後發現是晶元里有一部分電路已經損壞,多塊晶元組損壞的地方完全一致。最後,我們去檢查該主板的設計,發現晶元組的某個輸入電源,應該使用1.5V,卻使用了3.3V電壓。由於晶元組本身質量不錯,儘管設計需要1.5V但是在3.3V下仍舊可以忍辱負重工作很久才燒掉,所以這也就解釋了為什麼我們無論怎麼壓力測試都測不出來,要等機器在客戶手裡使用一年左右才會燒掉。 最後,全球召回更換主板,問題解決。
奇異的環境
- 某台式機墨西哥工廠生產線,操作系統有時會無法download(這邊普及一下知識,生產線上的操作系統不是安裝的,都是通過網路直接把image下載到硬碟)。該問題在其他國家的產線上完全無法複製。經過多個工廠嚴格的對比檢驗(工程師飛來飛去好幾個星期),發現唯一的區別是墨西哥工廠生產線上的網路環境使用的是hub(有點窮),而其他工廠使用的是switch(別的富裕一點)。進一步debug發現,台式機自帶的網卡的驅動,在用hub的環境下會丟包導致image download失敗,而在switch環境下就不會。通過網卡廠商驅動程序工程師debug之後,更新了驅動,問題解決。
==================2014/8/21更新===================
躺著都中槍
- 某機型,量產後穩定發售大半年,一切OK,用戶反映良好,銷售訂單不斷,大家都很開心。不料,從某個月起,返廠的數量逐漸增加,故障完全相同:主板上供電模塊燒毀。由於該供電模塊應用在非常多的機型中,只有這一個機型有大量返廠,於是懷疑供應商的供貨質量管控不佳,某一批次產品質量有問題。供應商被challenge的狗血淋頭,使用各種手段驗證,得出結論是產品質量控制沒問題。我們當然不信,繼續challenge供應商,逼得大家雞飛狗跳。後來,隨著時間推移,返廠的機器越來越多,損壞的供電模塊廣泛散佈於各個批次之間,這下供應商抬起頭來:總不見得我每批貨都有問題吧!好,只能繼續debug,供應商對模塊進行檢測後,告知損壞的原因是長期超負荷運行導致,基本上超負荷連續運行超過3個月,模塊就會損壞。我們很奇怪,電路設計各方面都符合標準,為啥模塊會超負荷運行?於是,開始各方面排查,經過兩個月的仔細研究,把每台返廠的機器的所有config都拉出來做對比,終於得出一個共同點:所有損壞的機器,都是從某年某月某日開始使用了某個新的顯卡驅動之後才發生的。神了,顯卡驅動能燒毀供電模塊?這時候,工藤新一開始附體:如果排除所有可能,剩下最後一個可能,即使它是多麼的不可思議,也一定就是真相! 好吧,繼續研究,發現這一版的顯卡驅動,在調配顯卡功耗的時候,會在供電模塊的輸出電路上產生一個尖峰(電壓高達額定電壓的十倍以上),儘管這個尖峰時間很短(以微秒計),但由於驅動會不斷的調整功耗,導致這個尖峰會極其頻繁的出現。所以,如果電腦是24小時開機並一直在運行高壓程序的話,這個尖峰的持續出現會導致供電模塊的損壞。後來,修正顯卡驅動,問題解決。供電模塊的供應商感慨道:這真是躺著都中槍啊!
- ====解釋的分割線======有人提到沒事不要更新驅動,其實這個有點草木皆兵的味道了。該更新的時候還是要更新的,畢竟新的驅動很多時候是解了不少bug以及提升不少性能的。這個bug當時存在的原因是該顯卡第一次內置動態功耗調整,所以驅動開發人員經驗不足。後續的產品在驅動開發的時候都會配合硬體工程師一起做測試來保證不出現類似的bug。
不差錢的土豪也有倒霉的時候
某機型,量產後穩定發售半年有餘,忽然從某個月開始,產線上不良率驟然提升,具體表現在某個出廠測試無法通過,不良品廣泛散佈於各條生產線各種配置上,毫無規律可言。工廠端仔細檢查後確認近期沒有引入任何新的物料,也沒有更改任何生產步驟,產線上的工人也沒有任何變動,於是將問題上報。研發人員介入後發現,似乎問題是跟著PCB板走的,因為在不良品上即使更換處理器晶元組,不良品依舊是不良品,而當你把不良品上的處理器晶元組換到良好的產品上,測試就通過了。於是,矛頭指向PCB製造廠,懷疑他們品控不良。PCB廠經過兩周的排查,確定他們出廠的PCB品控良好,並且他們對不良PCB做過檢驗,各項指標都在標準範圍之內。這下研發人員抓瞎了,問題被推送到我這裡。不巧的是,正好沒幾天就農曆新年了,我只好要求工廠把不良品寄給我,我再寄給美國總部的工程師幫助debug(老美不過新年也有好處啊)。隨後,工廠停產過年,等待年後復產。大家開開心心過年回來後,老美的報告出來了,經過不良品和良品的檢驗,發現不良品上處理器的某個控制電壓超出範圍,導致處理器工作不正常。研發人員進一步檢查後發現,原來在那個控制電壓上,研發過程中曾經為了debug的需要,串聯了一顆 0 歐姆的電阻,而那個電壓就是在通過了 0 歐姆的電阻後,壓降超出範圍導致的問題。隨後,經過對不良品上的 0 歐姆電阻檢測發現,該0 歐姆電阻的阻值遠超spec,原來是電阻廠品控不良啊! 研發通報了該事故給採購,採購立即將該電阻廠除名,問題解決。 解釋一下,開發過程中,電路上經常會預留一些0 歐姆的電阻,可以作為監測點來debug。通常來說,量產後,這些0歐姆的電阻都應該去除,改為直連,以節省成本。有趣的是,當初該客戶正好處於不差錢的狀態,又十分保守,決定在研髮結束到量產的過程中,所有電路一條線都不能改,於是這些用於debug的0 歐姆電阻依舊被保留著,直到該問題被發現。
強勢的事實壟斷者
一切都是因為不捨得花錢
我給大家講一個有關功耗的bug。
那是我在前東家所參與的第一個重點的晶元設計項目。那個項目之初的設計目標就是低功耗,當時市面上競爭對手的最低休眠功耗在1.1V電壓下可以做到1uA,但是他們用了較為舊的工藝,所以晶元面積大。而我們選擇了更新的工藝,面積可以減小一半多,但是由於新工藝的漏電流較大,經過初期的估算,我們的目標是接近1uA。最後在前端設計完成後,用PTPX後模擬的結果就是1.5uA。老大覺得達到了預期,於是就送出去流片了。
晶元回來後bring up,在基本功能正常, 無線收發的指標都達到預期之後,組裡的老闆,director,甚至部門的VP就關心一個東西:休眠狀態下的靜態功耗。當我們滿懷期待地接上電流表之後,電流表穩定在了6uA,是預期值的整整4倍,足足大了4.5uA!換了5塊板子,都是這個數,換了socket 板子,再測了三四顆晶元,都沒有比6uA低的。這可要了命了,我們的晶元主打就是面積小低功耗,現在這功耗簡直被競爭對手吊打啊,director下了死命令,必須在下一次流片之前把問題找出來,而下一次流片就是量產流片了。
組裡所有人開始行動起來開始找原因。我並不是always on模塊的設計者,但是是我跑的PTPX模擬,我於是先又跑了一遍模擬,重新檢查了各種設置,沒有發現任何問題,模擬就是告訴我是1.5uA。同時跑其他非休眠狀態的模擬,模擬功耗值和實測值可以對得上,證明設置是正確的,工藝庫的值也是準確的。
接下來懷疑是板子上哪裡有漏電或者是板子設計的問題,但是經過將近一周的重新排查,PCB板設計並沒有問題,那麼就是晶元內部的問題了。
always on模塊的設計者也和大家重新review了design,各種猜想被提出,但是又各種被實測否定。比如說,猜測某個isolation cell沒有插入對,於是我們和模擬團隊坐在一起,把上千個信號又一起review了一遍,最後發現都是正確的。類似這樣的頭腦風暴幾乎每天都在進行,每次大家滿懷希望以為找到一個合理解釋,但是最終都是失望而歸。
這裡要和大家講述一下silicon debug的難度。 軟體debug通常有日誌,有調試器的幫助,單步運行足以找出絕大多數bug。但是小小的晶元就難了,封裝好的晶元還沒有小拇指甲蓋大,上面的引腳比頭髮絲也粗不了多少,GPIO一共也就二三十個,每個IO後面能mux出來的信號也是有限的幾個,要是動態的信號好歹可以利用示波器和邏輯分析儀看波形,但是這種靜態功耗的debug,示波器和邏輯分析儀也只能抓瞎。我們測算過,4.5uA說大也大,說小也很小,一個transistor短路就足以引起這麼大的short circuit current,可是小小晶元裡面幾千萬上億個transistor,找出這個無異於大海撈針。
大海撈針也得撈啊,在我們大家都想不出其他解釋之後,老大批准了給晶元照熱成像和FIB。給晶元照熱成像是啥意思,因為晶元在運行的時候是有功耗,那麼在有電流流過的地方就會有功耗,那麼相應的溫度就比周邊稍稍高一點點,這個時候用專用的熱成像儀照一個照片,只要看到哪一個地方比其他地方紅一些,那麼就大概可以定位出功耗大的區域,然後再在layout上找到那片區域對應的模塊。但是照回來的結果是,熱成像分布非常均勻,完全看不出有哪個地方過熱。想想也是,4.5uA的電流,換算成功率也就是幾uW,太難了。
然後又在幾個懷疑的點做了FIB,簡單說就是把封裝打開,在die上面重新用儀器去把metal wire斷開,這個因為難度高,做一次就要好幾千美金,我們前後做了好幾次,每次都是沒有效果,上萬美金就這樣打了水漂。真是心疼啊,我們幾個年終獎加起來也不到這個數。
這樣大概折騰了2個月,下至工程師,上至director,我們都覺得要放棄了。只能猜測是廠家工藝的原因,隨著量產晶元tape out日期的臨近,我們只能寄希望於下一批次回來的晶元能夠功耗第一些。
直到有一天,我和另一個項目的後端工程師一起開會,review placement 和 critical timing path時,他給我們看了當前的placement, 我發現standard cell之間還有一些空位,就像下面這個圖, 所有的單元應該是按行擺放,但是中間會有空位。於是問他們這些空位要怎麼處理,他們說要放decap cell 和filler cell. 我之前知道filler cell是用來填滿空隙的, 可以去平衡metal density,可是decap cell是個什麼東東?這玩意有功耗嗎?開完會立馬打開lib文件一查,我擦,decap cell這玩意居然是有leakge power的!而且x2, x4, x8 (就是不同大小)的功耗也是不一樣。 我隱約覺得自己發現金礦了!
於是檢查後端給我們的netlist, 沒有filler cell, 沒有decap cell!難怪前端功耗模擬偏小,因為這些cell壓根就不存在。在後端給前端返回netlist的時候,因為decap cell和filler cell屬於沒有任何功能,沒有任何connection的cell, 他們通常的做法是在寫出netlist的時候不包括這些cell。 於是我們重新讓後端寫出帶這些cell的netlist, 再跑功耗模擬,非常準的6uA, 問題解決!
進一步分析表明,絕大多數的decap cell被放置在了always on的區域。這裡面插一句,現代SoC低功耗設計的一個常用方法是將晶元劃分成不同的power domain,有的power domain可以開可以關。在關閉的時候連power都關掉,這樣連漏電流就都沒有了,是最省功耗的做法。但是晶元睡眠後必須有一部分電路還是工作的,準備隨時喚醒整個晶元,這一部分always on的電路因為power rail不同,在版圖上通常是劃定一個特定的區域。我們的晶元由於always on邏輯很少,這片區域function cell比較稀疏,而後端在放置decap cell的時候是全局鋪放,當tool看見這部分空位比較多的時候,將大部分的decap cell都放在了always on區域里,這樣引入了多餘的4.5uA功耗。
這個bug坑的地方在於,前端拿到的netlist里沒有decap cell,而我們前期也壓根沒有往這方面想,花了大量時間去檢查看function上是不是有問題。修改本地文件卻預覽線上版本,調了一天。
手機版app好像沒法設置引用,不過 whatever
這是Dave Baggett發表在Quora上一篇The hardest bug you"ve ever debugged,讀起來讓人十分驚嘆。(如果是我的話,在代碼中找不到可能就直接放棄了。。。)
回想起這個bug,仍然讓我有些痛苦。作為一個程序員,在發現bug時,你學會了首先在自己代碼中找問題,或許在測試一萬次之後,你會把問題歸咎於編譯器。只有在這所有的都不起作用之後,你才會把問題歸咎於硬體。
這是我遭遇一個硬體bug的故事。
拋開別的不說,我曾為《Crash Bandicoot》寫存儲卡(讀寫)代碼。對於一個自大的遊戲程序員,這就像是在公園裡散步一樣輕鬆愉快,我認為只要幾天就寫完了。我中止調試六個禮拜。在此期間我做一些其他的事情,但我一直回來處理這個bug——幾天內每天幾個小時。這個bug實在煩人。
這個bug的癥狀是,當你需要保存你的進度時,代碼會訪問存儲卡,而大部分情況下沒有什麼問題…但是偶爾讀寫會超時…沒有任何明顯的原因。一個短小的寫入經常毀掉存儲卡。玩家要保存進度,我們不僅不保存,還擦除他們存儲卡上的全部東西。天哪。
過了一段時間,我們在Sony的製作人Connie Booth慌了。我們顯然不能帶著這個bug發布遊戲,而六個星期之後我對於問題出在哪一點線索都沒有。通過Connie我們向其他 PS1 開發者求助:有沒有人出現過像我們這樣的情況?沒有。絕對沒有任何人在存儲卡系統上出現任何問題。
在你絞盡腦汁之後,你能做的唯一一個調試方法就是分而治之:一點點去除程序中的代碼,直到留下的代碼很少但你仍然出問題。像木雕一樣去除沒有問題的代碼,留下的就是你的bug所在。
在這樣的背景下挑戰在於,視頻遊戲是很難去除某一部分的。在你刪除模擬重力或者顯示字元的代碼後,如何運行遊戲?
你必須做的是用一個假裝做真正的事情,但實際上只是做很簡單的不會出現bug事情的東西來替換掉整個模塊。你必須寫新的支撐代碼來讓這些玩意正常工作。這是一個緩慢而痛苦的過程。
長話短說:我做完了。我移除了大片大片的代碼,相當多,只留下了初始化代碼——就是準備遊戲運行系統,初始化底層硬體等等。當然,我不能顯示載入/保存菜單,因為我截除了所有的圖像代碼。但是我能夠假裝用戶使用(不可見的)載入/保存屏幕並且請求保存,然後寫入卡中。
我最終以一個帶有這個bug的很少量的代碼結束——但問題仍然隨機出現!在大多數情況下沒啥問題,但是偶爾會失效。基本上所有的Crash的實際代碼都被移除了,但還是這樣。這實在是莫名其妙:留下來的代碼基本上都沒做什麼事。
在那時——估計是凌晨3點——一個想法蹦了出來。讀寫(I/O)涉及精確定時。無論是硬碟、存儲卡、藍牙發送器——隨便啥——做讀寫的底層代碼都是根據時鐘來的。
時鐘讓不直接連接到CPU的硬體設備和cpu運行的代碼同步。時鐘決定了波特率——數據從一頭傳到另一頭的速率。如果計時有什麼問題,硬體或者軟體或者兩者都會亂七八糟的。這真的,真的很糟糕,並且通常導致數據損壞。
如果我們的初始化代碼以某種方式弄亂了計時會怎麼樣?我又看了一遍測試程序中和計時有關的代碼,並注意到我們將PS1上的可編程計時器設置到了1kHz(1000跳每秒)。這是比較快了,當PS1啟動的時候,默認狀態大概是100Hz。因此,大多數遊戲將他們的計時器設置為100Hz。
這個遊戲的帶頭(和除我外的唯一)開發者Andy,將計時器設置為1kHz,使得Crash的動作計算更加準確。Andy喜歡矯枉過正,如果我們要模擬重力,我們應該儘可能的提高精度!
然而如果提高計時器頻率莫名其妙的干擾了整個程序的計時,故而將這個計時器設置到存儲卡的波特率上會怎樣呢?
我將計時器代碼注釋掉。然後我就無法復原這個bug了。但是這並不表示bug被修復了,這個問題是隨機發生的。萬一我只是運氣好呢?
幾天過去了,我還是在玩我的測試程序。Bug沒有再出現。我回到全部的Crash代碼中,修改了載入/保存代碼,在訪問存儲卡之前將可編程計時器重置為默認設置(100Hz),之後設置回1kHz。從此之後沒有發現問題再次出現。
但是…為什麼?
我重新回到測試程序上,試著檢測當計時器設置為1kHz時出現的那些錯誤的模式。終於,我注意到這些錯誤出現在使用PS1手柄的人身上。因為我自己很少這樣做,所以我沒有注意到(為啥我要在測試載入/保存代碼的時候用手柄)。但是有一天我們的美工等我去完成測試(我確定那時候我在爆粗口),而他緊張的擺弄著手柄。卡損壞了。「等下,怎麼回事?喂,再來一次!」
一旦我發現了這兩件事是聯繫著的,就很容易重現bug:開始寫入存儲卡,動一下手柄,存儲卡損壞。在我看來完全是硬體bug。
我去找Connie告訴他我的發現。她轉述給設計過PS1的硬體工程師。她被告知:「不可能,這不可能是硬體問題。」我跟她說問一下我能不能直接和他說。
那個工程師給我打電話了,他用著他的爛英語,我用著我更爛的日語,我們爭論一會。我最後說:「我給你一個30行的測試程序,讓你在動手柄的時候能夠出現這問題。」他答應了。他向我保證,這是浪費時間,而他正在一個新項目上很忙,但因為我們是Sony很重要的開發者,他會試的。
第二天晚上(我們在洛杉磯,而他在東京,所以對於我來說是晚上而他是到了第二天),他給我打電話,不好意思的向我道歉。這是個硬體問題。
我還是沒有完全搞清楚問題到底在哪,但是我的印象中,從Sony總部的反饋聽到的是,如果將可編程計時器設置到足夠高的時鐘頻率,會影響到主板上時鐘晶振附近的一些東西。這些東西之一就是存儲卡的波特率控制器,同時也設置手柄的波特率。我不是搞硬體的,所以對於細節我相當模糊。
但是主旨是主板上兩個獨立部分的串擾,以及手柄介面和存儲卡介面數據發送的結合在1kHz的時鐘頻率下會導致丟位,從而數據丟失,以致卡損壞。
這是我全部編程生涯中,唯一一次因為量子力學debug的問題。
Retrieve from
http://www.quora.com/Programming-Interviews/Whats-the-hardest-bug-youve-debugged
Baggett, D.
高中的時候試圖用OpenGL在ATI的傻逼GPU上搞HDR渲染,結果總是全屏幕NaN。調試了一個月到現在都不知道為什麼,在nVidia上則沒有問題。現在想來可能是driver有bug(可能沒開centroid sampling導致光照中某個像素算出了nan,blur之後就污染了全部像素).
做GPU還是要珍愛生命遠離ATI。UTF-8 with BOM 的 html
客戶說這是BUG。
在C++ debug的書中看到的。一個伺服器每天半夜3點都會重啟一次,各種Debug無解。後來發現胖子網管每天半夜3點習慣去趟廁所,體重讓地板向下彎曲了一點點,斷路了電源。
一批試製PCB,收到後開始手焊。
第一塊焊好,燒程序,一切正常。
第二塊焊好,燒程序,不正常,後確認是電源問題,飛線、換件……一時無法解決。
狠心(狠心的原因是器件不便宜,焊上去不能用再吹下來也不保險了)焊好第三塊,燒程序,不正常,與第二塊差不多。
軟體組不耽誤事,反覆調第一塊板子就好了,但硬體組很蛋疼。
某日,終於決定一根線一根線地量,翻出發給廠家的PCB圖,一打開就發現一個特不自然的地方:電源浮地。馬上測量,證實了這一點。
板子需要重做是沒啥問題的了,程序倒也已經調了個差不多,基本上沒耽誤。所以在等待新板子的過程中,我們思考了兩件事:
第一,為啥電源還浮地,就把這圖發出去了——以那時的認知來看,只有這一處問題。
第二,為啥第一塊板子能用。
多線程環境下高壓力導致的並發bug。
難在重現上,本身也就個把月出現一次,調試模式下完全不會出現。在我的桌面上躺著一個文件,它不用面朝大海春暖花開,也會引起我無限的悲痛。
在我的桌面上躺著一個文件,它不用面朝大海春暖花開,也會引起我無限的悲痛。
_______________沒有長答就不符合知乎的氣質了————————先上圖
節選裡面一部分內容
記載在冊的bug都是非邏輯錯誤引起的具有嚴重影響的bug(請無視第一個bug,它是拿來開題的)。
但是題主問的是最難調試修復的bug, 那必須就是第2個!
這個bug歷時3個月時隱時現,就像鬼魅一樣,一來就直接死機躺在那裡。
復現它至少需要2個小時高頻率的發送才能重現。
而且出現時必須立刻抓住否則連臨終遺言都看不到了。(編譯器坑爹的臨終遺言法)
這就算難了嗎?
重點是它寫的遺言(指向問題的代碼)根本就沒重複過好嗎!
開始debug的時候我們用臨終遺言法,發現指向了一段問題代碼,
把這一大段代碼直接屏蔽了,居然能換一兇手一指,又死了!!!!
現象就是掉入硬體中斷,但是並不像普通的硬體故障,因為一旦重啟過了它又開始了下一輪跑的很歡跑著跑著又死機了。
題主你看到了嗎?這種bug符合你最難調試的口味嗎?你感受到我內心深處的對它深深的恐懼了嗎?
於是我開始了艱難的排錯過程,從虛焊,晶元過熱到內存溢出,空指針...
答主我要平復一下心情去吃飯了,過一段時間再把艱難的排錯過程寫上來。
——————————我是過了一段時間的分割線—————————
嗯……關於調試,開始是從軟體著手的。
因為以前也並沒有出現這種現象,所以沒有前車之鑒。只有自己發揮神經病人思路廣的優勢慢慢找。
經過一番觀察,我們得出的結論是:
只有進行頻繁通信2小時以後才會出現這個bug,其它模塊並不會導致該現象的發生。
所以答主開始查看通信模塊的代碼部分。
因為通信模塊的主要組成是對一段用指針寫的雙鏈表(父鏈表的內容指向子鏈表)進行操作,申請內存釋放內存的過程有很大概率出現內存泄露。
一番查找,果然,鏈表裡面有bug!賦值的時候沒有做異常處理,有概率出現申請的內存不夠用。
修改了以後,開始測試。
2個小時過去了,還沒有出現以前那種死機的現象,於是答主就休息去了,讓測試程序跑一晚上過過癮。
就在第2天早上,答主一起床就直奔測試機,結果還是死機了,此時的心情你們隨意感受一下。
痛定思痛,答主再測一了次,果不其然在4小時後死機了(這是不負所望嗎?)。
編譯器在死前指向一段看起來很無辜的代碼。
在多次的測試之後,得出了的結論是:
現象完全相同,只是在發作時間由2小時左右改成了4-6個小時(復現時間增加了1倍多,不知是喜是憂)。
這時答主按照正常人的邏輯猜測,可能是另一個內存泄露導致了bug沒有修復乾淨。
再找!
與此同時,答主的硬體小夥伴們也在檢查板子的虛焊或者元件質量不合格的可能性。(在此感謝一下2個小夥伴,他們在被答主當成製造bug的嫌疑犯時沒有隔岸觀火,而是幫答主出謀劃策,還順帶照顧答主三餐飲食保證答主沒有餓死在測試現場,嗯,他們好像不混知乎,就不點名了)
在檢查了元件的可靠性和焊接以後,答主的小夥伴們拿出了3個認為不存在問題的板子開始同時跑這一段程序。
因為是通信bug所以還順道檢查了通信模塊也沒有任何發現。
———————我是答案很快就會浮出水面的分割線————————
在長時間的查找無果後。
答主神經病人思路廣的優勢終於在一次debug中發揮了作用。
因為通信程序涉及了通信後存儲參數的過程,比按鍵後修改參數要快很多,於是答主索性屏蔽掉了通信後存儲參數的過程來排除可能性。
果然再也沒有出現死機的現象了!不能高興的太早,先跑1整天試試,然後當然是沒有出現了啊!答主手舞足蹈!普天同慶!老淚縱橫!終於找到原因了!終於知道是怎麼死的了!
原來是存儲晶元是後來擴容過的,比最初設計的大了不少,在保持極高的通信操作時會因為晶元增大引腳只能彎曲了以後焊接,彎折過的引腳導致電流的流通出現故障,存儲晶元無法訪問,編譯器當然認為是硬體問題咯。而當死機以後重啟有一個啟動時間和通信握手的時間使得晶元冷卻又恢復正常了。所以現象並不像硬體損壞引起的。
以前也就聽說存取如果頻繁會影響晶元壽命,原來還會導致晶元工作異常啊。
知道怎麼死的了還治不了你?治不了我也可以繞過去啊!
修復bug的過程比較簡單,直接把存儲最小間隔調整為5分鐘。
這時距離最初製造bug已經過去了3個月,期間由於在外測試錯過了母上大人的50歲生日,讓答主一度產生了放棄的念頭。
不過出於好奇、責任、還有小夥伴的支持,還有!一想到終於有一天會找到bug那種驕傲的心情,還是度過了這一段艱難的時光。
好吧,這個bug在大牛的眼中可能不值一提,可是這已經是答主遇到最難最難調試的bug了。
以上。曾經把幾台激光機連接在一起使用,所有信號保持一致。你可以簡單的理解成讓激光機整齊的動作。
測試也很簡單,就是在鐵板上畫圓。在護目鏡的後面,看到整齊的一排圓形火花也是很有成就感的。然後我們就開著機出去抽了根煙,回來就發現有幾個圓的外圍出現了曲線。由於是激光刻的,所以很清晰且無法消除。激光機從電源模塊 激光發生器 振鏡系統和控制系統都是我們親手裝親手調的。於是我們樂觀的拆了所有控制模塊,做替換實驗。觀察了半個小時,又發生了,但圖案與之前的完全不一樣!
基本判定這是一個干擾,我們排查了一整天天,關閉了所有的用電設備,包括使用電池的筆記本電腦,這個問題還是偶爾發生。項目已經超期了,每天的損失上萬,我們的壓力可想而知。
這是一個偶發問題,我們連它的發生規律都掌握不了!第二天繼續排查,我無意中發現最穩定的時候出現在午休時分。於是我覺得會不會是其他車間造成的干擾?
長話短說,最後查明是距我們百米開外的一個焊接車間電焊機每次啟動時造成的干擾。我們共用一個地線,接地電阻出了問題導致焊機的干擾竄了過來!
這個車間是一個獨立的小房間,我們既看不到光也聽不到聲音,就這麼默默的被折磨了一天!
最後是我們自己打了一根地線解決了問題。
最難調的 bug 是難以重現的 bug。如果找到重現方法,就好辦了。
有時候,難調是因為沒有源碼……
以前基於 Adobe Flash Media Server 寫流媒體程序的時候,碰到過一個糾結的 BUG,查了3天才再現出來,發現是 Adobe Flash Player 的 bug,提給 Adobe 後被解決了。這個 BUG 是這樣的(完整版:FlashPlayer在執行NetStream.play的時候崩潰的解決辦法) :
BUG表現
在使用NetStream連接FMS發布的流,並執行NetStream.play(『streamName』)方法時,FlashPlayer會崩潰。獨立版、調試版以及基於瀏覽器的插件版均如此。
但是,這還不是全部。必須滿足以下幾點,該BUG才會出現。
- 使用Windows 7操作系統。也就是說,Windows XP不會出現這個問題;
- 播放的必須是RTMP流,RTMP流可以由Flash Media Server或者Red5來發布。也就是說,使用NetStream播放本地的flv/f4v/mp4視頻不會出現這個問題;
- 播放的流包含音頻。也就是說,如果該流只包含視頻,不會出現這個問題;
- 播放的流中包含的音頻聲音較大。也就是說,即使該流包含音頻,但如果發布方沒有發出聲音,或者發出的聲音很小,該問題不會出現;當然,不需要很大的聲音就能讓播放端立即崩潰;
- 使用了Frame標籤來做預載入。不了解Frame標籤預載入的,看這篇文章:Preloaders in AS3;
- 在預載入完畢之後,使用removeChild移除了預載入類的實例(BUG就在這裡)。
開發和測試平台(出現BUG的平台)
- Flex SDK 4.5.1
- Flash Media Server 4.0
- Flash Player 10.3獨立版/調試版/插件版
- Windows 7 旗艦版
- Chrome12/Opera11.5/Firefox5/IE9
BUG再現
我寫了兩個簡單的Demo(一個發布端,一個接收端)來重現這個BUG。Demo需要FMS的支持。
錯誤的重點在於預載入類(PreloaderNSPlay.as)。由於預載入類在完成載入後就不再需要,一般的處理方法是將其從Stage中移
除。只要將移除,就會出現這個BUG(並非移除後立即出現,而是在接收音頻流的時候出現)。而如果使用visible將預載入類隱藏,就不會出現這個問
題。
Demo的使用方法(服務端以FMS為例):
- 安裝FMS,在安裝目錄下建立 /applications/testspeed/ 文件夾;
- 編譯NSPulish.as和NSPlay.as,或者在這裡直接下載swf文件;
- 確認本機安裝了攝像頭和麥克風,運行NSPublish.swf,單擊「連接」按鈕,查看log信息確定連接正常,見下圖:
- 運行NSPlay.swf,單擊「連接」按鈕,查看log信息確認連接正常。此時會看到發布端的攝像頭視頻。如果FlashPlaye沒有崩潰的話,就向著麥克風吹口氣……呼……整個世界清靜了……
使用 Adobe AIR 的時候碰到了一個 BUG 也是比較難找的,當然,這是因為我的功力不夠:BUG?AIR打包的iOS程序在整數比較上的問題
在使用 Adobe 的開發系列的時候,碰到過許多令人糾結的 BUG,當然最後我都歸結為自己的功力不夠,怪不得別人。所以我把它們集合在一起,時刻提醒自己:AdobeBug | zrong"s Blog。
記得有個bug大概是醬紫...
已經上線的200多個設備鏈接在交管局的大型交換機上, 正常運行了很久之後的某天開始, 程序開始不定期的關閉..然後重啟...(通過web看到的現象是不定時的上線,下線)
最開始簡單粗暴的更換了設備, 但問題依舊, 拿著筆記本在現場蹲著調了好多天, 甚至親眼目睹了工控機自動重啟. 作為一個搞軟體的感覺黔驢技窮的時候, 吾看到了工控機電源上的燈閃了一下= =!
於是找來硬體的測了半天, 最後結論是電壓不穩....
===========================
還有一個bug, 實現了某國標協議的服務系統, 用自己的客戶端沒問提, 用別人家的平台測試也能通過. 就是送去北京國標檢測的時候過不了, 而且只有一條控制指令過不了.
國標中有一行類似:
Seq : 000001
Seq是標籤名,000001是數值,
於是吾拼字串時就直接拼成"Seq:000001"這樣, 冒號前後少了空格. 加上後就過了....
我覺得最難調試修復的Bug應該是知乎的這個500錯誤頁面:
知乎又雙叒叕出Bug了
知乎又雙叒叕出Bug了 - 知乎專欄
打開一個拉黑了你的人的專欄文章,會出現一個排版灰常有個性的錯誤頁面:
從 @賀師俊 一個月前發現到現在,一個月時間都沒能修好,堪稱知乎史上最難修的Bug。現在這個Bug因為長期難以修復,所以乾脆直接升級成 feature ,總算解決了問題。
@Joy Neop 同學,你的需求已經實現了一小部分:
我在此重申什麼是正確的「屏蔽用戶」功能… - 知乎「 我當問其創建的回答、分享、專欄、專欄文章時伺服器返回 404 」,現在你訪問 屏蔽了的用戶 的專欄文章已經返回500了。為知乎的進步鼓掌!
做科研用Theano在GPU上編程。沒法debug,出現運行時錯誤(如矩陣相乘緯度不匹配)還好解決。但是出現了邏輯錯誤就苦逼了:"到底是我的想法有錯誤?還是我的代碼有錯誤?"
總結:最難改的bug不是你不知道怎麼改,也不是你找不到bug,而是在你不知道應該得到什麼結果時根本就不知道程序有沒有bug!大一時候參加ABU Robocon機器人大賽,我不懂機械也不懂電子,只會寫寫C++,於是就負責編寫機器視覺的閉環控制程序,大部分時間做圖像處理,小部分時間調用串口驅動電機。
結果有一天機器人突然一動不動了。趕緊改代碼,改了一會兒。
正當我懷疑是不是把板子燒了的時候,F5一跑發現,機器人居然又能動了!以為修復了bug,趕緊保存。
繼續寫程序不到半個小時,機器人再次罷工。我又以為自己把剛才修好的bug又觸發了。再趕緊回頭改。
如此,在「我操(四聲)」和「我操(二聲)」中不斷往複。調bug大家都懂的,吃飯睡覺都得盡量避免,必須得通宵才有感覺。
當折騰到第三天我人都快熬死了的時候,做硬體的師兄過來發現,有塊電容他忘了接地了。。。於是電容充滿電,機器人就罷工。斷電呆半個小時,等這塊兒質量不怎麼好的電容放乾淨電,就可以繼續正常調試了。。。這個我一定要怒答!
當年在IBM 的CellBE上 (就是PS3上那塊)做了不少圖像處理、視頻編解碼的工作。這個奇葩的異構體系結構有如下幾個特性:- 雖然號稱一個晶元上有9個核,但是只有一個是通用核,普通程序只能在這個核上跑,沒法和x86一樣直接多線程!
- 另外的8個運算核只有一種模式那就是128位的向量運算,只能跑一些及其精簡的指令,需要在C程序中嵌入偽彙編來編程。啊?加減乘除運算符?在運算核上放多了那個會被開除吧!
- 通用核與運算核並不共享內存空間, 他們之間所有的數據共享和同步都必須完全手工管理,想要傳數據得自己調用硬體DMA,然後自己同步!
- 因為代碼全部展開能最大增加優化潛力,基本一切函數都被變成了宏!
- 要想發揮性能一定把程序並行、向量化。用trick,gotcha一堆!人能看懂的程序都不是好程序!
- 8個運算核上跑的程序不能用gdb debug,唯一靠譜的調試手段就是printf,但是因為運算核上printf也是通過DMA跑去通用核列印到終端,所以不同核之間的printf並不能保證同步!
- 只有terminal access都不算問題了,至少還有vim!
這一年我需要在上面從頭寫一個MJPEG編解碼器。視頻編碼過的二進位流你們見過的!!!大年三十在家加班debug看dump出來的二進位流再調這種坑爹的程序你們腦補下!!!
不行了我一定要貼段代碼噁心下你們,哼!!
這段566行氣勢恢宏的代碼有且只有一個功能,那就是把rgba轉成了yuv!!!!
看不到圖的請戳大!!!!
哈哈哈哈哈哈!!!!
mian()
我也de過一個讓人無語的bug,雖然肯定不是最難的那種,但也算印象深刻了。
這個bug是我在做語音合成大作業的時候碰到的。我使用的工具包在Linux下運行完全正常,在Windows下用cygwin跑則會出錯。我做整個大作業的時間只有一周,我花了一整天的時間終於找到了bug的原因。原來工具包會把每個音素的模型存到一個文件里。有兩個音素的名稱分別是「n」和「N」,在Linux下文件名大小寫敏感,所以沒有問題;在Windows下,一個音素的模型文件會覆蓋掉另一個,這就出bug了。推薦閱讀: