gproc_info.erl 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
  2. %% --------------------------------------------------
  3. %% This file is provided to you under the Apache License,
  4. %% Version 2.0 (the "License"); you may not use this file
  5. %% except in compliance with the License. You may obtain
  6. %% a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing,
  11. %% software distributed under the License is distributed on an
  12. %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  13. %% KIND, either express or implied. See the License for the
  14. %% specific language governing permissions and limitations
  15. %% under the License.
  16. %% --------------------------------------------------
  17. %%
  18. %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
  19. %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
  20. %% AB. All Rights Reserved.''
  21. %%
  22. %% @author Ulf Wiger <ulf@wiger.net>
  23. %%
  24. -module(gproc_info).
  25. -export([i/0]).
  26. -import(lists, [foldl/3]).
  27. -import(io, [format/2]).
  28. %% c:i() extended with gproc info
  29. -spec i() -> 'ok'.
  30. i() -> i(processes()).
  31. -spec i([pid()]) -> 'ok'.
  32. i(Ps) ->
  33. i(Ps, length(Ps)).
  34. -spec i([pid()], non_neg_integer()) -> 'ok'.
  35. i(Ps, N) when N =< 100 ->
  36. iformat("Pid", "Initial Call", "Heap", "Reds",
  37. "Msgs"),
  38. iformat("Registered", "Current Function", "Stack", "",
  39. ""),
  40. {R,M,H,S} = foldl(fun(Pid, {R0,M0,H0,S0}) ->
  41. {A,B,C,D} = display_info(Pid),
  42. {R0+A,M0+B,H0+C,S0+D}
  43. end, {0,0,0,0}, Ps),
  44. iformat("Total", "", w(H), w(R), w(M)),
  45. iformat("", "", w(S), "", "");
  46. i(Ps, N) ->
  47. iformat("Pid", "Initial Call", "Heap", "Reds",
  48. "Msgs"),
  49. iformat("Registered", "Current Function", "Stack", "",
  50. ""),
  51. paged_i(Ps, {0,0,0,0}, N, 50).
  52. paged_i([], {R,M,H,S}, _, _) ->
  53. iformat("Total", "", w(H), w(R), w(M)),
  54. iformat("", "", w(S), "", "");
  55. paged_i(Ps, Acc, N, Page) ->
  56. {Pids, Rest, N1} =
  57. if N > Page ->
  58. {L1,L2} = lists:split(Page, Ps),
  59. {L1,L2,N-Page};
  60. true ->
  61. {Ps, [], 0}
  62. end,
  63. NewAcc = foldl(fun(Pid, {R,M,H,S}) ->
  64. {A,B,C,D} = display_info(Pid),
  65. {R+A,M+B,H+C,S+D}
  66. end, Acc, Pids),
  67. case Rest of
  68. [_|_] ->
  69. choice(fun() -> paged_i(Rest, NewAcc, N1, Page) end);
  70. [] ->
  71. paged_i([], NewAcc, 0, Page)
  72. end.
  73. choice(F) ->
  74. case get_line('(c)ontinue (q)uit -->', "c\n") of
  75. "c\n" ->
  76. F();
  77. <<"c\n">> ->
  78. F();
  79. "q\n" ->
  80. quit;
  81. <<"q\n">> ->
  82. quit;
  83. _ ->
  84. choice(F)
  85. end.
  86. iformat(A1, A2, A3, A4, A5) ->
  87. format("~-21s ~-33s ~8s ~8s ~4s~n", [A1,A2,A3,A4,A5]).
  88. get_line(P, Default) ->
  89. case io:get_line(P) of
  90. "\n" ->
  91. Default;
  92. L ->
  93. L
  94. end.
  95. w(X) ->
  96. io_lib:write(X).
  97. w(X, L) ->
  98. S = lists:flatten(io_lib:format("~w", [X])),
  99. case length(S) of
  100. Len when Len > L ->
  101. lists:sublist(S, 1, L-3) ++ "...";
  102. _ ->
  103. S
  104. end.
  105. display_info(Pid) ->
  106. Res = c:display_info(Pid),
  107. {gproc, GI} = gproc:info(Pid, gproc),
  108. case GI of
  109. [] ->
  110. skip;
  111. _ ->
  112. display_gproc_info("Gproc: ", [{n, N,S,V} || {{n,S,N},V} <- GI]),
  113. display_gproc_info(" ", [{p, N,S,V} || {{p,S,N},V} <- GI])
  114. end,
  115. Res.
  116. display_gproc_info(_, []) ->
  117. skip;
  118. display_gproc_info(Hdr, [H|T] = Entries) ->
  119. L = 3 + length(Hdr),
  120. Max = 78 - L - 8,
  121. {Ck, Cv} = info_cols(Entries, Max),
  122. Fmt = fun(I, {Type, K, Sc, V}) ->
  123. if Cv == 0 ->
  124. io_lib:format(
  125. I ++ "~w,~w: ~-" ++ i2l(Ck)
  126. ++ "s ~n", [Type, Sc, w(K, Ck)]);
  127. true ->
  128. io_lib:format(
  129. I ++ "~w,~w: ~-" ++ i2l(Ck)
  130. ++ "s | ~-" ++ i2l(Cv) ++ "s~n",
  131. [Type, Sc, w(K, Ck), w(V, Cv)])
  132. end
  133. end,
  134. format(" ~s~s", [Hdr, Fmt("", H)]),
  135. Indent = lists:duplicate(L, $\s),
  136. lists:foreach(
  137. fun(X) ->
  138. io:format(Fmt(Indent, X))
  139. end, T).
  140. info_cols(L, Max) ->
  141. case [V || {_,_,_,V} <- L, V =/= undefined] of
  142. [] ->
  143. {Max, 0};
  144. _ ->
  145. KMax = lists:max([w_length(K) || {_,K,_,_} <- L]),
  146. Ck = erlang:min(KMax, round(Max*2/3)),
  147. {Ck, Max - Ck}
  148. end.
  149. w_length(Term) ->
  150. lists:flatlength(io_lib:format("~w", [Term])).
  151. i2l(I) ->
  152. integer_to_list(I).