1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2002-2020. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20-module(cprof). 21 22%% Call count profiling tool. 23 24-export ([start/0, start/1, start/2, start/3, 25 stop/0, stop/1, stop/2, stop/3, 26 restart/0, restart/1, restart/2, restart/3, 27 pause/0, pause/1, pause/2, pause/3, 28 analyse/0, analyse/1, analyse/2, 29 analyze/0, analyze/1, analyze/2]). 30 31 32 33-spec start() -> non_neg_integer(). 34 35start() -> 36 tr({'_','_','_'}, true) + tr(on_load, true). 37 38-spec start(FuncSpec) -> non_neg_integer() when 39 FuncSpec :: (Mod :: module()) | mfa() | {FS :: term()}. 40 41start({_,_,_} = MFA) -> 42 tr(MFA, true); 43start({FuncSpec}) -> 44 tr(FuncSpec, true); 45start(M) -> 46 tr({M,'_','_'}, true). 47 48-spec start(Mod, Func) -> non_neg_integer() when 49 Mod :: module(), 50 Func :: atom(). 51 52start(M,F) -> 53 tr({M,F,'_'}, true). 54 55-spec start(Mod, Func, Arity) -> non_neg_integer() when 56 Mod :: module(), 57 Func :: atom(), 58 Arity :: arity(). 59 60start(M,F,A) -> 61 tr({M,F,A}, true). 62 63 64 65-spec stop() -> non_neg_integer(). 66 67stop() -> 68 tr({'_','_','_'}, false) + tr(on_load, false). 69 70-spec stop(FuncSpec) -> non_neg_integer() when 71 FuncSpec :: (Mod :: module()) | mfa() | {FS :: term()}. 72 73stop({_,_,_} = MFA) -> 74 tr(MFA, false); 75stop({FuncSpec}) -> 76 tr(FuncSpec, false); 77stop(M) -> 78 tr({M,'_','_'}, false). 79 80-spec stop(Mod, Func) -> non_neg_integer() when 81 Mod :: module(), 82 Func :: atom(). 83 84stop(M,F) -> 85 tr({M,F,'_'}, false). 86 87-spec stop(Mod, Func, Arity) -> non_neg_integer() when 88 Mod :: module(), 89 Func :: atom(), 90 Arity :: arity(). 91 92stop(M,F,A) -> 93 tr({M,F,A}, false). 94 95 96-spec restart() -> non_neg_integer(). 97 98restart() -> 99 tr({'_','_','_'}, restart). 100 101-spec restart(FuncSpec) -> non_neg_integer() when 102 FuncSpec :: (Mod :: module()) | mfa() | {FS :: term()}. 103 104restart({_,_,_} = MFA) -> 105 tr(MFA, restart); 106restart({FuncSpec}) -> 107 tr(FuncSpec, restart); 108restart(M) -> 109 tr({M,'_','_'}, restart). 110 111-spec restart(Mod, Func) -> non_neg_integer() when 112 Mod :: module(), 113 Func :: atom(). 114 115restart(M,F) -> 116 tr({M,F,'_'}, restart). 117 118-spec restart(Mod, Func, Arity) -> non_neg_integer() when 119 Mod :: module(), 120 Func :: atom(), 121 Arity :: arity(). 122 123restart(M,F,A) -> 124 tr({M,F,A}, restart). 125 126 127-spec pause() -> non_neg_integer(). 128 129pause() -> 130 tr({'_','_','_'}, pause) + tr(on_load, false). 131 132-spec pause(FuncSpec) -> non_neg_integer() when 133 FuncSpec :: (Mod :: module()) | mfa() | {FS :: term()}. 134 135pause({_,_,_} = MFA) -> 136 tr(MFA, pause); 137pause({FuncSpec}) -> 138 tr(FuncSpec, pause); 139pause(M) -> 140 tr({M,'_','_'}, pause). 141 142-spec pause(Mod, Func) -> non_neg_integer() when 143 Mod :: module(), 144 Func :: atom(). 145 146pause(M,F) -> 147 tr({M,F,'_'}, pause). 148 149-spec pause(Mod, Func, Arity) -> non_neg_integer() when 150 Mod :: module(), 151 Func :: atom(), 152 Arity :: arity(). 153 154pause(M,F,A) -> 155 tr({M,F,A}, pause). 156 157 158 159-type mod_analysis_list() :: [mod_analysis()]. 160-type mod_analysis() :: {Mod :: module(), 161 ModCallCount :: non_neg_integer(), 162 FuncAnalysisList :: func_analysis_list()}. 163-type func_analysis_list() :: [{mfa(), FuncCallCount :: non_neg_integer()}]. 164 165-spec analyse() -> {AllCallCount :: non_neg_integer(), 166 ModAnalysisList :: mod_analysis_list()}. 167 168analyse() -> 169 analyse(1). 170 171-spec analyse(Limit) -> {AllCallCount :: non_neg_integer(), 172 ModAnalysisList :: mod_analysis_list()} when 173 Limit :: non_neg_integer(); 174 (Mod) -> ModAnalysis :: mod_analysis() when 175 Mod :: module(). 176 177analyse(Limit) when is_integer(Limit) -> 178 L0 = [analyse(element(1, Mod), Limit) || Mod <- code:all_loaded()], 179 L1 = [{C,M,Lm} || {M,C,Lm} <- L0, C > 0, M =/= ?MODULE], 180 N = lists:foldl(fun ({C,_,_}, Q) -> Q+C end, 0, L1), 181 L = [{M,C,Lm} || {C,M,Lm} <- lists:reverse(lists:sort(L1))], 182 {N,L}; 183analyse(M) when is_atom(M) -> 184 analyse(M, 1). 185 186-spec analyse(Mod, Limit) -> ModAnalysis :: mod_analysis() when 187 Mod :: module(), 188 Limit :: non_neg_integer(). 189 190-dialyzer({no_improper_lists, analyse/2}). 191analyse(M, Limit) when is_atom(M), is_integer(Limit) -> 192 L0 = [begin 193 MFA = {M,F,A}, 194 {_,C} = erlang:trace_info(MFA, call_count), 195 [C|MFA] 196 end || {F,A} <- M:module_info(functions)], 197 L1 = [X || [C|_]=X <- L0, is_integer(C)], 198 N = lists:foldl(fun ([C|_], Q) -> Q+C end, 0, L1), 199 L2 = [X || [C|_]=X <- L1, C >= Limit], 200 L = [{MFA,C} || [C|MFA] <- lists:reverse(lists:sort(L2))], 201 {M,N,L}. 202 203 204 205analyze() -> 206 analyse(). 207 208analyze(X) -> 209 analyse(X). 210 211analyze(X, Y) -> 212 analyse(X, Y). 213 214 215 216tr(FuncSpec, State) -> 217 erlang:trace_pattern(FuncSpec, State, [call_count]). 218