1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2005-2017. 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 21-module(erts_debug_SUITE). 22-include_lib("common_test/include/ct.hrl"). 23 24-export([all/0, suite/0, 25 test_size/1,flat_size_big/1,df/1,term_type/1, 26 instructions/1, stack_check/1]). 27 28suite() -> 29 [{ct_hooks,[ts_install_cth]}, 30 {timetrap, {minutes, 2}}]. 31 32all() -> 33 [test_size, flat_size_big, df, instructions, term_type, 34 stack_check]. 35 36test_size(Config) when is_list(Config) -> 37 ConsCell1 = id([a|b]), 38 ConsCell2 = id(ConsCell1), 39 ConsCellSz = 2, 40 41 0 = do_test_size([]), 42 0 = do_test_size(42), 43 ConsCellSz = do_test_size(ConsCell1), 44 1 = do_test_size({}), 45 2 = do_test_size({[]}), 46 3 = do_test_size({a,b}), 47 7 = do_test_size({a,[b,c]}), 48 8 = do_test_size(#{b => 2,c => 3}), 49 4 = do_test_size(#{}), 50 32 = do_test_size(#{b => 2,c => 3,txt => "hello world"}), 51 52 true = do_test_size(maps:from_list([{I,I}||I<-lists:seq(1,256)])) >= map_size_lower_bound(256), 53 true = do_test_size(maps:from_list([{I,I}||I<-lists:seq(1,4096)])) >= map_size_lower_bound(4096), 54 true = do_test_size(maps:from_list([{I,I}||I<-lists:seq(1,254)])) >= map_size_lower_bound(254), 55 true = do_test_size(maps:from_list([{I,I}||I<-lists:seq(1,239)])) >= map_size_lower_bound(239), 56 57 %% Test internal consistency of sizes, but without testing 58 %% exact sizes. 59 Const = id(42), 60 AnotherConst = id(7), 61 62 %% Fun environment size = 0 (the smallest fun possible) 63 SimplestFun = fun() -> ok end, 64 FunSz0 = do_test_size(SimplestFun), 65 66 %% Fun environment size = 1 67 FunSz1 = do_test_size(fun() -> Const end), 68 FunSz1 = FunSz0 + 1, 69 70 %% Fun environment size = 2 71 FunSz2 = do_test_size(fun() -> Const+AnotherConst end), 72 FunSz2 = FunSz1 + 1, 73 74 FunSz1 = do_test_size(fun() -> ConsCell1 end) - do_test_size(ConsCell1), 75 76 %% Test shared data structures. 77 do_test_size([ConsCell1|ConsCell1], 78 3*ConsCellSz, 79 2*ConsCellSz), 80 do_test_size(fun() -> {ConsCell1,ConsCell2} end, 81 FunSz2 + 2*ConsCellSz, 82 FunSz2 + ConsCellSz), 83 do_test_size({SimplestFun,SimplestFun}, 84 2*FunSz0+do_test_size({a,b}), 85 FunSz0+do_test_size({a,b})), 86 87 M = id(#{ "atom" => first, i => 0}), 88 do_test_size([M,M#{ "atom" := other },M#{i := 42}],54,32), 89 ok. 90 91do_test_size(Term) -> 92 Sz = erts_debug:flat_size(Term), 93 Sz = erts_debug:size(Term). 94 95do_test_size(Term, FlatSz, Sz) -> 96 FlatSz = erts_debug:flat_size(Term), 97 Sz = erts_debug:size(Term). 98 99map_size_lower_bound(N) -> 100 %% this est. is a bit lower that actual lower bound 101 %% number of internal nodes 102 T = (N - 1) div 15, 103 %% total words 104 2 + 17 * T + 2 * N. 105 106flat_size_big(Config) when is_list(Config) -> 107 %% Build a term whose external size only fits in a big num (on 32-bit CPU). 108 flat_size_big_1(16#11111111111111117777777777777777888889999, 0, 16#FFFFFFF). 109 110flat_size_big_1(Term, Size0, Limit) when Size0 < Limit -> 111 case erts_debug:flat_size(Term) of 112 Size when is_integer(Size), Size0 < Size -> 113 io:format("~p", [Size]), 114 flat_size_big_1([Term|Term], Size, Limit) 115 end; 116flat_size_big_1(_, _, _) -> ok. 117 118 119term_type(Config) when is_list(Config) -> 120 Ts = [{fixnum, 1}, 121 {fixnum, -1}, 122 {bignum, 1 bsl 300}, 123 {bignum, -(1 bsl 300)}, 124 {hfloat, 0.0}, 125 {hfloat, 0.0/-1}, 126 {hfloat, 1.0/(1 bsl 302)}, 127 {hfloat, 1.0*(1 bsl 302)}, 128 {hfloat, -1.0/(1 bsl 302)}, 129 {hfloat, -1.0*(1 bsl 302)}, 130 {hfloat, 3.1416}, 131 {hfloat, 1.0e18}, 132 {hfloat, -3.1416}, 133 {hfloat, -1.0e18}, 134 135 {heap_binary, <<1,2,3>>}, 136 {refc_binary, <<0:(8*80)>>}, 137 {sub_binary, <<5:7>>}, 138 139 {flatmap, #{ a => 1}}, 140 {hashmap, maps:from_list([{I,I}||I <- lists:seq(1,76)])}, 141 142 {list, [1,2,3]}, 143 {nil, []}, 144 {tuple, {1,2,3}}, 145 {tuple, {}}, 146 147 {export, fun lists:sort/1}, 148 {'fun', fun() -> ok end}, 149 {pid, self()}, 150 {atom, atom}], 151 lists:foreach(fun({E,Val}) -> 152 R = erts_internal:term_type(Val), 153 io:format("expecting term type ~w, got ~w (~p)~n", [E,R,Val]), 154 E = R 155 end, Ts), 156 ok. 157 158 159df(Config) when is_list(Config) -> 160 P0 = pps(), 161 PrivDir = proplists:get_value(priv_dir, Config), 162 ok = file:set_cwd(PrivDir), 163 164 AllLoaded = [M || {M,_} <- code:all_loaded()], 165 {Pid,Ref} = spawn_monitor(fun() -> df_smoke(AllLoaded) end), 166 receive 167 {'DOWN',Ref,process,Pid,Status} -> 168 normal = Status 169 after 20*1000 -> 170 %% Not finished (i.e. a slow computer). Stop now. 171 Pid ! stop, 172 receive 173 {'DOWN',Ref,process,Pid,Status} -> 174 normal = Status, 175 io:format("...") 176 end 177 end, 178 io:nl(), 179 _ = [_ = file:delete(atom_to_list(M) ++ ".dis") || 180 M <- AllLoaded], 181 182 true = (P0 == pps()), 183 ok. 184 185stack_check(Config) when is_list(Config) -> 186 erts_debug:set_internal_state(available_internal_state,true), 187 %% Recurses on the C stack until stacklimit is reached. That 188 %% is, tests that the stack limit functionality works (used 189 %% by PCRE). VM will crash if it doesn't work... 190 Size = erts_debug:get_internal_state(stack_check), 191 erts_debug:set_internal_state(available_internal_state,false), 192 {comment, "Stack size: "++integer_to_list(Size)++" bytes"}. 193 194df_smoke([M|Ms]) -> 195 io:format("~p", [M]), 196 erts_debug:df(M), 197 receive 198 stop -> 199 ok 200 after 0 -> 201 df_smoke(Ms) 202 end; 203df_smoke([]) -> ok. 204 205pps() -> 206 {erlang:ports()}. 207 208instructions(Config) when is_list(Config) -> 209 Is = erts_debug:instructions(), 210 _ = [list_to_atom(I) || I <- Is], 211 ok. 212 213id(I) -> 214 I. 215