%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2012-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% -module(dyntrace_lttng_SUITE). -include_lib("common_test/include/ct.hrl"). -export([all/0, suite/0]). -export([init_per_suite/1, end_per_suite/1]). -export([init_per_testcase/2, end_per_testcase/2]). %% Test cases -export([t_lttng_list/1, t_procs/1, t_ports/1, t_running_process/1, t_running_port/1, t_call/1, t_call_return_to/1, t_call_silent/1, t_send/1, t_receive/1, t_garbage_collection/1, t_all/1]). suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap, {seconds, 10}}]. all() -> [t_lttng_list, t_procs, t_ports, t_running_process, t_running_port, t_call, t_call_return_to, t_call_silent, t_send, t_receive, t_garbage_collection, t_all]. init_per_suite(Config) -> case erlang:system_info(dynamic_trace) of lttng -> ensure_lttng_stopped("--all"), Config; _ -> {skip, "No LTTng configured on system."} end. end_per_suite(_Config) -> ensure_lttng_stopped("--all"), ok. init_per_testcase(Case, Config) -> %% ensure loaded _ = dyntrace:module_info(), Name = atom_to_list(Case), ok = ensure_lttng_started(Name, Config), [{session, Name}|Config]. end_per_testcase(Case, _Config) -> Name = atom_to_list(Case), ok = ensure_lttng_stopped(Name), ok. %% tracepoints %% %% org_erlang_dyntrace:gc_major_end %% org_erlang_dyntrace:gc_major_start %% org_erlang_dyntrace:gc_minor_end %% org_erlang_dyntrace:gc_minor_start %% org_erlang_dyntrace:message_receive %% org_erlang_dyntrace:message_send %% -org_erlang_dyntrace:message_queued %% org_erlang_dyntrace:function_exception %% org_erlang_dyntrace:function_return %% org_erlang_dyntrace:function_call %% org_erlang_dyntrace:port_link %% org_erlang_dyntrace:port_exit %% org_erlang_dyntrace:port_open %% org_erlang_dyntrace:port_scheduled %% org_erlang_dyntrace:process_scheduled %% org_erlang_dyntrace:process_register %% org_erlang_dyntrace:process_exit %% org_erlang_dyntrace:process_link %% org_erlang_dyntrace:process_spawn %% %% Testcases %% t_lttng_list(_Config) -> {ok, _} = cmd("lttng list -u"), ok. t_procs(Config) when is_list(Config) -> ok = lttng_start_event("org_erlang_dyntrace:process_*", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},procs]), Pid = spawn_link(fun() -> waiter() end), Pid ! {self(), ok}, ok = receive {Pid,ok} -> ok end, timer:sleep(1000), _ = erlang:trace(all, false, [procs]), Res = lttng_stop_and_view(Config), ok = check_tracepoint("org_erlang_dyntrace:process_spawn", Res), ok = check_tracepoint("org_erlang_dyntrace:process_link", Res), ok = check_tracepoint("org_erlang_dyntrace:process_exit", Res), ok = check_tracepoint("org_erlang_dyntrace:process_register", Res), ok. t_ports(Config) when is_list(Config) -> ok = lttng_start_event("org_erlang_dyntrace:port_*", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},ports]), _ = os:cmd("ls"), _ = erlang:trace(all, false, [{tracer, dyntrace, []},ports]), Res = lttng_stop_and_view(Config), ok = check_tracepoint("org_erlang_dyntrace:port_open", Res), ok = check_tracepoint("org_erlang_dyntrace:port_link", Res), ok = check_tracepoint("org_erlang_dyntrace:port_exit", Res), ok. t_running_process(Config) when is_list(Config) -> ok = lttng_start_event("org_erlang_dyntrace:process_scheduled", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},running]), Pid = spawn_link(fun() -> waiter() end), Pid ! {self(), ok}, ok = receive {Pid,ok} -> ok end, timer:sleep(1000), _ = erlang:trace(all, false, [running]), Res = lttng_stop_and_view(Config), ok = check_tracepoint("org_erlang_dyntrace:process_scheduled", Res), ok. t_running_port(Config) when is_list(Config) -> ok = lttng_start_event("org_erlang_dyntrace:port_scheduled", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},running_ports]), _ = os:cmd("ls"), _ = os:cmd("ls"), _ = erlang:trace(all, false, [running_ports]), Res = lttng_stop_and_view(Config), ok = check_tracepoint("org_erlang_dyntrace:port_scheduled", Res), ok. t_call(Config) when is_list(Config) -> ok = lttng_start_event("org_erlang_dyntrace:function_*", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []}, call]), _ = erlang:trace_pattern({?MODULE, '_', '_'}, [{'_',[],[{exception_trace}]}], [local]), DontLink = spawn(fun() -> foo_clause_exception(nope) end), Pid = spawn_link(fun() -> waiter() end), Pid ! {self(), ok}, ok = receive {Pid,ok} -> ok end, timer:sleep(10), undefined = erlang:process_info(DontLink), _ = erlang:trace_pattern({?MODULE, '_', '_'}, false, [local]), _ = erlang:trace(all, false, [call]), Res = lttng_stop_and_view(Config), ok = check_tracepoint("org_erlang_dyntrace:function_call", Res), ok = check_tracepoint("org_erlang_dyntrace:function_return", Res), ok = check_tracepoint("org_erlang_dyntrace:function_exception", Res), ok. t_send(Config) when is_list(Config) -> ok = lttng_start_event("org_erlang_dyntrace:message_send", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},send]), Pid = spawn_link(fun() -> waiter() end), Pid ! {self(), ok}, ok = receive {Pid,ok} -> ok end, _ = os:cmd("ls"), timer:sleep(10), _ = erlang:trace(all, false, [send]), Res = lttng_stop_and_view(Config), ok = check_tracepoint("org_erlang_dyntrace:message_send", Res), ok. t_call_return_to(Config) when is_list(Config) -> ok = lttng_start_event("org_erlang_dyntrace:function_*", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []}, call, return_to]), _ = erlang:trace_pattern({lists, '_', '_'}, true, [local]), _ = erlang:trace_pattern({?MODULE, '_', '_'}, true, [local]), Pid = spawn_link(fun() -> gcfier(10) end), Pid ! {self(), ok}, ok = receive {Pid,ok} -> ok end, timer:sleep(10), _ = erlang:trace_pattern({?MODULE, '_', '_'}, false, [local]), _ = erlang:trace_pattern({lists, '_', '_'}, false, [local]), _ = erlang:trace(all, false, [call,return_to]), Res = lttng_stop_and_view(Config), ok = check_tracepoint("org_erlang_dyntrace:function_call", Res), ok. t_call_silent(Config) when is_list(Config) -> ok = lttng_start_event("org_erlang_dyntrace:function_*", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []}, call, silent]), _ = erlang:trace_pattern({?MODULE, '_', '_'}, [{'_',[],[{exception_trace}]}], [local]), DontLink = spawn(fun() -> foo_clause_exception(nope) end), Pid = spawn_link(fun() -> waiter() end), Pid ! {self(), ok}, ok = receive {Pid,ok} -> ok end, timer:sleep(10), undefined = erlang:process_info(DontLink), _ = erlang:trace_pattern({?MODULE, '_', '_'}, false, [local]), _ = erlang:trace(all, false, [call]), Res = lttng_stop_and_view(Config), notfound = check_tracepoint("org_erlang_dyntrace:function_call", Res), notfound = check_tracepoint("org_erlang_dyntrace:function_return", Res), notfound = check_tracepoint("org_erlang_dyntrace:function_exception", Res), ok. t_receive(Config) when is_list(Config) -> ok = lttng_start_event("org_erlang_dyntrace:message_receive", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},'receive']), timer:sleep(20), Pid1 = spawn_link(fun() -> waiter() end), Pid1 ! {self(), ok}, ok = receive {Pid1,ok} -> ok end, Pid2 = spawn_link(fun() -> waiter() end), Pid2 ! {self(), ok}, ok = receive {Pid2,ok} -> ok end, timer:sleep(10), _ = erlang:trace(all, false, ['receive']), Res = lttng_stop_and_view(Config), ok = check_tracepoint("org_erlang_dyntrace:message_receive", Res), ok. t_garbage_collection(Config) when is_list(Config) -> ok = lttng_start_event("org_erlang_dyntrace:gc_*", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},garbage_collection]), Pid = spawn_link(fun() -> gcfier() end), Pid ! {self(), ok}, ok = receive {Pid,ok} -> ok end, timer:sleep(10), _ = erlang:trace(all, false, [garbage_collection]), Res = lttng_stop_and_view(Config), ok = check_tracepoint("org_erlang_dyntrace:gc_major_start", Res), ok = check_tracepoint("org_erlang_dyntrace:gc_major_end", Res), ok = check_tracepoint("org_erlang_dyntrace:gc_minor_start", Res), ok = check_tracepoint("org_erlang_dyntrace:gc_minor_end", Res), ok. t_all(Config) when is_list(Config) -> ok = lttng_start_event("org_erlang_dyntrace:*", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},all]), Pid1 = spawn_link(fun() -> waiter() end), Pid1 ! {self(), ok}, ok = receive {Pid1,ok} -> ok end, Pid2 = spawn_link(fun() -> gcfier() end), Pid2 ! {self(), ok}, ok = receive {Pid2,ok} -> ok end, _ = os:cmd("ls"), _ = os:cmd("ls"), timer:sleep(10), _ = erlang:trace(all, false, [all]), Res = lttng_stop_and_view(Config), ok = check_tracepoint("org_erlang_dyntrace:process_spawn", Res), ok = check_tracepoint("org_erlang_dyntrace:process_link", Res), ok = check_tracepoint("org_erlang_dyntrace:process_exit", Res), ok = check_tracepoint("org_erlang_dyntrace:process_register", Res), ok = check_tracepoint("org_erlang_dyntrace:port_open", Res), ok = check_tracepoint("org_erlang_dyntrace:port_link", Res), ok = check_tracepoint("org_erlang_dyntrace:port_exit", Res), ok = check_tracepoint("org_erlang_dyntrace:process_scheduled", Res), ok = check_tracepoint("org_erlang_dyntrace:port_scheduled", Res), ok = check_tracepoint("org_erlang_dyntrace:message_send", Res), ok = check_tracepoint("org_erlang_dyntrace:message_receive", Res), ok = check_tracepoint("org_erlang_dyntrace:gc_major_start", Res), ok = check_tracepoint("org_erlang_dyntrace:gc_major_end", Res), ok = check_tracepoint("org_erlang_dyntrace:gc_minor_start", Res), ok = check_tracepoint("org_erlang_dyntrace:gc_minor_end", Res), ok. %% aux gcfier() -> gcfier(10000). gcfier(N) -> receive {Pid, ok} -> _ = lists:reverse(lists:seq(1,N)), true = erlang:garbage_collect(), Pid ! {self(), ok} end. waiter() -> true = register(?MODULE, self()), receive {Pid, ok} -> Child = spawn(fun() -> receive ok -> ok end end), link(Child), unlink(Child), _ = lists:seq(1,1000), Child ! ok, true = unregister(?MODULE), Pid ! {self(),ok} end. foo_clause_exception({1,2}) -> badness. %% lttng lttng_stop_and_view(Config) -> Path = proplists:get_value(priv_dir, Config), Name = proplists:get_value(session, Config), {ok,_} = cmd("lttng stop " ++ Name), {ok,Res} = cmd("lttng view " ++ Name ++ " --trace-path=" ++ Path), Res. check_tracepoint(TP, Data) -> case re:run(Data, TP, [global]) of {match, _} -> ok; _ -> notfound end. lttng_start_event(Event, Config) -> Name = proplists:get_value(session, Config), {ok, _} = cmd("lttng enable-event -u " ++ Event ++ " --session=" ++ Name), {ok, _} = cmd("lttng start " ++ Name), ok. ensure_lttng_started(Name, Config) -> Out = case proplists:get_value(priv_dir, Config) of undefined -> []; Path -> "--output="++Path++" " end, {ok,_} = cmd("lttng create " ++ Out ++ Name), ok. ensure_lttng_stopped(Name) -> {ok,_} = cmd("lttng stop"), {ok,_} = cmd("lttng destroy " ++ Name), ok. cmd(Cmd) -> io:format("<< ~ts~n", [Cmd]), Res = os:cmd(Cmd), io:format(">> ~ts~n", [Res]), {ok,Res}.