cover的原理及其启示
October 6th, 2009
原创文章,转载请注明: 转载自系统技术非业余研究
本文链接地址: cover的原理及其启示
我们先看下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.
Categories: Erlang探索
Recent Comments