diff options
Diffstat (limited to 'lib/dtrace/src')
-rw-r--r-- | lib/dtrace/src/Makefile | 102 | ||||
-rw-r--r-- | lib/dtrace/src/dtrace.app.src | 27 | ||||
-rw-r--r-- | lib/dtrace/src/dtrace.appup.src | 19 | ||||
-rw-r--r-- | lib/dtrace/src/dtrace.erl | 216 |
4 files changed, 364 insertions, 0 deletions
diff --git a/lib/dtrace/src/Makefile b/lib/dtrace/src/Makefile new file mode 100644 index 0000000000..d613402a63 --- /dev/null +++ b/lib/dtrace/src/Makefile @@ -0,0 +1,102 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(DTRACE_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/dtrace-$(VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- + +MODULES= \ + dtrace + +HRL_FILES= \ + +INTERNAL_HRL_FILES= \ + +ERL_FILES= $(MODULES:%=%.erl) +EXAMPLE_FILES= \ + ../examples/* + +TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET) + +EXECUTABLES= \ + +APP_FILE= dtrace.app + +APP_SRC= $(APP_FILE).src +APP_TARGET= $(EBIN)/$(APP_FILE) + +APPUP_FILE= dtrace.appup + +APPUP_SRC= $(APPUP_FILE).src +APPUP_TARGET= $(EBIN)/$(APPUP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_COMPILE_FLAGS += \ + -I../include \ + -I ../../et/include \ + -I ../../../libraries/et/include + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt: $(TARGET_FILES) + +clean: + rm -f $(TARGET_FILES) + rm -f errs core *~ + +$(APP_TARGET): $(APP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src + # $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/examples + $(INSTALL_DATA) $(EXAMPLE_FILES) $(RELSYSDIR)/examples + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + +release_docs_spec: diff --git a/lib/dtrace/src/dtrace.app.src b/lib/dtrace/src/dtrace.app.src new file mode 100644 index 0000000000..764e863559 --- /dev/null +++ b/lib/dtrace/src/dtrace.app.src @@ -0,0 +1,27 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +{application, dtrace, + [{description, "DTRACE version 1"}, + {vsn, "%VSN%"}, + {modules, [ + dtrace + ]}, + {registered, []}, + {applications, [kernel, stdlib]}, + {env, []}]}. diff --git a/lib/dtrace/src/dtrace.appup.src b/lib/dtrace/src/dtrace.appup.src new file mode 100644 index 0000000000..f730a2f8df --- /dev/null +++ b/lib/dtrace/src/dtrace.appup.src @@ -0,0 +1,19 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +{"%VSN%",[],[]}. diff --git a/lib/dtrace/src/dtrace.erl b/lib/dtrace/src/dtrace.erl new file mode 100644 index 0000000000..45addafc53 --- /dev/null +++ b/lib/dtrace/src/dtrace.erl @@ -0,0 +1,216 @@ +-module(dtrace). + +%%% @doc The DTrace interface module +%%% +%%% This DTrace interface module, with the corresponding NIFs, should +%%% work on any operating system platform where user-space DTrace +%%% probes are supported. +%%% +%%% Use the `dtrace:init()' function to load the NIF shared library and +%%% to initialize library's private state. +%%% +%%% It is recommended that you use the `dtrace:p()' function to add +%%% DTrace probes to your Erlang code. This function can accept up to +%%% four integer arguments and four string arguments; the integer +%%% argument(s) must come before any string argument. For example: +%%% ``` +%%% 1> put(dtrace_utag, "GGOOOAAALL!!!!!"). +%%% undefined +%%% 2> dtrace:init(). +%%% ok +%%% +%%% % % % Enable the DTrace probe using the 'dtrace' command. +%%% +%%% 3> dtrace:p(7, 8, 9, "one", "four"). +%%% true +%%% ''' +%%% +%%% Output from the example D script `user-probe.d' looks like: +%%% ``` +%%% <0.34.0> GGOOOAAALL!!!!! 7 8 9 0 'one' 'four' '' '' +%%% ''' +%%% +%%% If the expected type of variable is not present, e.g. integer when +%%% integer() is expected, or an I/O list when iolist() is expected, +%%% then the driver will ignore the user's input and use a default +%%% value of 0 or NULL, respectively. + +-export([init/0, available/0, + user_trace_s1/1, % TODO: unify with pid & tag args like user_trace_i4s4 + p/0, p/1, p/2, p/3, p/4, p/5, p/6, p/7, p/8]). +-export([scaff/0]). % Development only +-export([user_trace_i4s4/9]). % Know what you're doing! + +-type probe_arg() :: integer() | iolist(). +-type int_p_arg() :: integer() | iolist() | undef. +%% The *_maybe() types use atom() instead of a stricter 'undef' +%% because user_trace_i4s4/9 is exposed to the outside world, and +%% because the driver will allow any atom to be used as a "not +%% present" indication, we'll allow any atom in the types. +-type integer_maybe() :: integer() | atom(). +-type iolist_maybe() :: iolist() | atom(). + +-spec init() -> ok | {error, {term(), term()}}. + +init() -> + PrivDir = code:priv_dir(dtrace), + Lib = filename:join([PrivDir, "lib", "dtrace"]), + erlang:load_nif(Lib, 0). + +%%% +%%% NIF placeholders +%%% + +-spec available() -> true | false. + +available() -> + erlang:nif_error(nif_not_loaded). + +-spec user_trace_s1(iolist()) -> true | false | error | badarg. + +user_trace_s1(Message) -> + erlang:nif_error(nif_not_loaded). + +-spec user_trace_i4s4(iolist(), + integer_maybe(), integer_maybe(), + integer_maybe(), integer_maybe(), + iolist_maybe(), iolist_maybe(), + iolist_maybe(), iolist_maybe()) -> + true | false | error | badarg. + +user_trace_i4s4(_, _, _, _, _, _, _, _, _) -> + erlang:nif_error(nif_not_loaded). + +%%% +%%% Erlang support functions +%%% + +-spec p() -> true | false | error | badarg. + +p() -> + user_trace_int(undef, undef, undef, undef, undef, undef, undef, undef). + +-spec p(probe_arg()) -> true | false | error | badarg. + +p(I1) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, undef, undef, undef, undef); +p(S1) -> + user_trace_int(undef, undef, undef, undef, S1, undef, undef, undef). + +-spec p(probe_arg(), probe_arg()) -> true | false | error | badarg. + +p(I1, I2) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, undef, undef, undef, undef); +p(I1, S1) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, undef, undef, undef); +p(S1, S2) -> + user_trace_int(undef, undef, undef, undef, S1, S2, undef, undef). + +-spec p(probe_arg(), probe_arg(), probe_arg()) -> true | false | error | badarg. + +p(I1, I2, I3) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, undef, undef, undef, undef); +p(I1, I2, S1) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, undef, undef, undef); +p(I1, S1, S2) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, undef, undef); +p(S1, S2, S3) -> + user_trace_int(undef, undef, undef, undef, S1, S2, S3, undef). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, undef, undef, undef, undef); +p(I1, I2, I3, S1) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, undef, undef, undef); +p(I1, I2, S1, S2) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, undef, undef); +p(I1, S1, S2, S3) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, S3, undef); +p(S1, S2, S3, S4) -> + user_trace_int(undef, undef, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, undef, undef, undef); +p(I1, I2, I3, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, undef, undef); +p(I1, I2, S1, S2, S3) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, S3, undef); +p(I1, S1, S2, S3, S4) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, undef, undef); +p(I1, I2, I3, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, S3, undef); +p(I1, I2, S1, S2, S3, S4) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, S3, undef); +p(I1, I2, I3, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4). + +-spec user_trace_int(int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg(), + int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg()) -> + true | false | error | badarg. + +user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4) -> + UTag = prim_file:get_dtrace_utag(), + user_trace_i4s4(UTag, I1, I2, I3, I4, S1, S2, S3, S4). + +%% Scaffolding to write tedious code: quick brute force and not 100% correct. + +scaff_int_args(N) -> + L = lists:sublist(["I1", "I2", "I3", "I4"], N), + [string:join(L, ", ")]. + +scaff_int_guards(N) -> + L = lists:sublist(["is_integer(I1)", "is_integer(I2)", "is_integer(I3)", + "is_integer(I4)"], N), + lists:flatten(string:join(L, ", ")). + +scaff_char_args(N) -> + L = lists:sublist(["S1", "S2", "S3", "S4"], N), + [string:join(L, ", ")]. + +scaff_fill(N) -> + [string:join(lists:duplicate(N, "undef"), ", ")]. + +scaff() -> + L = [begin + IntArgs = scaff_int_args(N_int), + IntGuards = scaff_int_guards(N_int), + IntFill = scaff_fill(4 - N_int), + CharArgs = scaff_char_args(N_char), + CharFill = scaff_fill(4 - N_char), + InArgs = string:join(IntArgs ++ CharArgs, ", "), + OutArgs = string:join(IntArgs ++ IntFill ++ CharArgs ++ CharFill, + ", "), + {N_int + N_char, + lists:flatten([io_lib:format("p(~s) when ~s ->\n", + [InArgs, IntGuards]), + io_lib:format(" user_trace_int(~s);\n", [OutArgs]) + ])} + end || N_int <- [0,1,2,3,4], N_char <- [0,1,2,3,4]], + [io:format("%%~p\n~s", [N, Str]) || {N, Str} <- lists:sort(L)]. |