Home > Linux, 调优 > GLIBC 2.16 支持systemtap静态检查点

GLIBC 2.16 支持systemtap静态检查点

July 1st, 2012

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: GLIBC 2.16 支持systemtap静态检查点

刚@淘宝雕梁 告诉我 GLIBC 2.16 支持systemtap静态检查点,消息源在这里, 摘抄相关部分如下:

* New configure option –enable-systemtap builds SystemTap static probes
into libc for setjmp and longjmp and into libpthread for various operations.
So far the setjmp/longjmp probes and some of the libpthread probes are
provided only for i*86 and x86_64.
Implemented by Roland McGrath and Rayson Ho.

目前主要是在setjmp/longjmp和pthread相关的锁操作,而且只支持 i*86 and x86_64 平台。我们到源码验证下:

这里下载源码glibc-2.16.0.tar.gz, 解开后简单的grep下:

[~/glibc-2.16.0]$grep -rin LIBC_PROBE .
./sysdeps/i386/__longjmp.S:35:  LIBC_PROBE (longjmp, 3, 4@%eax, -4@8(%esp), 4@%edx)
./sysdeps/i386/__longjmp.S:53:  LIBC_PROBE (longjmp_target, 3, 4@%eax, -4@8(%esp), 4@%edx)
./sysdeps/i386/__longjmp.S:61:  LIBC_PROBE (longjmp, 3, 4@%ecx, -4@%eax, 4@%edx)
./sysdeps/i386/__longjmp.S:68:  LIBC_PROBE (longjmp_target, 3, 4@%ecx, -4@%ecx, 4@%edx)
./sysdeps/i386/bsd-_setjmp.S:50:        LIBC_PROBE (setjmp, 3, 4@%edx, -4@$0, 4@%ecx)
./sysdeps/i386/setjmp.S:46:     LIBC_PROBE (setjmp, 3, 4@%eax, -4@SIGMSK(%esp), 4@%ecx)
./sysdeps/i386/bsd-setjmp.S:52: LIBC_PROBE (setjmp, 3, 4@%eax, -4@$1, 4@%ecx)
./sysdeps/unix/sysv/linux/i386/____longjmp_chk.S:83:    LIBC_PROBE (longjmp, 3, 4@%ecx, -4@8(%esp), 4@%edx)
./sysdeps/unix/sysv/linux/i386/____longjmp_chk.S:107:   LIBC_PROBE (longjmp_target, 3, 4@%ecx, -4@%eax, 4@%edx)
./sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S:108: LIBC_PROBE (longjmp, 3, LP_SIZE@%RDI_LP, -4@%esi, LP_SIZE@%RDX_LP)
./sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S:128: LIBC_PROBE (longjmp_target, 3,
./sysdeps/x86_64/__longjmp.S:45:        LIBC_PROBE (longjmp, 3, LP_SIZE@%RDI_LP, -4@%esi, LP_SIZE@%RDX_LP)
./sysdeps/x86_64/__longjmp.S:65:        LIBC_PROBE (longjmp_target, 3,
./sysdeps/x86_64/setjmp.S:51:   LIBC_PROBE (setjmp, 3, LP_SIZE@%RDI_LP, -4@%esi, LP_SIZE@%RAX_LP)
./include/stap-probe.h:26:/* Our code uses one macro LIBC_PROBE (name, n, arg1, ..., argn).
./include/stap-probe.h:41:   other headers that use LIBC_PROBE inside their own macros.  We
./include/stap-probe.h:47:# define LIBC_PROBE(name, n, ...)     \
./include/stap-probe.h:48:  LIBC_PROBE_1 (IN_LIB, name, n, ## __VA_ARGS__)
./include/stap-probe.h:50:# define LIBC_PROBE_1(lib, name, n, ...) \
./include/stap-probe.h:55:# define LIBC_PROBE_ASM(name, template) \
./include/stap-probe.h:58:# define LIBC_PROBE_ASM_OPERANDS STAP_PROBE_ASM_OPERANDS
./include/stap-probe.h:64:#  define LIBC_PROBE(name, n, ...)                                          \
./include/stap-probe.h:66:    _Bool __libc_probe_args[] = { 0, ## __VA_ARGS__ };                              \
./include/stap-probe.h:67:    _Bool __libc_probe_verify_n[(sizeof __libc_probe_args / sizeof (_Bool))   \
./include/stap-probe.h:69:    (void) __libc_probe_verify_n;                                           \
./include/stap-probe.h:72:#  define LIBC_PROBE(name, n, ...)            /* Nothing.  */
./include/stap-probe.h:75:# define LIBC_PROBE_ASM(name, template)               /* Nothing.  */
./include/stap-probe.h:76:# define LIBC_PROBE_ASM_OPERANDS(n, ...)      /* Nothing.  */
./nptl/pthread_join.c:59:  LIBC_PROBE (pthread_join, 1, threadid);
./nptl/pthread_join.c:116:  LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd->result);
./nptl/pthread_rwlock_wrlock.c:34:  LIBC_PROBE (wrlock_entry, 1, rwlock);
./nptl/pthread_rwlock_wrlock.c:47:        LIBC_PROBE (wrlock_acquire_write, 1, rwlock);
./nptl/ChangeLog:175:   * pthread_create.c (start_thread): Define pthread_start LIBC_PROBE.
./nptl/pthread_mutex_lock.c:52:  LIBC_PROBE (mutex_entry, 1, mutex);
./nptl/pthread_mutex_lock.c:133:  LIBC_PROBE (mutex_acquired, 1, mutex);
./nptl/pthread_mutex_lock.c:475:  LIBC_PROBE (mutex_acquired, 1, mutex);
./nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:230:    LIBC_PROBE (lll_futex_wake, 3, futex, nr, private);                       \
./nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S:63:   LIBC_PROBE (cond_timedwait, 3, %ebx, 24(%esp), %ebp)
./nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S:44:    LIBC_PROBE (rdlock_entry, 1, %ebx)
./nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S:95:1:   LIBC_PROBE (lll_lock_wait_private, 1, %ebx)
./nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S:52:   LIBC_PROBE (cond_broadcast, 1, %edx)
./nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S:64:        LIBC_PROBE (cond_wait, 2, 24(%esp), %ebx)
./nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S:47:      LIBC_PROBE (cond_signal, 1, %edi)
./nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S:44:    LIBC_PROBE (wrlock_entry, 1, %ebx)
./nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h:231:    LIBC_PROBE (lll_futex_wake, 3, futex, nr, private);                       \
./nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:71:      LIBC_PROBE (cond_timedwait, 3, %rdi, %rsi, %rdx)
./nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S:34:       LIBC_PROBE (rdlock_entry, 1, %rdi)
./nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:91:1:      LIBC_PROBE (lll_lock_wait_private, 1, %rdi)
./nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:131:1:     LIBC_PROBE (lll_lock_wait, 2, %rdi, %rsi)
./nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S:36:      LIBC_PROBE (cond_broadcast, 1, %rdi)
./nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:69:   LIBC_PROBE (cond_wait, 2, %rdi, %rsi)
./nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S:37: LIBC_PROBE (cond_signal, 1, %rdi)
./nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S:34:       LIBC_PROBE (wrlock_entry, 1, %rdi)
./nptl/pthread_cond_destroy.c:32:  LIBC_PROBE (cond_destroy, 1, cond);
./nptl/pthread_cond_broadcast.c:35:  LIBC_PROBE (cond_broadcast, 1, cond);
./nptl/pthread_cond_signal.c:38:  LIBC_PROBE (cond_signal, 1, cond);
./nptl/pthread_rwlock_destroy.c:27:  LIBC_PROBE (rwlock_destroy, 1, rwlock);
./nptl/pthread_mutex_init.c:138:  LIBC_PROBE (mutex_init, 1, mutex);
./nptl/pthread_rwlock_rdlock.c:34:  LIBC_PROBE (rdlock_entry, 1, rwlock);
./nptl/pthread_rwlock_rdlock.c:55:          LIBC_PROBE (rdlock_acquire_read, 1, rwlock);
./nptl/pthread_mutex_timedlock.c:38:  LIBC_PROBE (mutex_timedlock_entry, 2, mutex, abstime);
./nptl/pthread_mutex_timedlock.c:178:             LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
./nptl/pthread_mutex_timedlock.c:250:           LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
./nptl/pthread_mutex_timedlock.c:387:           LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
./nptl/pthread_mutex_timedlock.c:490:      LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
./nptl/pthread_mutex_unlock.c:54:      LIBC_PROBE (mutex_release, 1, mutex);
./nptl/pthread_mutex_unlock.c:279:      LIBC_PROBE (mutex_release, 1, mutex);
./nptl/pthread_mutex_unlock.c:288:  LIBC_PROBE (mutex_release, 1, mutex);
./nptl/pthread_cond_wait.c:104:  LIBC_PROBE (cond_wait, 2, cond, mutex);
./nptl/pthread_cond_init.c:44:  LIBC_PROBE (cond_init, 2, cond, cond_attr);
./nptl/pthread_create.c:304:      LIBC_PROBE (pthread_start, 3, (pthread_t) pd, pd->start_routine, pd->arg);
./nptl/pthread_create.c:563:  LIBC_PROBE (pthread_create, 4, newthread, attr, start_routine, arg);
./nptl/pthread_rwlock_unlock.c:30:  LIBC_PROBE (rwlock_unlock, 1, rwlock);
./nptl/pthread_mutex_destroy.c:29:  LIBC_PROBE (mutex_destroy, 1, mutex);

确实验证了官方的说法。 那么这个特性如何的启用呢?

在编译libc的时候 configure –enable-systemtap 就好了。
那么如何验证这些检查点的存在呢? 参看systemtap官网的这篇文章,详细的介绍了静态检查点,参看这里
简单的说就是用 stap -L ‘process(“libc.so”).mark(“*”)’ 看可否列出所有的检查点。

那么这些检查点如何使用呢? 参数如何呢?
文档在这里 ./nptl/DESIGN-systemtap-probes.txt
我们来看下:

Systemtap is a dynamic tracing/instrumenting tool available on Linux. Probes
that are not fired at run time have close to zero overhead.

The following probes are available for NPTL:

Thread creation & Join Probes
=============================
pthread_create – probe for pthread_create
arg1 = pointer (pthread_t*) to thread
arg2 = pointer (pthread_attr_t*) to attr
arg3 = pointer (void *) to start_routine
arg4 = arguments to start_routine
pthread_start – probe for actual thread creation
arg1 = struct pthread (members include thread ID, process ID)
arg2 = address of start_routine
arg3 = pointer to the list of arguments
pthread_join – probe for pthread_join
arg1 = thread ID
pthread_join_ret – probe for pthread_join return
arg1 = thread ID
arg2 = return value

Lock-related Probes
===================
mutex_init – probe for pthread_mutex_init
arg1 = address of mutex lock
mutex_acquired – probe for succ. return of pthread_mutex_lock
arg1 = address of mutex lock
mutex_timedlock_acquired – probe for succ. return of pthread_mutex_timedlock
arg1 = address of mutex lock
mutex_entry – probe for entry to the pthread_mutex_lock function
arg1 = address of mutex lock
mutex_timedlock_entry – probe for entry to the pthread_mutex_timedlock function
arg1 = address of mutex lock, arg2 = address of timespec
mutex_release – probe for pthread_mutex_unlock after the successful release of a
mutex lock
arg1 = address of mutex lock
mutex_destroy – probe for pthread_mutex_destroy
arg1 = address of mutex lock

wrlock_entry – probe for entry to the pthread_rwlock_wrlock function
arg1 = address of rw lock
rdlock_entry – probe for entry to the pthread_rwlock_rdlock function
arg1 = address of rw lock

rwlock_destroy – probe for pthread_rwlock_destroy
arg1 = address of rw lock
wrlock_acquire_write – probe for pthread_rwlock_wrlock (after getting the lock)
arg1 = address of rw lock
rdlock_acquire_read – probe for pthread_rwlock_rdlock after successfully getting
the lock
arg1 = address of rw lock
rwlock_unlock – probe for pthread_rwlock_unlock
arg1 = address of rw lock

lll_lock_wait – probe in low-level (assembly language) locking code, only fired
when futex/FUTEX_WAIT is called (i.e. when trying to acquire a
contented lock)
arg1 = pointer to futex
arg2 = flags passed to the futex system call
lll_lock_wait_private – probe in low-level (assembly language) locking code,
only fired when futex/FUTEX_WAIT is called (i.e. when
trying to acquire a contented lock)
arg1 = pointer to futex

lll_futex_wake – probe in low-level (assembly language) locking code, only fired
when futex (FUTEX_WAKE) is called
arg1 = pointer to futex
arg2 = number of processes to wake
arg3 = additional flags

Condition variable Probes
=========================
cond_init – probe for pthread_cond_init
arg1 = condition
arg2 = attr
cond_destroy – probe for pthread_cond_destroy
arg1 = cond
cond_wait – probe for pthread_cond_wait
arg1 = condition
arg2 = mutex lock
cond_timedwait – probe for pthread_cond_timedwait
arg1 = condition
arg2 = mutex lock
arg3 = timespec
cond_signal – probe for pthread_cond_signal
arg1 = condition
cond_broadcast – probe for pthread_cond_broadcast
arg1 = condition

还是很详细的。setjmp/longjmp不常用就算了。

有这些静态检查点的帮助,我们定位libc相关锁的问题就非常方便了,而且只有使用的时候才需要付出性能代价。

祝玩得开心!

Post Footer automatically generated by wp-posturl plugin for wordpress.

Categories: Linux, 调优 Tags: , ,
  1. July 1st, 2012 at 21:31 | #1

    使用systemtap脚本应该可以探查到function pointer背后具体的实现函数,但是下面的system tap脚本打印出的始终是函数的地址,请问有什么解决办法吗?
    global addr

    probe kernel.function(“mpage_readpages”)
    {
    print(“hit func…\n”)
    addr = sprintf(“%p”, $get_block)
    exit()
    }

    probe begin
    {
    print(“staring probe…\n”);
    }

    probe end
    {
    print(“Function address and name are:\n”)
    print_stack(addr)
    }

    Yu Feng Reply:

    context-symbols.stp的symname是用来翻译地址和符号的。
    原型如下:
    function symname:string (addr: long) %{ /* pure */ /* pragma:symbols */

    casualfish Reply:

    多谢回复,我试了下,输出的还是函数地址,我的系统内核版本是2.6.32-220.el6.i686,是ext4的文件系统,按模块的形式编译。get_block对应的应该是ext4_get_block,但是没有输出。

    casualfish Reply:

    已经解决了,可以使用–all-modules或者-d 模块名(低版本systemtap没有
    –all-modules选项)来加载模块信息,
    不过只能使用print_stack输出函数名,symname还是不行。

Comments are closed.