From 665e12562a4aa4f40aeeed0cfd207b49f89c9fd1 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Wed, 8 Jul 2009 13:04:10 -0400 Subject: PR3498 cont'd, fix wildcard module("*") probes * dwflpp.cxx (name_has_wildcard): Make static. (dwfl_report_offline_predicate): Check & adjust behavior. * dwflpp.h: Corresponding changes. * tapsets.cxx: Note that kern_dw[] keys may be wildcard strings. * testsuite/buildok/fortysix.stp: New test. --- dwflpp.cxx | 44 +++++++++++++++++++++--------------------- dwflpp.h | 2 +- tapsets.cxx | 2 +- testsuite/buildok/fortysix.stp | 3 +++ 4 files changed, 27 insertions(+), 24 deletions(-) create mode 100755 testsuite/buildok/fortysix.stp diff --git a/dwflpp.cxx b/dwflpp.cxx index 17bce608..531d413e 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -205,7 +205,7 @@ dwflpp::module_name_matches(const string& pattern) bool -dwflpp::name_has_wildcard(const string& pattern) +dwflpp::name_has_wildcard (const string& pattern) { return (pattern.find('*') != string::npos || pattern.find('?') != string::npos || @@ -258,19 +258,30 @@ static int dwfl_report_offline_predicate (const char* modname, const char* filen if (pending_interrupts) return -1; - if (offline_search_match_p) - return -1; - assert (offline_search_modname); - /* Reject mismatching module names */ - if (strcmp(modname, offline_search_modname)) - return 0; - else - { + if (dwflpp::name_has_wildcard (offline_search_modname)) { + int match_p = !fnmatch(offline_search_modname, modname, 0); + // In the wildcard case, we don't short-circuit (return -1) upon + // offline_search_match_p, analogously to dwflpp::module_name_final_match(). + + if (match_p) offline_search_match_p ++; - return 1; - } + + return match_p; + } else { /* non-wildcard mode */ + if (offline_search_match_p) + return -1; + + /* Reject mismatching module names */ + if (strcmp(modname, offline_search_modname)) + return 0; + else + { + offline_search_match_p ++; + return 1; + } + } } @@ -339,17 +350,6 @@ dwflpp::setup_kernel(const string& name, bool debuginfo_needed) sess.kernel_build_tree + string("'")); } - // XXX: it would be nice if we could do a single - // ..._report_offline call for an entire systemtap script, so - // that a selection predicate would filter out modules outside - // the union of all the requested wildcards. But we build - // derived_probes one-by-one and we don't have lookahead. - // PR 3498. - - // XXX: a special case: if we have only kernel.* probe points, - // we shouldn't waste time looking for module debug-info (and - // vice versa). - // NB: the result of an _offline call is the assignment of // virtualized addresses to relocatable objects such as // modules. These have to be converted to real addresses at diff --git a/dwflpp.h b/dwflpp.h index d6d97cd0..e0098b9b 100644 --- a/dwflpp.h +++ b/dwflpp.h @@ -178,7 +178,7 @@ struct dwflpp Dwarf_Die *query_cu_containing_address(Dwarf_Addr a); bool module_name_matches(const std::string& pattern); - bool name_has_wildcard(const std::string& pattern); + static bool name_has_wildcard(const std::string& pattern); bool module_name_final_match(const std::string& pattern); bool function_name_matches_pattern(const std::string& name, const std::string& pattern); diff --git a/tapsets.cxx b/tapsets.cxx index 4988b7e7..aecdca61 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -589,7 +589,7 @@ struct dwarf_query : public base_query struct dwarf_builder: public derived_probe_builder { - map kern_dw; + map kern_dw; /* NB: key string could be a wildcard */ map user_dw; dwarf_builder() {} diff --git a/testsuite/buildok/fortysix.stp b/testsuite/buildok/fortysix.stp new file mode 100755 index 00000000..013ca5bc --- /dev/null +++ b/testsuite/buildok/fortysix.stp @@ -0,0 +1,3 @@ +#! stap -p4 +// PR 3498 + wildcarded modules +probe module("*scsi*").function("*").call { } -- cgit From 1e959ba39674f73ba0691ec2a77d151baeb3381e Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Wed, 8 Jul 2009 16:30:15 -0400 Subject: Do not use GPL for sdt.h. --- includes/sys/sdt.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/includes/sys/sdt.h b/includes/sys/sdt.h index 07ece7c1..e12b1482 100644 --- a/includes/sys/sdt.h +++ b/includes/sys/sdt.h @@ -1,10 +1,6 @@ /* Copyright (C) 2005-2009 Red Hat Inc. - Copyright (C) 2006 Intel Corporation. - This file is part of systemtap, and is free software. You can - redistribute it and/or modify it under the terms of the GNU General - Public License (GPL); either version 2, or (at your option) any - later version. + This file is part of systemtap, and is free software. */ #ifndef _SYS_SDT_H -- cgit From b4fbb579fdd73eb1e61784ffa8c9ba02f89f8e26 Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Wed, 8 Jul 2009 17:05:27 -0400 Subject: Clarify sdt.h license for public domain. --- includes/sys/sdt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/sys/sdt.h b/includes/sys/sdt.h index e12b1482..e448c90e 100644 --- a/includes/sys/sdt.h +++ b/includes/sys/sdt.h @@ -1,6 +1,6 @@ /* Copyright (C) 2005-2009 Red Hat Inc. - This file is part of systemtap, and is free software. + This file is part of systemtap, and is free software in the public domain. */ #ifndef _SYS_SDT_H -- cgit From 07089f8b693de995b5fd51b28a4846122143138e Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 9 Jul 2009 00:02:52 -0700 Subject: Fix signal.send matching for 2.6.30+. --- tapset/signal.stp | 54 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/tapset/signal.stp b/tapset/signal.stp index e8470a9c..02c761c3 100644 --- a/tapset/signal.stp +++ b/tapset/signal.stp @@ -1,7 +1,7 @@ // Signal tapset // Copyright (C) 2006 IBM Corp. // Copyright (C) 2006 Intel Corporation. -// Copyright (C) 2008 Red Hat, Inc. +// Copyright (C) 2008-2009 Red Hat, Inc. // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General @@ -17,7 +17,7 @@ // (if sig==2) or for a particular process (if pid_name==stap). // -/** +/** * probe signal.send - Signal being sent to a process * Arguments: * @sig: The number of the signal @@ -83,7 +83,9 @@ probe _signal.send.part4 = kernel.function("specific_send_sig_info") %) %( kernel_v > "2.6.25" %? -probe _signal.send.part1 = kernel.function("send_signal") +probe _signal.send.part1 = + kernel.function("__send_signal") !, + kernel.function("send_signal") { if ($group == 1) { name = "__group_send_sig_info" @@ -128,7 +130,7 @@ probe _signal.send.part3 = kernel.function("send_sigqueue") * Context: * The signal's sender. (correct?) * - * Possible __group_send_sig_info and + * Possible __group_send_sig_info and * specific_send_sig_info return values are as follows; * * 0 -- The signal is sucessfully sent to a process, @@ -137,11 +139,11 @@ probe _signal.send.part3 = kernel.function("send_sigqueue") * <2> this is a non-RT signal and the system already has one queued, and * <3> the signal was successfully added to the sigqueue of the receiving process. * - * -EAGAIN -- The sigqueue of the receiving process is - * overflowing, the signal was RT, and the signal was sent by a user using something other - * than kill(). + * -EAGAIN -- The sigqueue of the receiving process is + * overflowing, the signal was RT, and the signal was sent by a user using something other + * than kill(). * - * Possible send_group_sigqueue and + * Possible send_group_sigqueue and * send_sigqueue return values are as follows; * * 0 -- The signal was either sucessfully added into the @@ -152,7 +154,7 @@ probe _signal.send.part3 = kernel.function("send_sigqueue") * * -1 -- (send_sigqueue only) The task was marked * exiting, allowing * posix_timer_event to redirect it to the group - * leader. + * leader. * */ probe signal.send.return = _signal.send.*.return @@ -302,7 +304,7 @@ probe signal.wakeup = kernel.function("signal_wake_up") /** * probe signal.check_ignored - Checking to see signal is ignored - * @sig_pid: The PID of the process receiving the signal + * @sig_pid: The PID of the process receiving the signal * @pid_name: Name of the process receiving the signal * @sig: The number of the signal * @sig_name: A string representation of the signal @@ -350,7 +352,7 @@ probe signal.handle_stop = kernel.function("handle_stop_signal") * @sig_pid: The PID of the process receiving the signal * @pid_name: Name of the process receiving the signal * @sig: The number of the signal - * @sig_name: A string representation of the signal + * @sig_name: A string representation of the signal */ probe signal.force_segv = _signal.force_segv.* { @@ -404,7 +406,7 @@ probe signal.syskill.return = syscall.kill.return { } -/** +/** * probe signal.sys_tkill - Sending a kill signal to a thread * @pid: The PID of the process receiving the kill signal * @sig: The specific signal sent to the process @@ -413,7 +415,7 @@ probe signal.syskill.return = syscall.kill.return * The tkill call is analogous to kill(2), * except that it also allows a process within a specific thread group to * be targetted. Such processes are targetted through their unique - * thread IDs (TID). + * thread IDs (TID). */ probe signal.systkill = syscall.tkill { @@ -434,9 +436,9 @@ probe signal.systkill.return = syscall.tkill.return * @sig: The specific kill signal sent to the process * @sig_name: A string representation of the signal * - * The tgkill call is similar to tkill, - * except that it also allows the caller to specify the thread group ID of - * the thread to be signalled. This protects against TID reuse. + * The tgkill call is similar to tkill, + * except that it also allows the caller to specify the thread group ID of + * the thread to be signalled. This protects against TID reuse. */ probe signal.systgkill = syscall.tgkill { @@ -481,14 +483,14 @@ probe signal.send_sig_queue.return = } -/** +/** * probe signal.pending - Examining pending signal * @sigset_add: The address of the user-space signal set * (sigset_t) * @sigset_size: The size of the user-space signal set - * - * This probe is used to examine a set of signals pending for delivery - * to a specific thread. This normally occurs when the + * + * This probe is used to examine a set of signals pending for delivery + * to a specific thread. This normally occurs when the * do_sigpending kernel function is executed. */ probe signal.pending = kernel.function("do_sigpending") @@ -497,7 +499,7 @@ probe signal.pending = kernel.function("do_sigpending") sigset_size=$sigsetsize } -/** +/** * probe signal.pending.return - Examination of pending signal completed * @retstr: Return value as a string */ @@ -515,7 +517,7 @@ probe signal.pending.return = kernel.function("do_sigpending").return * siginfo signal * @ka_addr: The address of the k_sigaction table * associated with the signal - * @oldset_addr: The address of the bitmask array of blocked signals + * @oldset_addr: The address of the bitmask array of blocked signals * @regs: The address of the kernel-mode stack area * @sig_mode: Indicates whether the signal was a user-mode or kernel-mode signal */ @@ -593,9 +595,9 @@ function __get_action_mask:long(act:long) %{ /* pure */ /** * probe signal.procmask - Examining or changing blocked signals - * @how: Indicates how to change the blocked signals; possible values are - * SIG_BLOCK=0 (for blocking signals), - * SIG_UNBLOCK=1 (for unblocking signals), and + * @how: Indicates how to change the blocked signals; possible values are + * SIG_BLOCK=0 (for blocking signals), + * SIG_UNBLOCK=1 (for unblocking signals), and * SIG_SETMASK=2 for setting the signal mask. * @sigset_addr: The address of the signal set (sigset_t) * to be implemented @@ -635,7 +637,7 @@ probe signal.procmask.return = kernel.function("sigprocmask").return * @sig_pid: The PID of the process associated with the task * performing the flush * @pid_name: The name of the process associated with the task - * performing the flush + * performing the flush */ probe signal.flush = kernel.function("flush_signals") { -- cgit From fd6fef3d049555f7af24ba94fbcf42a846390dd1 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 9 Jul 2009 13:39:03 -0400 Subject: PR3498, cont'd * dwflpp.cxx (dwfl_report_offline_predicate): Reject NULL filenames. --- dwflpp.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dwflpp.cxx b/dwflpp.cxx index 531d413e..8fa31c6a 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -260,6 +260,10 @@ static int dwfl_report_offline_predicate (const char* modname, const char* filen assert (offline_search_modname); + // elfutils sends us NULL filenames sometimes if it can't find dwarf + if (filename == NULL) + return 0; + if (dwflpp::name_has_wildcard (offline_search_modname)) { int match_p = !fnmatch(offline_search_modname, modname, 0); // In the wildcard case, we don't short-circuit (return -1) upon -- cgit From c145b9cb053a1275865302d23fb3072143534fc8 Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 9 Jul 2009 15:16:57 -0500 Subject: Added timer data flushing and overwrite handling to the ring_buffer transport. * buildrun.cxx (compile_pass): Checks for ring_buffer api change. * runtime/autoconf-ring_buffer-flags.c: New file. * runtime/transport/ring_buffer.c (tracing_wait_pipe): No longer schedules, just returns. The timer function will handle it later. (_stp_data_write_reserve): Handles ring_buffer api change. Added overwrite processing. If we're full, delete an event to make room. (_stp_data_write_commit): Handles ring_buffer api change. (__stp_relay_wakeup_timer): New function. (__stp_relay_timer_start): Ditto. (__stp_relay_timer_stop): Ditto. (_stp_transport_data_fs_start): Calls __stp_relay_timer_start(). (_stp_transport_data_fs_stop): Calls __stp_relay_timer_stop(). (_stp_transport_data_fs_overwrite): Sets overwrite flag. --- buildrun.cxx | 1 + runtime/autoconf-ring_buffer-flags.c | 6 ++ runtime/transport/ring_buffer.c | 136 ++++++++++++++++++++++++----------- 3 files changed, 103 insertions(+), 40 deletions(-) create mode 100644 runtime/autoconf-ring_buffer-flags.c diff --git a/buildrun.cxx b/buildrun.cxx index 54aa5d4f..ccf1ca15 100644 --- a/buildrun.cxx +++ b/buildrun.cxx @@ -171,6 +171,7 @@ compile_pass (systemtap_session& s) "STAPCONF_KERNEL_STACKTRACE", NULL); output_autoconf(s, o, "autoconf-asm-syscall.c", "STAPCONF_ASM_SYSCALL_H", NULL); + output_autoconf(s, o, "autoconf-ring_buffer-flags.c", "STAPCONF_RING_BUFFER_FLAGS", NULL); o << module_cflags << " += -include $(STAPCONF_HEADER)" << endl; diff --git a/runtime/autoconf-ring_buffer-flags.c b/runtime/autoconf-ring_buffer-flags.c new file mode 100644 index 00000000..7d7b8df0 --- /dev/null +++ b/runtime/autoconf-ring_buffer-flags.c @@ -0,0 +1,6 @@ +#include + +void ___autoconf_func(void) +{ + (void)ring_buffer_lock_reserve(NULL, 0, 0); +} diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 0b73d4b4..fe63bc83 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -4,6 +4,11 @@ #include #include +#ifndef STP_RELAY_TIMER_INTERVAL +/* Wakeup timer interval in jiffies (default 10 ms) */ +#define STP_RELAY_TIMER_INTERVAL ((HZ + 99) / 100) +#endif + struct _stp_data_entry { size_t len; unsigned char buf[]; @@ -23,6 +28,8 @@ struct _stp_relay_data_type { struct ring_buffer *rb; struct _stp_ring_buffer_data rb_data; cpumask_var_t trace_reader_cpumask; + struct timer_list timer; + int overwrite_flag; }; static struct _stp_relay_data_type _stp_relay_data; @@ -134,48 +141,33 @@ _stp_event_to_user(struct ring_buffer_event *event, char __user *ubuf, return cnt; } -static ssize_t tracing_wait_pipe(struct file *filp) +static ssize_t _stp_tracing_wait_pipe(struct file *filp) { - while (ring_buffer_empty(_stp_relay_data.rb)) { - + if (ring_buffer_empty(_stp_relay_data.rb)) { if ((filp->f_flags & O_NONBLOCK)) { dbug_trans(1, "returning -EAGAIN\n"); return -EAGAIN; } - /* - * This is a make-shift waitqueue. The reason we don't use - * an actual wait queue is because: - * 1) we only ever have one waiter - * 2) the tracing, traces all functions, we don't want - * the overhead of calling wake_up and friends - * (and tracing them too) - * Anyway, this is really very primitive wakeup. - */ - set_current_state(TASK_INTERRUPTIBLE); - - /* sleep for 100 msecs, and try again. */ - schedule_timeout(HZ/10); - if (signal_pending(current)) { dbug_trans(1, "returning -EINTR\n"); return -EINTR; } + dbug_trans(1, "returning 0\n"); + return 0; } dbug_trans(1, "returning 1\n"); return 1; } -static struct ring_buffer_event * -peek_next_event(int cpu, u64 *ts) +static struct ring_buffer_event *_stp_peek_next_event(int cpu, u64 *ts) { return ring_buffer_peek(_stp_relay_data.rb, cpu, ts); } /* Find the next real event */ -static struct ring_buffer_event * -_stp_find_next_event(long cpu_file) +static struct ring_buffer_event *_stp_find_next_event(long cpu_file) { struct ring_buffer_event *event; @@ -186,7 +178,7 @@ _stp_find_next_event(long cpu_file) */ if (ring_buffer_empty_cpu(_stp_relay_data.rb, (int)cpu_file)) return NULL; - event = peek_next_event(cpu_file, &_stp_relay_data.rb_data.ts); + event = _stp_peek_next_event(cpu_file, &_stp_relay_data.rb_data.ts); _stp_relay_data.rb_data.cpu = cpu_file; return event; @@ -201,7 +193,7 @@ _stp_find_next_event(long cpu_file) if (ring_buffer_empty_cpu(_stp_relay_data.rb, cpu)) continue; - event = peek_next_event(cpu, &ts); + event = _stp_peek_next_event(cpu, &ts); /* * Pick the event with the smallest timestamp: @@ -234,8 +226,8 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, dbug_trans(1, "%lu\n", (unsigned long)cnt); - sret = tracing_wait_pipe(filp); - dbug_trans(1, "tracing_wait_pipe returned %ld\n", sret); + sret = _stp_tracing_wait_pipe(filp); + dbug_trans(1, "_stp_tracing_wait_pipe returned %ld\n", sret); if (sret <= 0) goto out; @@ -291,9 +283,6 @@ static struct file_operations __stp_data_fops = { .release = _stp_data_release_trace, .poll = _stp_data_poll_trace, .read = _stp_data_read_trace, -#if 0 - .splice_read = tracing_splice_read_pipe, -#endif }; /* @@ -331,13 +320,56 @@ _stp_data_write_reserve(size_t size_request, void **entry) size_request = __STP_MAX_RESERVE_SIZE; } +#ifdef STAPCONF_RING_BUFFER_FLAGS + event = ring_buffer_lock_reserve(_stp_relay_data.rb, + (sizeof(struct _stp_data_entry) + + size_request), 0); +#else event = ring_buffer_lock_reserve(_stp_relay_data.rb, - sizeof(struct _stp_data_entry) + size_request, - 0); + (sizeof(struct _stp_data_entry) + + size_request)); +#endif if (unlikely(! event)) { - dbug_trans(1, "event = NULL (%p)?\n", event); - entry = NULL; - return 0; + int cpu; + + dbug_trans(0, "event = NULL (%p)?\n", event); + if (! _stp_relay_data.overwrite_flag) { + entry = NULL; + return 0; + } + + /* If we're in overwrite mode and all the buffers are + * full, take a event out of the buffer and consume it + * (throw it away). This should make room for the new + * data. */ + cpu = raw_smp_processor_id(); + event = _stp_find_next_event(cpu); + if (event) { + ssize_t len; + + sde = (struct _stp_data_entry *)ring_buffer_event_data(event); + if (sde->len < size_request) + size_request = sde->len; + ring_buffer_consume(_stp_relay_data.rb, cpu, + &_stp_relay_data.rb_data.ts); + _stp_relay_data.rb_data.cpu = cpu; + + /* Try to reserve again. */ +#ifdef STAPCONF_RING_BUFFER_FLAGS + event = ring_buffer_lock_reserve(_stp_relay_data.rb, + sizeof(struct _stp_data_entry) + size_request, + 0); +#else + event = ring_buffer_lock_reserve(_stp_relay_data.rb, + sizeof(struct _stp_data_entry) + size_request); +#endif + dbug_trans(0, "overwritten event = 0x%p\n", event); + } + + if (unlikely(! event)) { + entry = NULL; + return 0; + } } sde = (struct _stp_data_entry *)ring_buffer_event_data(event); @@ -361,7 +393,6 @@ static unsigned char *_stp_data_entry_data(void *entry) static int _stp_data_write_commit(void *entry) { - int ret; struct ring_buffer_event *event = (struct ring_buffer_event *)entry; if (unlikely(! entry)) { @@ -369,14 +400,35 @@ static int _stp_data_write_commit(void *entry) return -EINVAL; } - ret = ring_buffer_unlock_commit(_stp_relay_data.rb, event, 0); - dbug_trans(1, "after commit, empty returns %d\n", - ring_buffer_empty(_stp_relay_data.rb)); +#ifdef STAPCONF_RING_BUFFER_FLAGS + return ring_buffer_unlock_commit(_stp_relay_data.rb, event, 0); +#else + return ring_buffer_unlock_commit(_stp_relay_data.rb, event); +#endif +} + +static void __stp_relay_wakeup_timer(unsigned long val) +{ + if (waitqueue_active(&_stp_poll_wait) + && ! ring_buffer_empty(_stp_relay_data.rb)) + wake_up_interruptible(&_stp_poll_wait); + mod_timer(&_stp_relay_data.timer, jiffies + STP_RELAY_TIMER_INTERVAL); +} - wake_up_interruptible(&_stp_poll_wait); - return ret; +static void __stp_relay_timer_start(void) +{ + init_timer(&_stp_relay_data.timer); + _stp_relay_data.timer.expires = jiffies + STP_RELAY_TIMER_INTERVAL; + _stp_relay_data.timer.function = __stp_relay_wakeup_timer; + _stp_relay_data.timer.data = 0; + add_timer(&_stp_relay_data.timer); + smp_mb(); } +static void __stp_relay_timer_stop(void) +{ + del_timer_sync(&_stp_relay_data.timer); +} static struct dentry *__stp_entry[NR_CPUS] = { NULL }; @@ -422,6 +474,7 @@ static int _stp_transport_data_fs_init(void) __stp_entry[cpu]->d_inode->i_uid = _stp_uid; __stp_entry[cpu]->d_inode->i_gid = _stp_gid; + __stp_entry[cpu]->d_inode->i_private = (void *)cpu; #ifndef STP_BULKMODE if (cpu != 0) @@ -437,6 +490,7 @@ static int _stp_transport_data_fs_init(void) static void _stp_transport_data_fs_start(void) { if (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED) { + __stp_relay_timer_start(); _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; } } @@ -444,6 +498,7 @@ static void _stp_transport_data_fs_start(void) static void _stp_transport_data_fs_stop(void) { if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) { + __stp_relay_timer_stop(); _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; } } @@ -468,5 +523,6 @@ static enum _stp_transport_state _stp_transport_get_state(void) static void _stp_transport_data_fs_overwrite(int overwrite) { - /* FIXME: Just a place holder for now. */ + dbug_trans(0, "setting ovewrite to %d\n", overwrite); + _stp_relay_data.overwrite_flag = overwrite; } -- cgit From 66c7d4c1a4147bc05abd1e69f41ec9d59685c433 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 9 Jul 2009 12:43:00 -0700 Subject: Optimize string usage in the lexer This speeds up the parsing stage >2x, mostly by minimizing string construction and comparison where char comparison will do. --- parse.cxx | 203 +++++++++++++++++++++++++++++--------------------------------- parse.h | 11 ++-- 2 files changed, 101 insertions(+), 113 deletions(-) diff --git a/parse.cxx b/parse.cxx index a26d594c..028ac71a 100644 --- a/parse.cxx +++ b/parse.cxx @@ -583,16 +583,38 @@ parser::peek_kw (std::string const & kw) -lexer::lexer (istream& i, const string& in, systemtap_session& s): - input (i), input_name (in), input_contents (""), - input_pointer (0), cursor_suspend_count(0), - cursor_line (1), cursor_column (1), session(s), - current_file (0) -{ - char c; - while(input.get(c)) - input_contents.push_back(c); -} +lexer::lexer (istream& input, const string& in, systemtap_session& s): + input_name (in), input_contents (""), input_pointer (0), + cursor_suspend_count(0), cursor_line (1), cursor_column (1), + session(s), current_file (0) +{ + getline(input, input_contents, '\0'); + input_pointer = input_contents.data(); + input_end = input_contents.data() + input_contents.size(); + + if (keywords.empty()) + { + keywords.insert("probe"); + keywords.insert("global"); + keywords.insert("function"); + keywords.insert("if"); + keywords.insert("else"); + keywords.insert("for"); + keywords.insert("foreach"); + keywords.insert("in"); + keywords.insert("limit"); + keywords.insert("return"); + keywords.insert("delete"); + keywords.insert("while"); + keywords.insert("break"); + keywords.insert("continue"); + keywords.insert("next"); + keywords.insert("string"); + keywords.insert("long"); + } +} + +set lexer::keywords; std::string lexer::get_input_contents () @@ -609,21 +631,20 @@ lexer::set_current_file (stapfile* f) int lexer::input_peek (unsigned n) { - if (input_contents.size() > (input_pointer + n)) - return (int)(unsigned char)input_contents[input_pointer+n]; - else - return -1; + if (input_pointer + n >= input_end) + return -1; // EOF + return (unsigned char)*(input_pointer + n); } int lexer::input_get () { - int c = input_peek (0); - input_pointer ++; - + int c = input_peek(); if (c < 0) return c; // EOF + ++input_pointer; + if (cursor_suspend_count) // Track effect of input_put: preserve previous cursor/line_column // until all of its characters are consumed. @@ -648,9 +669,12 @@ lexer::input_get () void lexer::input_put (const string& chars) { - // clog << "[put:" << chars << " @" << input_pointer << "]"; - input_contents.insert (input_contents.begin() + input_pointer, chars.begin(), chars.end()); + size_t pos = input_pointer - input_contents.data(); + // clog << "[put:" << chars << " @" << pos << "]"; + input_contents.insert (pos, chars); cursor_suspend_count += chars.size(); + input_pointer = input_contents.data() + pos; + input_end = input_contents.data() + input_contents.size(); } @@ -676,7 +700,6 @@ lexer::scan (bool wildcard) } int c = input_get(); - int c2 = input_peek (); // clog << "{" << (char)c << (char)c2 << "}"; if (c < 0) { @@ -687,6 +710,8 @@ lexer::scan (bool wildcard) if (isspace (c)) goto skip; + int c2 = input_peek (); + // Paste command line arguments as character streams into // the beginning of a token. $1..$999 go through as raw // characters; @1..@999 are quoted/escaped as strings. @@ -740,23 +765,7 @@ lexer::scan (bool wildcard) c2 = input_peek (); } - if (n->content == "probe" - || n->content == "global" - || n->content == "function" - || n->content == "if" - || n->content == "else" - || n->content == "for" - || n->content == "foreach" - || n->content == "in" - || n->content == "limit" - || n->content == "return" - || n->content == "delete" - || n->content == "while" - || n->content == "break" - || n->content == "continue" - || n->content == "next" - || n->content == "string" - || n->content == "long") + if (keywords.count(n->content)) n->type = tok_keyword; return n; @@ -767,23 +776,15 @@ lexer::scan (bool wildcard) n->type = tok_number; n->content = (char) c; - while (1) + while (isalnum (c2)) { - int c2 = input_peek (); - if (c2 < 0) - break; - // NB: isalnum is very permissive. We rely on strtol, called in // parser::parse_literal below, to confirm that the number string // is correctly formatted and in range. - if (isalnum (c2)) - { - n->content.push_back (c2); - input_get (); - } - else - break; + input_get (); + n->content.push_back (c2); + c2 = input_peek (); } return n; } @@ -835,25 +836,21 @@ lexer::scan (bool wildcard) else if (ispunct (c)) { - int c2 = input_peek (); int c3 = input_peek (1); - string s1 = string("") + (char) c; - string s2 = (c2 > 0 ? s1 + (char) c2 : s1); - string s3 = (c3 > 0 ? s2 + (char) c3 : s2); // NB: if we were to recognize negative numeric literals here, // we'd introduce another grammar ambiguity: // 1-1 would be parsed as tok_number(1) and tok_number(-1) // instead of tok_number(1) tok_operator('-') tok_number(1) - if (s1 == "#") // shell comment + if (c == '#') // shell comment { unsigned this_line = cursor_line; do { c = input_get (); } while (c >= 0 && cursor_line == this_line); goto skip; } - else if (s2 == "//") // C++ comment + else if ((c == '/' && c2 == '/')) // C++ comment { unsigned this_line = cursor_line; do { c = input_get (); } @@ -862,15 +859,15 @@ lexer::scan (bool wildcard) } else if (c == '/' && c2 == '*') // C comment { + (void) input_get (); // swallow '*' already in c2 + c = input_get (); c2 = input_get (); - unsigned chars = 0; while (c2 >= 0) { - chars ++; // track this to prevent "/*/" from being accepted + if (c == '*' && c2 == '/') + break; c = c2; c2 = input_get (); - if (chars > 1 && c == '*' && c2 == '/') - break; } goto skip; } @@ -878,73 +875,63 @@ lexer::scan (bool wildcard) { n->type = tok_embedded; (void) input_get (); // swallow '{' already in c2 - while (true) + c = input_get (); + c2 = input_get (); + while (c2 >= 0) { - c = input_get (); - if (c < 0) // EOF - { - n->type = tok_junk; - break; - } - if (c == '%') - { - c2 = input_peek (); - if (c2 == '}') - { - (void) input_get (); // swallow '}' too - break; - } - } + if (c == '%' && c2 == '}') + return n; n->content += c; + c = c2; + c2 = input_get (); } + n->type = tok_junk; return n; } // We're committed to recognizing at least the first character // as an operator. n->type = tok_operator; + n->content = c; // match all valid operators, in decreasing size order - if (s3 == "<<<" || - s3 == "<<=" || - s3 == ">>=") + if ((c == '<' && c2 == '<' && c3 == '<') || + (c == '<' && c2 == '<' && c3 == '=') || + (c == '>' && c2 == '>' && c3 == '=')) { - n->content = s3; + n->content += c2; + n->content += c3; input_get (); input_get (); // swallow other two characters } - else if (s2 == "==" || - s2 == "!=" || - s2 == "<=" || - s2 == ">=" || - s2 == "+=" || - s2 == "-=" || - s2 == "*=" || - s2 == "/=" || - s2 == "%=" || - s2 == "&=" || - s2 == "^=" || - s2 == "|=" || - s2 == ".=" || - s2 == "&&" || - s2 == "||" || - s2 == "++" || - s2 == "--" || - s2 == "->" || - s2 == "<<" || - s2 == ">>" || + else if ((c == '=' && c2 == '=') || + (c == '!' && c2 == '=') || + (c == '<' && c2 == '=') || + (c == '>' && c2 == '=') || + (c == '+' && c2 == '=') || + (c == '-' && c2 == '=') || + (c == '*' && c2 == '=') || + (c == '/' && c2 == '=') || + (c == '%' && c2 == '=') || + (c == '&' && c2 == '=') || + (c == '^' && c2 == '=') || + (c == '|' && c2 == '=') || + (c == '.' && c2 == '=') || + (c == '&' && c2 == '&') || + (c == '|' && c2 == '|') || + (c == '+' && c2 == '+') || + (c == '-' && c2 == '-') || + (c == '-' && c2 == '>') || + (c == '<' && c2 == '<') || + (c == '>' && c2 == '>') || // preprocessor tokens - s2 == "%(" || - s2 == "%?" || - s2 == "%:" || - s2 == "%)") + (c == '%' && c2 == '(') || + (c == '%' && c2 == '?') || + (c == '%' && c2 == ':') || + (c == '%' && c2 == ')')) { - n->content = s2; + n->content += c2; input_get (); // swallow other character } - else - { - n->content = s1; - } return n; } diff --git a/parse.h b/parse.h index 59046bf3..4cc4f7b2 100644 --- a/parse.h +++ b/parse.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -78,19 +79,19 @@ public: void set_current_file (stapfile* f); private: - int input_get (); - void input_put (int); + inline int input_get (); + inline int input_peek (unsigned n=0); void input_put (const std::string&); - int input_peek (unsigned n=0); - std::istream& input; std::string input_name; std::string input_contents; - int input_pointer; // index into input_contents + const char *input_pointer; // index into input_contents + const char *input_end; unsigned cursor_suspend_count; unsigned cursor_line; unsigned cursor_column; systemtap_session& session; stapfile* current_file; + static std::set keywords; }; struct probe; -- cgit From 2203b03262e340b25fc26996cc2786c1c02041e3 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 9 Jul 2009 12:46:57 -0700 Subject: Remove the filename copy from token->location The location already has a pointer to a stapfile with the filename, so there's no need to keep an extra copy. --- coveragedb.h | 11 ++++++----- elaborate.cxx | 24 ++++++++++++------------ parse.cxx | 28 +++++++++++----------------- parse.h | 4 +--- 4 files changed, 30 insertions(+), 37 deletions(-) diff --git a/coveragedb.h b/coveragedb.h index 3675e3b4..f0f071c4 100644 --- a/coveragedb.h +++ b/coveragedb.h @@ -10,6 +10,7 @@ #define COVERAGEDB_H #include "session.h" +#include "staptree.h" #include @@ -62,12 +63,12 @@ public: int compiled; int executed; - coverage_element() { line = 0; col = 0; - compiled = 0; executed = 0; } + coverage_element(): + line(0), col(0), compiled(0), executed(0) {} - coverage_element(source_loc &place) { - file = place.file; line = place.line; col = place.column; - compiled = 0; executed = 0; } + coverage_element(source_loc &place): + file(place.file->name), line(place.line), col(place.column), + compiled(0), executed(0) {} }; diff --git a/elaborate.cxx b/elaborate.cxx index 30e9a775..fafc5e63 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -1491,9 +1491,9 @@ systemtap_session::print_token (ostream& o, const token* tok) tmpo << *tok; string ts = tmpo.str(); // search & replace the file name with nothing - size_t idx = ts.find (tok->location.file); + size_t idx = ts.find (tok->location.file->name); if (idx != string::npos) - ts.replace (idx, tok->location.file.size(), ""); + ts.replace (idx, tok->location.file->name.size(), ""); o << ts; } @@ -1560,16 +1560,16 @@ systemtap_session::print_error_source (std::ostream& message, std::string& align, const token* tok) { unsigned i = 0; - unsigned line = tok->location.line; - unsigned col = tok->location.column; - string file_contents; assert (tok); - if (tok->location.stap_file) - file_contents = tok->location.stap_file->file_contents; - else + if (!tok->location.file) //No source to print, silently exit return; + + unsigned line = tok->location.line; + unsigned col = tok->location.column; + const string &file_contents = tok->location.file->file_contents; + size_t start_pos = 0, end_pos = 0; //Navigate to the appropriate line while (i != line && end_pos != std::string::npos) @@ -1937,7 +1937,7 @@ void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p) functiondecl* fd = it->second; if (ftv.traversed.find(fd) == ftv.traversed.end()) { - if (fd->tok->location.file == s.user_file->name && // !tapset + if (fd->tok->location.file->name == s.user_file->name && // !tapset ! s.suppress_warnings) s.print_warning ("eliding unused function '" + fd->name + "'", fd->tok); else if (s.verbose>2) @@ -1993,7 +1993,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterati if (vut.read.find (l) == vut.read.end() && vut.written.find (l) == vut.written.end()) { - if (l->tok->location.file == s.user_file->name && // !tapset + if (l->tok->location.file->name == s.user_file->name && // !tapset ! s.suppress_warnings) s.print_warning ("eliding unused variable '" + l->name + "'", l->tok); else if (s.verbose>2) @@ -2037,7 +2037,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterati if (vut.read.find (l) == vut.read.end() && vut.written.find (l) == vut.written.end()) { - if (l->tok->location.file == s.user_file->name && // !tapset + if (l->tok->location.file->name == s.user_file->name && // !tapset ! s.suppress_warnings) s.print_warning ("eliding unused variable '" + l->name + "'", l->tok); else if (s.verbose>2) @@ -2083,7 +2083,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterati if (vut.read.find (l) == vut.read.end() && vut.written.find (l) == vut.written.end()) { - if (l->tok->location.file == s.user_file->name && // !tapset + if (l->tok->location.file->name == s.user_file->name && // !tapset ! s.suppress_warnings) s.print_warning ("eliding unused variable '" + l->name + "'", l->tok); else if (s.verbose>2) diff --git a/parse.cxx b/parse.cxx index 028ac71a..cfa33cb4 100644 --- a/parse.cxx +++ b/parse.cxx @@ -584,11 +584,12 @@ parser::peek_kw (std::string const & kw) lexer::lexer (istream& input, const string& in, systemtap_session& s): - input_name (in), input_contents (""), input_pointer (0), + input_name (in), input_pointer (0), input_end (0), cursor_suspend_count(0), cursor_line (1), cursor_column (1), session(s), current_file (0) { getline(input, input_contents, '\0'); + input_pointer = input_contents.data(); input_end = input_contents.data() + input_contents.size(); @@ -616,16 +617,15 @@ lexer::lexer (istream& input, const string& in, systemtap_session& s): set lexer::keywords; -std::string -lexer::get_input_contents () -{ - return input_contents; -} - void lexer::set_current_file (stapfile* f) { current_file = f; + if (f) + { + f->file_contents = input_contents; + f->name = input_name; + } } int @@ -682,9 +682,7 @@ token* lexer::scan (bool wildcard) { token* n = new token; - n->location.file = input_name; - if (current_file) - n->location.stap_file = current_file; + n->location.file = current_file; unsigned semiskipped_p = 0; @@ -952,8 +950,6 @@ parser::parse () { stapfile* f = new stapfile; input.set_current_file (f); - f->file_contents = input.get_input_contents (); - f->name = input_name; bool empty = true; @@ -1021,18 +1017,16 @@ parser::parse () { cerr << "Input file '" << input_name << "' is empty or missing." << endl; delete f; - input.set_current_file (0); - return 0; + f = 0; } else if (num_errors > 0) { cerr << num_errors << " parse error(s)." << endl; delete f; - input.set_current_file (0); - return 0; + f = 0; } - input.set_current_file (0); + input.set_current_file(0); return f; } diff --git a/parse.h b/parse.h index 4cc4f7b2..cae49b65 100644 --- a/parse.h +++ b/parse.h @@ -23,10 +23,9 @@ struct stapfile; struct source_loc { - std::string file; + stapfile* file; unsigned line; unsigned column; - stapfile* stap_file; }; std::ostream& operator << (std::ostream& o, const source_loc& loc); @@ -75,7 +74,6 @@ class lexer public: token* scan (bool wildcard=false); lexer (std::istream&, const std::string&, systemtap_session&); - std::string get_input_contents (); void set_current_file (stapfile* f); private: -- cgit From 880fc23fa180ae9c9557e7ff945f5f1e750aef15 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Fri, 10 Jul 2009 13:53:00 +0200 Subject: PR10381 sdt.h macros create relocatable addresses in non-writable section. Allocated section needs to be writable when creating pic shared objects because we store relocatable addresses in them. * includes/sys/sdt.h (ALLOCSEC): New macro, depends on __PIC__. (STAP_PROBE_DATA_): Use new ALLOCSEC macro. --- includes/sys/sdt.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/includes/sys/sdt.h b/includes/sys/sdt.h index e448c90e..3b788b88 100644 --- a/includes/sys/sdt.h +++ b/includes/sys/sdt.h @@ -17,9 +17,17 @@ #define STAP_PROBE_ADDR "\t.long " #endif +/* Allocated section needs to be writable when creating pic shared objects + because we store relocatable addresses in them. */ +#ifdef __PIC__ +#define ALLOCSEC "\"aw\"" +#else +#define ALLOCSEC "\"a\"" +#endif + /* An allocated section .probes that holds the probe names and addrs. */ #define STAP_PROBE_DATA_(probe,guard,arg) \ - __asm__ volatile (".section .probes, \"a\"\n" \ + __asm__ volatile (".section .probes," ALLOCSEC "\n" \ "\t.align 8\n" \ "1:\n\t.asciz " #probe "\n" \ "\t.align 4\n" \ -- cgit From c728b7da8be430367aa33f9fbacda93d4add9ea2 Mon Sep 17 00:00:00 2001 From: William Cohen Date: Fri, 10 Jul 2009 10:34:13 -0400 Subject: Add numa_faults.stp example. --- testsuite/systemtap.examples/index.html | 3 ++ testsuite/systemtap.examples/index.txt | 11 +++++++ testsuite/systemtap.examples/keyword-index.html | 11 ++++++- testsuite/systemtap.examples/keyword-index.txt | 24 ++++++++++++++ .../systemtap.examples/memory/numa_faults.meta | 13 ++++++++ .../systemtap.examples/memory/numa_faults.stp | 38 ++++++++++++++++++++++ 6 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 testsuite/systemtap.examples/memory/numa_faults.meta create mode 100755 testsuite/systemtap.examples/memory/numa_faults.stp diff --git a/testsuite/systemtap.examples/index.html b/testsuite/systemtap.examples/index.html index 5435829f..e186b615 100644 --- a/testsuite/systemtap.examples/index.html +++ b/testsuite/systemtap.examples/index.html @@ -94,6 +94,9 @@ keywords: LOCKING
  • memory/kmalloc-top - Show Paths to Kernel Malloc (kmalloc) Invocations
    keywords: MEMORY

    The kmalloc-top perl program runs a small systemtap script to collect stack traces for each call to the kmalloc function and counts the time that each stack trace is observed. When kmalloc-top exits it prints out sorted list. The output can be be filtered to print only only the first stack traces (-t) stack traces with more a minimum counts (-m), or exclude certain stack traces (-e).

  • +
  • memory/numa_faults.stp - Summarize Process Misses across NUMA Nodes
    +keywords: MEMORY NUMA
    +

    The numa_faults.stp script tracks the read and write pages faults for each process. When the script exits it prints out the total read and write pages faults for each process. The script also providea a break down of page faults per node for each process. This script is useful for determining whether the program has good locality (page faults limited to a single node) on a NUMA computer.

  • memory/pfaults.stp - Generate Log of Major and Minor Page Faults
    keywords: MEMORY

    The pfaults.stp script generates a simple log for each major and minor page fault that occurs on the system. Each line contains a timestamp (in microseconds) when the page fault servicing was completed, the pid of the process, the address of the page fault, the type of access (read or write), the type of fault (major or minor), and the elapsed time for page fault. This log can be examined to determine where the page faults are occuring.

  • diff --git a/testsuite/systemtap.examples/index.txt b/testsuite/systemtap.examples/index.txt index 53270b01..35decb82 100644 --- a/testsuite/systemtap.examples/index.txt +++ b/testsuite/systemtap.examples/index.txt @@ -175,6 +175,17 @@ keywords: memory counts (-m), or exclude certain stack traces (-e). +memory/numa_faults.stp - Summarize Process Misses across NUMA Nodes +keywords: memory numa + + The numa_faults.stp script tracks the read and write pages faults for + each process. When the script exits it prints out the total read and + write pages faults for each process. The script also providea a break + down of page faults per node for each process. This script is useful + for determining whether the program has good locality (page faults + limited to a single node) on a NUMA computer. + + memory/pfaults.stp - Generate Log of Major and Minor Page Faults keywords: memory diff --git a/testsuite/systemtap.examples/keyword-index.html b/testsuite/systemtap.examples/keyword-index.html index f3db1429..4de28426 100644 --- a/testsuite/systemtap.examples/keyword-index.html +++ b/testsuite/systemtap.examples/keyword-index.html @@ -39,7 +39,7 @@

    Examples by Keyword

    -

    BACKTRACE BUFFER CALLGRAPH CPU DISK FORMAT FREE FUNCTIONS FUTEX GRAPH INTERRUPT IO LOCKING MEMORY MONITOR NETWORK PER-PROCESS PROCESS PROFILING READ SCHEDULER SIGNALS SIMPLE SLEEP SOCKET SYSCALL TCP TIME TRACE TRACEPOINT TRAFFIC TTY USE WAIT4 WRITE

    +

    BACKTRACE BUFFER CALLGRAPH CPU DISK FORMAT FREE FUNCTIONS FUTEX GRAPH INTERRUPT IO LOCKING MEMORY MONITOR NETWORK NUMA PER-PROCESS PROCESS PROFILING READ SCHEDULER SIGNALS SIMPLE SLEEP SOCKET SYSCALL TCP TIME TRACE TRACEPOINT TRAFFIC TTY USE WAIT4 WRITE

    BACKTRACE

    • interrupt/scf.stp - Tally Backtraces for Inter-Processor Interrupt (IPI)
      @@ -168,6 +168,9 @@ keywords: SYSCALL memory/kmalloc-top - Show Paths to Kernel Malloc (kmalloc) Invocations
      keywords: MEMORY

      The kmalloc-top perl program runs a small systemtap script to collect stack traces for each call to the kmalloc function and counts the time that each stack trace is observed. When kmalloc-top exits it prints out sorted list. The output can be be filtered to print only only the first stack traces (-t) stack traces with more a minimum counts (-m), or exclude certain stack traces (-e).

    • +
    • memory/numa_faults.stp - Summarize Process Misses across NUMA Nodes
      +keywords: MEMORY NUMA
      +

      The numa_faults.stp script tracks the read and write pages faults for each process. When the script exits it prints out the total read and write pages faults for each process. The script also providea a break down of page faults per node for each process. This script is useful for determining whether the program has good locality (page faults limited to a single node) on a NUMA computer.

    • memory/pfaults.stp - Generate Log of Major and Minor Page Faults
      keywords: MEMORY

      The pfaults.stp script generates a simple log for each major and minor page fault that occurs on the system. Each line contains a timestamp (in microseconds) when the page fault servicing was completed, the pid of the process, the address of the page fault, the type of access (read or write), the type of fault (major or minor), and the elapsed time for page fault. This log can be examined to determine where the page faults are occuring.

    • @@ -202,6 +205,12 @@ keywords: NETWORK NETWORK TRAFFIC

      The tcpdumplike.stp prints out a line for each TCP packet received. Each line includes the source and destination IP addresses, the source and destination ports, and flags.

    +

    NUMA

    +
      +
    • memory/numa_faults.stp - Summarize Process Misses across NUMA Nodes
      +keywords: MEMORY NUMA
      +

      The numa_faults.stp script tracks the read and write pages faults for each process. When the script exits it prints out the total read and write pages faults for each process. The script also providea a break down of page faults per node for each process. This script is useful for determining whether the program has good locality (page faults limited to a single node) on a NUMA computer.

    • +

    PER-PROCESS

    • io/ttyspy.stp - Monitor tty typing.
      diff --git a/testsuite/systemtap.examples/keyword-index.txt b/testsuite/systemtap.examples/keyword-index.txt index d3d66fe2..bbee341f 100644 --- a/testsuite/systemtap.examples/keyword-index.txt +++ b/testsuite/systemtap.examples/keyword-index.txt @@ -299,6 +299,17 @@ keywords: memory counts (-m), or exclude certain stack traces (-e). +memory/numa_faults.stp - Summarize Process Misses across NUMA Nodes +keywords: memory numa + + The numa_faults.stp script tracks the read and write pages faults for + each process. When the script exits it prints out the total read and + write pages faults for each process. The script also providea a break + down of page faults per node for each process. This script is useful + for determining whether the program has good locality (page faults + limited to a single node) on a NUMA computer. + + memory/pfaults.stp - Generate Log of Major and Minor Page Faults keywords: memory @@ -386,6 +397,19 @@ keywords: network traffic source and destination ports, and flags. += NUMA = + +memory/numa_faults.stp - Summarize Process Misses across NUMA Nodes +keywords: memory numa + + The numa_faults.stp script tracks the read and write pages faults for + each process. When the script exits it prints out the total read and + write pages faults for each process. The script also providea a break + down of page faults per node for each process. This script is useful + for determining whether the program has good locality (page faults + limited to a single node) on a NUMA computer. + + = PER-PROCESS = io/ttyspy.stp - Monitor tty typing. diff --git a/testsuite/systemtap.examples/memory/numa_faults.meta b/testsuite/systemtap.examples/memory/numa_faults.meta new file mode 100644 index 00000000..34034bef --- /dev/null +++ b/testsuite/systemtap.examples/memory/numa_faults.meta @@ -0,0 +1,13 @@ +title: Summarize Process Misses across NUMA Nodes +name: numa_faults.stp +version: 1.0 +author: IBM +keywords: memory numa +subsystem: memory +status: production +exit: user-controlled +output: list +scope: system-wide +description: The numa_faults.stp script tracks the read and write pages faults for each process. When the script exits it prints out the total read and write pages faults for each process. The script also providea a break down of page faults per node for each process. This script is useful for determining whether the program has good locality (page faults limited to a single node) on a NUMA computer. +test_check: stap -p4 numa_faults.stp +test_installcheck: stap numa_faults.stp -c "sleep 1" diff --git a/testsuite/systemtap.examples/memory/numa_faults.stp b/testsuite/systemtap.examples/memory/numa_faults.stp new file mode 100755 index 00000000..34a0ace7 --- /dev/null +++ b/testsuite/systemtap.examples/memory/numa_faults.stp @@ -0,0 +1,38 @@ +#! /usr/bin/env stap + +global execnames, page_faults, node_faults, nodes + +probe vm.pagefault { + p = pid(); n=addr_to_node(address) + execnames[p] = execname() + page_faults[p, write_access ? 1 : 0] <<< 1 + node_faults[p, n] <<< 1 + nodes[n] <<< 1 +} + +function print_pf () { + printf ("\n") + printf ("%-16s %-6s %10s %10s %-20s\n", + "Execname", "PID", "RD Faults", "WR Faults", "Node:Faults") + print ("======================= ========== ========== =============\n") + foreach (pid in execnames) { + printf ("%-16s %6d %10d %10d ", execnames[pid], pid, + @count(page_faults[pid,0]), @count(page_faults[pid,1])) + foreach ([node+] in nodes) { + if ([pid, node] in node_faults) + printf ("%d:%d ", node, @count(node_faults[pid, node])) + } + printf ("\n") + } + printf("\n") +} + +probe begin { + printf("Starting pagefault counters \n") +} + +probe end { + printf("Printing counters: \n") + print_pf () + printf("Done\n") +} -- cgit From 7d54db1a2c0b3831b6fbc8282f1155426c4be540 Mon Sep 17 00:00:00 2001 From: Dave Brolley Date: Fri, 10 Jul 2009 11:09:36 -0400 Subject: Rename systemtap_exit to cleanup. Allow shutdown_server to test $server_pid in order to determine whether we started a server. --- testsuite/lib/systemtap.exp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp index e04fe837..76fd57bd 100644 --- a/testsuite/lib/systemtap.exp +++ b/testsuite/lib/systemtap.exp @@ -53,7 +53,7 @@ proc print_systemtap_version {} { proc setup_systemtap_environment {} { - global srcdir env + global srcdir env server_pid net_path # need an absolute SRCDIR for the top-level src/ tree # XXX: or, we could change nearby uses of ${SRCDIR}/testsuite to ${SRCDIR} @@ -68,6 +68,8 @@ proc setup_systemtap_environment {} { set env(SYSTEMTAP_DIR) [exec pwd]/.systemtap-[exec whoami] # Find or start a systemtap server, if requested. + set net_path "" + set server_pid 0 if {[use_server_p]} then { if {! [setup_server]} then { return 0 @@ -151,6 +153,7 @@ proc shutdown_server {} { if { $server_pid != 0 } then { print "Stopping the systemtap server with PID==$server_pid" exec stap-stop-server $server_pid + set server_pid 0 } # Remove the temporary stap script @@ -198,11 +201,9 @@ get_system_info proc systemtap_init {args} {} proc systemtap_version {} {} -proc systemtap_exit {} { +proc cleanup {} { # Stop the stap server, if we started it. - if {[use_server_p]} then { - shutdown_server - } + shutdown_server } -- cgit