diff options
Diffstat (limited to 'lib/runtime_tools')
-rw-r--r-- | lib/runtime_tools/c_src/trace_file_drv.c | 90 | ||||
-rw-r--r-- | lib/runtime_tools/c_src/trace_ip_drv.c | 19 | ||||
-rw-r--r-- | lib/runtime_tools/src/observer_backend.erl | 215 |
3 files changed, 298 insertions, 26 deletions
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..713ae924f6 100644 --- a/lib/runtime_tools/c_src/trace_ip_drv.c +++ b/lib/runtime_tools/c_src/trace_ip_drv.c @@ -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/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl index 9c1f9da5b1..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"). @@ -42,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 @@ -395,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. |