Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

289 řádky
10 KiB

před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
  1. -module(lg_SUITE).
  2. -compile(export_all).
  3. -import(ct_helper, [config/2]).
  4. -import(ct_helper, [doc/1]).
  5. %% ct.
  6. all() ->
  7. [{group, all}].
  8. %% We cannot run the tests in parallel or they would
  9. %% interfere with each other.
  10. groups() ->
  11. [{all, [], ct_helper:all(?MODULE)}].
  12. %% Tests.
  13. app(Config) ->
  14. doc("Trace a specific application."),
  15. eTpf:trace({app, stdlib}, tpTracerFile, config(priv_dir, Config) ++ "/app.lz4"),
  16. lists:seq(1, 10),
  17. eTpf:stop(),
  18. do_ensure_decompress(config(priv_dir, Config) ++ "/app.lz4").
  19. callback(Config) ->
  20. doc("Trace using patterns from a callback function."),
  21. eTpf:trace({callback, ?MODULE, do_callback}, tpTracerFile,
  22. config(priv_dir, Config) ++ "/callback.lz4"),
  23. lists:seq(1, 10),
  24. eTpf:stop(),
  25. do_ensure_decompress(config(priv_dir, Config) ++ "/callback.lz4").
  26. do_callback() ->
  27. [{scope, [self()]}, lists].
  28. callgrind_running(Config) ->
  29. doc("Save events to files on disk then build callgrind files."),
  30. PrivDir = config(priv_dir, Config),
  31. eTpf:trace([{scope, [self()]}, ?MODULE, {app, stdlib}], tpTracerFile,
  32. PrivDir ++ "/callgrind_running.lz4",
  33. #{mode => profile, running => true}),
  34. do_callgrind_running(),
  35. eTpf:stop(),
  36. tpCallGrind:pfm(
  37. PrivDir ++ "/callgrind_running.lz4.*",
  38. PrivDir ++ "/callgrind_running.out",
  39. #{running => true}),
  40. %% For debugging purposes, print the contents of the callgrind.out files.
  41. %% Uncomment for easier debugging, otherwise look into the files directly.
  42. % _ = [begin
  43. % {ok, File} = file:read_file(PrivDir ++ "/callgrind_running.out." ++ integer_to_list(N)),
  44. % io:format(user, "# callgrind_running.out.~p~n~s", [N, File]),
  45. % lg_file_reader:foreach(fun(E) -> io:format(user, "~p~n", [E]) end,
  46. % PrivDir ++ "/callgrind_running.lz4." ++ integer_to_list(N))
  47. % end || N <- lists:seq(1, erlang:system_info(schedulers))],
  48. ok.
  49. do_callgrind_running() ->
  50. timer:sleep(1000),
  51. Ref = make_ref(),
  52. erlang:send_after(1000, self(), {go, Ref}),
  53. lists:seq(1, 100),
  54. do_callgrind_running_receive(Ref),
  55. lists:seq(1, 100),
  56. ok.
  57. do_callgrind_running_receive(Ref) ->
  58. receive
  59. {go, Ref} ->
  60. ok
  61. end.
  62. callgrind_running_cycle(Config) ->
  63. doc("Save events to files on disk then build callgrind files. "
  64. "Create a recursive cycle using two functions calling each other."),
  65. PrivDir = config(priv_dir, Config),
  66. eTpf:trace([{scope, [self()]}, ?MODULE, {app, stdlib}], tpTracerFile,
  67. PrivDir ++ "/callgrind_running_cycle.lz4",
  68. #{mode => profile, running => true}),
  69. do_callgrind_running_cycle(),
  70. eTpf:stop(),
  71. tpCallGrind:pfm(
  72. PrivDir ++ "/callgrind_running_cycle.lz4.*",
  73. PrivDir ++ "/callgrind_running_cycle.out",
  74. #{running => true}),
  75. %% For debugging purposes, print the contents of the callgrind.out files.
  76. %% Uncomment for easier debugging, otherwise look into the files directly.
  77. % _ = [begin
  78. % {ok, File} = file:read_file(PrivDir ++ "/callgrind_running_cycle.out." ++ integer_to_list(N)),
  79. % io:format(user, "# callgrind_running_cycle.out.~p~n~s", [N, File]),
  80. % lg_file_reader:foreach(fun(E) -> io:format(user, "~p~n", [E]) end,
  81. % PrivDir ++ "/callgrind_running_cycle.lz4." ++ integer_to_list(N))
  82. % end || N <- lists:seq(1, erlang:system_info(schedulers))],
  83. ok.
  84. do_callgrind_running_cycle() ->
  85. timer:sleep(1000),
  86. lists:seq(1, 100),
  87. do_callgrind_running_cycle1(do_callgrind_running_cycle_timer(20)),
  88. lists:seq(1, 100),
  89. ok.
  90. do_callgrind_running_cycle_timer(N) ->
  91. erlang:start_timer(N * 10, self(), N).
  92. do_callgrind_running_cycle1(Ref) ->
  93. receive
  94. {timeout, Ref, 0} ->
  95. ok;
  96. {timeout, Ref, N} when N rem 5 =:= 0 ->
  97. do_callgrind_running_cycle2(do_callgrind_running_cycle_timer(N - 1));
  98. {timeout, Ref, N} ->
  99. do_callgrind_running_cycle1(do_callgrind_running_cycle_timer(N - 1))
  100. end.
  101. do_callgrind_running_cycle2(Ref) ->
  102. receive
  103. {timeout, Ref, 0} ->
  104. ok;
  105. {timeout, Ref, N} when N rem 4 =:= 0 ->
  106. do_callgrind_running_cycle1(do_callgrind_running_cycle_timer(N - 1));
  107. {timeout, Ref, N} ->
  108. do_callgrind_running_cycle2(do_callgrind_running_cycle_timer(N - 1))
  109. end.
  110. file_tracer(Config) ->
  111. doc("Save events to files on disk."),
  112. eTpf:trace(lists, tpTracerFile, config(priv_dir, Config) ++ "/file_tracer.lz4"),
  113. lists:seq(1, 10),
  114. eTpf:stop(),
  115. do_ensure_decompress(config(priv_dir, Config) ++ "/file_tracer.lz4").
  116. file_tracer_rotation(Config) ->
  117. doc("Save events to files on disk; rotate the files if they get too big."),
  118. Prefix = config(priv_dir, Config) ++ "/file_tracer.lz4",
  119. eTpf:trace(lists, tpTracerFile, #{
  120. fBaseName => Prefix,
  121. fMaxSize => 100, %% Intentionally low.
  122. fMaxLog => 10 %% Needed to trigger the rotation, default is too high.
  123. }),
  124. lists:seq(1, 1000),
  125. eTpf:stop(),
  126. %% We should have one or more rotated files.
  127. Result = [begin
  128. Filename = Prefix ++ "." ++ integer_to_list(N) ++ ".bak",
  129. filelib:is_file(Filename)
  130. end || N <- lists:seq(1, erlang:system_info(schedulers))],
  131. true = lists:member(true, lists:usort(Result)),
  132. ok.
  133. mod(Config) ->
  134. doc("Trace a specific module."),
  135. eTpf:trace(lists, tpTracerFile, config(priv_dir, Config) ++ "/mod.lz4"),
  136. lists:seq(1, 10),
  137. eTpf:stop(),
  138. do_ensure_decompress(config(priv_dir, Config) ++ "/mod.lz4").
  139. profile_mode(Config) ->
  140. doc("Trace a specific module in profile mode."),
  141. eTpf:trace(lists, tpTracerFile, config(priv_dir, Config) ++ "/profile_mode.lz4",
  142. #{mode => profile}),
  143. lists:seq(1, 10),
  144. eTpf:stop(),
  145. do_ensure_decompress(config(priv_dir, Config) ++ "/profile_mode.lz4").
  146. raw_console_tracer(_) ->
  147. doc("Print raw events to the console."),
  148. ct:print("Start tracing to the console."),
  149. %% @todo It seems the order matters when starting. Should it?
  150. eTpf:trace([{scope, [self()]}, lists]),
  151. lists:seq(1, 10),
  152. eTpf:stop(),
  153. ct:print("Stop tracing to the console.").
  154. running_true(Config) ->
  155. doc("Trace a specific module with running option enabled."),
  156. eTpf:trace(lists, tpTracerFile, config(priv_dir, Config) ++ "/running_true.lz4",
  157. #{running => true}),
  158. lists:seq(1, 10),
  159. eTpf:stop(),
  160. do_ensure_decompress(config(priv_dir, Config) ++ "/running_true.lz4").
  161. send_true(Config) ->
  162. doc("Trace a specific module with send option enabled."),
  163. eTpf:trace(lists, tpTracerFile, config(priv_dir, Config) ++ "/send_true.lz4",
  164. #{send => true}),
  165. Self = self(),
  166. %% Send a message to and from an existing process.
  167. Pid = spawn(fun() ->
  168. receive {msg_from, Self} ->
  169. Self ! {msg_from, self()}
  170. end
  171. end),
  172. Pid ! {msg_from, Self},
  173. receive {msg_from, Pid} -> ok end,
  174. %% Also send a message to a non existing process.
  175. DeadPid = spawn(fun() -> ok end),
  176. receive after 100 -> ok end,
  177. DeadPid ! {msg_from, Self},
  178. eTpf:stop(),
  179. do_ensure_decompress(config(priv_dir, Config) ++ "/send_true.lz4").
  180. socket_tracer(_) ->
  181. doc("Send events to a socket."),
  182. Port = 61234,
  183. eTpf:trace(lists, tpTracerSocket, Port, #{poolSize => 1}),
  184. {ok, Socket} = gen_tcp:connect("localhost", Port,
  185. [binary, {packet, 2}, {active, true}]),
  186. lists:seq(1, 10),
  187. eTpf:stop(),
  188. do_socket_tracer_recv(Socket).
  189. socket_tracer_client(Config) ->
  190. doc("Send events to a socket client."),
  191. Port = 61234,
  192. eTpf:trace(lists, tpTracerSocket, Port, #{poolSize => 1}),
  193. BaseFilename = config(priv_dir, Config) ++ "/socket_tracer_client.lz4",
  194. {ok, Pid} = tpSocketCli:start_link(Port, BaseFilename),
  195. timer:sleep(1000),
  196. lists:seq(1, 10),
  197. eTpf:stop(),
  198. tpSocketCli:stop(Pid),
  199. {ok, File} = file:read_file(BaseFilename ++ ".0"),
  200. _ = lz4f:decompress(File),
  201. true = filelib:file_size(BaseFilename ++ ".0") > 0,
  202. ok.
  203. socket_tracer_many(_) ->
  204. doc("Send events to many sockets."),
  205. Port = 61234,
  206. eTpf:trace(lists, tpTracerSocket, Port, #{poolSize => 5}),
  207. {ok, _} = gen_tcp:connect("localhost", Port, []),
  208. {ok, _} = gen_tcp:connect("localhost", Port + 1, []),
  209. {ok, _} = gen_tcp:connect("localhost", Port + 2, []),
  210. {ok, _} = gen_tcp:connect("localhost", Port + 3, []),
  211. {ok, _} = gen_tcp:connect("localhost", Port + 4, []),
  212. {error, _} = gen_tcp:connect("localhost", Port + 5, []),
  213. eTpf:stop().
  214. socket_tracer_reconnect(_) ->
  215. doc("Confirm we can reconnect to the tracer."),
  216. Port = 61234,
  217. eTpf:trace(lists, tpTracerSocket, Port, #{poolSize => 1}),
  218. {ok, Socket0} = gen_tcp:connect("localhost", Port,
  219. [binary, {packet, 2}, {active, true}]),
  220. ok = gen_tcp:close(Socket0),
  221. {ok, Socket} = gen_tcp:connect("localhost", Port,
  222. [binary, {packet, 2}, {active, true}]),
  223. lists:seq(1, 10),
  224. eTpf:stop(),
  225. do_socket_tracer_recv(Socket).
  226. do_socket_tracer_recv(Socket) ->
  227. receive
  228. {tcp, Socket, Data} ->
  229. Term = binary_to_term(Data),
  230. true = is_tuple(Term),
  231. do_socket_tracer_recv(Socket);
  232. {tcp_closed, Socket} ->
  233. ok
  234. after 1000 ->
  235. error(timeout)
  236. end.
  237. stop_while_trace_is_running(Config) ->
  238. doc("Stop tracing while events are still coming in."),
  239. Self = self(),
  240. Pid = spawn_link(fun() -> Self ! {self(), continue}, lists:seq(1, 10000000) end),
  241. eTpf:trace([{scope, [Pid]}, lists], tpTracerFile,
  242. config(priv_dir, Config) ++ "/stop_while_trace_is_running.lz4"),
  243. receive {Pid, continue} -> ok after 100 -> error(timeout) end,
  244. eTpf:stop(),
  245. do_ensure_decompress(config(priv_dir, Config) ++ "/stop_while_trace_is_running.lz4").
  246. %% Internal.
  247. do_ensure_decompress(Prefix) ->
  248. %% Ensure the files can be decompressed.
  249. Sizes = [begin
  250. Filename = Prefix ++ "." ++ integer_to_list(N),
  251. {ok, File} = file:read_file(Filename),
  252. _ = lz4f:decompress(File),
  253. filelib:file_size(Filename)
  254. end || N <- lists:seq(1, erlang:system_info(schedulers))],
  255. %% We also need to make sure there is actual data in the files,
  256. %% as lz4f:decompress will succeed when provided with no data.
  257. true = 0 < lists:sum(Sizes),
  258. ok.