1: %%
    2: %% %CopyrightBegin%
    3: %% 
    4: %% Copyright Ericsson AB 1997-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: %% Test the garbage collector (or Memory Recycler)
   21: 
   22: -module(gc_SUITE).
   23: 
   24: -include_lib("test_server/include/test_server.hrl").
   25: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   26: 	 init_per_group/2,end_per_group/2]).
   27: 
   28: -define(default_timeout, ?t:minutes(10)).
   29: 
   30: -export([grow_heap/1, grow_stack/1, grow_stack_heap/1]).
   31: 
   32: suite() -> [{ct_hooks,[ts_install_cth]}].
   33: 
   34: all() -> 
   35:     [grow_heap, grow_stack, grow_stack_heap].
   36: 
   37: groups() -> 
   38:     [].
   39: 
   40: init_per_suite(Config) ->
   41:     Config.
   42: 
   43: end_per_suite(_Config) ->
   44:     ok.
   45: 
   46: init_per_group(_GroupName, Config) ->
   47:     Config.
   48: 
   49: end_per_group(_GroupName, Config) ->
   50:     Config.
   51: 
   52: 
   53: grow_heap(doc) -> ["Produce a growing list of elements, ",
   54: 		   "for X calls, then drop one item per call",
   55: 		   "until the list is empty."];
   56: grow_heap(Config) when is_list(Config) ->
   57:     Dog = test_server:timetrap(test_server:minutes(40)),
   58:     ok  = grow_heap1(256),
   59:     ok  = grow_heap1(512),
   60:     ok  = grow_heap1(1024),
   61:     ok  = grow_heap1(2048),
   62:     test_server:timetrap_cancel(Dog),
   63:     ok.
   64: 
   65: grow_heap1(Len) ->
   66:     io:format("~ngrow_heap with ~p items.",[Len]),
   67:     show_heap("before:"),
   68:     grow_heap1([], Len, 0, up),
   69:     show_heap("after:").
   70: 
   71: grow_heap1(List, MaxLen, MaxLen, up) ->
   72:     show_heap("top:"),
   73:     grow_heap1(List, MaxLen, MaxLen-1, down);
   74: grow_heap1(List, MaxLen, CurLen, up) ->
   75:     NewList=[make_arbit()|List],
   76:     grow_heap1(NewList, MaxLen, CurLen+1, up);
   77: grow_heap1([], _MaxLen, _, down) ->
   78:     ok;
   79: grow_heap1([_|List], MaxLen, CurLen, down) ->
   80:     {_,_,C} = erlang:now(),
   81:     Num     = C rem (length(List))+1,
   82:     Elem    = lists:nth(Num, List),
   83:     NewList = lists:delete(Elem, List),
   84:     grow_heap1(NewList, MaxLen, CurLen-1, down).
   85: 
   86: 
   87: 
   88: grow_stack(doc) -> ["Increase and decrease stack size, and ",
   89: 		    "drop off some garbage from time to time."];
   90: grow_stack(Config) when is_list(Config) ->
   91:     Dog = test_server:timetrap(test_server:minutes(80)),
   92:     show_heap("before:"),
   93:     grow_stack1(200, 0),
   94:     show_heap("after:"),
   95:     test_server:timetrap_cancel(Dog),
   96:     ok.
   97: 
   98: grow_stack1(0, _) ->
   99:     ok;
  100: grow_stack1(Recs, 0) ->
  101: %    show_heap("running:"),
  102:     grow_stack1(Recs-1, Recs),
  103:     grow_stack1(0,0);
  104: grow_stack1(Recs, CurRecs) ->
  105:     grow_stack1(Recs, CurRecs-1),
  106:     make_arbit(),
  107:     grow_stack1(1,0),
  108:     ok.
  109: 
  110: 
  111: %% Let's see how BEAM handles this one...
  112: grow_stack_heap(doc) -> ["While growing the heap, bounces the size ",
  113: 			 "of the stack, and while reducing the heap",
  114: 			 "bounces the stack usage."];
  115: grow_stack_heap(Config) when is_list(Config) ->
  116:     Dog = test_server:timetrap(test_server:minutes(40)),
  117:     grow_stack_heap1(16),
  118:     grow_stack_heap1(32),
  119:     test_server:timetrap_cancel(Dog),
  120:     ok.
  121: 
  122: grow_stack_heap1(MaxLen) ->
  123:     io:format("~ngrow_stack_heap with ~p items.",[MaxLen]),
  124:     show_heap("before:"),
  125:     grow_stack_heap1([], MaxLen, 0, up),
  126:     show_heap("after:").
  127: 
  128: grow_stack_heap1(List, MaxLen, MaxLen, up) ->
  129:     show_heap("top:"),
  130:     grow_stack_heap1(List, MaxLen, MaxLen-1, down);
  131: grow_stack_heap1(List, MaxLen, CurLen, up) ->
  132:     grow_stack1(CurLen*2,0),
  133:     grow_stack_heap1([make_arbit()|List], MaxLen, CurLen+1, up),
  134:     ok;
  135: 
  136: grow_stack_heap1([], _MaxLen, _, down) -> ok;
  137: grow_stack_heap1([_|List], MaxLen, CurLen, down) ->
  138:     grow_stack1(CurLen*2,0),
  139:     {_,_,C}=erlang:now(),
  140:     Num=C rem (length(List))+1,
  141:     Elem=lists:nth(Num, List),
  142:     NewList=lists:delete(Elem, List),
  143:     grow_stack_heap1(NewList, MaxLen, CurLen-1, down),
  144:     ok.
  145: 
  146: 
  147: %% Create an arbitrary element/term.
  148: make_arbit() ->
  149:     {AA,BB,CC}=erlang:now(),
  150:     A=AA+1, B=BB+1, C=CC+1,
  151:     New =
  152: 	case C rem 9 of
  153: 	    0 -> make_string((B div C) +5);
  154: 	    1 -> C;
  155: 	    2 -> make_ref();
  156: 	    3 -> self();
  157: 	    4 -> list_to_binary(make_string((C div B) + 12));
  158: 	    5 -> (C*B)/(A+1);
  159: 	    6 -> list_to_tuple(make_string((B div C) +5));
  160: 	    7 -> list_to_atom(make_string(((C div B) rem 254) + 2));
  161: 	    8 -> fun(X) -> {X,AA,make_string((B div C)+10)} end
  162: 	end,
  163:     New.
  164: 
  165: %% Create an arbitrary string of a certain length.
  166: make_string(Length) ->
  167:     Alph="abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"++
  168: 	"0123456789",
  169:     make_string(Alph, Length, []).
  170: 
  171: make_string(_, 0, Acc) ->
  172:     Acc;
  173: make_string(Alph, Length, Acc) ->
  174:     {_,_,C}=erlang:now(),
  175:     Pos=1+(Length*C rem length(Alph)),
  176:     make_string(Alph, Length-1, 
  177: 		[lists:nth(Pos,Alph)|Acc]).
  178: 
  179: show_heap(String) ->
  180:     garbage_collect(self()),
  181:     receive after 1 -> ok end,
  182:     {heap_size, HSize}=process_info(self(), heap_size),
  183:     {stack_size, SSize}=process_info(self(), stack_size),
  184:     io:format("Heap/Stack "++String++"~p/~p", [HSize, SSize]).
  185: