系統技術非業餘研究 » cover的原理及其啟示
阿新 • • 發佈:2018-12-31
我們先看下cover模組的功能:
The module cover provides a set of functions for coverage analysis of Erlang programs, counting how many times each executable line of code is executed when a program is run.
那它是如何做到的呢?
它是這樣實現的: cover一個模組的時候要先編譯, 這個過程中, 根據模組的abstract code 裡面的行號,在每個有效的語句前面插入一個 ets:update_couter() 語句,這樣編譯出來的模組執行的時候,我們就可以收集到每個有效行的執行資訊。
我hack了下cover.erl:
yu-fengdemacbook-2:src yufeng$ diff cover.erl cover_orig.erl 1242,1243c1242 < {ok, Module, Binary} = compile:forms(Forms, [debug_info]), < io:format("abstract code: ~n~p~n", [get_abstract_code(Module, Binary)]), --- > {ok, Module, Binary} = compile:forms(Forms, []), yu-fengdemacbook-2:~ yufeng$ cat float.erl
-module(float). -export([new/1,update/3]). new(N) -> hipe_bifs:bytearray(N*8,0). update(Arr,N,Float) -> <<A1,A2,A3,A4,A5,A6,A7,A8>> = <<Float/float>>, Start=N*8, hipe_bifs:bytearray_update(Arr,Start,A1), hipe_bifs:bytearray_update(Arr,Start+1,A2), hipe_bifs:bytearray_update(Arr,Start+2,A3), hipe_bifs:bytearray_update(Arr,Start+3,A4), hipe_bifs:bytearray_update(Arr,Start+4,A5), hipe_bifs:bytearray_update(Arr,Start+5,A6), hipe_bifs:bytearray_update(Arr,Start+6,A7), hipe_bifs:bytearray_update(Arr,Start+7,A8).
yu-fengdemacbook-2:~ yufeng$ otp_src_R13B02-1/bin/erl Erlang R13B02 (erts-5.7.3) [/source] [smp:2:2] [rq:2] [async-threads:0] [kernel-poll:false] Eshell V5.7.3 (abort with ^G) 1> cover:start(). {ok,<0.33.0>} 2> cover:compile(float). abstract code: {raw_abstract_v1, [{attribute,1,file,{"/Users/yufeng/float.erl",1}}, {attribute,1,module,float}, {attribute,3,export,[{new,1},{update,3}]}, {function,5,new,1, [{clause,5, [{var,5,'N'}], [], [{call,0, {remote,0,{atom,0,ets},{atom,0,update_counter}}, [{atom,0,cover_internal_data_table}, {tuple,0, [{atom,0,bump}, {atom,0,float}, {atom,0,new}, {integer,0,1}, {integer,0,1}, {integer,0,6}]}, {integer,0,1}]}, %% 我們清楚的看到 ets:update_counter()的呼叫 {call,6, {remote,6,{atom,6,hipe_bifs},{atom,6,bytearray}}, [{op,6,'*',{var,6,'N'},{integer,6,8}},{integer,6,0}]}]}]}, {function,8,update,3, [{clause,8, [{var,8,'Arr'},{var,8,'N'},{var,8,'Float'}], [], [{call,0, {remote,0,{atom,0,ets},{atom,0,update_counter}}, [{atom,0,cover_internal_data_table}, {tuple,0, [{atom,0,bump}, {atom,0,float}, {atom,0,update}, {integer,0,3}, {integer,0,1}, {integer,0,9}]}, {integer,0,1}]}, {match,9, {bin,9, [{bin_element,9,{var,9,'A1'},default,default}, {bin_element,9,{var,9,'A2'},default,default}, {bin_element,9,{var,9,'A3'},default,default}, {bin_element,9,{var,9,'A4'},default,default}, {bin_element,9,{var,9,'A5'},default,default}, {bin_element,9,{var,9,'A6'},default,default}, {bin_element,9,{var,9,'A7'},default,default}, {bin_element,9,{var,9,'A8'},default,default}]}, {bin,9,[{bin_element,9,{var,9,'Float'},default,[float]}]}}, {call,0, {remote,0,{atom,0,ets},{atom,0,update_counter}}, [{atom,0,cover_internal_data_table}, {tuple,0, [{atom,0,bump}, {atom,0,float}, {atom,0,update}, {integer,0,3}, {integer,0,1}, {integer,0,10}]}, {integer,0,1}]}, {match,10, {var,10,'Start'}, {op,10,'*',{var,10,'N'},{integer,10,8}}}, {call,0, {remote,0,{atom,0,ets},{atom,0,update_counter}}, [{atom,0,cover_internal_data_table}, {tuple,0, [{atom,0,bump}, {atom,0,float}, {atom,0,update}, {integer,0,3}, {integer,0,1}, {integer,0,11}]}, {integer,0,1}]}, {call,11, {remote,11,{atom,11,hipe_bifs},{atom,11,bytearray_update}}, [{var,11,'Arr'},{var,11,'Start'},{var,11,'A1'}]}, {call,0, {remote,0,{atom,0,ets},{atom,0,update_counter}}, [{atom,0,cover_internal_data_table}, {tuple,0, [{atom,0,bump}, {atom,0,float}, {atom,0,update}, {integer,0,3}, {integer,0,1}, {integer,0,12}]}, {integer,0,1}]}, {call,12, {remote,12,{atom,12,hipe_bifs},{atom,12,bytearray_update}}, [{var,12,'Arr'}, {op,12,'+',{var,12,'Start'},{integer,12,1}}, {var,12,'A2'}]}, {call,0, {remote,0,{atom,0,ets},{atom,0,update_counter}}, [{atom,0,cover_internal_data_table}, {tuple,0, [{atom,0,bump}, {atom,0,float}, {atom,0,update}, {integer,0,3}, {integer,0,1}, {integer,0,13}]}, {integer,0,1}]}, {call,13, {remote,13,{atom,13,hipe_bifs},{atom,13,bytearray_update}}, [{var,13,'Arr'}, {op,13,'+',{var,13,'Start'},{integer,13,2}}, {var,13,'A3'}]}, {call,0, {remote,0,{atom,0,ets},{atom,0,update_counter}}, [{atom,0,cover_internal_data_table}, {tuple,0, [{atom,0,bump}, {atom,0,float}, {atom,0,update}, {integer,0,3}, {integer,0,1}, {integer,0,14}]}, {integer,0,1}]}, {call,14, {remote,14,{atom,14,hipe_bifs},{atom,14,bytearray_update}}, [{var,14,'Arr'}, {op,14,'+',{var,14,'Start'},{integer,14,3}}, {var,14,'A4'}]}, {call,0, {remote,0,{atom,0,ets},{atom,0,update_counter}}, [{atom,0,cover_internal_data_table}, {tuple,0, [{atom,0,bump}, {atom,0,float}, {atom,0,update}, {integer,0,3}, {integer,0,1}, {integer,0,15}]}, {integer,0,1}]}, {call,15, {remote,15,{atom,15,hipe_bifs},{atom,15,bytearray_update}}, [{var,15,'Arr'}, {op,15,'+',{var,15,'Start'},{integer,15,4}}, {var,15,'A5'}]}, {call,0, {remote,0,{atom,0,ets},{atom,0,update_counter}}, [{atom,0,cover_internal_data_table}, {tuple,0, [{atom,0,bump}, {atom,0,float}, {atom,0,update}, {integer,0,3}, {integer,0,1}, {integer,0,16}]}, {integer,0,1}]}, {call,16, {remote,16,{atom,16,hipe_bifs},{atom,16,bytearray_update}}, [{var,16,'Arr'}, {op,16,'+',{var,16,'Start'},{integer,16,5}}, {var,16,'A6'}]}, {call,0, {remote,0,{atom,0,ets},{atom,0,update_counter}}, [{atom,0,cover_internal_data_table}, {tuple,0, [{atom,0,bump}, {atom,0,float}, {atom,0,update}, {integer,0,3}, {integer,0,1}, {integer,0,17}]}, {integer,0,1}]}, {call,17, {remote,17,{atom,17,hipe_bifs},{atom,17,bytearray_update}}, [{var,17,'Arr'}, {op,17,'+',{var,17,'Start'},{integer,17,6}}, {var,17,'A7'}]}, {call,0, {remote,0,{atom,0,ets},{atom,0,update_counter}}, [{atom,0,cover_internal_data_table}, {tuple,0, [{atom,0,bump}, {atom,0,float}, {atom,0,update}, {integer,0,3}, {integer,0,1}, {integer,0,18}]}, {integer,0,1}]}, {call,18, {remote,18,{atom,18,hipe_bifs},{atom,18,bytearray_update}}, [{var,18,'Arr'}, {op,18,'+',{var,18,'Start'},{integer,18,7}}, {var,18,'A8'}]}]}]}, {eof,19}]} {ok,float}
這個故事告訴我們對 erlang系統的跟蹤除了trace機制以為, 我們還可以用parse transform在編譯的時候加入我們想要的程式碼,達到跟蹤, 瞭解系統的目的。具體的可以參考 compiler模組 parse_transform的文件。
Post Footer automatically generated by wp-posturl plugin for wordpress.