aboutsummaryrefslogtreecommitdiffstats
path: root/lib/runtime_tools
diff options
context:
space:
mode:
Diffstat (limited to 'lib/runtime_tools')
-rw-r--r--lib/runtime_tools/c_src/Makefile.in17
-rw-r--r--lib/runtime_tools/c_src/trace_file_drv.c90
-rw-r--r--lib/runtime_tools/c_src/trace_ip_drv.c21
-rw-r--r--lib/runtime_tools/doc/src/dbg.xml23
-rw-r--r--lib/runtime_tools/doc/src/make.dep20
-rw-r--r--lib/runtime_tools/doc/src/notes.xml50
-rw-r--r--lib/runtime_tools/src/Makefile5
-rw-r--r--lib/runtime_tools/src/dbg.erl65
-rw-r--r--lib/runtime_tools/src/erts_alloc_config.erl12
-rw-r--r--lib/runtime_tools/src/inviso_rt.erl4
-rw-r--r--lib/runtime_tools/src/inviso_rt_lib.erl18
-rw-r--r--lib/runtime_tools/src/observer_backend.erl338
-rw-r--r--lib/runtime_tools/src/runtime_tools.app.src5
-rw-r--r--lib/runtime_tools/src/runtime_tools_sup.erl6
-rw-r--r--lib/runtime_tools/src/ttb_autostart.erl55
-rw-r--r--lib/runtime_tools/test/inviso_SUITE.erl22
-rw-r--r--lib/runtime_tools/vsn.mk2
17 files changed, 607 insertions, 146 deletions
diff --git a/lib/runtime_tools/c_src/Makefile.in b/lib/runtime_tools/c_src/Makefile.in
index 840de39f07..3d9a7ed69d 100644
--- a/lib/runtime_tools/c_src/Makefile.in
+++ b/lib/runtime_tools/c_src/Makefile.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2010. All Rights Reserved.
+# Copyright Ericsson AB 1999-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
@@ -89,42 +89,31 @@ endif
# Targets
# ----------------------------------------------------
-debug opt: $(OBJDIR) $(BINDIR) $(SOLIBS)
+_create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR))
-$(OBJDIR):
- -@mkdir -p $(OBJDIR)
-
-$(BINDIR):
- -@mkdir -p $(BINDIR)
+debug opt: $(SOLIBS)
$(OBJDIR)/%.o: %.c
- $(INSTALL_DIR) $(OBJDIR)
$(CC) -c -o $@ $(ALL_CFLAGS) $<
$(LIBDIR)/trace_ip_drv.so: $(TRACE_IP_DRV_OBJS)
- $(INSTALL_DIR) $(LIBDIR)
$(LD) $(LDFLAGS) -o $@ $^ -lc $(LIBS)
$(LIBDIR)/trace_file_drv.so: $(TRACE_FILE_DRV_OBJS)
- $(INSTALL_DIR) $(LIBDIR)
$(LD) $(LDFLAGS) -o $@ $^ -lc $(LIBS)
$(LIBDIR)/trace_ip_drv.dll: $(TRACE_IP_DRV_OBJS)
- $(INSTALL_DIR) $(LIBDIR)
$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
$(LIBDIR)/trace_file_drv.dll: $(TRACE_FILE_DRV_OBJS)
- $(INSTALL_DIR) $(LIBDIR)
$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
#
# VxWorks is simply to different from Unix in this sense.
# Here are the inference rules for VxWorks
#
$(LIBDIR)/trace_ip_drv.eld: $(TRACE_IP_DRV_OBJS)
- $(INSTALL_DIR) $(LIBDIR)
$(LD) $(LDFLAGS) -o $@ $^
$(LIBDIR)/trace_file_drv.eld: $(TRACE_FILE_DRV_OBJS)
- $(INSTALL_DIR) $(LIBDIR)
$(LD) $(LDFLAGS) -o $@ $^
clean:
diff --git a/lib/runtime_tools/c_src/trace_file_drv.c b/lib/runtime_tools/c_src/trace_file_drv.c
index 668f6f4af3..08bace80ef 100644
--- a/lib/runtime_tools/c_src/trace_file_drv.c
+++ b/lib/runtime_tools/c_src/trace_file_drv.c
@@ -21,6 +21,9 @@
* Purpose: Send trace messages to a file.
*/
+#ifdef __WIN32__
+#include <windows.h>
+#endif
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
@@ -31,7 +34,6 @@
#ifdef __WIN32__
# include <io.h>
# define write _write
-# define open _open
# define close _close
# define unlink _unlink
#else
@@ -40,11 +42,6 @@
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
-#ifdef VXWORKS
-# include "reclaim.h"
-#endif
-
-
/*
* Deduce MAXPATHLEN, which is the one to use in this file,
@@ -176,11 +173,13 @@ static TraceFileData *first_data;
*/
static ErlDrvData trace_file_start(ErlDrvPort port, char *buff);
static void trace_file_stop(ErlDrvData handle);
-static void trace_file_output(ErlDrvData handle, char *buff, int bufflen);
+static void trace_file_output(ErlDrvData handle, char *buff,
+ ErlDrvSizeT bufflen);
static void trace_file_finish(void);
-static int trace_file_control(ErlDrvData handle, unsigned int command,
- char* buff, int count,
- char** res, int res_size);
+static ErlDrvSSizeT trace_file_control(ErlDrvData handle,
+ unsigned int command,
+ char* buff, ErlDrvSizeT count,
+ char** res, ErlDrvSizeT res_size);
static void trace_file_timeout(ErlDrvData handle);
/*
@@ -194,6 +193,12 @@ static int my_flush(TraceFileData *data);
static void put_be(unsigned n, unsigned char *s);
static void close_unlink_port(TraceFileData *data);
static int wrap_file(TraceFileData *data);
+#ifdef __WIN32__
+static int win_open(char *path, int flags, int mask);
+#define open win_open
+#else
+ErlDrvEntry *driver_init(void);
+#endif
/*
** The driver struct
@@ -212,7 +217,18 @@ ErlDrvEntry trace_file_driver_entry = {
NULL, /* void * that is not used (BC) */
trace_file_control, /* F_PTR control, port_control callback */
trace_file_timeout, /* F_PTR timeout, driver_set_timer callback */
- NULL /* F_PTR outputv, reserved */
+ NULL, /* F_PTR outputv, reserved */
+ NULL, /* ready_async */
+ NULL, /* flush */
+ NULL, /* call */
+ NULL, /* event */
+ ERL_DRV_EXTENDED_MARKER,
+ ERL_DRV_EXTENDED_MAJOR_VERSION,
+ ERL_DRV_EXTENDED_MINOR_VERSION,
+ 0,
+ NULL,
+ NULL,
+ NULL,
};
/*
@@ -241,6 +257,7 @@ static ErlDrvData trace_file_start(ErlDrvPort port, char *buff)
int n, w;
static const char name[] = "trace_file_drv";
+
#ifdef HARDDEBUG
fprintf(stderr,"hello (%s)\r\n", buff);
#endif
@@ -347,17 +364,18 @@ static void trace_file_stop(ErlDrvData handle)
/*
** Data sent from erlang to port.
*/
-static void trace_file_output(ErlDrvData handle, char *buff, int bufflen)
+static void trace_file_output(ErlDrvData handle, char *buff,
+ ErlDrvSizeT bufflen)
{
int heavy = 0;
TraceFileData *data = (TraceFileData *) handle;
unsigned char b[5] = "";
put_be((unsigned) bufflen, b + 1);
- switch (my_write(data, b, sizeof(b))) {
+ switch (my_write(data, (unsigned char *) b, sizeof(b))) {
case 1:
heavy = !0;
case 0:
- switch (my_write(data, buff, bufflen)) {
+ switch (my_write(data, (unsigned char *) buff, bufflen)) {
case 1:
heavy = !0;
case 0:
@@ -391,9 +409,10 @@ static void trace_file_output(ErlDrvData handle, char *buff, int bufflen)
/*
** Control message from erlang, we handle $f, which is flush.
*/
-static int trace_file_control(ErlDrvData handle, unsigned int command,
- char* buff, int count,
- char** res, int res_size)
+static ErlDrvSSizeT trace_file_control(ErlDrvData handle,
+ unsigned int command,
+ char* buff, ErlDrvSizeT count,
+ char** res, ErlDrvSizeT res_size)
{
if (command == 'f') {
TraceFileData *data = (TraceFileData *) handle;
@@ -636,3 +655,40 @@ static int wrap_file(TraceFileData *data) {
return 0;
}
+#ifdef __WIN32__
+static int win_open(char *path, int flags, int mask)
+{
+ DWORD access = 0;
+ DWORD creation = 0;
+ HANDLE fd;
+ int ret;
+ if (flags & O_WRONLY) {
+ access = GENERIC_WRITE;
+ } else if (flags & O_RDONLY) {
+ access = GENERIC_READ;
+ } else {
+ access = (GENERIC_READ | GENERIC_WRITE);
+ }
+
+ if (flags & O_CREAT) {
+ creation |= CREATE_ALWAYS;
+ } else {
+ creation |= OPEN_ALWAYS;
+ }
+
+ fd = CreateFileA(path, access,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (fd == INVALID_HANDLE_VALUE) {
+
+ return -1;
+ }
+
+ if ((ret = _open_osfhandle((intptr_t)fd, (flags & O_RDONLY) ? O_RDONLY : 0))
+ < 0) {
+ CloseHandle(fd);
+ }
+
+ return ret;
+}
+#endif
diff --git a/lib/runtime_tools/c_src/trace_ip_drv.c b/lib/runtime_tools/c_src/trace_ip_drv.c
index d2ed1a294b..5396b8afa9 100644
--- a/lib/runtime_tools/c_src/trace_ip_drv.c
+++ b/lib/runtime_tools/c_src/trace_ip_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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
@@ -185,7 +185,8 @@ static TraceIpData *first_data;
*/
static ErlDrvData trace_ip_start(ErlDrvPort port, char *buff);
static void trace_ip_stop(ErlDrvData handle);
-static void trace_ip_output(ErlDrvData handle, char *buff, int bufflen);
+static void trace_ip_output(ErlDrvData handle, char *buff,
+ ErlDrvSizeT bufflen);
#ifdef __WIN32__
static void trace_ip_event(ErlDrvData handle, ErlDrvEvent event);
#endif
@@ -193,9 +194,10 @@ static void trace_ip_ready_input(ErlDrvData handle, ErlDrvEvent fd);
static void trace_ip_ready_output(ErlDrvData handle, ErlDrvEvent fd);
static void trace_ip_finish(void); /* No arguments, despite what might be stated
in any documentation */
-static int trace_ip_control(ErlDrvData handle, unsigned int command,
- char* buff, int count,
- char** res, int res_size);
+static ErlDrvSSizeT trace_ip_control(ErlDrvData handle,
+ unsigned int command,
+ char* buff, ErlDrvSizeT count,
+ char** res, ErlDrvSizeT res_size);
/*
** Internal routines
@@ -382,7 +384,7 @@ static void trace_ip_stop(ErlDrvData handle)
/*
** Data sent from erlang to port.
*/
-static void trace_ip_output(ErlDrvData handle, char *buff, int bufflen)
+static void trace_ip_output(ErlDrvData handle, char *buff, ErlDrvSizeT bufflen)
{
TraceIpData *data = (TraceIpData *) handle;
if (data->flags & FLAG_LISTEN_PORT) {
@@ -548,9 +550,10 @@ static void trace_ip_ready_output(ErlDrvData handle, ErlDrvEvent fd)
/*
** Control message from erlang, we handle $p, which is get_listen_port.
*/
-static int trace_ip_control(ErlDrvData handle, unsigned int command,
- char* buff, int count,
- char** res, int res_size)
+static ErlDrvSSizeT trace_ip_control(ErlDrvData handle,
+ unsigned int command,
+ char* buff, ErlDrvSizeT count,
+ char** res, ErlDrvSizeT res_size)
{
register void *void_ptr; /* Soft type cast */
diff --git a/lib/runtime_tools/doc/src/dbg.xml b/lib/runtime_tools/doc/src/dbg.xml
index f26789fa21..c7c5cd4ff0 100644
--- a/lib/runtime_tools/doc/src/dbg.xml
+++ b/lib/runtime_tools/doc/src/dbg.xml
@@ -316,7 +316,8 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard) c
<v>Module = atom() | '_'</v>
<v>Function = atom() | '_'</v>
<v>Arity = integer() |'_'</v>
- <v>MatchSpec = integer() | atom() | [] | match_spec()</v>
+ <v>MatchSpec = integer() | Built-inAlias | [] | match_spec()</v>
+ <v>Built-inAlias = x | c | cx</v>
<v>MatchDesc = [MatchInfo]</v>
<v>MatchInfo = {saved, integer()} | MatchNum</v>
<v>MatchNum = {matched, node(), integer()} | {matched, node(), 0, RPCError}</v>
@@ -349,8 +350,9 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard) c
if the MatchSpec is other
than []. The integer <c>N</c> may then be used in
subsequent calls to this function and will stand as an
- "alias" for the given expression. There are also built-in
- aliases named with atoms (see also <c>ltp/0</c> below).</p>
+ "alias" for the given expression. There are also a couple of
+ built-in aliases for common expressions, see <c>ltp/0</c> below
+ for details.</p>
<p>If an error is returned, it can be due to errors in
compilation of the match specification. Such errors are
presented as a list of tuples <c>{error, string()}</c> where
@@ -528,6 +530,21 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard) c
<p>Match specifications used can be saved in a file (if a
read-write file system is present) for use in later
debugging sessions, see <c>wtp/1</c> and <c>rtp/1</c></p>
+ <p>There are three built-in trace patterns:
+ <c>exception_trace</c>, <c>caller_trace</c>
+ and <c>caller_exception_trace</c> (or <c>x</c>, <c>c</c> and
+ <c>cx</c> respectively).
+ Exception trace sets a trace which will show function names,
+ parameters, return values and exceptions thrown from functions.
+ Caller traces display function names, parameters and information
+ about which function called it. An example using a built-in alias:</p>
+ <pre>
+(x@y)4> <input>dbg:tp(lists,sort,cx).</input>
+{ok,[{matched,nonode@nohost,2},{saved,cx}]}
+(x@y)4> <input>lists:sort([2,1]).</input>
+(&lt;0.32.0&gt;) call lists:sort([2,1]) ({erl_eval,do_apply,5})
+(&lt;0.32.0&gt;) returned from lists:sort/1 -> [1,2]
+[1,2]</pre>
</desc>
</func>
<func>
diff --git a/lib/runtime_tools/doc/src/make.dep b/lib/runtime_tools/doc/src/make.dep
deleted file mode 100644
index 85eae88adf..0000000000
--- a/lib/runtime_tools/doc/src/make.dep
+++ /dev/null
@@ -1,20 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex dbg.tex erts_alloc_config.tex refman.tex \
- runtime_tools_app.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: refman.xml
-
diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml
index 0bb76e1ea4..ccf11bf0fe 100644
--- a/lib/runtime_tools/doc/src/notes.xml
+++ b/lib/runtime_tools/doc/src/notes.xml
@@ -31,6 +31,56 @@
<p>This document describes the changes made to the Runtime_Tools
application.</p>
+<section><title>Runtime_Tools 1.8.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Earlier dbg:stop only did erlang:trace_delivered and did
+ not flush the trace file driver. Therefore there could
+ still be trace messages that were delivered to the driver
+ (guaranteed by erlang:trace_delivered) but not yet
+ written to the file when dbg:stop returned. Flushing is
+ now added on each node before the dbg process terminates.</p>
+ <p>
+ Own Id: OTP-9651</p>
+ </item>
+ <item>
+ <p>
+ File handles created by the trace_file_drv driver was
+ inherited to child processes. This is now corrected.</p>
+ <p>
+ Own Id: OTP-9658</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Erlang/OTP can now be built using parallel make if you
+ limit the number of jobs, for instance using '<c>make
+ -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not
+ work at the moment because of some missing
+ dependencies.</p>
+ <p>
+ Own Id: OTP-9451</p>
+ </item>
+ <item>
+ <p>
+ Two new built-in trace pattern aliases have been added:
+ caller_trace (c) and caller_exception_trace (cx). See the
+ dbg:ltp/0 documentation for more info.</p>
+ <p>
+ Own Id: OTP-9458</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Runtime_Tools 1.8.6</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/runtime_tools/src/Makefile b/lib/runtime_tools/src/Makefile
index 4f831f3dd8..946409b262 100644
--- a/lib/runtime_tools/src/Makefile
+++ b/lib/runtime_tools/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2009. All Rights Reserved.
+# Copyright Ericsson AB 1999-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
@@ -46,7 +46,8 @@ MODULES= \
runtime_tools_sup \
dbg \
percept_profile \
- observer_backend
+ observer_backend \
+ ttb_autostart
HRL_FILES= ../include/observer_backend.hrl
ERL_FILES= $(MODULES:%=%.erl)
diff --git a/lib/runtime_tools/src/dbg.erl b/lib/runtime_tools/src/dbg.erl
index 56283f4d3d..385047ee73 100644
--- a/lib/runtime_tools/src/dbg.erl
+++ b/lib/runtime_tools/src/dbg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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
@@ -32,7 +32,7 @@
-export([fun2ms/1]).
%% Local exports
--export([erlang_trace/3,get_info/0]).
+-export([erlang_trace/3,get_info/0,deliver_and_flush/1]).
%% Debug exports
-export([wrap_presort/2, wrap_sort/2, wrap_postsort/1, wrap_sortfix/2,
@@ -348,17 +348,16 @@ trace_port_control(Operation) ->
trace_port_control(node(), Operation).
trace_port_control(Node, flush) ->
- Ref = erlang:trace_delivered(all),
- receive
- {trace_delivered,all,Ref} -> ok
- end,
- case trace_port_control(Node, $f, "") of
- {ok, [0]} ->
- ok;
- {ok, _} ->
- {error, not_supported_by_trace_driver};
- Other ->
- Other
+ case get_tracer(Node) of
+ {ok, Port} when is_port(Port) ->
+ case catch rpc:call(Node,?MODULE,deliver_and_flush,[Port]) of
+ [0] ->
+ ok;
+ _ ->
+ {error, not_supported_by_trace_driver}
+ end;
+ _ ->
+ {error, no_trace_driver}
end;
trace_port_control(Node,get_listen_port) ->
case trace_port_control(Node,$p, "") of
@@ -378,7 +377,14 @@ trace_port_control(Node, Command, Arg) ->
{error, no_trace_driver}
end.
-
+%% A bit more than just flush - it also makes sure all trace messages
+%% are delivered first, before flushing the driver.
+deliver_and_flush(Port) ->
+ Ref = erlang:trace_delivered(all),
+ receive
+ {trace_delivered,all,Ref} -> ok
+ end,
+ erlang:port_control(Port, $f, "").
trace_port(file, {Filename, wrap, Tail}) ->
@@ -684,18 +690,12 @@ loop({C,T}=SurviveLinks, Table) ->
%% tracing on the node it removes from the list of active trace nodes,
%% we will call erlang:trace_delivered/1 on ALL nodes that we have
%% connections to.
- Delivered = fun() ->
- Ref = erlang:trace_delivered(all),
- receive
- {trace_delivered,all,Ref} -> ok
- end
- end,
- catch rpc:multicall(nodes(), erlang, apply, [Delivered,[]]),
- Ref = erlang:trace_delivered(all),
- receive
- {trace_delivered,all,Ref} ->
- exit(done)
- end;
+ %% If it is a file trace driver, we will also flush the port.
+ lists:foreach(fun({Node,{_Relay,Port}}) ->
+ rpc:call(Node,?MODULE,deliver_and_flush,[Port])
+ end,
+ get()),
+ exit(done);
{From, {link_to, Pid}} ->
case (catch link(Pid)) of
{'EXIT', Reason} ->
@@ -1449,6 +1449,19 @@ new_pattern_table() ->
ets:insert(PT,
{exception_trace,
term_to_binary(x)}),
+ ets:insert(PT,
+ {c,
+ term_to_binary([{'_',[],[{message,{caller}}]}])}),
+ ets:insert(PT,
+ {caller_trace,
+ term_to_binary(c)}),
+ ets:insert(PT,
+ {cx,
+ term_to_binary([{'_',[],[{exception_trace},
+ {message,{caller}}]}])}),
+ ets:insert(PT,
+ {caller_exception_trace,
+ term_to_binary(cx)}),
PT.
diff --git a/lib/runtime_tools/src/erts_alloc_config.erl b/lib/runtime_tools/src/erts_alloc_config.erl
index 0bcb202fd8..284e88d4a7 100644
--- a/lib/runtime_tools/src/erts_alloc_config.erl
+++ b/lib/runtime_tools/src/erts_alloc_config.erl
@@ -1,6 +1,7 @@
+%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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
@@ -16,6 +17,7 @@
%% The Initial Developer of the Original Code is Ericsson AB.
%%
%% %CopyrightEnd%
+%%
%%%-------------------------------------------------------------------
%%% File : erts_alloc_config.erl
@@ -71,6 +73,7 @@
A == binary_alloc;
A == std_alloc;
A == ets_alloc;
+ A == fix_alloc;
A == eheap_alloc;
A == ll_alloc;
A == sl_alloc;
@@ -94,6 +97,7 @@
[{binary_alloc, 131072},
{std_alloc, 131072},
{ets_alloc, 131072},
+ {fix_alloc, 131072},
{eheap_alloc, 524288},
{ll_alloc, 2097152},
{sl_alloc, 131072},
@@ -104,6 +108,7 @@
[{binary_alloc, 10},
{std_alloc, 10},
{ets_alloc, 10},
+ {fix_alloc, 10},
{eheap_alloc, 10},
{ll_alloc, 0},
{sl_alloc, 10},
@@ -438,9 +443,6 @@ conf_alloc(#conf{format_to = FTO} = Conf, #alloc{name = A} = Alc) ->
chk_xnote(Conf, Alc).
chk_xnote(#conf{format_to = FTO},
- #alloc{name = fix_alloc}) ->
- fcp(FTO, "Cannot be configured.");
-chk_xnote(#conf{format_to = FTO},
#alloc{name = sys_alloc}) ->
fcp(FTO, "Cannot be configured. Default malloc implementation used.");
chk_xnote(#conf{format_to = FTO},
@@ -470,7 +472,7 @@ au_conf_alloc(#conf{format_to = FTO} = Conf,
_ ->
fc(FTO, "~p instances used.",
[Insts]),
- format(FTO, " +M~ct ~p~n", [alloc_char(A), Insts])
+ format(FTO, " +M~ct true~n", [alloc_char(A)])
end,
mmbcs(Conf, Alc),
smbcs_lmbcs_mmmbc(Conf, Alc),
diff --git a/lib/runtime_tools/src/inviso_rt.erl b/lib/runtime_tools/src/inviso_rt.erl
index ac7ac2a584..b162f5b045 100644
--- a/lib/runtime_tools/src/inviso_rt.erl
+++ b/lib/runtime_tools/src/inviso_rt.erl
@@ -2359,8 +2359,8 @@ list_wrapset(Prefix,Suffix) ->
list_wrapset_2([File|Rest],RegExp) ->
Length=length(File),
- case regexp:first_match(File,RegExp) of
- {match,1,Length} -> % This is a member of the set.
+ case re:run(File,RegExp) of
+ {match,[{0,Length}]} -> % This is a member of the set.
[File|list_wrapset_2(Rest,RegExp)];
_ ->
list_wrapset_2(Rest,RegExp)
diff --git a/lib/runtime_tools/src/inviso_rt_lib.erl b/lib/runtime_tools/src/inviso_rt_lib.erl
index 2c6964e53e..5dfe14068a 100644
--- a/lib/runtime_tools/src/inviso_rt_lib.erl
+++ b/lib/runtime_tools/src/inviso_rt_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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
@@ -197,15 +197,15 @@ match_modules(RegExpDir,RegExpMod,Actions) ->
handle_expand_regexp_2([{Mod,Path}|Rest],RegExpDir,RegExpMod,Result) ->
ModStr=atom_to_list(Mod),
ModLen=length(ModStr),
- case regexp:first_match(ModStr,RegExpMod) of
- {match,1,ModLen} -> % Ok, The regexp matches the module.
+ case re:run(ModStr,RegExpMod) of
+ {match,[{0,ModLen}]} -> % Ok, The regexp matches the module.
if
is_list(RegExpDir),is_atom(Path) -> % Preloaded or covercompiled...
handle_expand_regexp_2(Rest,RegExpDir,RegExpMod,Result);
is_list(RegExpDir),is_list(Path) -> % Dir reg-exp is used!
PathOnly=filename:dirname(Path), % Must remove beam-file name.
- case regexp:first_match(PathOnly,RegExpDir) of
- {match,_,_} -> % Did find a match, that is enough!
+ case re:run(PathOnly,RegExpDir,[{capture,none}]) of
+ match -> % Did find a match, that is enough!
handle_expand_regexp_2(Rest,RegExpDir,RegExpMod,[Mod|Result]);
_ -> % Either error or nomatch.
handle_expand_regexp_2(Rest,RegExpDir,RegExpMod,Result)
@@ -233,8 +233,8 @@ handle_expand_regexp_3([Path|Rest],RegExpDir,RegExpMod,AllLoaded,Result) ->
volumerelative -> % Only on Windows!?
filename:absname(Path)
end,
- case regexp:first_match(AbsPath,RegExpDir) of
- {match,_,_} -> % Ok, the directory is allowed.
+ case re:run(AbsPath,RegExpDir,[{capture,none}]) of
+ match -> % Ok, the directory is allowed.
NewResult=handle_expand_regexp_3_1(Path,RegExpMod,AllLoaded,Result),
handle_expand_regexp_3(Rest,RegExpDir,RegExpMod,AllLoaded,NewResult);
_ -> % This directory does not qualify.
@@ -262,8 +262,8 @@ handle_expand_regexp_3_2([File|Rest],RegExpMod,AllLoaded,Result) ->
case {lists:keysearch(Mod,1,AllLoaded),lists:member(Mod,Result)} of
{false,false} -> % This module is not tried before.
ModLen=length(ModStr),
- case regexp:first_match(ModStr,RegExpMod) of
- {match,1,ModLen} -> % This module satisfies the regexp.
+ case re:run(ModStr,RegExpMod) of
+ {match,[{0,ModLen}]} -> % This module satisfies the regexp.
handle_expand_regexp_3_2(Rest,RegExpMod,AllLoaded,[Mod|Result]);
_ -> % Error or not perfect match.
handle_expand_regexp_3_2(Rest,RegExpMod,AllLoaded,Result)
diff --git a/lib/runtime_tools/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl
index 0f428de07a..2f8ffbcdb6 100644
--- a/lib/runtime_tools/src/observer_backend.erl
+++ b/lib/runtime_tools/src/observer_backend.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%% 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
@@ -21,6 +21,9 @@
%% General
-export([vsn/0]).
+%% observer stuff
+-export([sys_info/0, get_table/3, get_table_list/2]).
+
%% etop stuff
-export([etop_collect/1]).
-include("observer_backend.hrl").
@@ -31,6 +34,7 @@
ttb_write_binary/2,
ttb_stop/1,
ttb_fetch/2,
+ ttb_resume_trace/0,
ttb_get_filenames/1]).
-define(CHUNKSIZE,8191). % 8 kbytes - 1 byte
@@ -41,7 +45,158 @@ vsn() ->
Error -> Error
end.
+%%
+%% observer backend
+%%
+sys_info() ->
+ {{_,Input},{_,Output}} = erlang:statistics(io),
+ [{process_count, erlang:system_info(process_count)},
+ {process_limit, erlang:system_info(process_limit)},
+ {uptime, element(1, erlang:statistics(wall_clock))},
+ {run_queue, erlang:statistics(run_queue)},
+ {io_input, Input},
+ {io_output, Output},
+ {logical_processors, erlang:system_info(logical_processors)},
+ {logical_processors_available, erlang:system_info(logical_processors_available)},
+ {logical_processors_online, erlang:system_info(logical_processors_online)},
+
+ {otp_release, erlang:system_info(otp_release)},
+ {version, erlang:system_info(version)},
+ {system_architecture, erlang:system_info(system_architecture)},
+ {kernel_poll, erlang:system_info(kernel_poll)},
+ {smp_support, erlang:system_info(smp_support)},
+ {threads, erlang:system_info(threads)},
+ {thread_pool_size, erlang:system_info(thread_pool_size)},
+ {wordsize_internal, erlang:system_info({wordsize, internal})},
+ {wordsize_external, erlang:system_info({wordsize, external})} |
+ erlang:memory()
+ ].
+
+get_table(Parent, Table, Module) ->
+ spawn(fun() ->
+ link(Parent),
+ get_table2(Parent, Table, Module)
+ end).
+
+get_table2(Parent, Table, Type) ->
+ Size = case Type of
+ ets -> ets:info(Table, size);
+ mnesia -> mnesia:table_info(Table, size)
+ end,
+ case Size > 0 of
+ false ->
+ Parent ! {self(), '$end_of_table'},
+ normal;
+ true when Type =:= ets ->
+ Mem = ets:info(Table, memory),
+ Average = Mem div Size,
+ NoElements = max(10, 20000 div Average),
+ get_ets_loop(Parent, ets:match(Table, '$1', NoElements));
+ true ->
+ Mem = mnesia:table_info(Table, memory),
+ Average = Mem div Size,
+ NoElements = max(10, 20000 div Average),
+ Ms = [{'$1', [], ['$1']}],
+ Get = fun() ->
+ get_mnesia_loop(Parent, mnesia:select(Table, Ms, NoElements, read))
+ end,
+ %% Not a transaction, we don't want to grab locks when inspecting the table
+ mnesia:async_dirty(Get)
+ end.
+get_ets_loop(Parent, '$end_of_table') ->
+ Parent ! {self(), '$end_of_table'};
+get_ets_loop(Parent, {Match, Cont}) ->
+ Parent ! {self(), Match},
+ get_ets_loop(Parent, ets:match(Cont)).
+
+get_mnesia_loop(Parent, '$end_of_table') ->
+ Parent ! {self(), '$end_of_table'};
+get_mnesia_loop(Parent, {Match, Cont}) ->
+ Parent ! {self(), Match},
+ get_mnesia_loop(Parent, mnesia:select(Cont)).
+
+get_table_list(ets, Opts) ->
+ HideUnread = proplists:get_value(unread_hidden, Opts, true),
+ HideSys = proplists:get_value(sys_hidden, Opts, true),
+ Info = fun(Id, Acc) ->
+ try
+ TabId = case ets:info(Id, named_table) of
+ true -> ignore;
+ false -> Id
+ end,
+ Name = ets:info(Id, name),
+ Protection = ets:info(Id, protection),
+ ignore(HideUnread andalso Protection == private, unreadable),
+ Owner = ets:info(Id, owner),
+ RegName = case catch process_info(Owner, registered_name) of
+ [] -> ignore;
+ {registered_name, ProcName} -> ProcName
+ end,
+ ignore(HideSys andalso ordsets:is_element(RegName, sys_processes()), system_tab),
+ ignore(HideSys andalso ordsets:is_element(Name, sys_tables()), system_tab),
+ ignore((RegName == mnesia_monitor)
+ andalso Name /= schema
+ andalso is_atom((catch mnesia:table_info(Name, where_to_read))), mnesia_tab),
+ Memory = ets:info(Id, memory) * erlang:system_info(wordsize),
+ Tab = [{name,Name},
+ {id,TabId},
+ {protection,Protection},
+ {owner,Owner},
+ {size,ets:info(Id, size)},
+ {reg_name,RegName},
+ {type,ets:info(Id, type)},
+ {keypos,ets:info(Id, keypos)},
+ {heir,ets:info(Id, heir)},
+ {memory,Memory},
+ {compressed,ets:info(Id, compressed)},
+ {fixed,ets:info(Id, fixed)}
+ ],
+ [Tab|Acc]
+ catch _:_What ->
+ %% io:format("Skipped ~p: ~p ~n",[Id, _What]),
+ Acc
+ end
+ end,
+ lists:foldl(Info, [], ets:all());
+
+get_table_list(mnesia, Opts) ->
+ HideSys = proplists:get_value(sys_hidden, Opts, true),
+ Owner = ets:info(schema, owner),
+ Owner /= undefined orelse
+ throw({error, "Mnesia is not running on: " ++ atom_to_list(node())}),
+ {registered_name, RegName} = process_info(Owner, registered_name),
+ Info = fun(Id, Acc) ->
+ try
+ Name = Id,
+ ignore(HideSys andalso ordsets:is_element(Name, mnesia_tables()), system_tab),
+ ignore(Name =:= schema, mnesia_tab),
+ Storage = mnesia:table_info(Id, storage_type),
+ Tab0 = [{name,Name},
+ {owner,Owner},
+ {size,mnesia:table_info(Id, size)},
+ {reg_name,RegName},
+ {type,mnesia:table_info(Id, type)},
+ {keypos,2},
+ {memory,mnesia:table_info(Id, memory) * erlang:system_info(wordsize)},
+ {storage,Storage},
+ {index,mnesia:table_info(Id, index)}
+ ],
+ Tab = if Storage == disc_only_copies ->
+ [{fixed, dets:info(Id, safe_fixed)}|Tab0];
+ (Storage == ram_copies) orelse
+ (Storage == disc_copies) ->
+ [{fixed, ets:info(Id, fixed)},
+ {compressed, ets:info(Id, compressed)}|Tab0];
+ true -> Tab0
+ end,
+ [Tab|Acc]
+ catch _:_What ->
+ %% io:format("Skipped ~p: ~p ~p ~n",[Id, _What, erlang:get_stacktrace()]),
+ Acc
+ end
+ end,
+ lists:foldl(Info, [], mnesia:system_info(tables)).
%%
%% etop backend
@@ -92,16 +247,22 @@ etop_collect([], Acc) -> Acc.
%%
%% ttb backend
%%
-ttb_init_node(MetaFile,PI,Traci) ->
+ttb_init_node(MetaFile_0,PI,Traci) ->
if
- is_list(MetaFile);
- is_atom(MetaFile) ->
+ is_list(MetaFile_0);
+ is_atom(MetaFile_0) ->
+ {ok, Cwd} = file:get_cwd(),
+ MetaFile = filename:join(Cwd, MetaFile_0),
file:delete(MetaFile);
true -> % {local,_,_}
- ok
+ MetaFile = MetaFile_0
+ end,
+ case proplists:get_value(resume, Traci) of
+ {true, _} -> (autostart_module()):write_config(Traci);
+ _ -> ok
end,
Self = self(),
- MetaPid = spawn(fun() -> ttb_meta_tracer(MetaFile,PI,Self) end),
+ MetaPid = spawn(fun() -> ttb_meta_tracer(MetaFile,PI,Self,Traci) end),
receive {MetaPid,started} -> ok end,
MetaPid ! {metadata,Traci},
case PI of
@@ -111,13 +272,14 @@ ttb_init_node(MetaFile,PI,Traci) ->
false ->
ok
end,
- {ok,MetaPid}.
+ {ok,MetaFile,MetaPid}.
ttb_write_trace_info(MetaPid,Key,What) ->
MetaPid ! {metadata,Key,What},
ok.
-ttb_meta_tracer(MetaFile,PI,Parent) ->
+ttb_meta_tracer(MetaFile,PI,Parent,SessionData) ->
+ erlang:monitor(process, proplists:get_value(ttb_control, SessionData)),
case PI of
true ->
ReturnMS = [{'_',[],[{return_trace}]}],
@@ -130,22 +292,29 @@ ttb_meta_tracer(MetaFile,PI,Parent) ->
ok
end,
Parent ! {self(),started},
- ttb_meta_tracer_loop(MetaFile,PI,dict:new()).
+ case proplists:get_value(overload_check, SessionData) of
+ {Ms, M, F} ->
+ catch M:F(init),
+ erlang:send_after(Ms, self(), overload_check);
+ _ ->
+ ok
+ end,
+ ttb_meta_tracer_loop(MetaFile,PI,dict:new(),SessionData).
-ttb_meta_tracer_loop(MetaFile,PI,Acc) ->
+ttb_meta_tracer_loop(MetaFile,PI,Acc,State) ->
receive
{trace_ts,_,call,{erlang,register,[Name,Pid]},_} ->
ttb_store_meta({pid,{Pid,Name}},MetaFile),
- ttb_meta_tracer_loop(MetaFile,PI,Acc);
+ ttb_meta_tracer_loop(MetaFile,PI,Acc,State);
{trace_ts,_,call,{global,register_name,[Name,Pid]},_} ->
ttb_store_meta({pid,{Pid,{global,Name}}},MetaFile),
- ttb_meta_tracer_loop(MetaFile,PI,Acc);
+ ttb_meta_tracer_loop(MetaFile,PI,Acc,State);
{trace_ts,CallingPid,call,{erlang,spawn_opt,[{M,F,Args,_}]},_} ->
MFA = {M,F,length(Args)},
NewAcc = dict:update(CallingPid,
fun(Old) -> [MFA|Old] end, [MFA],
Acc),
- ttb_meta_tracer_loop(MetaFile,PI,NewAcc);
+ ttb_meta_tracer_loop(MetaFile,PI,NewAcc,State);
{trace_ts,CallingPid,return_from,{erlang,spawn_opt,_Arity},Ret,_} ->
case Ret of
{NewPid,_Mref} when is_pid(NewPid) -> ok;
@@ -158,14 +327,14 @@ ttb_meta_tracer_loop(MetaFile,PI,Acc) ->
T
end,
Acc),
- ttb_meta_tracer_loop(MetaFile,PI,NewAcc);
+ ttb_meta_tracer_loop(MetaFile,PI,NewAcc,State);
{trace_ts,CallingPid,call,{erlang,Spawn,[M,F,Args]},_}
when Spawn==spawn;Spawn==spawn_link ->
MFA = {M,F,length(Args)},
NewAcc = dict:update(CallingPid,
fun(Old) -> [MFA|Old] end, [MFA],
Acc),
- ttb_meta_tracer_loop(MetaFile,PI,NewAcc);
+ ttb_meta_tracer_loop(MetaFile,PI,NewAcc,State);
{trace_ts,CallingPid,return_from,{erlang,Spawn,_Arity},NewPid,_}
when Spawn==spawn;Spawn==spawn_link ->
@@ -176,28 +345,53 @@ ttb_meta_tracer_loop(MetaFile,PI,Acc) ->
T
end,
Acc),
- ttb_meta_tracer_loop(MetaFile,PI,NewAcc);
+ ttb_meta_tracer_loop(MetaFile,PI,NewAcc,State);
{metadata,Data} when is_list(Data) ->
ttb_store_meta(Data,MetaFile),
- ttb_meta_tracer_loop(MetaFile,PI,Acc);
+ ttb_meta_tracer_loop(MetaFile,PI,Acc,State);
{metadata,Key,Fun} when is_function(Fun) ->
ttb_store_meta([{Key,Fun()}],MetaFile),
- ttb_meta_tracer_loop(MetaFile,PI,Acc);
+ ttb_meta_tracer_loop(MetaFile,PI,Acc,State);
{metadata,Key,What} ->
ttb_store_meta([{Key,What}],MetaFile),
- ttb_meta_tracer_loop(MetaFile,PI,Acc);
-
- stop when PI=:=true ->
- erlang:trace_pattern({erlang,spawn,3},false,[meta]),
+ ttb_meta_tracer_loop(MetaFile,PI,Acc,State);
+ overload_check ->
+ {Ms, M, F} = proplists:get_value(overload_check, State),
+ case catch M:F(check) of
+ true ->
+ erlang:trace(all, false, [all]),
+ ControlPid = proplists:get_value(ttb_control, State),
+ ControlPid ! {node_overloaded, node()},
+ catch M:F(stop),
+ ttb_meta_tracer_loop(MetaFile,PI,Acc,lists:keydelete(overload_check, 1, State));
+ _ ->
+ erlang:send_after(Ms, self(), overload_check),
+ ttb_meta_tracer_loop(MetaFile,PI,Acc, State)
+ end;
+ {'DOWN', _, _, _, _} ->
+ stop_seq_trace(),
+ self() ! stop,
+ ttb_meta_tracer_loop(MetaFile,PI,Acc, State);
+ stop when PI=:=true ->
+ try_stop_resume(State),
+ try_stop_overload_check(State),
+ erlang:trace_pattern({erlang,spawn,3},false,[meta]),
erlang:trace_pattern({erlang,spawn_link,3},false,[meta]),
erlang:trace_pattern({erlang,spawn_opt,1},false,[meta]),
erlang:trace_pattern({erlang,register,2},false,[meta]),
erlang:trace_pattern({global,register_name,2},false,[meta]);
stop ->
- ok
+ try_stop_resume(State),
+ try_stop_overload_check(State)
+ end.
+
+try_stop_overload_check(State) ->
+ case proplists:get_value(overload, State) of
+ undefined -> ok;
+ {_, M, F} -> catch M:F(stop)
end.
pnames() ->
@@ -222,6 +416,40 @@ pinfo(P,Globals) ->
undefined -> [] % the process has terminated
end.
+autostart_module() ->
+ element(2, application:get_env(runtime_tools, ttb_autostart_module)).
+
+try_stop_resume(State) ->
+ case proplists:get_value(resume, State) of
+ true -> (autostart_module()):delete_config();
+ _ -> ok
+ end.
+
+ttb_resume_trace() ->
+ case (autostart_module()):read_config() of
+ {error, _} ->
+ ok;
+ {ok, Data} ->
+ Pid = proplists:get_value(ttb_control, Data),
+ {_, Timeout} = proplists:get_value(resume, Data),
+ case rpc:call(node(Pid), erlang, whereis, [ttb]) of
+ Pid ->
+ Pid ! {noderesumed, node(), self()},
+ wait_for_fetch_ready(Timeout);
+ _ ->
+ ok
+ end,
+ (autostart_module()):delete_config(),
+ ok
+ end.
+
+wait_for_fetch_ready(Timeout) ->
+ receive
+ trace_resumed ->
+ ok
+ after Timeout ->
+ ok
+ end.
ttb_store_meta(Data,{local,MetaFile,Port}) when is_list(Data) ->
ttb_send_to_port(Port,MetaFile,Data);
@@ -273,6 +501,9 @@ ttb_stop(MetaPid) ->
%% returns, and then the Port (in {local,MetaFile,Port})
%% cannot be accessed any more.
receive {'DOWN', Ref, process, MetaPid, _Info} -> ok end,
+ stop_seq_trace().
+
+stop_seq_trace() ->
seq_trace:reset_trace(),
seq_trace:set_system_tracer(false).
@@ -287,7 +518,7 @@ ttb_fetch(MetaFile,{Port,Host}) ->
send_files({Sock,Host},[File|Files]) ->
{ok,Fd} = file:open(File,[raw,read,binary]),
- gen_tcp:send(Sock,<<1,(list_to_binary(File))/binary>>),
+ gen_tcp:send(Sock,<<1,(list_to_binary(filename:basename(File)))/binary>>),
send_chunks(Sock,Fd),
file:delete(File),
send_files({Sock,Host},Files);
@@ -318,3 +549,62 @@ match_filenames(Dir,MetaFile,[H|T],Files) ->
end;
match_filenames(_Dir,_MetaFile,[],Files) ->
Files.
+
+
+%%%%%%%%%%%%%%%%%
+
+sys_tables() ->
+ [ac_tab, asn1,
+ cdv_dump_index_table, cdv_menu_table, cdv_decode_heap_table,
+ cell_id, cell_pos, clist,
+ cover_internal_data_table, cover_collected_remote_data_table, cover_binary_code_table,
+ code, code_names, cookies,
+ corba_policy, corba_policy_associations,
+ dets, dets_owners, dets_registry,
+ disk_log_names, disk_log_pids,
+ eprof, erl_atom_cache, erl_epmd_nodes,
+ etop_accum_tab, etop_tr,
+ ets_coverage_data,
+ file_io_servers,
+ gs_mapping, gs_names, gstk_db,
+ gstk_grid_cellid, gstk_grid_cellpos, gstk_grid_id,
+ httpd,
+ id,
+ ign_req_index, ign_requests,
+ index,
+ inet_cache, inet_db, inet_hosts,
+ 'InitialReferences',
+ int_db,
+ interpreter_includedirs_macros,
+ ir_WstringDef,
+ lmcounter, locks,
+ % mnesia_decision,
+ mnesia_gvar, mnesia_stats,
+ % mnesia_transient_decision,
+ pg2_table,
+ queue,
+ schema,
+ shell_records,
+ snmp_agent_table, snmp_local_db2, snmp_mib_data, snmp_note_store, snmp_symbolic_ets,
+ tkFun, tkLink, tkPriv,
+ ttb, ttb_history_table,
+ udp_fds, udp_pids
+ ].
+
+sys_processes() ->
+ [auth, code_server, global_name_server, inet_db,
+ mnesia_recover, net_kernel, timer_server, wxe_master].
+
+mnesia_tables() ->
+ [ir_AliasDef, ir_ArrayDef, ir_AttributeDef, ir_ConstantDef,
+ ir_Contained, ir_Container, ir_EnumDef, ir_ExceptionDef,
+ ir_IDLType, ir_IRObject, ir_InterfaceDef, ir_ModuleDef,
+ ir_ORB, ir_OperationDef, ir_PrimitiveDef, ir_Repository,
+ ir_SequenceDef, ir_StringDef, ir_StructDef, ir_TypedefDef,
+ ir_UnionDef, logTable, logTransferTable, mesh_meas,
+ mesh_type, mnesia_clist, orber_CosNaming,
+ orber_objkeys, user
+ ].
+
+ignore(true, Reason) -> throw(Reason);
+ignore(_,_ ) -> ok.
diff --git a/lib/runtime_tools/src/runtime_tools.app.src b/lib/runtime_tools/src/runtime_tools.app.src
index e6dc7a21d4..76fd998530 100644
--- a/lib/runtime_tools/src/runtime_tools.app.src
+++ b/lib/runtime_tools/src/runtime_tools.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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
@@ -22,7 +22,8 @@
{modules, [dbg,observer_backend,percept_profile,
inviso_rt,inviso_rt_lib,inviso_rt_meta,
inviso_as_lib,inviso_autostart,inviso_autostart_server,
- runtime_tools,runtime_tools_sup,erts_alloc_config]},
+ runtime_tools,runtime_tools_sup,erts_alloc_config,
+ ttb_autostart]},
{registered, [runtime_tools_sup,inviso_rt,inviso_rt_meta]},
{applications, [kernel, stdlib]},
% {env, [{inviso_autostart_mod,your_own_autostart_module}]},
diff --git a/lib/runtime_tools/src/runtime_tools_sup.erl b/lib/runtime_tools/src/runtime_tools_sup.erl
index 1a872c355d..913719c449 100644
--- a/lib/runtime_tools/src/runtime_tools_sup.erl
+++ b/lib/runtime_tools/src/runtime_tools_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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
@@ -38,6 +38,8 @@
init(AutoModArgs) ->
Flags = {one_for_one, 0, 3600},
Children = [{inviso_rt, {inviso_rt, start_link_auto, [AutoModArgs]},
- temporary, 3000, worker, [inviso_rt]}],
+ temporary, 3000, worker, [inviso_rt]},
+ {ttb_autostart, {ttb_autostart, start_link, []},
+ temporary, 3000, worker, [ttb_autostart]}],
{ok, {Flags, Children}}.
%% -----------------------------------------------------------------------------
diff --git a/lib/runtime_tools/src/ttb_autostart.erl b/lib/runtime_tools/src/ttb_autostart.erl
new file mode 100644
index 0000000000..4c6971c119
--- /dev/null
+++ b/lib/runtime_tools/src/ttb_autostart.erl
@@ -0,0 +1,55 @@
+%%%-------------------------------------------------------------------
+%%% File : ttb_autostart.erl
+%%% Author : Bartłomiej Puzoń <[email protected]>
+%%% Description : This supervisor is used to resume ttb tracing
+%%% Users are able to provide custom restart modules for *_config, as
+%%% file:write/read/delete may not be possible on diskless nodes.
+%%%
+%%% Created : 31 Jul 2010 by <[email protected]>
+%%%-------------------------------------------------------------------
+-module(ttb_autostart).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/0,
+ read_config/0,
+ write_config/1,
+ delete_config/0]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-define(DEF_AUTOSTART_MODULE, ?MODULE).
+-define(AUTOSTART_FILENAME, "ttb_autostart.bin").
+
+start_link() ->
+ gen_server:start_link(?MODULE, no_args, []).
+
+delete_config() ->
+ file:delete(?AUTOSTART_FILENAME).
+
+read_config() ->
+ case file:read_file(?AUTOSTART_FILENAME) of
+ {ok, Data} -> {ok, binary_to_term(Data)};
+ Error -> Error
+ end.
+
+write_config(Data) ->
+ file:write_file(?AUTOSTART_FILENAME, term_to_binary(Data)).
+
+init(no_args) ->
+ case application:get_env(runtime_tools, ttb_autostart_module) of
+ {ok, _} -> ok;
+ undefined -> application:set_env(runtime_tools, ttb_autostart_module, ?DEF_AUTOSTART_MODULE)
+ end,
+ observer_backend:ttb_resume_trace(),
+ %%As the process is not needed any more, it will shut itself down
+ {ok, no_args, 10000}.
+
+handle_call(_,_,_) -> {noreply, no_args}.
+handle_cast(_,_) -> {noreply, no_args}.
+handle_info(timeout,_) -> {stop, normal, no_args}.
+terminate(_,_) -> ok.
+code_change(_,_,_) -> {ok, no_args}.
diff --git a/lib/runtime_tools/test/inviso_SUITE.erl b/lib/runtime_tools/test/inviso_SUITE.erl
index 3ae8d34dd6..758867cf45 100644
--- a/lib/runtime_tools/test/inviso_SUITE.erl
+++ b/lib/runtime_tools/test/inviso_SUITE.erl
@@ -1380,9 +1380,10 @@ fetch_log_dist_trace_2(Config) ->
io:format("~p~n",[NodeResults]),
CheckFun=fun({N,{complete,[{trace_log,FileResults1},{ti_log,[{ok,TiFile}]}]}}) ->
Fun2=fun({ok,File}) ->
- {match,1,_}=
- regexp:first_match(File,
- "^"++"p1"++Name++atom_to_list(N)),
+ match=
+ re:run(File,
+ "^"++"p1"++Name++atom_to_list(N),
+ [{capture,none}]),
true;
(_) ->
false
@@ -1425,8 +1426,8 @@ fetch_log_dist_trace_3(Config) ->
CheckFun=fun({N,{ok,[{trace_log,PrivDir2,[F1,F2]},{ti_log,PrivDir2,[F3]}]}})->
PrivDir2=PrivDir,
RegExp="^"++Name++atom_to_list(N)++"[0-9]+"++"\.log",
- {match,1,_}=regexp:first_match(F1,RegExp),
- {match,1,_}=regexp:first_match(F2,RegExp),
+ match=re:run(F1,RegExp,[{capture,none}]),
+ match=re:run(F2,RegExp,[{capture,none}]),
F3=Name++"_ti_"++atom_to_list(N)++".ti",
true;
(_) ->
@@ -1439,9 +1440,10 @@ fetch_log_dist_trace_3(Config) ->
io:format("~p~n",[NodeResults2]),
CheckFun2=fun({N,{complete,[{trace_log,FileResults1},{ti_log,[{ok,TiFile}]}]}}) ->
Fun2=fun({ok,File}) ->
- {match,1,_}=
- regexp:first_match(File,
- "^"++"p1"++Name++atom_to_list(N)),
+ match=
+ re:run(File,
+ "^"++"p1"++Name++atom_to_list(N),
+ [{capture,none}]),
true;
(_) ->
false
@@ -2649,8 +2651,8 @@ check_on_nodes([],_,_,_,_) ->
how_many_files_regexp([],_,N) ->
{ok,N};
how_many_files_regexp([FName|Rest],RegExp,N) ->
- case regexp:first_match(FName,RegExp) of
- {match,1,_} ->
+ case re:run(FName,RegExp,[{capture,none}]) of
+ match ->
how_many_files_regexp(Rest,RegExp,N+1);
nomatch ->
how_many_files_regexp(Rest,RegExp,N);
diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk
index 0bcd261861..3fbc1b3379 100644
--- a/lib/runtime_tools/vsn.mk
+++ b/lib/runtime_tools/vsn.mk
@@ -1 +1 @@
-RUNTIME_TOOLS_VSN = 1.8.6
+RUNTIME_TOOLS_VSN = 1.8.7