diff options
-rw-r--r-- | tapset/ChangeLog | 7 | ||||
-rw-r--r-- | tapset/LKET/Changelog | 7 | ||||
-rwxr-xr-x | tapset/LKET/hookid_defs.stp | 107 | ||||
-rwxr-xr-x | tapset/LKET/ioscheduler.stp | 182 | ||||
-rwxr-xr-x | tapset/LKET/lket_trace.stp | 129 | ||||
-rwxr-xr-x | tapset/LKET/netdev.stp | 66 | ||||
-rwxr-xr-x | tapset/LKET/pagefault.stp | 22 | ||||
-rwxr-xr-x | tapset/LKET/process.stp | 68 | ||||
-rwxr-xr-x | tapset/LKET/scsi.stp | 206 | ||||
-rwxr-xr-x | tapset/LKET/syscalls.stp | 41 | ||||
-rwxr-xr-x | tapset/LKET/tskdispatch.stp | 71 | ||||
-rwxr-xr-x | tapset/LKET/utils.stp | 33 | ||||
-rw-r--r-- | tapset/context.stp | 4 | ||||
-rw-r--r-- | tapset/ppc64/syscalls.stp | 3 | ||||
-rw-r--r-- | tapset/scheduler.stp | 6 |
15 files changed, 951 insertions, 1 deletions
diff --git a/tapset/ChangeLog b/tapset/ChangeLog index aa5fef32..8491b460 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -1,5 +1,12 @@ 2006-05-18 Li Guanglei <guanglei@cn.ibm.com> + * tapset/LKET/*: tracing tapsets of LKET + * tapset/context.stp: add stp_pid() func + * tapset/ppc64/syscalls.stp: add conditional preprocessing + since sys64_time is removed from kernel >= 2.6.1 + +2006-05-18 Li Guanglei <guanglei@cn.ibm.com> + * tapset/tskschedule.stp: deleted, merge into scheduler.stp * tapset/scheduler.stp: incorporate tskschedule.stp diff --git a/tapset/LKET/Changelog b/tapset/LKET/Changelog new file mode 100644 index 00000000..af1b9dab --- /dev/null +++ b/tapset/LKET/Changelog @@ -0,0 +1,7 @@ +2006-05-18 Li Guanglei <guanglei@cn.ibm.com> + + Initial version by Li Guanglei. + * hookid_defs.stp, ioscheduler.stp, lket_trace.stp, netdev.stp, + pagefault.stp, process.stp, scsi.stp, syscalls.stp, tskdispatch.stp, + utils.stp + diff --git a/tapset/LKET/hookid_defs.stp b/tapset/LKET/hookid_defs.stp new file mode 100755 index 00000000..dc6f7749 --- /dev/null +++ b/tapset/LKET/hookid_defs.stp @@ -0,0 +1,107 @@ +global + /* syscall */ + GROUP_SYSCALL, + HOOKID_SYSCALL_ENTRY, HOOKID_SYSCALL_RETURN, + + /* process creation */ + GROUP_PROCESS, + HOOKID_PROCESS_SNAPSHOT, HOOKID_PROCESS_FORK, + HOOKID_PROCESS_EXECVE, + + /* io scheduler */ + GROUP_IOSCHED, + HOOKID_IOSCHED_NEXT_REQ, HOOKID_IOSCHED_ADD_REQ, + HOOKID_IOSCHED_REMOVE_REQ, + + /* task dispatching */ + GROUP_TASK, + HOOKID_TASK_CTXSWITCH, HOOKID_TASK_CPUIDLE, + + /* scsi */ + GROUP_SCSI, + HOOKID_SCSI_IOENTRY, HOOKID_SCSI_IO_TO_LLD, + HOOKID_SCSI_IODONE_BY_LLD, HOOKID_SCSI_IOCOMP_BY_MIDLEVEL, + + /* page fault */ + GROUP_PAGEFAULT, + HOOKID_PAGEFAULT, + + /* network device */ + GROUP_NETDEV, + HOOKID_NETDEV_RECEIVE, HOOKID_NETDEV_TRANSMIT +%{ +/* used in embedded c codes */ + +/* Group ID Definitions */ +int _GROUP_SYSCALL = 1; +int _GROUP_PROCESS = 2; +int _GROUP_IOSCHED = 3; +int _GROUP_TASK = 4; +int _GROUP_SCSI = 5; +int _GROUP_PAGEFAULT = 6; +int _GROUP_NETDEV = 7; + +/* hookIDs defined inside each group */ +int _HOOKID_SYSCALL_ENTRY = 1; +int _HOOKID_SYSCALL_RETURN = 2; + +int _HOOKID_PROCESS_SNAPSHOT = 1; +int _HOOKID_PROCESS_EXECVE = 2; +int _HOOKID_PROCESS_FORK = 3; + +int _HOOKID_IOSCHED_NEXT_REQ = 1; +int _HOOKID_IOSCHED_ADD_REQ = 2; +int _HOOKID_IOSCHED_REMOVE_REQ = 3; + +int _HOOKID_TASK_CTXSWITCH = 1; +int _HOOKID_TASK_CPUIDLE = 2; + +int _HOOKID_SCSI_IOENTRY = 1; +int _HOOKID_SCSI_IO_TO_LLD = 2; +int _HOOKID_SCSI_IODONE_BY_LLD = 3; +int _HOOKID_SCSI_IOCOMP_BY_MIDLEVEL = 4; + +int _HOOKID_PAGEFAULT = 1; + +int _HOOKID_NETDEV_RECEIVE = 1; +int _HOOKID_NETDEV_TRANSMIT = 2; + +%} + +probe begin +{ + GROUP_SYSCALL = 1 + HOOKID_SYSCALL_ENTRY = 1 + HOOKID_SYSCALL_RETURN = 2 + + GROUP_PROCESS = 2 + HOOKID_PROCESS_SNAPSHOT = 1 + HOOKID_PROCESS_EXECVE = 2 + HOOKID_PROCESS_FORK = 3 + + GROUP_IOSCHED = 3 + HOOKID_IOSCHED_NEXT_REQ = 1 + HOOKID_IOSCHED_ADD_REQ = 2 + HOOKID_IOSCHED_REMOVE_REQ = 3 + + GROUP_TASK = 4 + HOOKID_TASK_CTXSWITCH = 1 + HOOKID_TASK_CPUIDLE = 2 + + GROUP_SCSI = 5 + HOOKID_SCSI_IOENTRY = 1 + HOOKID_SCSI_IO_TO_LLD = 2 + HOOKID_SCSI_IODONE_BY_LLD = 3 + HOOKID_SCSI_IOCOMP_BY_MIDLEVEL = 4 + + GROUP_PAGEFAULT = 6 + HOOKID_PAGEFAULT = 1 + + GROUP_NETDEV = 7 + HOOKID_NETDEV_RECEIVE = 1 + HOOKID_NETDEV_TRANSMIT = 2 + + lket_trace_init() + + process_snapshot() +} diff --git a/tapset/LKET/ioscheduler.stp b/tapset/LKET/ioscheduler.stp new file mode 100755 index 00000000..8e238a8d --- /dev/null +++ b/tapset/LKET/ioscheduler.stp @@ -0,0 +1,182 @@ +// Copyright (C) 2005, 2006 IBM Corp. +// +// 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. + +/* only print backtrace for elv_add_request & elv_next_request*/ +probe addevent.ioscheduler + = addevent.ioscheduler.elv_next_request, + addevent.ioscheduler.elv_completed_request, + addevent.ioscheduler.elv_add_request +{ +} + +/* when a request is retrieved from request queue */ +probe addevent.ioscheduler.elv_next_request + += ioscheduler.elv_next_request +{ + if(filter_by_pid() == 1 ) { + log_ioscheduler_tracedata_elv_next(HOOKID_IOSCHED_NEXT_REQ, $q, backtrace) + } +} + + +/* when a request is added to the request queue */ +probe addevent.ioscheduler.elv_add_request + += ioscheduler.elv_add_request +{ + if(filter_by_pid() == 1 ) { + log_ioscheduler_tracedata_others(HOOKID_IOSCHED_ADD_REQ, $q, $rq, backtrace) + } +} + +/* when a request is completed */ +probe addevent.ioscheduler.elv_completed_request + = ioscheduler.elv_completed_request +{ + if(filter_by_pid() == 1 ) { + log_ioscheduler_tracedata_others(HOOKID_IOSCHED_REMOVE_REQ, $q, $rq, backtrace) + } +} + + +%{ +#include <linux/blkdev.h> +#include <linux/elevator.h> +%} + +/* log the data specific to __elv_add_request and elv_remove_request */ +%( kernel_v >= "2.6.10" %? + +function log_ioscheduler_tracedata_others(var_id:long, var_q:long, var_rq:long, backtrace:long) +%{ + struct request *rq = (struct request *)((long)THIS->var_rq); + struct request_queue *q = (struct request_queue *)((long)THIS->var_q); + + /* elevator name|major|minor| */ + + /* only print backtrace for elv_add_request */ + if(THIS->backtrace == 1) { + String str = _stp_string_init (0); + _stp_stack_sprint (str, CONTEXT->regs, 0); + + _lket_trace(_GROUP_IOSCHED, THIS->var_id, "%0s%1b%1b%0s", q->elevator->elevator_type->elevator_name, + rq->rq_disk->major, rq->rq_disk->first_minor, _stp_string_ptr(str)); + } else { + _lket_trace(_GROUP_IOSCHED, THIS->var_id, "%0s%1b%1b", q->elevator->elevator_type->elevator_name, + rq->rq_disk->major, rq->rq_disk->first_minor); + } +%} + +%: + +function log_ioscheduler_tracedata_others(var_id:long, var_q:long, var_rq:long, backtrace:long) +%{ + struct request *rq = (struct request *)((long)THIS->var_rq); + struct request_queue *q = (struct request_queue *)((long)THIS->var_q); + + /* elevator name|major|minor| */ + + /* only print backtrace for elv_add_request */ + if(THIS->backtrace == 1) { + String str = _stp_string_init (0); + _stp_stack_sprint (str, CONTEXT->regs, 0); + + _lket_trace(_GROUP_IOSCHED, THIS->var_id, "%0s%1b%1b%0s", q->elevator.elevator_name, + rq->rq_disk->major, rq->rq_disk->first_minor, _stp_string_ptr(str)); + } else { + _lket_trace(_GROUP_IOSCHED, THIS->var_id, "%0s%1b%1b", q->elevator.elevator_name, + rq->rq_disk->major, rq->rq_disk->first_minor); + } +%} + +%) + +/* log the data specific to elv_next_request, for kernel == 2.6.9 */ +%( kernel_v >= "2.6.10" %? + +/* log the data specific to elv_next_request , for kernel > 2.6.9*/ +function log_ioscheduler_tracedata_elv_next(var_id:long, var:long, backtrace:long) +%{ + + struct request_queue *q; + struct request *rq; + + q = (struct request_queue *)((long)THIS->var); + + /* If there is a request in the request queue: + elevator name|major|minor| + if there is no request in the request queue: + elevator name|empty| + */ + + if(THIS->backtrace == 1) { + String str = _stp_string_init (0); + _stp_stack_sprint (str, CONTEXT->regs, 0); + + if(list_empty(&(q->queue_head))) { + _lket_trace(_GROUP_IOSCHED, THIS->var_id, "%0s%1b%1b%0s", + q->elevator->elevator_type->elevator_name, -1, -1, _stp_string_ptr(str)); + } else { + rq = list_entry_rq(q->queue_head.next); + _lket_trace(_GROUP_IOSCHED, THIS->var_id, "%0s%1b%1b%0s", + q->elevator->elevator_type->elevator_name, rq->rq_disk->major, + rq->rq_disk->first_minor, _stp_string_ptr(str)); + } + } else { + if(list_empty(&(q->queue_head))) { + _lket_trace(_GROUP_IOSCHED, THIS->var_id, "%0s%1b%1b", + q->elevator->elevator_type->elevator_name, -1, -1); + } else { + rq = list_entry_rq(q->queue_head.next); + _lket_trace(_GROUP_IOSCHED, THIS->var_id, "%0s%1b%1b", + q->elevator->elevator_type->elevator_name, rq->rq_disk->major, + rq->rq_disk->first_minor); + } + + } +%} + +%: + +function log_ioscheduler_tracedata_elv_next(var_id:long, var:long, backtrace:long) +%{ + + struct request_queue *q; + struct request *rq; + + q = (struct request_queue *)((long)THIS->var); + + /* If there is a request in the request queue: + elevator name|major|minor| + if there is no request in the request queue: + elevator name|empty| + */ + if(THIS->backtrace == 1) { + String str = _stp_string_init (0); + _stp_stack_sprint (str, CONTEXT->regs, 0); + + if(list_empty(&(q->queue_head))) { + _lket_trace(_GROUP_IOSCHED, THIS->var_id, "%0s%1b%1b%0s", + q->elevator.elevator_name, -1, -1, _stp_string_ptr(str)); + } else { + rq = list_entry_rq(q->queue_head.next); + _lket_trace(_GROUP_IOSCHED, THIS->var_id, "%0s%1b%1b%0s", q->elevator.elevator_name, + rq->rq_disk->major, rq->rq_disk->first_minor, _stp_string_ptr(str)); + } + } else { + if(list_empty(&(q->queue_head))) { + _lket_trace(_GROUP_IOSCHED, THIS->var_id, "%0s%1b%1b", + q->elevator.elevator_name, -1, -1); + } else { + rq = list_entry_rq(q->queue_head.next); + _lket_trace(_GROUP_IOSCHED, THIS->var_id, "%0s%1b%1b", q->elevator.elevator_name, + rq->rq_disk->major, rq->rq_disk->first_minor); + } + } + +%} + +%) diff --git a/tapset/LKET/lket_trace.stp b/tapset/LKET/lket_trace.stp new file mode 100755 index 00000000..d06d09d2 --- /dev/null +++ b/tapset/LKET/lket_trace.stp @@ -0,0 +1,129 @@ +// Copyright (C) 2005, 2006 IBM Corp. +// +// 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. + +function lket_trace_header_init() +%{ + +/* header info for binary format*/ +#if !defined(ASCII_TRACE) && !defined(ASCII_TRACE_LEGACY) + +#define MAGIC_NUMBER 0xAEFCDB6B +#define LKET_TRACE_VER_MAJOR 0x01 +#define LKET_TRACE_VER_MINOR 0x01 /* used for user customization */ +#define LITTLE_ENDIAN 0x01 +#define BIG_ENDIAN 0x02 +#define BITS_WIDTH 64 /* 32-bit or 64-bit environment*/ + +#define LKET_HEADER_LEN 0 /* fake number, bin_write will fill in the + actual length of trace header */ + + _stp_printf("%4b%2n%1b%1b%1b%1b", MAGIC_NUMBER, LKET_HEADER_LEN, LKET_TRACE_VER_MAJOR, + LKET_TRACE_VER_MINOR, BIG_ENDIAN, BITS_WIDTH); + _stp_print_flush(); +#endif + +%} + +function lket_trace_init() +{ + lket_trace_header_init() +} + +%{ +#ifndef __LKET_TRACE__ +#define __LKET_TRACE__ + +#define STP_BIN_PACKET 1 + + +#define MAX_FMT_LEN 128 +char newfmt[MAX_FMT_LEN] = "\n%d|%d|%d|%d|%d|%d|%d|%d"; +#define NEW_FMT_START 24 + +void fmt_change(char *oldfmt) +{ + char *old_ptr, *new_ptr; + + old_ptr = oldfmt; + new_ptr = newfmt + NEW_FMT_START; + + while(*old_ptr != 0 && (new_ptr - newfmt) < MAX_FMT_LEN) { + if(*old_ptr != '%') { + *new_ptr++ = *old_ptr++; + continue; + } else { + *new_ptr++ = '|'; /* delimier to make it readable */ + *new_ptr++ = *old_ptr++; + while( *old_ptr == 'L' || *old_ptr == 'l' + || isdigit(*old_ptr) ) { + *new_ptr++ = *old_ptr++; + } + if( *old_ptr == 'b') { + if(isdigit(*(old_ptr-1))) { + if(*(old_ptr-1) == '1' || + *(old_ptr-1) == '2' || + *(old_ptr-1) == '3' || + *(old_ptr-1) == '4') { + new_ptr--; + } else if(*(old_ptr-1) == '8') { + *--new_ptr='l'; + *++new_ptr='l'; + new_ptr++; + } + } + *new_ptr++ = 'd'; + old_ptr++; + } + else if ( *old_ptr == 's') { + if(isdigit(*(old_ptr-1)) && *(old_ptr-1)=='0') + new_ptr--; + *new_ptr++ = 's'; + old_ptr++; + } else + *new_ptr++ = *old_ptr++; + } + } + *new_ptr=0; +} + +/* trace data in ASCII format + Format of the common prefix of the trace data: + groupid|subhookid|sec|usec|tgid|ppid|pid|cpuid| +*/ +#if defined(ASCII_TRACE) + +#define _lket_trace(GroupID, hookID, fmt, args...) do { \ + struct timeval tv; \ + do_gettimeofday (&tv); \ + fmt_change(fmt); \ + _stp_printf(newfmt, \ + GroupID, hookID, tv.tv_sec, tv.tv_usec, current->tgid, \ + current->parent->pid, current->pid, \ + current->thread_info->cpu, args);\ +} while(0) + +#else //binary trace + +static inline int this_event_len(void) +{ + return 0; +} + +/* we use 2 bytes to store the length. 256 may be not enough for backtrace event */ +#define _lket_trace(GroupID, hookID, fmt, args...) do { \ + struct timeval tv; \ + do_gettimeofday (&tv); \ + _stp_printf("%1b%2n%1b%1b%4b%4b%4b%4b%4b%1b"fmt, \ + (int64_t)STP_BIN_PACKET, (int64_t)GroupID, (int64_t)hookID, \ + (int64_t)tv.tv_sec, (int64_t)tv.tv_usec, (int64_t)current->tgid, \ + (int64_t)current->parent->pid, (int64_t)current->pid, \ + (int64_t)current->thread_info->cpu, args);\ +} while(0) + +#endif +#endif +%} diff --git a/tapset/LKET/netdev.stp b/tapset/LKET/netdev.stp new file mode 100755 index 00000000..04413b23 --- /dev/null +++ b/tapset/LKET/netdev.stp @@ -0,0 +1,66 @@ +// Copyright (C) 2005, 2006 IBM Corp. +// +// 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 + +%{ +#include <linux/netdevice.h> +%} + +probe addevent.netdev + = addevent.netdev.receive, addevent.netdev.transmit +{ +} + +/* Main device receive routine, be called when packet arrives on network device */ +probe addevent.netdev.receive + = netdev.receive +{ + /* no need to filter by pid */ + log_netdev_extra(HOOKID_NETDEV_RECEIVE,$skb, backtrace) +} + +/* Queue a buffer for transmission to a network device */ +probe addevent.netdev.transmit + += netdev.transmit +{ + if(filter_by_pid() == 1 ) { + log_netdev_extra(HOOKID_NETDEV_TRANSMIT, $skb, backtrace) + } +} + +function log_netdev_extra(var_id:long, var:long, backtrace:long) +%{ + struct sk_buff *skb = (struct sk_buff *)THIS->var; + + /* dev_name | Length of actual data | protocol | Buffer size + + skb->protocol is: + 0800 IP + 8100 802.1Q VLAN + 0001 802.3 + 0002 AX.25 + 0004 802.2 + 8035 RARP + 0005 SNAP + 0805 X.25 + 0806 ARP + 8137 IPX + 0009 Localtalk + 86DD IPv6 + */ + + /* only print backtrace for netdev.transmit */ + if(THIS->backtrace == 1) { + String str = _stp_string_init (0); + _stp_stack_sprint (str, CONTEXT->regs, 0); + + _lket_trace(_GROUP_NETDEV, THIS->var_id, "%0s%4b%2b%4b%0s", skb->dev->name, + skb->len, skb->protocol, skb->truesize, _stp_string_ptr(str)); + } else { + _lket_trace(_GROUP_NETDEV, THIS->var_id, "%0s%4b%2b%4b", skb->dev->name, + skb->len, skb->protocol, skb->truesize); + } +%} diff --git a/tapset/LKET/pagefault.stp b/tapset/LKET/pagefault.stp new file mode 100755 index 00000000..2ac44af0 --- /dev/null +++ b/tapset/LKET/pagefault.stp @@ -0,0 +1,22 @@ +// networking tapset +// Copyright (C) 2005, 2006 IBM Corp. +// +// 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. + +function log_pagefault_tracedata(var_id:long, var_addr:long, var_rwflag:long) +%{ + _lket_trace(_GROUP_PAGEFAULT, THIS->var_id, "%8b%1b", (long)(THIS->var_addr), (THIS->var_rwflag)?1:0); +%} + + +/* Record the page fault event */ +probe addevent.pagefault + = pagefault +{ + if(filter_by_pid() == 1 ) { + log_pagefault_tracedata(HOOKID_PAGEFAULT, $address, $write_access) + } +} diff --git a/tapset/LKET/process.stp b/tapset/LKET/process.stp new file mode 100755 index 00000000..e17a5514 --- /dev/null +++ b/tapset/LKET/process.stp @@ -0,0 +1,68 @@ +// Copyright (C) 2005, 2006 IBM Corp. +// +// 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. + +/* record the newly created process name */ +function log_execve_tracedata(var_id:long, var:long) +%{ + long tmp=(long)THIS->var; + _lket_trace(_GROUP_PROCESS, THIS->var_id, "%0s", (char *)tmp); +%} + + +/* record the newly forked process id */ +function log_fork_tracedata(var_id:long, var:long) +%{ + pid_t pid = (pid_t)THIS->var; + _lket_trace(_GROUP_PROCESS, THIS->var_id, "%4b", pid); +%} + + +/************************************************************ +* This function could be used to take a snapshot of all the * +* processes. It's not a probe, so the data format doesn't * +* follow the format used by probe handlers * +************************************************************/ +function process_snapshot() +%{ + struct task_struct *tsk; + struct list_head *cur, *head; + head = &(current->tasks); + + /* iterate all the processes, and record the pid and process + name for each entry */ + list_for_each(cur, head) { + tsk = (struct task_struct *)(list_entry(cur, struct task_struct, tasks)); + _lket_trace(_GROUP_PROCESS, _HOOKID_PROCESS_SNAPSHOT, "%4b%0s", tsk->pid, tsk->comm); + _stp_print_flush(); + } +%} + + +probe addevent.process + = addevent.process.fork, addevent.process.execve +{ +} + +/* + we should capture both do_execve for 64-bit app + and compat_do_execve for 32-bit app +*/ +probe addevent.process.execve + = process.exec +{ + if(filter_by_pid() == 1 ) { + log_execve_tracedata(HOOKID_PROCESS_EXECVE, $filename) + } +} + +probe addevent.process.fork + = process.create +{ + if(filter_by_pid() == 1 ) { + log_fork_tracedata(HOOKID_PROCESS_FORK, new_pid) + } +} diff --git a/tapset/LKET/scsi.stp b/tapset/LKET/scsi.stp new file mode 100755 index 00000000..0f38b33c --- /dev/null +++ b/tapset/LKET/scsi.stp @@ -0,0 +1,206 @@ +// Copyright (C) 2005, 2006 IBM Corp. +// +// 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 + +/*********************************************************** +* Trace the following activities of scsi layer: * +* 1. I/O Entry * +* 2. Issuing I/O to LLD * +* 3. I/O done by LLD * +* 4. I/O Complete * +* * +***********************************************************/ + +%{ +#include <linux/types.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include <linux/timer.h> +#include <linux/blkdev.h> +%} + +probe addevent.scsi + = addevent.scsi.ioentry, + addevent.scsi.iodispatching, + addevent.scsi.iodone, + addevent.scsi.iocompleted +{ +} + +/* mid-layer prepare a IO request */ +probe addevent.scsi.ioentry + += scsi.ioentry +{ + log_scsi_ioentry(HOOKID_SCSI_IOENTRY, $q, $req, backtrace) +} + +/* Dispatch a command to the low-level driver. */ +probe addevent.scsi.iodispatching + += scsi.iodispatching +{ + log_scsi_dispatch(HOOKID_SCSI_IO_TO_LLD, $cmd, backtrace) +} + +/* I/O is done by low-level driver*/ +probe addevent.scsi.iodone + = scsi.iodone +{ + /* scsi timer check. We should record the hook only + * when the timer is inactive. But there's a gap between + * the checking and the actual calling of scsi_delete_timer. + */ + if( scsi_timer_pending($cmd) == 1) { + log_scsi_iodone_extra(HOOKID_SCSI_IODONE_BY_LLD, $cmd) + } +} + +/* mid-layer processes the completed IO */ +probe addevent.scsi.iocompleted + = scsi.iocompleted +{ + log_scsi_iocompleted(HOOKID_SCSI_IOCOMP_BY_MIDLEVEL, $cmd, $good_bytes) +} + +/* log the info about scsi io entry */ +function log_scsi_ioentry(var_id:long, var_q:long, var_rq:long, backtrace:long) +%{ + struct request_queue *q = (struct request_queue *)((long)THIS->var_q); + struct request *rq = (struct request *)((long)THIS->var_rq); + struct scsi_device *sdev = (struct scsi_device *)(q->queuedata); + + /* + major|minor|scsi_device_state| + */ + if(THIS->backtrace == 1) { + String str = _stp_string_init (0); + _stp_stack_sprint (str, CONTEXT->regs, 0); + _lket_trace(_GROUP_SCSI, THIS->var_id, "%1b%1b%1b%0s", rq->rq_disk->major, + rq->rq_disk->first_minor, sdev->sdev_state, _stp_string_ptr(str)); + } else { + _lket_trace(_GROUP_SCSI, THIS->var_id, "%1b%1b%1b", rq->rq_disk->major, + rq->rq_disk->first_minor, sdev->sdev_state); + } +%} + +/* log the info about scsi_dispatching_cmd + * + * + * Now we can use cmd->serial_number as cmd identifier + * But according to the comments of struct scsi_cmnd, it's + * a better to use cmd->pid since cmd->serial_number will be killed one + * day in the future + * + * But when scsi_dispatch_cmd is called, cmd->serial_number is still not + * initialized. + * + * For kernel >= 2.6.12, it will be set later by calling scsi_cmd_get_serial. + * So I choose to record cmd->device->host->cmd_pid. But there is a gap between + * the time when cmd->device->host->cmd_pid is retrieved at the beginning of + * scsi_dispatch_cmd and the actual calling of scsi_cmd_get_serial. + * + * For kernel <=2.6.9, it will be set by a global counter. + * + * NOTE: The kernel version need further investigation. + */ + +/* sdev_state|scsi_info|data_direction|request_buffer|request_bufflen|cmd_identifier| */ +%( kernel_v >= "2.6.12" %? +function log_scsi_dispatch(var_id:long, var:long, backtrace:long) +%{ + struct scsi_cmnd *cmd = (struct scsi_cmnd *)((long)THIS->var); + int scsi_info; + + scsi_info = ((cmd->device->host->host_no & 0xFF) << 24) | + ((cmd->device->channel & 0xFF) << 16) | + ((cmd->device->lun & 0xFF) << 8) | + (cmd->device->id & 0xFF); + + /* sdev_state|scsi_info|data_direction|cmd_identifier|request_buffer|request_bufflen + * + * sdev_state could be: SDEV_DEL, SDEV_BLOCK or something else. + * Instead of skipping SDEV_DEL & SDEV_BLOCK, I choose to log them + */ + + if(THIS->backtrace == 1) { + String str = _stp_string_init (0); + _stp_stack_sprint (str, CONTEXT->regs, 0); + + _lket_trace(_GROUP_SCSI, THIS->var_id, "%1b%4b%1b%8b%4b%8b%0s", cmd->device->sdev_state, + scsi_info, cmd->sc_data_direction, cmd->request_buffer, cmd->request_bufflen, + cmd->device->host->cmd_pid, _stp_string_ptr(str)); + } else { + + _lket_trace(_GROUP_SCSI, THIS->var_id, "%1b%4b%1b%8b%4b%8b", cmd->device->sdev_state, + scsi_info, cmd->sc_data_direction, cmd->request_buffer, cmd->request_bufflen, + cmd->device->host->cmd_pid); + } + +%} +%: + +function log_scsi_dispatch(var_id:long, var:long, backtrace:long) +%{ + struct scsi_cmnd *cmd = (struct scsi_cmnd *)((long)THIS->var); + int scsi_info; + + scsi_info = ((cmd->device->host->host_no & 0xFF) << 24) | + ((cmd->device->channel & 0xFF) << 16) | + ((cmd->device->lun & 0xFF) << 8) | + (cmd->device->id & 0xFF); + + /* sdev_state|scsi_info|data_direction|cmd_identifier|request_buffer|request_bufflen + * + * sdev_state could be: SDEV_DEL, SDEV_BLOCK or something else. + * Instead of skipping SDEV_DEL & SDEV_BLOCK, I choose to log them + */ + + /* systemTap failed to access global variable. So I temporarily use 0. + _stp_printf("%d|", scsi_pid); + */ + if(THIS->backtrace == 1) { + String str = _stp_string_init (0); + _stp_stack_sprint (str, CONTEXT->regs, 0); + + _lket_trace(_GROUP_SCSI, THIS->var_id, "%1b%4b%1b%8b%4b%8b%0s", cmd->device->sdev_state, scsi_info, + cmd->sc_data_direction, cmd->request_buffer, cmd->request_bufflen, 0, _stp_string_ptr(str)); + } else { + _lket_trace(_GROUP_SCSI, THIS->var_id, "%1b%4b%1b%8b%4b%8b", cmd->device->sdev_state, scsi_info, + cmd->sc_data_direction, cmd->request_buffer, cmd->request_bufflen, 0); + } +%} +%) + +/* log the info about scsi_done */ +function log_scsi_iodone_extra(var_id:long, var:long) +%{ + struct scsi_cmnd *cmd = (struct scsi_cmnd *)((long)THIS->var); + int scsi_info; + + scsi_info = ((cmd->device->host->host_no & 0xFF) << 24) | + ((cmd->device->channel & 0xFF) << 16) | + ((cmd->device->lun & 0xFF) << 8) | + (cmd->device->id & 0xFF); + + /* scsi_info|data_direction|cmd_identifier| */ + _lket_trace(_GROUP_SCSI, THIS->var_id, "%4b%1b%8b", scsi_info, cmd->sc_data_direction, cmd->pid); +%} + +/* log the info about scsi_dispatching_cmd */ +function log_scsi_iocompleted(var_id:long, var_cmd:long, var_goodbytes:long) +%{ + struct scsi_cmnd *cmd = (struct scsi_cmnd *)((long)THIS->var_cmd); + int scsi_info; + unsigned long goodbytes = (unsigned long)(THIS->var_goodbytes); + + scsi_info = ((cmd->device->host->host_no & 0xFF) << 24) | + ((cmd->device->channel & 0xFF) << 16) | + ((cmd->device->lun & 0xFF) << 8) | + (cmd->device->id & 0xFF); + + /* scsi_info|data_direction|cmd_identifier|goodbytes */ + _lket_trace(_GROUP_SCSI, THIS->var_id, "%4b%1b%8b%4b", scsi_info, cmd->sc_data_direction, cmd->pid, goodbytes); +%} diff --git a/tapset/LKET/syscalls.stp b/tapset/LKET/syscalls.stp new file mode 100755 index 00000000..7215f4f5 --- /dev/null +++ b/tapset/LKET/syscalls.stp @@ -0,0 +1,41 @@ +// Copyright (C) 2005, 2006 IBM Corp. +// +// 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. + +probe addevent.syscall + = addevent.syscall.entry, addevent.syscall.return +{ +} + +/* log the system call name */ +function log_syscall_tracedata(var_id:long, name:string, backtrace:long) +%{ + if(THIS->backtrace == 1) { + String str = _stp_string_init (0); + _stp_stack_sprint (str, CONTEXT->regs, 0); + + _lket_trace(_GROUP_SYSCALL, THIS->var_id, "%0s%0s", THIS->name, _stp_string_ptr(str)); + } else { + _lket_trace(_GROUP_SYSCALL, THIS->var_id, "%0s", THIS->name); + } +%} + + +probe addevent.syscall.entry + += syscall.* +{ + if(filter_by_pid() == 1 ) { + log_syscall_tracedata(HOOKID_SYSCALL_ENTRY, name, backtrace) + } +} + +probe addevent.syscall.return + += syscall.*.return +{ + if(filter_by_pid() == 1 ) { + log_syscall_tracedata(HOOKID_SYSCALL_RETURN, name, backtrace) + } +} diff --git a/tapset/LKET/tskdispatch.stp b/tapset/LKET/tskdispatch.stp new file mode 100755 index 00000000..bb758144 --- /dev/null +++ b/tapset/LKET/tskdispatch.stp @@ -0,0 +1,71 @@ +// Copyright (C) 2005, 2006 IBM Corp. +// +// 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. + +/********************************************************** +* Dispatching when the cpu is idle or when a new process * +* is chosen to run. * +* * +* The actual locations for these two kinds of events are * +* the labels go_idle and switch_tasks inside the function * +* schedule. But currently SystemTap doesn't support * +* specifying probe points by label. * +* * +**********************************************************/ +probe addevent.tskdispatch + = addevent.tskdispatch.ctxswitch, + addevent.tskdispatch.cpuidle +{ +} + +/* Only applicable to SMP systems */ +probe addevent.tskdispatch.cpuidle + += scheduler.balance +{ + /* we didn't call filter_by_pid() here, + so that we can get all the idle events + despite how the cpu enters idle */ + log_cpuidle_tracedata(HOOKID_TASK_CPUIDLE, backtrace) +} + +probe addevent.tskdispatch.ctxswitch + = scheduler.ctxswitch +{ + target_pid = target() + cur_pid = pid() + if( stp_pid() != cur_pid ) { /* skip stpd itself */ + if(target_pid == 0 || (target_pid !=0 && ($prev->pid == target_pid + || $new->pid == target_pid))) { + log_ctxswitch_tracedata(HOOKID_TASK_CTXSWITCH, $prev, $new) + } + } +} + +function log_ctxswitch_tracedata(var_id:long, prev:long, next_pid:long) +%{ + struct task_struct *prev_tsk, *next_tsk; + + prev_tsk = (struct task_struct *)((long)THIS->prev); + next_tsk = (struct task_struct *)((long)THIS->next_pid); + + _lket_trace(_GROUP_TASK, THIS->var_id, "%4b%4b%1b", prev_tsk->pid, next_tsk->pid, prev_tsk->state); +%} + +function log_cpuidle_tracedata(var_id:long, backtrace:long) +%{ + struct task_struct *cur = current; + + if(THIS->backtrace == 1) { + String str = _stp_string_init (0); + _stp_stack_sprint (str, CONTEXT->regs, 0); + _lket_trace(_GROUP_TASK, THIS->var_id, "%4b%0s", cur->pid, _stp_string_ptr(str)); + } else { + _lket_trace(_GROUP_TASK, THIS->var_id, "%4b", cur->pid); + } +%} + + + diff --git a/tapset/LKET/utils.stp b/tapset/LKET/utils.stp new file mode 100755 index 00000000..0006246e --- /dev/null +++ b/tapset/LKET/utils.stp @@ -0,0 +1,33 @@ +// Copyright (C) 2005, 2006 IBM Corp. +// +// 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. + +/* data tracing filter by pid + return: + 1 - if continue to log the raw data + 0 - return without logging the raw data + */ +function filter_by_pid:long() +%{ + struct task_struct *cur = current; + + if(cur->tgid != _stp_pid) { + /* to trace a specific process if we explicitly specify + which process we want to trace by: + 1. stap -c "process_to_trace" ... + 2. stap -x pid_to_trace ... + else we will trace all the processes + */ + if( _stp_target != 0 && cur->tgid != _stp_target) { + THIS->__retvalue = 0; + return; + } + + THIS->__retvalue = 1; + } else /*skip the events generated by stap itself*/ + THIS->__retvalue = 0; + return; +%} diff --git a/tapset/context.stp b/tapset/context.stp index 00629900..9a46df19 100644 --- a/tapset/context.stp +++ b/tapset/context.stp @@ -136,3 +136,7 @@ function target:long () %{ /* pure */ %} function returnval () { return retval () } # deprecated + +function stp_pid:long () %{ /* pure */ + THIS->__retvalue = _stp_pid; +%} diff --git a/tapset/ppc64/syscalls.stp b/tapset/ppc64/syscalls.stp index 52b97c50..41a31580 100644 --- a/tapset/ppc64/syscalls.stp +++ b/tapset/ppc64/syscalls.stp @@ -1779,6 +1779,8 @@ probe syscall.old32_readdir.return = # # time_t sys64_time(time_t __user * tloc) # +%( kernel_v <= "2.6.15" %? + probe syscall.sys64_time = kernel.function("sys64_time") { name = "sys64_time" /* FIXME */ @@ -1789,6 +1791,7 @@ probe syscall.sys64_time.return = kernel.function("sys64_time").return { name = "sys64_time" retstr = returnstr(1) } +%) # ppc64_personality ________________________________________ # # long ppc64_personality(unsigned long personality) diff --git a/tapset/scheduler.stp b/tapset/scheduler.stp index 08581332..442a8105 100644 --- a/tapset/scheduler.stp +++ b/tapset/scheduler.stp @@ -110,7 +110,11 @@ probe scheduler.balance = kernel.inline("idle_balance") {} /* probe scheduler.ctxswitch * * Fires when there is a context switch - * + + * Currently systemTap can't access arguments of inline + * functions. So we choose to probe __switch_to instead + * of context_switch() + * Arguments: * prev_pid: The pid of the process to be switched out * next_pid: The pid of the process to be switched in |