1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 2002-2013. All Rights Reserved. 5: %% 6: %% The contents of this file are subject to the Erlang Public License, 7: %% Version 1.1, (the "License"); you may not use this file except in 8: %% compliance with the License. You should have received a copy of the 9: %% Erlang Public License along with this software. If not, it can be 10: %% retrieved online at http://www.erlang.org/. 11: %% 12: %% Software distributed under the License is distributed on an "AS IS" 13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 14: %% the License for the specific language governing rights and limitations 15: %% under the License. 16: %% 17: %% %CopyrightEnd% 18: %% 19: 20: %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21: %%% 22: %%% Define to run outside of test server 23: %%% 24: %%% -define(STANDALONE,1). 25: %%% 26: %%% 27: %%% Define for debug output 28: %%% 29: %%% -define(debug,1). 30: 31: -module(cprof_SUITE). 32: 33: %% Exported end user tests 34: -export([basic_test/0, on_load_test/1, modules_test/1]). 35: 36: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 37: %% Test server related stuff 38: %% 39: 40: -ifdef(STANDALONE). 41: -define(config(A,B),config(A,B)). 42: -export([config/2]). 43: -else. 44: -include_lib("test_server/include/test_server.hrl"). 45: -endif. 46: 47: -ifdef(debug). 48: -ifdef(STANDALONE). 49: -define(line, erlang:display({?MODULE,?LINE}), ). 50: -endif. 51: -define(dbgformat(A,B),io:format(A,B)). 52: -else. 53: -ifdef(STANDALONE). 54: -define(line, noop, ). 55: -endif. 56: -define(dbgformat(A,B),noop). 57: -endif. 58: 59: -ifdef(STANDALONE). 60: config(priv_dir, _) -> 61: "."; 62: config(data_dir, _) -> 63: "cprof_SUITE_data". 64: -else. 65: %% When run in test server. 66: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 67: init_per_group/2,end_per_group/2, 68: init_per_testcase/2, end_per_testcase/2, 69: not_run/1]). 70: -export([basic/1, on_load/1, modules/1]). 71: 72: init_per_testcase(_Case, Config) -> 73: ?line Dog=test_server:timetrap(test_server:seconds(30)), 74: [{watchdog, Dog}|Config]. 75: 76: end_per_testcase(_Case, Config) -> 77: erlang:trace_pattern({'_','_','_'}, false, [local,meta,call_count]), 78: erlang:trace_pattern(on_load, false, [local,meta,call_count]), 79: erlang:trace(all, false, [all]), 80: Dog=?config(watchdog, Config), 81: test_server:timetrap_cancel(Dog), 82: ok. 83: 84: suite() -> [{ct_hooks,[ts_install_cth]}]. 85: 86: all() -> 87: case test_server:is_native(cprof_SUITE) of 88: true -> [not_run]; 89: false -> [basic, on_load, modules] 90: end. 91: 92: groups() -> 93: []. 94: 95: init_per_suite(Config) -> 96: Config. 97: 98: end_per_suite(_Config) -> 99: ok. 100: 101: init_per_group(_GroupName, Config) -> 102: Config. 103: 104: end_per_group(_GroupName, Config) -> 105: Config. 106: 107: 108: not_run(Config) when is_list(Config) -> 109: {skipped,"Native code"}. 110: 111: basic(suite) -> 112: []; 113: basic(doc) -> 114: ["Tests basic profiling"]; 115: basic(Config) when is_list(Config) -> 116: basic_test(). 117: 118: on_load(suite) -> 119: []; 120: on_load(doc) -> 121: ["Tests profiling of unloaded module"]; 122: on_load(Config) when is_list(Config) -> 123: on_load_test(Config). 124: 125: modules(suite) -> 126: []; 127: modules(doc) -> 128: ["Tests profiling of several modules"]; 129: modules(Config) when is_list(Config) -> 130: modules_test(Config). 131: 132: -endif. %-ifdef(STANDALONE). ... -else. 133: 134: %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 135: %%% The Tests 136: %%% 137: 138: basic_test() -> 139: ?line M = 1000, 140: %% 141: ?line M2 = M*2, 142: ?line M3 = M*3, 143: ?line M2__1 = M2 + 1, 144: ?line M3__1 = M3 + 1, 145: ?line N = cprof:stop(), 146: %% 147: ?line 2 = cprof:start(?MODULE, seq_r), 148: ?line 1 = cprof:start(?MODULE, seq, 3), 149: ?line L = seq(1, M, fun succ/1), 150: ?line Lr = seq_r(1, M, fun succ/1), 151: ?line L = lists:reverse(Lr), 152: %% 153: ?line io:format("~p~n~p~n~p~n", 154: [erlang:trace_info({?MODULE,sec_r,3}, all), 155: erlang:trace_info({?MODULE,sec_r,4}, all), 156: erlang:trace_info({?MODULE,sec,3}, all)]), 157: %% 158: ?line ModAna1 = {?MODULE,M2__1,[{{?MODULE,seq_r,4},M}, 159: {{?MODULE,seq,3},M}, 160: {{?MODULE,seq_r,3},1}]}, 161: ?line ModAna1 = cprof:analyse(?MODULE,0), 162: ?line {M2__1, [ModAna1]} = cprof:analyse(), 163: ?line ModAna1 = cprof:analyse(?MODULE, 1), 164: ?line {M2__1, [ModAna1]} = cprof:analyse(1), 165: %% 166: ?line ModAna2 = {?MODULE,M2__1,[{{?MODULE,seq_r,4},M}, 167: {{?MODULE,seq,3},M}]}, 168: ?line ModAna2 = cprof:analyse(?MODULE, 2), 169: ?line {M2__1, [ModAna2]} = cprof:analyse(2), 170: %% 171: 2 = cprof:pause(?MODULE, seq_r), 172: ?line L = seq(1, M, fun succ/1), 173: ?line Lr = seq_r(1, M, fun succ/1), 174: %% 175: ?line ModAna3 = {?MODULE,M3__1,[{{?MODULE,seq,3},M2}, 176: {{?MODULE,seq_r,4},M}, 177: {{?MODULE,seq_r,3},1}]}, 178: ?line ModAna3 = cprof:analyse(?MODULE), 179: %% 180: ?line N = cprof:pause(), 181: ?line L = seq(1, M, fun succ/1), 182: ?line Lr = seq_r(1, M, fun succ/1), 183: %% 184: ?line {M3__1, [ModAna3]} = cprof:analyse(), 185: %% 186: ?line N = cprof:restart(), 187: ?line L = seq(1, M, fun succ/1), 188: ?line Lr = seq_r(1, M, fun succ/1), 189: %% 190: ?line ModAna1 = cprof:analyse(?MODULE), 191: %% 192: ?line N = cprof:stop(), 193: ?line {?MODULE,0,[]} = cprof:analyse(?MODULE), 194: ?line {0,[]} = cprof:analyse(), 195: ok. 196: 197: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 198: 199: on_load_test(Config) -> 200: ?line Priv = ?config(priv_dir, Config), 201: ?line Data = ?config(data_dir, Config), 202: ?line File = filename:join(Data, "cprof_SUITE_test"), 203: ?line Module = cprof_SUITE_test, 204: ?line M = 1000, 205: %% 206: ?line M2 = M*2, 207: ?line M2__1 = M2 + 1, 208: ?line N1 = cprof:start(), 209: 210: ?line {ok,Module} = c:c(File, [{outdir,Priv}]), 211: 212: %% If this system is hipe-enabled, the loader may have called module_info/1 213: %% when Module was loaded above. Reset the call count to avoid seeing 214: %% the call in the analysis below. 215: 216: ?line 1 = cprof:restart(Module, module_info, 1), 217: 218: ?line L = Module:seq(1, M, fun succ/1), 219: ?line Lr = Module:seq_r(1, M, fun succ/1), 220: ?line Lr = lists:reverse(L), 221: ?line N2 = cprof:pause(), 222: ?line N3 = cprof:pause(Module), 223: ?line {Module,M2__1,[{{Module,seq_r,4},M}, 224: {{Module,seq,3},M}, 225: {{Module,seq_r,3},1}]} = cprof:analyse(Module), 226: ?line io:format("~p ~p ~p~n", [N1, N2, N3]), 227: ?line code:purge(Module), 228: ?line code:delete(Module), 229: ?line N4 = N2 - N3, 230: %% 231: ?line N4 = cprof:restart(), 232: ?line {ok,Module} = c:c(File, [{outdir,Priv}]), 233: ?line L = Module:seq(1, M, fun succ/1), 234: ?line Lr = Module:seq_r(1, M, fun succ/1), 235: ?line L = seq(1, M, fun succ/1), 236: ?line Lr = seq_r(1, M, fun succ/1), 237: ?line N2 = cprof:pause(), 238: ?line {Module,0,[]} = cprof:analyse(Module), 239: ?line M_1 = M - 1, 240: ?line M4__4 = M*4 - 4, 241: ?line M10_7 = M*10 - 7, 242: ?line {?MODULE,M10_7,[{{?MODULE,succ,1},M4__4}, 243: {{?MODULE,seq_r,4},M}, 244: {{?MODULE,seq,3},M}, 245: {{?MODULE,'-on_load_test/1-fun-5-',1},M_1}, 246: {{?MODULE,'-on_load_test/1-fun-4-',1},M_1}, 247: {{?MODULE,'-on_load_test/1-fun-3-',1},M_1}, 248: {{?MODULE,'-on_load_test/1-fun-2-',1},M_1}, 249: {{?MODULE,seq_r,3},1}]} 250: = cprof:analyse(?MODULE), 251: ?line N2 = cprof:stop(), 252: ok. 253: 254: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 255: 256: modules_test(Config) -> 257: ?line Priv = ?config(priv_dir, Config), 258: ?line Data = ?config(data_dir, Config), 259: ?line File = filename:join(Data, "cprof_SUITE_test"), 260: ?line Module = cprof_SUITE_test, 261: ?line {ok,Module} = c:c(File, [{outdir,Priv}]), 262: ?line M = 10, 263: %% 264: ?line M2 = M*2, 265: ?line M2__1 = M2 + 1, 266: ?line erlang:yield(), 267: ?line N = cprof:start(), 268: ?line L = Module:seq(1, M, fun succ/1), 269: ?line Lr = Module:seq_r(1, M, fun succ/1), 270: ?line L = seq(1, M, fun succ/1), 271: ?line Lr = seq_r(1, M, fun succ/1), 272: ?line N = cprof:pause(), 273: ?line Lr = lists:reverse(L), 274: ?line M_1 = M - 1, 275: ?line M4_4 = M*4 - 4, 276: ?line M10_7 = M*10 - 7, 277: ?line M2__1 = M*2 + 1, 278: ?line {Tot,ModList} = cprof:analyse(), 279: ?line {value,{?MODULE,M10_7,[{{?MODULE,succ,1},M4_4}, 280: {{?MODULE,seq_r,4},M}, 281: {{?MODULE,seq,3},M}, 282: {{?MODULE,'-modules_test/1-fun-3-',1},M_1}, 283: {{?MODULE,'-modules_test/1-fun-2-',1},M_1}, 284: {{?MODULE,'-modules_test/1-fun-1-',1},M_1}, 285: {{?MODULE,'-modules_test/1-fun-0-',1},M_1}, 286: {{?MODULE,seq_r,3},1}]}} = 287: lists:keysearch(?MODULE, 1, ModList), 288: ?line {value,{Module,M2__1,[{{Module,seq_r,4},M}, 289: {{Module,seq,3},M}, 290: {{Module,seq_r,3},1}]}} = 291: lists:keysearch(Module, 1, ModList), 292: ?line Tot = lists:foldl(fun ({_,C,_}, A) -> C+A end, 0, ModList), 293: ?line {cprof,_,Prof} = cprof:analyse(cprof), 294: ?line {value,{{cprof,pause,0},1}} = 295: lists:keysearch({cprof,pause,0}, 1, Prof), 296: ?line N = cprof:stop(), 297: ok. 298: 299: 300: 301: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 302: %% Local helpers 303: 304: 305: 306: %% Stack recursive seq 307: seq(Stop, Stop, Succ) when is_function(Succ) -> 308: [Stop]; 309: seq(Start, Stop, Succ) when is_function(Succ) -> 310: [Start | seq(Succ(Start), Stop, Succ)]. 311: 312: 313: 314: %% Tail recursive seq, result list is reversed 315: seq_r(Start, Stop, Succ) when is_function(Succ) -> 316: seq_r(Start, Stop, Succ, []). 317: 318: seq_r(Stop, Stop, _, R) -> 319: [Stop | R]; 320: seq_r(Start, Stop, Succ, R) -> 321: seq_r(Succ(Start), Stop, Succ, [Start | R]). 322: 323: 324: 325: %% Successor 326: succ(X) -> X+1.