[libvirt] [PATCH 00/13] Add multiple trace backend function and add new ftrace backend for libvirt

From: Xinghai Yu <yuxinghai@cn.fujitsu.com> This patch set will let libvirt to support multiple trace backend function and add a new 'ftrace' backend at the same time. Then, libvirt would have 2 trace backend: dtrace, ftrace.They can be used alone or together. Patchs 1,2,3,4,5 are used for supporting multiple trace backend function. Patch 6 are used for adding ftrace as a new trace backend for libvirt. Patchs 7,8,9,10,11,12,13 add ftrace initial code in programs who use it. Thanks very much for Stefan Hajnoczi for I have used his scripts in patch 4 which commited in qemu. Thanks very much for Eiichi Tsukata for I have used his ftrace codes in patch 6 which commited in qemu. Backgroud: The existing trace mechanism in libvirt is dtrace. Although the dtrace can work, it's not work well enough. Every time we want get information from the trace point we must write a systemtap script and run it together with libvirt. That's really unpractical on some occasion, especially on production server since the systemtap script can't be executed automatically. And some problems may be not easy to reproduce, then it will cost a lot of time to get the trace information again. So I think it is essential to add supporting for record the trace information automatically in libvirt to satisfy the user's requirement. That's why I implemented multiple trace backend function and ftrace support in libvirt. Xinghai Yu (13): configure.ac: Define new macro 'WITH_TRACE_PROBES' to indicate trace function are available Makefile.am: Add new multiple trace backend supporting framework src: Use new tracepoint declaration files to replace the old dtrace declaration files to support multiple trace function src: Add scripts 'tracetool' to supporting the translation from tracepoint files to multiple trace backend supporting files daemon,src: Use new tracepoint function calls to replace old PROBE macro calls to support multiple trace function configure.ac, Makefile.am, src: Add new ftrace backend src/libvirt.c: Init ftrace backend in libvirt library so that programs containing it can use ftrace src/qemu/qemu_driver.c: Init ftrace backend in qemu driver so that qemu driver can support ftrace src/locking/lock_daemon.c: Init ftrace backend in program 'virtlockd' src/util/iohelper.c: Init ftrace backend in program 'libvirt_iohelper' src/storage/parthelper.c: Init ftrace backend in program 'libvirt_parthelper' src/lxc/lxc_controller.c: Init ftrace backend in program 'libvirt_lxc' src/security/virt-aa-helper.c: Init ftrace backend in program 'virt-aa-helper' config-post.h | 2 +- configure.ac | 24 ++++ daemon/Makefile.am | 13 +- daemon/remote.c | 77 +++++------ src/Makefile.am | 179 +++++++++++++++++++------ src/ftrace.c | 91 +++++++++++++ src/ftrace.h | 14 ++ src/internal.h | 69 +---------- src/libvirt.c | 9 ++ src/libvirt_probes.d | 82 ------------ src/libvirt_qemu_probes.d | 22 ---- src/libvirt_qemu_trace_events | 15 +++ src/libvirt_trace_events | 70 ++++++++++ src/locking/lock_daemon.c | 9 ++ src/lxc/lxc_controller.c | 9 ++ src/qemu/qemu_driver.c | 10 ++ src/qemu/qemu_monitor.c | 42 +++--- src/qemu/qemu_monitor_json.c | 12 +- src/qemu/qemu_monitor_text.c | 8 +- src/rpc/virkeepalive.c | 42 +++--- src/rpc/virnetclient.c | 43 +++--- src/rpc/virnetserverclient.c | 31 ++--- src/rpc/virnetsocket.c | 22 ++-- src/rpc/virnettlscontext.c | 42 +++--- src/security/virt-aa-helper.c | 9 ++ src/storage/parthelper.c | 9 ++ src/tracetool.py | 103 +++++++++++++++ src/tracetool/__init__.py | 268 ++++++++++++++++++++++++++++++++++++++ src/tracetool/backend/__init__.py | 120 +++++++++++++++++ src/tracetool/backend/trace.py | 112 ++++++++++++++++ src/tracetool/format/__init__.py | 103 +++++++++++++++ src/tracetool/format/c.py | 22 ++++ src/tracetool/format/d.py | 20 +++ src/tracetool/format/h.py | 22 ++++ src/util/iohelper.c | 9 ++ src/util/vireventpoll.c | 66 +++++----- src/util/virobject.c | 16 ++- tests/Makefile.am | 13 +- tools/virsh.c | 3 + 39 files changed, 1429 insertions(+), 401 deletions(-) create mode 100644 src/ftrace.c create mode 100644 src/ftrace.h delete mode 100644 src/libvirt_probes.d delete mode 100644 src/libvirt_qemu_probes.d create mode 100644 src/libvirt_qemu_trace_events create mode 100644 src/libvirt_trace_events create mode 100644 src/tracetool.py create mode 100644 src/tracetool/__init__.py create mode 100644 src/tracetool/backend/__init__.py create mode 100644 src/tracetool/backend/trace.py create mode 100644 src/tracetool/format/__init__.py create mode 100644 src/tracetool/format/c.py create mode 100644 src/tracetool/format/d.py create mode 100644 src/tracetool/format/h.py -- 1.8.3.1

From: Xinghai Yu <yuxinghai@cn.fujitsu.com> Add the new multiple trace backend framework, and the 'Dtrace' should be one of the trace backends libvirt supporting. Using the macro exported by configure.ac to decide which trace backend to build for libvirt. We got 2 trace macros below: WITH_TRACE_PROBES, if --with-dtrace or other trace option was set, this macro would be true and it tell the codes that we will use trace function, dtrace or ftrace will be supported in libvirt. WITH_DTRACE_PROBES, if --with-dtrace was set this macro would be true and the dtrace will be supported in libvirt. Signed-off-by: Xinghai Yu <yuxinghai@cn.fujitsu.com> --- daemon/Makefile.am | 10 ++++- src/Makefile.am | 113 ++++++++++++++++++++++++++++++++++++++++++----------- tests/Makefile.am | 10 ++++- 3 files changed, 106 insertions(+), 27 deletions(-) diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 00221ab..bd77623 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -160,8 +160,11 @@ libvirtd_LDADD = \ $(POLKIT_LIBS) \ $(LIBNL_LIBS) -if WITH_DTRACE_PROBES +if WITH_TRACE_PROBES libvirtd_LDADD += ../src/libvirt_probes.lo +endif WITH_TRACE_PROBES +if WITH_DTRACE_PROBES +libvirtd_LDADD += ../src/libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES libvirtd_LDADD += \ @@ -174,8 +177,11 @@ libvirtd_LDADD += \ if ! WITH_DRIVER_MODULES if WITH_QEMU libvirtd_LDADD += ../src/libvirt_driver_qemu.la -if WITH_DTRACE_PROBES +if WITH_TRACE_PROBES libvirtd_LDADD += ../src/libvirt_qemu_probes.lo +endif WITH_TRACE_PROBES +if WITH_DTRACE_PROBES + libvirtd_LDADD += ../src/libvirt_qemu_probes_dtrace.lo endif WITH_DTRACE_PROBES endif WITH_QEMU diff --git a/src/Makefile.am b/src/Makefile.am index 25d0370..0e50ebc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1943,36 +1943,77 @@ libvirt_la_CFLAGS = -DIN_LIBVIRT $(AM_CFLAGS) # picked out for us. libvirt_la_DEPENDENCIES = $(libvirt_la_BUILT_LIBADD) $(LIBVIRT_SYMBOL_FILE) -if WITH_DTRACE_PROBES +TRACETOOL=$(srcdir)/tracetool.py +if WITH_TRACE_PROBES libvirt_la_BUILT_LIBADD += libvirt_probes.lo -libvirt_la_DEPENDENCIES += libvirt_probes.lo libvirt_probes.o nodist_libvirt_la_SOURCES = libvirt_probes.h +BUILT_SOURCES += libvirt_probes.c libvirt_probes.h +if WITH_QEMU +libvirt_driver_qemu_impl_la_LIBADD += libvirt_qemu_probes.lo +nodist_libvirt_driver_qemu_impl_la_SOURCES = libvirt_qemu_probes.h +BUILT_SOURCES += libvirt_qemu_probes.c libvirt_qemu_probes.h +endif WITH_QEMU +.PRECIOUS: %_probes.o +# Contain the trace_function's definition +%_probes.c: %_trace_events + $(AM_V_GEN)$(PYTHON) $(TRACETOOL) \ + --format=c \ + --backend=trace \ + < $< > $@ +# Contain the trace_function's declaration +%_probes.h: %_trace_events + $(AM_V_GEN)$(PYTHON) $(TRACETOOL) \ + --format=h \ + --backend=trace \ + < $< > $@ +%_probes.lo: %_probes.o + $(AM_V_GEN)printf %s\\n \ + '# $@ - a libtool object file' \ + '# Generated by libtool (GNU libtool) 2.4' \ + '# Actually generated by Makefile.am, in order to shut up libtool' \ + "pic_object='$<'" \ + "non_pic_object='$<'" \ + > $@ +CLEANFILES += libvirt_probes.c libvirt_probes.h libvirt_probes.o libvirt_probes.lo \ + libvirt_qemu_probes.c libvirt_qemu_probes.h libvirt_qemu_probes.o \ + libvirt_qemu_probes.lo +endif + +if WITH_DTRACE_PROBES +libvirt_la_BUILT_LIBADD += libvirt_probes_dtrace.lo +libvirt_la_DEPENDENCIES += libvirt_probes_dtrace.o libvirt_probes_dtrace.lo +nodist_libvirt_la_SOURCES = libvirt_probes_dtrace.h if WITH_REMOTE -nodist_libvirt_driver_remote_la_SOURCES = libvirt_probes.h +nodist_libvirt_driver_remote_la_SOURCES = libvirt_probes_dtrace.h endif WITH_REMOTE if WITH_DRIVER_MODULES DTRACE2SYSTEMTAP_FLAGS = --with-modules endif WITH_DRIVER_MODULES -BUILT_SOURCES += libvirt_probes.h libvirt_probes.stp libvirt_functions.stp +BUILT_SOURCES += libvirt_probes_dtrace.h libvirt_probes.stp libvirt_functions.stp if WITH_QEMU -libvirt_driver_qemu_la_LIBADD += libvirt_qemu_probes.lo -nodist_libvirt_driver_qemu_la_SOURCES = libvirt_qemu_probes.h -BUILT_SOURCES += libvirt_qemu_probes.h +libvirt_driver_qemu_impl_la_LIBADD += libvirt_qemu_probes_dtrace.lo +nodist_libvirt_driver_qemu_impl_la_SOURCES = libvirt_qemu_probes.h libvirt_qemu_probes_dtrace.h +BUILT_SOURCES += libvirt_qemu_probes_dtrace.h endif WITH_QEMU tapsetdir = $(datadir)/systemtap/tapset tapset_DATA = libvirt_probes.stp libvirt_qemu_probes.stp libvirt_functions.stp -%_probes.h: %_probes.d +%_probes.d: %_trace_events + $(AM_V_GEN)$(PYTHON) $(TRACETOOL) \ + --format=d \ + --backend=trace \ + < $< > $@ +%_probes_dtrace.h: %_probes.d $(AM_V_GEN)$(DTRACE) -o $@ -h -s $< -.PRECIOUS: %_probes.o -%_probes.o: %_probes.d +.PRECIOUS: %_probes_dtrace.o +%_probes_dtrace.o: %_probes.d $(AM_V_GEN)$(DTRACE) -o $@ -G -s $< -%_probes.lo: %_probes.o +%_probes_dtrace.lo: %_probes_dtrace.o $(AM_V_GEN)printf %s\\n \ '# $@ - a libtool object file' \ '# Generated by libtool (GNU libtool) 2.4' \ @@ -1998,14 +2039,14 @@ libvirt_functions.stp: $(RPC_PROBE_FILES) $(srcdir)/rpc/gensystemtap.pl $(AM_V_GEN)$(PERL) -w $(srcdir)/dtrace2systemtap.pl \ $(DTRACE2SYSTEMTAP_FLAGS) $(bindir) $(sbindir) $(libdir) $< > $@ -CLEANFILES += libvirt_probes.h libvirt_probes.o libvirt_probes.lo \ - libvirt_qemu_probes.h libvirt_qemu_probes.o \ - libvirt_qemu_probes.lo\ - libvirt_functions.stp libvirt_probes.stp \ - libvirt_qemu_probes.stp +CLEANFILES += libvirt_probes_dtrace.o libvirt_probes_dtrace.lo \ + libvirt_qemu_probes_dtrace.o libvirt_qemu_probes_dtrace.lo \ + libvirt_functions.stp libvirt_probes.stp libvirt_qemu_probes.stp \ + libvirt_qemu_probes_dtrace.h libvirt_probes_dtrace.h \ + libvirt_qemu_probes.d libvirt_probes.d endif WITH_DTRACE_PROBES -EXTRA_DIST += libvirt_probes.d libvirt_qemu_probes.d +EXTRA_DIST += libvirt_trace_events libvirt_qemu_trace_events libvirt_qemu_la_SOURCES = libvirt-qemu.c libvirt_qemu_la_LDFLAGS = \ @@ -2124,8 +2165,11 @@ lockd_la_LIBADD = ../gnulib/lib/libgnu.la \ augeas_DATA += locking/libvirt_lockd.aug augeastest_DATA += test_libvirt_lockd.aug CLEANFILES += test_libvirt_lockd.aug -if WITH_DTRACE_PROBES +if WITH_TRACE_PROBES lockd_la_LIBADD += libvirt_probes.lo +endif WITH_TRACE_PROBES +if WITH_DTRACE_PROBES +lockd_la_LIBADD += libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES if WITH_QEMU nodist_conf_DATA += locking/qemu-lockd.conf @@ -2163,8 +2207,11 @@ virtlockd_LDADD = \ ../gnulib/lib/libgnu.la \ $(CYGWIN_EXTRA_LIBADD) \ $(NULL) -if WITH_DTRACE_PROBES +if WITH_TRACE_PROBES virtlockd_LDADD += libvirt_probes.lo +endif WITH_TRACE_PROBES +if WITH_DTRACE_PROBES +virtlockd_LDADD += libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES else ! WITH_LIBVIRTD @@ -2331,6 +2378,14 @@ noinst_LTLIBRARIES += \ libvirt-net-rpc-client.la EXTRA_DIST += \ + tracetool.py \ + tracetool/__init__.py \ + tracetool/backend/__init__.py \ + tracetool/backend/trace.py \ + tracetool/format/__init__.py \ + tracetool/format/d.py \ + tracetool/format/c.py \ + tracetool/format/h.py \ dtrace2systemtap.pl \ rpc/gendispatch.pl \ rpc/genprotocol.pl \ @@ -2437,8 +2492,11 @@ libvirt_iohelper_LDFLAGS = \ libvirt_iohelper_LDADD = \ libvirt_util.la \ ../gnulib/lib/libgnu.la -if WITH_DTRACE_PROBES +if WITH_TRACE_PROBES libvirt_iohelper_LDADD += libvirt_probes.lo +endif WITH_TRACE_PROBES +if WITH_DTRACE_PROBES +libvirt_iohelper_LDADD += libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES libvirt_iohelper_CFLAGS = \ @@ -2460,8 +2518,11 @@ libvirt_parthelper_LDADD = \ $(LIBPARTED_LIBS) \ libvirt_util.la \ ../gnulib/lib/libgnu.la -if WITH_DTRACE_PROBES +if WITH_TRACE_PROBES libvirt_parthelper_LDADD += libvirt_probes.lo +endif WITH_TRACE_PROBES +if WITH_DTRACE_PROBES +libvirt_parthelper_LDADD += libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES libvirt_parthelper_CFLAGS = \ @@ -2510,8 +2571,11 @@ libvirt_lxc_LDADD = \ libvirt_conf.la \ libvirt_util.la \ ../gnulib/lib/libgnu.la -if WITH_DTRACE_PROBES +if WITH_TRACE_PROBES libvirt_lxc_LDADD += libvirt_probes.lo +endif WITH_TRACE_PROBES +if WITH_DTRACE_PROBES +libvirt_lxc_LDADD += libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES libvirt_lxc_LDADD += $(SECDRIVER_LIBS) libvirt_lxc_CFLAGS = \ @@ -2545,8 +2609,11 @@ virt_aa_helper_LDADD = \ libvirt_conf.la \ libvirt_util.la \ ../gnulib/lib/libgnu.la -if WITH_DTRACE_PROBES +if WITH_TRACE_PROBES virt_aa_helper_LDADD += libvirt_probes.lo +endif WITH_TRACE_PROBES +if WITH_DTRACE_PROBES +virt_aa_helper_LDADD += libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES virt_aa_helper_CFLAGS = \ -I$(top_srcdir)/src/conf \ diff --git a/tests/Makefile.am b/tests/Makefile.am index cd91734..8d24cd9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -45,8 +45,11 @@ INCLUDES += \ endif WITH_DRIVER_MODULES PROBES_O = -if WITH_DTRACE_PROBES +if WITH_TRACE_PROBES PROBES_O += ../src/libvirt_probes.lo +endif WITH_TRACE_PROBES +if WITH_DTRACE_PROBES +PROBES_O += ../src/libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES GNULIB_LIBS = \ @@ -453,8 +456,11 @@ endif WITH_NETWORK if WITH_STORAGE qemu_LDADDS += ../src/libvirt_driver_storage_impl.la endif WITH_STORAGE -if WITH_DTRACE_PROBES +if WITH_TRACE_PROBES qemu_LDADDS += ../src/libvirt_qemu_probes.lo +endif WITH_TRACE_PROBES +if WITH_DTRACE_PROBES +qemu_LDADDS += ../src/libvirt_qemu_probes_dtrace.lo endif WITH_DTRACE_PROBES qemu_LDADDS += $(LDADDS) -- 1.8.3.1

From: Xinghai Yu <yuxinghai@cn.fujitsu.com> Remove the macro PROBE's definition in 'internal.h' and repalce the old 'PROBE' calls with new tracepoint function in source codes. Preprocess judgement by 'WITH_TRACE_PROBES' is to avoid the undefined errors which come from 'virt-login-shell' which code containing tracepoints but will not link tracepoints definition target file since 'virt-login-shell' will be setuid. Signed-off-by: Xinghai Yu <yuxinghai@cn.fujitsu.com> --- daemon/remote.c | 77 +++++++++++++++++++++++--------------------- src/internal.h | 69 +----------------------------------------- src/qemu/qemu_monitor.c | 42 ++++++++++++------------ src/qemu/qemu_monitor_json.c | 12 ++++--- src/qemu/qemu_monitor_text.c | 8 ++--- src/rpc/virkeepalive.c | 42 ++++++++++++------------ src/rpc/virnetclient.c | 43 +++++++++++++------------ src/rpc/virnetserverclient.c | 31 +++++++++--------- src/rpc/virnetsocket.c | 22 +++++++------ src/rpc/virnettlscontext.c | 42 +++++++++++++----------- src/util/vireventpoll.c | 66 ++++++++++++++++++------------------- src/util/virobject.c | 16 ++++++--- 12 files changed, 213 insertions(+), 263 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index b48d456..77e1f84 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -2752,9 +2752,9 @@ authfail: virReportError(VIR_ERR_AUTH_FAILED, "%s", _("authentication failed")); virNetMessageSaveError(rerr); - PROBE(RPC_SERVER_CLIENT_AUTH_FAIL, - "client=%p auth=%d", - client, REMOTE_AUTH_SASL); +#ifdef WITH_TRACE_PROBES + trace_rpc_server_client_auth_fail(client, REMOTE_AUTH_SASL); +#endif virObjectUnref(sasl); virMutexUnlock(&priv->lock); return -1; @@ -2793,10 +2793,9 @@ remoteSASLFinish(virNetServerClientPtr client) VIR_DEBUG("Authentication successful %d", virNetServerClientGetFD(client)); - PROBE(RPC_SERVER_CLIENT_AUTH_ALLOW, - "client=%p auth=%d identity=%s", - client, REMOTE_AUTH_SASL, identity); - +#ifdef WITH_TRACE_PROBES + trace_rpc_server_client_auth_allow(client, REMOTE_AUTH_SASL, identity); +#endif virObjectUnref(priv->sasl); priv->sasl = NULL; @@ -2823,7 +2822,9 @@ remoteDispatchAuthSaslStart(virNetServerPtr server ATTRIBUTE_UNUSED, int rv = -1; struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); +#ifdef WITH_TRACE_PROBES const char *identity; +#endif virMutexLock(&priv->lock); @@ -2882,16 +2883,16 @@ remoteDispatchAuthSaslStart(virNetServerPtr server ATTRIBUTE_UNUSED, return 0; authfail: - PROBE(RPC_SERVER_CLIENT_AUTH_FAIL, - "client=%p auth=%d", - client, REMOTE_AUTH_SASL); +#ifdef WITH_TRACE_PROBES + trace_rpc_server_client_auth_fail(client, REMOTE_AUTH_SASL); +#endif goto error; authdeny: +#ifdef WITH_TRACE_PROBES identity = virNetSASLSessionGetIdentity(priv->sasl); - PROBE(RPC_SERVER_CLIENT_AUTH_DENY, - "client=%p auth=%d identity=%s", - client, REMOTE_AUTH_SASL, identity); + trace_rpc_server_client_auth_deny(client, REMOTE_AUTH_SASL, identity); +#endif goto error; error: @@ -2921,7 +2922,9 @@ remoteDispatchAuthSaslStep(virNetServerPtr server ATTRIBUTE_UNUSED, int rv = -1; struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); +#ifdef WITH_TRACE_PROBES const char *identity; +#endif virMutexLock(&priv->lock); @@ -2980,16 +2983,16 @@ remoteDispatchAuthSaslStep(virNetServerPtr server ATTRIBUTE_UNUSED, return 0; authfail: - PROBE(RPC_SERVER_CLIENT_AUTH_FAIL, - "client=%p auth=%d", - client, REMOTE_AUTH_SASL); +#ifdef WITH_TRACE_PROBES + trace_rpc_server_client_auth_fail(client, REMOTE_AUTH_SASL); +#endif goto error; authdeny: +#ifdef WITH_TRACE_PROBES identity = virNetSASLSessionGetIdentity(priv->sasl); - PROBE(RPC_SERVER_CLIENT_AUTH_DENY, - "client=%p auth=%d identity=%s", - client, REMOTE_AUTH_SASL, identity); + trace_rpc_server_client_auth_deny(client, REMOTE_AUTH_SASL, identity); +#endif goto error; error: @@ -3134,9 +3137,9 @@ remoteDispatchAuthPolkit(virNetServerPtr server ATTRIBUTE_UNUSED, action, (long long) callerPid, callerUid, status); goto authdeny; } - PROBE(RPC_SERVER_CLIENT_AUTH_ALLOW, - "client=%p auth=%d identity=%s", - client, REMOTE_AUTH_POLKIT, ident); +#ifdef WITH_TRACE_PROBES + trace_rpc_server_client_auth_allow(client,REMOTE_AUTH_POLKIT, ident); +#endif VIR_INFO("Policy allowed action %s from pid %lld, uid %d", action, (long long) callerPid, callerUid); ret->complete = 1; @@ -3169,15 +3172,15 @@ error: return -1; authfail: - PROBE(RPC_SERVER_CLIENT_AUTH_FAIL, - "client=%p auth=%d", - client, REMOTE_AUTH_POLKIT); +#ifdef WITH_TRACE_PROBES + trace_rpc_server_client_auth_fail(client, REMOTE_AUTH_POLKIT); +#endif goto error; authdeny: - PROBE(RPC_SERVER_CLIENT_AUTH_DENY, - "client=%p auth=%d identity=%s", - client, REMOTE_AUTH_POLKIT, ident); +#ifdef WITH_TRACE_PROBES + trace_rpc_server_client_auth_deny(client, REMOTE_AUTH_POLKIT, ident); +#endif goto error; } #elif WITH_POLKIT0 @@ -3288,9 +3291,9 @@ remoteDispatchAuthPolkit(virNetServerPtr server ATTRIBUTE_UNUSED, polkit_result_to_string_representation(pkresult)); goto authdeny; } - PROBE(RPC_SERVER_CLIENT_AUTH_ALLOW, - "client=%p auth=%d identity=%s", - client, REMOTE_AUTH_POLKIT, ident); +#ifdef WITH_TRACE_PROBES + trace_rpc_server_client_auth_allow(client, REMOTE_AUTH_POLKIT, identity); +#endif VIR_INFO("Policy allowed action %s from pid %lld, uid %d, result %s", action, (long long) callerPid, callerUid, polkit_result_to_string_representation(pkresult)); @@ -3311,15 +3314,15 @@ error: return -1; authfail: - PROBE(RPC_SERVER_CLIENT_AUTH_FAIL, - "client=%p auth=%d", - client, REMOTE_AUTH_POLKIT); +#ifdef WITH_TRACE_PROBES + trace_rpc_server_client_auth_fail(client, REMOTE_AUTH_POLKIT); +#endif goto error; authdeny: - PROBE(RPC_SERVER_CLIENT_AUTH_DENY, - "client=%p auth=%d identity=%s", - client, REMOTE_AUTH_POLKIT, ident); +#ifdef WITH_TRACE_PROBES + trace_rpc_server_client_auth_deny(client, REMOTE_AUTH_POLKIT, identity); +#endif goto error; } diff --git a/src/internal.h b/src/internal.h index 5a38448..042c896 100644 --- a/src/internal.h +++ b/src/internal.h @@ -366,75 +366,10 @@ # define VIR_ROUND_UP(value, size) (VIR_DIV_UP(value, size) * (size)) -# if WITH_DTRACE_PROBES +#ifdef WITH_TRACE_PROBES # ifndef LIBVIRT_PROBES_H # define LIBVIRT_PROBES_H # include "libvirt_probes.h" # endif /* LIBVIRT_PROBES_H */ - -/* Systemtap 1.2 headers have a bug where they cannot handle a - * variable declared with array type. Work around this by casting all - * arguments. This is some gross use of the preprocessor because - * PROBE is a var-arg macro, but it is better than the alternative of - * making all callers to PROBE have to be aware of the issues. And - * hopefully, if we ever add a call to PROBE with other than 9 - * end arguments, you can figure out the pattern to extend this hack. - */ -# define VIR_COUNT_ARGS(...) VIR_ARG11(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) -# define VIR_ARG11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) _11 -# define VIR_ADD_CAST_EXPAND(a, b, ...) VIR_ADD_CAST_PASTE(a, b, __VA_ARGS__) -# define VIR_ADD_CAST_PASTE(a, b, ...) a##b(__VA_ARGS__) - -/* The double cast is necessary to silence gcc warnings; any pointer - * can safely go to intptr_t and back to void *, which collapses - * arrays into pointers; while any integer can be widened to intptr_t - * then cast to void *. */ -# define VIR_ADD_CAST(a) ((void *)(intptr_t)(a)) -# define VIR_ADD_CAST1(a) \ - VIR_ADD_CAST(a) -# define VIR_ADD_CAST2(a, b) \ - VIR_ADD_CAST(a), VIR_ADD_CAST(b) -# define VIR_ADD_CAST3(a, b, c) \ - VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c) -# define VIR_ADD_CAST4(a, b, c, d) \ - VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ - VIR_ADD_CAST(d) -# define VIR_ADD_CAST5(a, b, c, d, e) \ - VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ - VIR_ADD_CAST(d), VIR_ADD_CAST(e) -# define VIR_ADD_CAST6(a, b, c, d, e, f) \ - VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ - VIR_ADD_CAST(d), VIR_ADD_CAST(e), VIR_ADD_CAST(f) -# define VIR_ADD_CAST7(a, b, c, d, e, f, g) \ - VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ - VIR_ADD_CAST(d), VIR_ADD_CAST(e), VIR_ADD_CAST(f), \ - VIR_ADD_CAST(g) -# define VIR_ADD_CAST8(a, b, c, d, e, f, g, h) \ - VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ - VIR_ADD_CAST(d), VIR_ADD_CAST(e), VIR_ADD_CAST(f), \ - VIR_ADD_CAST(g), VIR_ADD_CAST(h) -# define VIR_ADD_CAST9(a, b, c, d, e, f, g, h, i) \ - VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ - VIR_ADD_CAST(d), VIR_ADD_CAST(e), VIR_ADD_CAST(f), \ - VIR_ADD_CAST(g), VIR_ADD_CAST(h), VIR_ADD_CAST(i) - -# define VIR_ADD_CASTS(...) \ - VIR_ADD_CAST_EXPAND(VIR_ADD_CAST, VIR_COUNT_ARGS(__VA_ARGS__), \ - __VA_ARGS__) - -# define PROBE_EXPAND(NAME, ARGS) NAME(ARGS) -# define PROBE(NAME, FMT, ...) \ - VIR_DEBUG_INT(VIR_LOG_FROM_TRACE, \ - __FILE__, __LINE__, __func__, \ - #NAME ": " FMT, __VA_ARGS__); \ - if (LIBVIRT_ ## NAME ## _ENABLED()) { \ - PROBE_EXPAND(LIBVIRT_ ## NAME, \ - VIR_ADD_CASTS(__VA_ARGS__)); \ - } -# else -# define PROBE(NAME, FMT, ...) \ - VIR_DEBUG_INT(VIR_LOG_FROM_TRACE, \ - __FILE__, __LINE__, __func__, \ - #NAME ": " FMT, __VA_ARGS__); # endif diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index a2769db..d874710 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -42,7 +42,7 @@ #include "virobject.h" #include "virstring.h" -#ifdef WITH_DTRACE_PROBES +#ifdef WITH_TRACE_PROBES # include "libvirt_qemu_probes.h" #endif @@ -392,8 +392,9 @@ qemuMonitorIOProcess(qemuMonitorPtr mon) # endif #endif - PROBE(QEMU_MONITOR_IO_PROCESS, - "mon=%p buf=%s len=%zu", mon, mon->buffer, mon->bufferOffset); +#ifdef WITH_TRACE_PROBES + trace_qemu_monitor_io_process(mon, mon->buffer, mon->bufferOffset); +#endif if (mon->json) len = qemuMonitorJSONIOProcess(mon, @@ -496,17 +497,17 @@ qemuMonitorIOWrite(qemuMonitorPtr mon) mon->msg->txLength - mon->msg->txOffset, mon->msg->txFD); - PROBE(QEMU_MONITOR_IO_WRITE, - "mon=%p buf=%s len=%d ret=%d errno=%d", - mon, - mon->msg->txBuffer + mon->msg->txOffset, - mon->msg->txLength - mon->msg->txOffset, - done, errno); +#ifdef WITH_TRACE_PROBES + trace_qemu_monitor_io_write(mon, + mon->msg->txBuffer + mon->msg->txOffset, + mon->msg->txLength - mon->msg->txOffset, + done, errno); +#endif if (mon->msg->txFD != -1) - PROBE(QEMU_MONITOR_IO_SEND_FD, - "mon=%p fd=%d ret=%d errno=%d", - mon, mon->msg->txFD, done, errno); +#ifdef WITH_TRACE_PROBES + trace_qemu_monitor_io_send_fd(mon, mon->msg->txFD, done, errno); +#endif if (done < 0) { if (errno == EAGAIN) @@ -819,9 +820,9 @@ qemuMonitorOpenInternal(virDomainObjPtr vm, goto cleanup; } - PROBE(QEMU_MONITOR_NEW, - "mon=%p refs=%d fd=%d", - mon, mon->parent.parent.u.s.refs, mon->fd); +#ifdef WITH_TRACE_PROBES + trace_qemu_monitor_new(mon, mon->parent.parent.u.s.refs, mon->fd); +#endif virObjectUnlock(mon); return mon; @@ -892,8 +893,9 @@ void qemuMonitorClose(qemuMonitorPtr mon) return; virObjectLock(mon); - PROBE(QEMU_MONITOR_CLOSE, - "mon=%p refs=%d", mon, mon->parent.parent.u.s.refs); +#ifdef WITH_TRACE_PROBES + trace_qemu_monitor_close(mon, mon->parent.parent.u.s.refs); +#endif if (mon->fd >= 0) { if (mon->watch) { @@ -954,9 +956,9 @@ int qemuMonitorSend(qemuMonitorPtr mon, mon->msg = msg; qemuMonitorUpdateWatch(mon); - PROBE(QEMU_MONITOR_SEND_MSG, - "mon=%p msg=%s fd=%d", - mon, mon->msg->txBuffer, mon->msg->txFD); +#ifdef WITH_TRACE_PROBES + trace_qemu_monitor_send_msg(mon, mon->msg->txBuffer, mon->msg->txFD); +#endif while (!mon->msg->finished) { if (virCondWait(&mon->notify, &mon->parent.lock) < 0) { diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 9a5b812..3cf5e1a 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -44,7 +44,7 @@ #include "virstring.h" #include "cpu/cpu_x86.h" -#ifdef WITH_DTRACE_PROBES +#ifdef WITH_TRACE_PROBES # include "libvirt_qemu_probes.h" #endif @@ -168,13 +168,15 @@ qemuMonitorJSONIOProcessLine(qemuMonitorPtr mon, if (virJSONValueObjectHasKey(obj, "QMP") == 1) { ret = 0; } else if (virJSONValueObjectHasKey(obj, "event") == 1) { - PROBE(QEMU_MONITOR_RECV_EVENT, - "mon=%p event=%s", mon, line); +#ifdef WITH_TRACE_PROBES + trace_qemu_monitor_recv_event(mon, line); +#endif ret = qemuMonitorJSONIOProcessEvent(mon, obj); } else if (virJSONValueObjectHasKey(obj, "error") == 1 || virJSONValueObjectHasKey(obj, "return") == 1) { - PROBE(QEMU_MONITOR_RECV_REPLY, - "mon=%p reply=%s", mon, line); +#ifdef WITH_TRACE_PROBES + trace_qemu_monitor_recv_reply(mon, line); +#endif if (msg) { msg->rxObject = obj; msg->finished = 1; diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 7b81079..9b3d772 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -42,7 +42,7 @@ #include "virbuffer.h" #include "virstring.h" -#ifdef WITH_DTRACE_PROBES +#ifdef WITH_TRACE_PROBES # include "libvirt_qemu_probes.h" #endif @@ -201,9 +201,9 @@ int qemuMonitorTextIOProcess(qemuMonitorPtr mon ATTRIBUTE_UNUSED, VIR_DEBUG("Finished 0 byte reply"); #endif } - PROBE(QEMU_MONITOR_RECV_REPLY, - "mon=%p reply=%s", - mon, msg->rxBuffer); +#ifdef WITH_TRACE_PROBES + trace_qemu_monitor_recv_reply(mon, msg->rxBuffer); +#endif msg->finished = 1; used += end - (data + used); used += strlen(BASIC_PROMPT); diff --git a/src/rpc/virkeepalive.c b/src/rpc/virkeepalive.c index 8ae5c6c..265b7a6 100644 --- a/src/rpc/virkeepalive.c +++ b/src/rpc/virkeepalive.c @@ -99,9 +99,9 @@ virKeepAliveMessage(virKeepAlivePtr ka, int proc) } VIR_DEBUG("Sending keepalive %s to client %p", procstr, ka->client); - PROBE(RPC_KEEPALIVE_SEND, - "ka=%p client=%p prog=%d vers=%d proc=%d", - ka, ka->client, msg->header.prog, msg->header.vers, msg->header.proc); +#ifdef WITH_TRACE_PROBES + trace_rpc_keepalive_send(ka, ka->client, msg->header.prog, msg->header.vers, msg->header.proc); +#endif return msg; @@ -128,9 +128,9 @@ virKeepAliveTimerInternal(virKeepAlivePtr ka, } timeval = now - ka->lastPacketReceived; - PROBE(RPC_KEEPALIVE_TIMEOUT, - "ka=%p client=%p countToDeath=%d idle=%d", - ka, ka->client, ka->countToDeath, timeval); +#ifdef WITH_TRACE_PROBES + trace_rpc_keepalive_timeout(ka, ka->client, ka->countToDeath, timeval); +#endif if (ka->countToDeath == 0) { VIR_WARN("No response from client %p after %d keepalive messages in" @@ -210,9 +210,9 @@ virKeepAliveNew(int interval, ka->deadCB = deadCB; ka->freeCB = freeCB; - PROBE(RPC_KEEPALIVE_NEW, - "ka=%p client=%p", - ka, ka->client); +#ifdef WITH_TRACE_PROBES + trace_rpc_keepalive_new(ka, ka->client); +#endif return ka; } @@ -223,8 +223,9 @@ virKeepAliveDispose(void *obj) { virKeepAlivePtr ka = obj; - PROBE(RPC_KEEPALIVE_DISPOSE, - "ka=%p", ka); +#ifdef WITH_TRACE_PROBES + trace_rpc_keepalive_dispose(ka); +#endif ka->freeCB(ka->client); } @@ -271,9 +272,9 @@ virKeepAliveStart(virKeepAlivePtr ka, goto cleanup; } - PROBE(RPC_KEEPALIVE_START, - "ka=%p client=%p interval=%d count=%u", - ka, ka->client, interval, count); +#ifdef WITH_TRACE_PROBES + trace_rpc_keepalive_start(ka, ka->client, interval, count); +#endif now = time(NULL); delay = now - ka->lastPacketReceived; @@ -302,9 +303,9 @@ virKeepAliveStop(virKeepAlivePtr ka) { virObjectLock(ka); - PROBE(RPC_KEEPALIVE_STOP, - "ka=%p client=%p", - ka, ka->client); +#ifdef WITH_TRACE_PROBES + trace_rpc_keepalive_stop(ka, ka->client); +#endif if (ka->timer > 0) { virEventRemoveTimeout(ka->timer); @@ -385,10 +386,9 @@ virKeepAliveCheckMessage(virKeepAlivePtr ka, if (msg->header.prog == KEEPALIVE_PROGRAM && msg->header.vers == KEEPALIVE_PROTOCOL_VERSION && msg->header.type == VIR_NET_MESSAGE) { - PROBE(RPC_KEEPALIVE_RECEIVED, - "ka=%p client=%p prog=%d vers=%d proc=%d", - ka, ka->client, msg->header.prog, - msg->header.vers, msg->header.proc); +#ifdef WITH_TRACE_PROBES + trace_rpc_keepalive_received(ka, ka->client, msg->header.prog, msg->header.vers, msg->header.proc); +#endif ret = true; switch (msg->header.proc) { case KEEPALIVE_PROC_PING: diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index 9deec9e..51799cd 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -321,9 +321,9 @@ static virNetClientPtr virNetClientNew(virNetSocketPtr sock, if (VIR_STRDUP(client->hostname, hostname) < 0) goto error; - PROBE(RPC_CLIENT_NEW, - "client=%p sock=%p", - client, client->sock); +#ifdef WITH_TRACE_PROBES + trace_rpc_client_new(client, client->sock); +#endif return client; error: @@ -595,8 +595,9 @@ void virNetClientDispose(void *obj) virNetClientPtr client = obj; size_t i; - PROBE(RPC_CLIENT_DISPOSE, - "client=%p", client); +#ifdef WITH_TRACE_PROBES + trace_rpc_client_dispose(client); +#endif if (client->closeFf) client->closeFf(client->closeOpaque); @@ -1116,11 +1117,12 @@ virNetClientCallDispatch(virNetClientPtr client) { virNetMessagePtr response = NULL; - PROBE(RPC_CLIENT_MSG_RX, - "client=%p len=%zu prog=%u vers=%u proc=%u type=%u status=%u serial=%u", - client, client->msg.bufferLength, - client->msg.header.prog, client->msg.header.vers, client->msg.header.proc, - client->msg.header.type, client->msg.header.status, client->msg.header.serial); +#ifdef WITH_TRACE_PROBES + trace_rpc_client_msg_rx(client, client->msg.bufferLength, client->msg.header.prog, + client->msg.header.vers, client->msg.header.proc, + client->msg.header.type, client->msg.header.status, + client->msg.header.serial); +#endif if (virKeepAliveCheckMessage(client->keepalive, &client->msg, &response)) { if (response && @@ -1918,12 +1920,11 @@ virNetClientQueueNonBlocking(virNetClientPtr client, { virNetClientCallPtr call; - PROBE(RPC_CLIENT_MSG_TX_QUEUE, - "client=%p len=%zu prog=%u vers=%u proc=%u" - " type=%u status=%u serial=%u", - client, msg->bufferLength, - msg->header.prog, msg->header.vers, msg->header.proc, - msg->header.type, msg->header.status, msg->header.serial); +#ifdef WITH_TRACE_PROBES + trace_rpc_client_msg_tx_queue(client, msg->bufferLength, + msg->header.prog, msg->header.vers, msg->header.proc, + msg->header.type, msg->header.status, msg->header.serial); +#endif if (!(call = virNetClientCallNew(msg, false, true))) return -1; @@ -1945,11 +1946,11 @@ static int virNetClientSendInternal(virNetClientPtr client, virNetClientCallPtr call; int ret = -1; - PROBE(RPC_CLIENT_MSG_TX_QUEUE, - "client=%p len=%zu prog=%u vers=%u proc=%u type=%u status=%u serial=%u", - client, msg->bufferLength, - msg->header.prog, msg->header.vers, msg->header.proc, - msg->header.type, msg->header.status, msg->header.serial); +#ifdef WITH_TRACE_PROBES + trace_rpc_client_msg_tx_queue(client, msg->bufferLength, + msg->header.prog, msg->header.vers, msg->header.proc, + msg->header.type, msg->header.status, msg->header.serial); +#endif if (!client->sock || client->wantClose) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index 52b4941..5a4bc8e 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -379,9 +379,9 @@ virNetServerClientNewInternal(virNetSocketPtr sock, goto error; client->nrequests = 1; - PROBE(RPC_SERVER_CLIENT_NEW, - "client=%p sock=%p", - client, client->sock); +#ifdef WITH_TRACE_PROBES + trace_rpc_server_client_new(client, client->sock); +#endif return client; @@ -907,8 +907,9 @@ void virNetServerClientDispose(void *obj) { virNetServerClientPtr client = obj; - PROBE(RPC_SERVER_CLIENT_DISPOSE, - "client=%p", client); +#ifdef WITH_TRACE_PROBES + trace_rpc_server_client_dispose(client); +#endif virObjectUnref(client->identity); @@ -1201,11 +1202,11 @@ readmore: /* Definitely finished reading, so remove from queue */ virNetMessageQueueServe(&client->rx); - PROBE(RPC_SERVER_CLIENT_MSG_RX, - "client=%p len=%zu prog=%u vers=%u proc=%u type=%u status=%u serial=%u", - client, msg->bufferLength, - msg->header.prog, msg->header.vers, msg->header.proc, - msg->header.type, msg->header.status, msg->header.serial); +#ifdef WITH_TRACE_PROBES + trace_rpc_server_client_msg_rx(client, msg->bufferLength, + msg->header.prog,msg->header.vers, msg->header.proc, + msg->header.type, msg->header.status, msg->header.serial); +#endif if (virKeepAliveCheckMessage(client->keepalive, msg, &response)) { virNetMessageFree(msg); @@ -1458,11 +1459,11 @@ virNetServerClientSendMessageLocked(virNetServerClientPtr client, msg->donefds = 0; if (client->sock && !client->wantClose) { - PROBE(RPC_SERVER_CLIENT_MSG_TX_QUEUE, - "client=%p len=%zu prog=%u vers=%u proc=%u type=%u status=%u serial=%u", - client, msg->bufferLength, - msg->header.prog, msg->header.vers, msg->header.proc, - msg->header.type, msg->header.status, msg->header.serial); +#ifdef WITH_TRACE_PROBES + trace_rpc_server_client_msg_tx_queue(client, msg->bufferLength, + msg->header.prog, msg->header.vers, msg->header.proc, + msg->header.type, msg->header.status, msg->header.serial); +#endif virNetMessageQueuePush(&client->tx, msg); virNetServerClientUpdateEvent(client); diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index 04bf25a..f18059a 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -199,10 +199,9 @@ static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr, sock->client = isClient; - PROBE(RPC_SOCKET_NEW, - "sock=%p fd=%d errfd=%d pid=%lld localAddr=%s, remoteAddr=%s", - sock, fd, errfd, (long long) pid, - NULLSTR(sock->localAddrStr), NULLSTR(sock->remoteAddrStr)); +#ifdef WITH_TRACE_PROBES + trace_rpc_socket_new(sock, fd, errfd, (long long)pid, NULLSTR(sock->localAddrStr), NULLSTR(sock->remoteAddrStr)); +#endif return sock; @@ -1016,8 +1015,9 @@ void virNetSocketDispose(void *obj) { virNetSocketPtr sock = obj; - PROBE(RPC_SOCKET_DISPOSE, - "sock=%p", sock); +#ifdef WITH_TRACE_PROBES + trace_rpc_socket_dispose(sock); +#endif if (sock->watch > 0) { virEventRemoveHandle(sock->watch); @@ -1640,8 +1640,9 @@ int virNetSocketSendFD(virNetSocketPtr sock, int fd) return -1; } virObjectLock(sock); - PROBE(RPC_SOCKET_SEND_FD, - "sock=%p fd=%d", sock, fd); +#ifdef WITH_TRACE_PROBES + trace_rpc_socket_send_fd(sock, fd); +#endif if (sendfd(sock->fd, fd) < 0) { if (errno == EAGAIN) ret = 0; @@ -1683,8 +1684,9 @@ int virNetSocketRecvFD(virNetSocketPtr sock, int *fd) _("Failed to recv file descriptor")); goto cleanup; } - PROBE(RPC_SOCKET_RECV_FD, - "sock=%p fd=%d", sock, *fd); +#ifdef WITH_TRACE_PROBES + trace_rpc_socket_recv_fd( sock, *fd); +#endif ret = 1; cleanup: diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c index cd69794..7716dd2 100644 --- a/src/rpc/virnettlscontext.c +++ b/src/rpc/virnettlscontext.c @@ -773,9 +773,9 @@ static virNetTLSContextPtr virNetTLSContextNew(const char *cacert, ctxt->x509dnWhitelist = x509dnWhitelist; ctxt->isServer = isServer; - PROBE(RPC_TLS_CONTEXT_NEW, - "ctxt=%p cacert=%s cacrl=%s cert=%s key=%s sanityCheckCert=%d requireValidCert=%d isServer=%d", - ctxt, cacert, NULLSTR(cacrl), cert, key, sanityCheckCert, requireValidCert, isServer); +#ifdef WITH_TRACE_PROBES + trace_rpc_tls_context_new(ctxt, cacert, NULLSTR(cacrl), cert, key, sanityCheckCert, requireValidCert, isServer); +#endif return ctxt; @@ -993,7 +993,9 @@ static int virNetTLSContextValidCertificate(virNetTLSContextPtr ctxt, unsigned int nCerts; size_t i; char dname[256]; +#ifdef WITH_TRACE_PROBES char *dnameptr = dname; +#endif size_t dnamesize = sizeof(dname); memset(dname, 0, dnamesize); @@ -1107,23 +1109,23 @@ static int virNetTLSContextValidCertificate(virNetTLSContextPtr ctxt, gnutls_x509_crt_deinit(cert); } - PROBE(RPC_TLS_CONTEXT_SESSION_ALLOW, - "ctxt=%p sess=%p dname=%s", - ctxt, sess, dnameptr); +#ifdef WITH_TRACE_PROBES + trace_rpc_tls_context_session_allow(ctxt, sess, dnameptr); +#endif return 0; authdeny: - PROBE(RPC_TLS_CONTEXT_SESSION_DENY, - "ctxt=%p sess=%p dname=%s", - ctxt, sess, dnameptr); +#ifdef WITH_TRACE_PROBES + trace_rpc_tls_context_session_deny(ctxt, sess, dnameptr); +#endif return -1; authfail: - PROBE(RPC_TLS_CONTEXT_SESSION_FAIL, - "ctxt=%p sess=%p", - ctxt, sess); +#ifdef WITH_TRACE_PROBES + trace_rpc_tls_context_session_fail(ctxt, sess); +#endif return -1; } @@ -1160,8 +1162,9 @@ void virNetTLSContextDispose(void *obj) { virNetTLSContextPtr ctxt = obj; - PROBE(RPC_TLS_CONTEXT_DISPOSE, - "ctxt=%p", ctxt); +#ifdef WITH_TRACE_PROBES + trace_rpc_tls_context_dispose(ctxt); +#endif gnutls_dh_params_deinit(ctxt->dhParams); gnutls_certificate_free_credentials(ctxt->x509cred); @@ -1254,9 +1257,9 @@ virNetTLSSessionPtr virNetTLSSessionNew(virNetTLSContextPtr ctxt, sess->isServer = ctxt->isServer; - PROBE(RPC_TLS_SESSION_NEW, - "sess=%p ctxt=%p hostname=%s isServer=%d", - sess, ctxt, hostname, sess->isServer); +#ifdef WITH_TRACE_PROBES + trace_rpc_tls_session_new(sess, ctxt, hostname, sess->isServer); +#endif return sess; @@ -1424,8 +1427,9 @@ void virNetTLSSessionDispose(void *obj) { virNetTLSSessionPtr sess = obj; - PROBE(RPC_TLS_SESSION_DISPOSE, - "sess=%p", sess); +#ifdef WITH_TRACE_PROBES + trace_rpc_tls_session_dispose( sess); +#endif VIR_FREE(sess->x509dname); VIR_FREE(sess->hostname); diff --git a/src/util/vireventpoll.c b/src/util/vireventpoll.c index 8a4c8bc..89db91c 100644 --- a/src/util/vireventpoll.c +++ b/src/util/vireventpoll.c @@ -131,9 +131,9 @@ int virEventPollAddHandle(int fd, int events, virEventPollInterruptLocked(); - PROBE(EVENT_POLL_ADD_HANDLE, - "watch=%d fd=%d events=%d cb=%p opaque=%p ff=%p", - watch, fd, events, cb, opaque, ff); +#ifdef WITH_TRACE_PROBES + trace_event_poll_add_handle(watch, fd, events, cb, opaque, ff); +#endif virMutexUnlock(&eventLoop.lock); return watch; @@ -142,9 +142,9 @@ int virEventPollAddHandle(int fd, int events, void virEventPollUpdateHandle(int watch, int events) { size_t i; bool found = false; - PROBE(EVENT_POLL_UPDATE_HANDLE, - "watch=%d events=%d", - watch, events); +#ifdef WITH_TRACE_PROBES + trace_event_poll_update_handle(watch, events); +#endif if (watch <= 0) { VIR_WARN("Ignoring invalid update watch %d", watch); @@ -175,9 +175,9 @@ void virEventPollUpdateHandle(int watch, int events) { */ int virEventPollRemoveHandle(int watch) { size_t i; - PROBE(EVENT_POLL_REMOVE_HANDLE, - "watch=%d", - watch); +#ifdef WITH_TRACE_PROBES + trace_event_poll_remove_handle(watch); +#endif if (watch <= 0) { VIR_WARN("Ignoring invalid remove watch %d", watch); @@ -243,9 +243,9 @@ int virEventPollAddTimeout(int frequency, ret = nextTimer-1; virEventPollInterruptLocked(); - PROBE(EVENT_POLL_ADD_TIMEOUT, - "timer=%d frequency=%d cb=%p opaque=%p ff=%p", - ret, frequency, cb, opaque, ff); +#ifdef WITH_TRACE_PROBES + trace_event_poll_add_timeout(ret, frequency, cb, opaque, ff); +#endif virMutexUnlock(&eventLoop.lock); return ret; } @@ -255,9 +255,9 @@ void virEventPollUpdateTimeout(int timer, int frequency) unsigned long long now; size_t i; bool found = false; - PROBE(EVENT_POLL_UPDATE_TIMEOUT, - "timer=%d frequency=%d", - timer, frequency); +#ifdef WITH_TRACE_PROBES + trace_event_poll_update_timeout(timer, frequency); +#endif if (timer <= 0) { VIR_WARN("Ignoring invalid update timer %d", timer); @@ -295,9 +295,9 @@ void virEventPollUpdateTimeout(int timer, int frequency) */ int virEventPollRemoveTimeout(int timer) { size_t i; - PROBE(EVENT_POLL_REMOVE_TIMEOUT, - "timer=%d", - timer); +#ifdef WITH_TRACE_PROBES + trace_event_poll_remove_timeout(timer); +#endif if (timer <= 0) { VIR_WARN("Ignoring invalid remove timer %d", timer); @@ -444,9 +444,9 @@ static int virEventPollDispatchTimeouts(void) eventLoop.timeouts[i].expiresAt = now + eventLoop.timeouts[i].frequency; - PROBE(EVENT_POLL_DISPATCH_TIMEOUT, - "timer=%d", - timer); +#ifdef WITH_TRACE_PROBES + trace_event_poll_dispatch_timeout(timer); +#endif virMutexUnlock(&eventLoop.lock); (cb)(timer, opaque); virMutexLock(&eventLoop.lock); @@ -494,9 +494,9 @@ static int virEventPollDispatchHandles(int nfds, struct pollfd *fds) { int watch = eventLoop.handles[i].watch; void *opaque = eventLoop.handles[i].opaque; int hEvents = virEventPollFromNativeEvents(fds[n].revents); - PROBE(EVENT_POLL_DISPATCH_HANDLE, - "watch=%d events=%d", - watch, hEvents); +#ifdef WITH_TRACE_PROBES + trace_event_poll_dispatch_handle( watch, hEvents); +#endif virMutexUnlock(&eventLoop.lock); (cb)(watch, fds[n].fd, hEvents, opaque); virMutexLock(&eventLoop.lock); @@ -525,9 +525,9 @@ static void virEventPollCleanupTimeouts(void) { continue; } - PROBE(EVENT_POLL_PURGE_TIMEOUT, - "timer=%d", - eventLoop.timeouts[i].timer); +#ifdef WITH_TRACE_PROBES + trace_event_poll_purge_timeout(eventLoop.timeouts[i].timer); +#endif if (eventLoop.timeouts[i].ff) { virFreeCallback ff = eventLoop.timeouts[i].ff; void *opaque = eventLoop.timeouts[i].opaque; @@ -573,9 +573,9 @@ static void virEventPollCleanupHandles(void) { continue; } - PROBE(EVENT_POLL_PURGE_HANDLE, - "watch=%d", - eventLoop.handles[i].watch); +#ifdef WITH_TRACE_PROBES + trace_event_poll_purge_handle(eventLoop.handles[i].watch); +#endif if (eventLoop.handles[i].ff) { virFreeCallback ff = eventLoop.handles[i].ff; void *opaque = eventLoop.handles[i].opaque; @@ -625,9 +625,9 @@ int virEventPollRunOnce(void) { virMutexUnlock(&eventLoop.lock); retry: - PROBE(EVENT_POLL_RUN, - "nhandles=%d timeout=%d", - nfds, timeout); +#ifdef WITH_TRACE_PROBES + trace_event_poll_run(nfds, timeout); +#endif ret = poll(fds, nfds, timeout); if (ret < 0) { EVENT_DEBUG("Poll got error event %d", errno); diff --git a/src/util/virobject.c b/src/util/virobject.c index 4f83bc1..349bd6a 100644 --- a/src/util/virobject.c +++ b/src/util/virobject.c @@ -196,7 +196,9 @@ void *virObjectNew(virClassPtr klass) obj->klass = klass; virAtomicIntSet(&obj->u.s.refs, 1); - PROBE(OBJECT_NEW, "obj=%p classname=%s", obj, obj->klass->name); +#ifdef WITH_TRACE_PROBES + trace_object_new( obj, obj->klass->name); +#endif return obj; } @@ -253,9 +255,13 @@ bool virObjectUnref(void *anyobj) return false; bool lastRef = virAtomicIntDecAndTest(&obj->u.s.refs); - PROBE(OBJECT_UNREF, "obj=%p", obj); +#ifdef WITH_TRACE_PROBES + trace_object_unref(obj); +#endif if (lastRef) { - PROBE(OBJECT_DISPOSE, "obj=%p", obj); +#ifdef WITH_TRACE_PROBES + trace_object_dispose(obj); +#endif virClassPtr klass = obj->klass; while (klass) { if (klass->dispose) @@ -290,7 +296,9 @@ void *virObjectRef(void *anyobj) if (!obj) return NULL; virAtomicIntInc(&obj->u.s.refs); - PROBE(OBJECT_REF, "obj=%p", obj); +#ifdef WITH_TRACE_PROBES + trace_object_ref(obj); +#endif return anyobj; } -- 1.8.3.1

From: Xinghai Yu <yuxinghai@cn.fujitsu.com> This 'tracetool' is used for converting the tracepoint format file to all other files we need to supporting dtrace, ftrace or them together. Signed-off-by: Yang Zhiyong <yangzy.fnst@cn.fujitsu.com> Signed-off-by: Xinghai Yu <yuxinghai@cn.fujitsu.com> Cc: Stefan Hajnoczi <stefanha@redhat.com> --- src/tracetool.py | 103 +++++++++++++++ src/tracetool/__init__.py | 268 ++++++++++++++++++++++++++++++++++++++ src/tracetool/backend/__init__.py | 120 +++++++++++++++++ src/tracetool/backend/trace.py | 112 ++++++++++++++++ src/tracetool/format/__init__.py | 103 +++++++++++++++ src/tracetool/format/c.py | 22 ++++ src/tracetool/format/d.py | 20 +++ src/tracetool/format/h.py | 22 ++++ 8 files changed, 770 insertions(+) create mode 100644 src/tracetool.py create mode 100644 src/tracetool/__init__.py create mode 100644 src/tracetool/backend/__init__.py create mode 100644 src/tracetool/backend/trace.py create mode 100644 src/tracetool/format/__init__.py create mode 100644 src/tracetool/format/c.py create mode 100644 src/tracetool/format/d.py create mode 100644 src/tracetool/format/h.py diff --git a/src/tracetool.py b/src/tracetool.py new file mode 100644 index 0000000..b8cdede --- /dev/null +++ b/src/tracetool.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Command-line wrapper for the tracetool machinery. +""" + +__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Stefan Hajnoczi" +__email__ = "stefanha@linux.vnet.ibm.com" + + +import sys +import getopt + +from tracetool import error_write, out +import tracetool.backend +import tracetool.format + + +_SCRIPT = "" + +def error_opt(msg = None): + if msg is not None: + error_write("Error: " + msg + "\n") + + backend_descr = "\n".join([ " %-15s %s" % (n, d) + for n,d in tracetool.backend.get_list() ]) + format_descr = "\n".join([ " %-15s %s" % (n, d) + for n,d in tracetool.format.get_list() ]) + error_write("""\ +Usage: %(script)s --format=<format> --backend=<backend> + +Backends: +%(backends)s + +Formats: +%(formats)s + +Options: + --help This help message. + --format Available values are ftrace,dtrace or dtrace_ftrace. + --backend Available values are c,h or d. \ +""" % { + "script" : _SCRIPT, + "backends" : backend_descr, + "formats" : format_descr, + }) + + if msg is None: + sys.exit(0) + else: + sys.exit(1) + + +def main(args): + global _SCRIPT + _SCRIPT = args[0] + + long_opts = [ "backend=", "format=", "help" ] + + try: + opts, args = getopt.getopt(args[1:], "", long_opts) + except getopt.GetoptError, err: + error_opt(str(err)) + + check_backend = False + arg_backend = "" + arg_format = "" + for opt, arg in opts: + if opt == "--help": + error_opt() + + elif opt == "--backend": + arg_backend = arg + elif opt == "--format": + arg_format = arg + elif opt == "--check-backend": + check_backend = True + + else: + error_opt("unhandled option: %s" % opt) + + if arg_backend is None: + error_opt("backend not set") + + if check_backend: + if tracetool.backend.exists(arg_backend): + sys.exit(0) + else: + sys.exit(1) + + + try: + tracetool.generate(sys.stdin, arg_format, arg_backend) + except tracetool.TracetoolError, e: + error_opt(str(e)) + +if __name__ == "__main__": + main(sys.argv) diff --git a/src/tracetool/__init__.py b/src/tracetool/__init__.py new file mode 100644 index 0000000..5e9a951 --- /dev/null +++ b/src/tracetool/__init__.py @@ -0,0 +1,268 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Machinery for generating tracing-related intermediate files. +""" + +__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Stefan Hajnoczi" +__email__ = "stefanha@linux.vnet.ibm.com" + + +import re +import sys + +import tracetool.format +import tracetool.backend + + +def error_write(*lines): + """Write a set of error lines.""" + sys.stderr.writelines("\n".join(lines) + "\n") + +def error(*lines): + """Write a set of error lines and exit.""" + error_write(*lines) + sys.exit(1) + + +def out(*lines, **kwargs): + """Write a set of output lines. + + You can use kwargs as a shorthand for mapping variables when formating all + the strings in lines. + """ + lines = [ l % kwargs for l in lines ] + sys.stdout.writelines("\n".join(lines) + "\n") + + +class Arguments: + """Event arguments description.""" + + def __init__(self, args): + """ + Parameters + ---------- + args : + List of (type, name) tuples. + """ + self._args = args + + @staticmethod + def build(arg_str): + """Build and Arguments instance from an argument string. + + Parameters + ---------- + arg_str : str + String describing the event arguments. + """ + res = [] + for arg in arg_str.split(","): + arg = arg.strip() + if arg == 'void': + continue + + if '*' in arg: + arg_type, identifier = arg.rsplit('*', 1) + arg_type += '*' + identifier = identifier.strip() + else: + arg_type, identifier = arg.rsplit(None, 1) + + res.append((arg_type, identifier)) + return Arguments(res) + + def __iter__(self): + """Iterate over the (type, name) pairs.""" + return iter(self._args) + + def __len__(self): + """Number of arguments.""" + return len(self._args) + + def __str__(self): + """String suitable for declaring function arguments.""" + if len(self._args) == 0: + return "void" + else: + return ", ".join([ " ".join([t, n]) for t,n in self._args ]) + + def __repr__(self): + """Evaluable string representation for this object.""" + return "Arguments(\"%s\")" % str(self) + + def names(self): + """List of argument names.""" + return [ name for _, name in self._args ] + + def types(self): + """List of argument types.""" + return [ type_ for type_, _ in self._args ] + + +class Event(object): + """Event description. + + Attributes + ---------- + name : str + The event name. + fmt : str + The event format string. + properties : set(str) + Properties of the event. + args : Arguments + The event arguments. + """ + + _CRE = re.compile("((?P<props>.*)\s+)?(?P<name>[^(\s]+)\((?P<args>[^)]*)\)\s*(?P<fmt>\".*)?") + + _VALID_PROPS = set(["disable"]) + + def __init__(self, name="", props="", fmt="", args="", isTitle = False): + """ + Parameters + ---------- + name : string + Event name. + props : list of str + Property names. + fmt : str + Event printing format. + args : Arguments + Event arguments. + """ + self.name = name + self.properties = props + self.fmt = fmt + self.args = args + self.isTitle = isTitle + + unknown_props = set(self.properties) - self._VALID_PROPS + if len(unknown_props) > 0: + raise ValueError("Unknown properties: %s" % ", ".join(unknown_props)) + + @staticmethod + def build(line_str): + """Build an Event instance from a string. + + Parameters + ---------- + line_str : str + Line describing the event. + """ + m = Event._CRE.match(line_str) + assert m is not None + groups = m.groupdict('') + + name = groups["name"] + props = groups["props"].split() + fmt = groups["fmt"] + args = Arguments.build(groups["args"]) + + return Event(name, props, fmt, args) + @staticmethod + def buildTitle(line_str): + return Event(name = line_str.rstrip("\n"), isTitle = True) + + def __repr__(self): + """Evaluable string representation for this object.""" + return "Event('%s %s(%s) %s')" % (" ".join(self.properties), + self.name, + self.args, + self.fmt) + +def _read_events(fobj): + res = [] + for line in fobj: + if not line.strip(): + continue + if line.lstrip().startswith('#'): + res.append(Event.buildTitle(line)) + continue + res.append(Event.build(line)) + return res + + +class TracetoolError (Exception): + """Exception for calls to generate.""" + pass + + +def try_import(mod_name, attr_name = None, attr_default = None): + """Try to import a module and get an attribute from it. + + Parameters + ---------- + mod_name : str + Module name. + attr_name : str, optional + Name of an attribute in the module. + attr_default : optional + Default value if the attribute does not exist in the module. + + Returns + ------- + A pair indicating whether the module could be imported and the module or + object or attribute value. + """ + try: + module = __import__(mod_name, globals(), locals(), ["__package__"]) + if attr_name is None: + return True, module + return True, getattr(module, str(attr_name), attr_default) + except ImportError: + return False, None + + +def generate(fevents, format, backend): + """Generate the output for the given (format, backend) pair. + + Parameters + ---------- + fevents : file + Event description file. + format : str + Output format name. + backend : str + Output backend name. + binary : str or None + See tracetool.backend.dtrace.BINARY. + probe_prefix : str or None + See tracetool.backend.dtrace.PROBEPREFIX. + """ + # fix strange python error (UnboundLocalError tracetool) + import tracetool + + format = str(format) + if len(format) is 0: + raise TracetoolError("format not set") + mformat = format.replace("-", "_") + if not tracetool.format.exists(mformat): + raise TracetoolError("unknown format: %s" % format) + + backend = str(backend) + if len(backend) is 0: + raise TracetoolError("backend not set") + mbackend = backend.replace("-", "_") + if not tracetool.backend.exists(mbackend): + raise TracetoolError("unknown backend: %s" % backend) + + if not tracetool.backend.compatible(mbackend, mformat): + raise TracetoolError("backend '%s' not compatible with format '%s'" % + (backend, format)) + + + events = _read_events(fevents) + + tracetool.format.generate_begin(mformat, events) + tracetool.backend.generate(backend, format, + [ e + for e in events + if "disable" not in e.properties ]) + tracetool.format.generate_end(mformat, events) diff --git a/src/tracetool/backend/__init__.py b/src/tracetool/backend/__init__.py new file mode 100644 index 0000000..e4f5247 --- /dev/null +++ b/src/tracetool/backend/__init__.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Backend management. + + +Creating new backends +--------------------- + +A new backend named 'foo-bar' corresponds to Python module +'tracetool/backend/foo_bar.py'. + +A backend module should provide a docstring, whose first non-empty line will be +considered its short description. + +All backends must generate their contents through the 'tracetool.out' routine. + + +Backend attributes +------------------ + +========= ==================================================================== +Attribute Description +========= ==================================================================== +PUBLIC If exists and is set to 'True', the backend is considered "public". +========= ==================================================================== + + +Backend functions +----------------- + +======== ======================================================================= +Function Description +======== ======================================================================= +<format> Called to generate the format- and backend-specific code for each of + the specified events. If the function does not exist, the backend is + considered not compatible with the given format. +======== ======================================================================= +""" + +__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Stefan Hajnoczi" +__email__ = "stefanha@linux.vnet.ibm.com" + + +import os + +import tracetool + + +def get_list(only_public = False): + """Get a list of (name, description) pairs.""" + res = [] + modnames = [] + for filename in os.listdir(tracetool.backend.__path__[0]): + if filename.endswith('.py') and filename != '__init__.py': + modnames.append(filename.rsplit('.', 1)[0]) + for modname in modnames: + module = tracetool.try_import("tracetool.backend." + modname) + + # just in case; should never fail unless non-module files are put there + if not module[0]: + continue + module = module[1] + + public = getattr(module, "PUBLIC", False) + if only_public and not public: + continue + + doc = module.__doc__ + if doc is None: + doc = "" + doc = doc.strip().split("\n")[0] + + name = modname.replace("_", "-") + res.append((name, doc)) + return res + + +def exists(name): + """Return whether the given backend exists.""" + if len(name) == 0: + return False + name = name.replace("-", "_") + return tracetool.try_import("tracetool.backend." + name)[1] + + +def compatible(backend, format): + """Whether a backend is compatible with the given format.""" + if not exists(backend): + raise ValueError("unknown backend: %s" % backend) + + backend = backend.replace("-", "_") + format = format.replace("-", "_") + + func = tracetool.try_import("tracetool.backend." + backend, + format, None)[1] + return func is not None + + +def _empty(events): + pass + +def generate(backend, format, events): + """Generate the per-event output for the given (backend, format) pair.""" + if not compatible(backend, format): + raise ValueError("backend '%s' not compatible with format '%s'" % + (backend, format)) + + backend = backend.replace("-", "_") + format = format.replace("-", "_") + + func = tracetool.try_import("tracetool.backend." + backend, + format, None)[1] + + func(events) diff --git a/src/tracetool/backend/trace.py b/src/tracetool/backend/trace.py new file mode 100644 index 0000000..d6b4322 --- /dev/null +++ b/src/tracetool/backend/trace.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +ALL_trace built-in backend. +""" + +__author__ = "Eiichi Tsukata <eiichi.tsukata.xh@hitachi.com>" +__copyright__ = "Copyright (C) 2013 Hitachi, Ltd." +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Stefan Hajnoczi" +__email__ = "stefanha@redhat.com" + + +from tracetool import out + + +PUBLIC = True + + +def c(events): + out('#include <config.h>', + '#include <stdio.h>', + '', + '#ifdef WITH_QEMU', + '#include "libvirt_probes.h"', + '#include "libvirt_qemu_probes.h"', + '#else', + '#include "libvirt_probes.h"', + '#endif', + '', + '#ifdef WITH_FTRACE_PROBES', + '#include <sys/param.h>', + '#include "ftrace.h"', + '#endif', + '', + '#ifdef WITH_DTRACE_PROBES', + '#include "libvirt_probes_dtrace.h"', + '#include "libvirt_qemu_probes_dtrace.h"', + '#endif', + '') + + for e in events: + if e.isTitle: + continue + argnames_f = ", ".join(e.args.names()) + if len(e.args) > 0: + argnames_f= ", " + argnames_f + + out('void trace_%(name)s(%(args)s) {', + '#ifdef WITH_FTRACE_PROBES', + ' char ftrace_buf[MAX_TRACE_STRLEN];', + ' int unused __attribute__ ((unused));', + ' int trlen;', + ' trlen = snprintf(ftrace_buf, MAX_TRACE_STRLEN,', + ' "%(name)s " %(fmt)s "\\n" %(argnames_f)s);', + ' trlen = MIN(trlen, MAX_TRACE_STRLEN - 1);', + ' unused = write(trace_marker_fd, ftrace_buf, trlen);', + '#endif', + '', + '#ifdef WITH_DTRACE_PROBES', + ' LIBVIRT_%(uppername)s(%(argnames_d)s);', + '#endif', + '}', + '', + name = e.name, + args = e.args, + event_id = "TRACE_" + e.name.upper(), + fmt = e.fmt.rstrip("\n"), + argnames_f = argnames_f, + argnames_d = ", ".join(e.args.names()), + uppername = e.name.upper(), + ) +def h(events): + for e in events: + if e.isTitle: + continue + argnames_f = ", ".join(e.args.names()) + if len(e.args) > 0: + argnames_f= ", " + argnames_f + + out('extern void trace_%(name)s(%(args)s);', + '', + name = e.name, + args = e.args, + ) +def d(events): + out('provider libvirt {') + + for e in events: + if e.isTitle: + out(' %(title)s', + title = e.name + ) + continue + args = str(e.args) + + # DTrace provider syntax expects foo() for empty + # params, not foo(void) + if args == 'void': + args = '' + + # Define prototype for probe arguments + out(' probe %(name)s(%(args)s);', + name = e.name, + args = args, + ) + + out('', + '};') + diff --git a/src/tracetool/format/__init__.py b/src/tracetool/format/__init__.py new file mode 100644 index 0000000..3c2a0d8 --- /dev/null +++ b/src/tracetool/format/__init__.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Format management. + + +Creating new formats +-------------------- + +A new format named 'foo-bar' corresponds to Python module +'tracetool/format/foo_bar.py'. + +A format module should provide a docstring, whose first non-empty line will be +considered its short description. + +All formats must generate their contents through the 'tracetool.out' routine. + + +Format functions +---------------- + +All the following functions are optional, and no output will be generated if +they do not exist. + +======== ======================================================================= +Function Description +======== ======================================================================= +begin Called to generate the format-specific file header. +end Called to generate the format-specific file footer. +nop Called to generate the per-event contents when the event is disabled or + the selected backend is 'nop'. +======== ======================================================================= +""" + +__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Stefan Hajnoczi" +__email__ = "stefanha@linux.vnet.ibm.com" + + +import os + +import tracetool + + +def get_list(): + """Get a list of (name, description) pairs.""" + res = [] + modnames = [] + for filename in os.listdir(tracetool.format.__path__[0]): + if filename.endswith('.py') and filename != '__init__.py': + modnames.append(filename.rsplit('.', 1)[0]) + for modname in modnames: + module = tracetool.try_import("tracetool.format." + modname) + + # just in case; should never fail unless non-module files are put there + if not module[0]: + continue + module = module[1] + + doc = module.__doc__ + if doc is None: + doc = "" + doc = doc.strip().split("\n")[0] + + name = modname.replace("_", "-") + res.append((name, doc)) + return res + + +def exists(name): + """Return whether the given format exists.""" + if len(name) == 0: + return False + name = name.replace("-", "_") + return tracetool.try_import("tracetool.format." + name)[1] + + +def _empty(events): + pass + +def generate_begin(name, events): + """Generate the header of the format-specific file.""" + if not exists(name): + raise ValueError("unknown format: %s" % name) + + name = name.replace("-", "_") + func = tracetool.try_import("tracetool.format." + name, + "begin", _empty)[1] + func(events) + +def generate_end(name, events): + """Generate the footer of the format-specific file.""" + if not exists(name): + raise ValueError("unknown format: %s" % name) + + name = name.replace("-", "_") + func = tracetool.try_import("tracetool.format." + name, + "end", _empty)[1] + func(events) diff --git a/src/tracetool/format/c.py b/src/tracetool/format/c.py new file mode 100644 index 0000000..57032db --- /dev/null +++ b/src/tracetool/format/c.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Generate .c file. +""" + +__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Stefan Hajnoczi" +__email__ = "stefanha@linux.vnet.ibm.com" + + +from tracetool import out + + +def begin(events): + pass +def end(events): + pass diff --git a/src/tracetool/format/d.py b/src/tracetool/format/d.py new file mode 100644 index 0000000..c762961 --- /dev/null +++ b/src/tracetool/format/d.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Generate .d file (DTrace only). +""" + +__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Stefan Hajnoczi" +__email__ = "stefanha@linux.vnet.ibm.com" + + +from tracetool import out + + +def begin(events): + pass diff --git a/src/tracetool/format/h.py b/src/tracetool/format/h.py new file mode 100644 index 0000000..8603a33 --- /dev/null +++ b/src/tracetool/format/h.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Generate .h file. +""" + +__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>" +__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>" +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Stefan Hajnoczi" +__email__ = "stefanha@linux.vnet.ibm.com" + + +from tracetool import out + + +def begin(events): + pass +def end(events): + pass -- 1.8.3.1

From: Xinghai Yu <yuxinghai@cn.fujitsu.com> Define new 'WITH_TRACE_PROBES' macros which indicate the trace function are available and this macro will be used in Makefile.am and source codes. Signed-off-by: Xinghai Yu <yuxinghai@cn.fujitsu.com> --- config-post.h | 2 +- configure.ac | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/config-post.h b/config-post.h index 8367200..e2d45ef 100644 --- a/config-post.h +++ b/config-post.h @@ -32,7 +32,7 @@ # undef HAVE_LIBSASL2 # undef WITH_CAPNG # undef WITH_CURL -# undef WITH_DTRACE_PROBES +# undef WITH_TRACE_PROBES # undef WITH_GNUTLS # undef WITH_GNUTLS_GCRYPT # undef WITH_MACVTAP diff --git a/configure.ac b/configure.ac index a9339ce..63744ee 100644 --- a/configure.ac +++ b/configure.ac @@ -1500,6 +1500,10 @@ if test "$with_dtrace" != "no" ; then fi AM_CONDITIONAL([WITH_DTRACE_PROBES], [test "$with_dtrace" != "no"]) +if test "$with_dtrace" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_TRACE_PROBES], 1, [whether Trace function are available]) +fi +AM_CONDITIONAL([WITH_TRACE_PROBES], [test "$with_dtrace" != "no"]) dnl numad AC_ARG_WITH([numad], -- 1.8.3.1

From: Xinghai Yu <yuxinghai@cn.fujitsu.com> In order to support multiple trace backend, we have to quit the existing dtrace points definition files for they are only used by dtrace and their format are not easy to use for supporting multiple trace backend. The new tracepoint format files can generate the dtrace format files to support dtrace backend and also generate the ftrace format files to support ftrace backend. Signed-off-by: Xinghai Yu <yuxinghai@cn.fujitsu.com> --- src/libvirt_probes.d | 82 ------------------------------------------- src/libvirt_qemu_probes.d | 22 ------------ src/libvirt_qemu_trace_events | 15 ++++++++ src/libvirt_trace_events | 70 ++++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 104 deletions(-) delete mode 100644 src/libvirt_probes.d delete mode 100644 src/libvirt_qemu_probes.d create mode 100644 src/libvirt_qemu_trace_events create mode 100644 src/libvirt_trace_events diff --git a/src/libvirt_probes.d b/src/libvirt_probes.d deleted file mode 100644 index 340d665..0000000 --- a/src/libvirt_probes.d +++ /dev/null @@ -1,82 +0,0 @@ -provider libvirt { - # file: src/util/event_poll.c - # prefix: event_poll - probe event_poll_add_handle(int watch, int fd, int events, void *cb, void *opaque, void *ff); - probe event_poll_update_handle(int watch, int events); - probe event_poll_remove_handle(int watch); - probe event_poll_dispatch_handle(int watch, int events); - probe event_poll_purge_handle(int watch); - - probe event_poll_add_timeout(int timer, int frequency, void *cb, void *opaque, void *ff); - probe event_poll_update_timeout(int timer, int frequency); - probe event_poll_remove_timeout(int timer); - probe event_poll_dispatch_timeout(int timer); - probe event_poll_purge_timeout(int timer); - - probe event_poll_run(int nfds, int timeout); - - - # file: src/util/virobject.c - # prefix: object - probe object_new(void *obj, const char *klassname); - probe object_ref(void *obj); - probe object_unref(void *obj); - probe object_dispose(void *obj); - - # file: src/rpc/virnetsocket.c - # prefix: rpc - probe rpc_socket_new(void *sock, int fd, int errfd, pid_t pid, const char *localAddr, const char *remoteAddr); - probe rpc_socket_dispose(void *sock); - probe rpc_socket_send_fd(void *sock, int fd); - probe rpc_socket_recv_fd(void *sock, int fd); - - - # file: src/rpc/virnetserverclient.c - # prefix: rpc - probe rpc_server_client_new(void *client, void *sock); - probe rpc_server_client_dispose(void *client); - probe rpc_server_client_msg_tx_queue(void *client, int len, int prog, int vers, int proc, int type, int status, int serial); - probe rpc_server_client_msg_rx(void *client, int len, int prog, int vers, int proc, int type, int status, int serial); - - - # file: src/rpc/virnetclient.c - # prefix: rpc - probe rpc_client_new(void *client, void *sock); - probe rpc_client_dispose(void *client); - probe rpc_client_msg_tx_queue(void *client, int len, int prog, int vers, int proc, int type, int status, int serial); - probe rpc_client_msg_rx(void *client, int len, int prog, int vers, int proc, int type, int status, int serial); - - - # file: daemon/libvirtd.c - # prefix: rpc - probe rpc_server_client_auth_allow(void *client, int authtype, const char *identity); - probe rpc_server_client_auth_deny(void *client, int authtype, const char *identity); - probe rpc_server_client_auth_fail(void *client, int authtype); - - - # file: src/rpc/virnettlscontext.c - # prefix: rpc - probe rpc_tls_context_new(void *ctxt, const char *cacert, const char *cacrl, - const char *cert, const char *key, int sanityCheckCert, int requireValidCert, int isServer); - probe rpc_tls_context_dispose(void *ctxt); - probe rpc_tls_context_session_allow(void *ctxt, void *sess, const char *dname); - probe rpc_tls_context_session_deny(void *ctxt, void *sess, const char *dname); - probe rpc_tls_context_session_fail(void *ctxt, void *sess); - - - probe rpc_tls_session_new(void *sess, void *ctxt, const char *hostname, int isServer); - probe rpc_tls_session_dispose(void *sess); - probe rpc_tls_session_handshake_pass(void *sess); - probe rpc_tls_session_handshake_fail(void *sess); - - - # file: src/rpc/virkeepalive.c - # prefix: rpc - probe rpc_keepalive_new(void *ka, void *client); - probe rpc_keepalive_dispose(void *ka); - probe rpc_keepalive_start(void *ka, void *client, int interval, int count); - probe rpc_keepalive_stop(void *ka, void *client); - probe rpc_keepalive_send(void *ka, void *client, int prog, int vers, int proc); - probe rpc_keepalive_received(void *ka, void *client, int prog, int vers, int proc); - probe rpc_keepalive_timeout(void *ka, void *client, int coundToDeath, int idle); -}; diff --git a/src/libvirt_qemu_probes.d b/src/libvirt_qemu_probes.d deleted file mode 100644 index e4449a9..0000000 --- a/src/libvirt_qemu_probes.d +++ /dev/null @@ -1,22 +0,0 @@ -provider libvirt { - # file: src/qemu/qemu_monitor.c - # prefix: qemu - # binary: libvirtd - # module: libvirt/connection-driver/libvirt_driver_qemu.so - # Monitor lifecycle - probe qemu_monitor_new(void *mon, int refs, int fd); - probe qemu_monitor_ref(void *mon, int refs); - probe qemu_monitor_unref(void *mon, int refs); - probe qemu_monitor_close(void *monm, int refs); - - # High level monitor message processing - probe qemu_monitor_send_msg(void *mon, const char *msg, int fd); - probe qemu_monitor_recv_reply(void *mon, const char *reply); - probe qemu_monitor_recv_event(void *mon, const char *event); - - # Low level monitor I/O processing - probe qemu_monitor_io_process(void *mon, const char *buf, unsigned int len); - probe qemu_monitor_io_read(void *mon, const char *buf, unsigned int len, int ret, int errno); - probe qemu_monitor_io_write(void *mon, const char *buf, unsigned int len, int ret, int errno); - probe qemu_monitor_io_send_fd(void *mon, int fd, int ret, int errno); -}; diff --git a/src/libvirt_qemu_trace_events b/src/libvirt_qemu_trace_events new file mode 100644 index 0000000..f6c3fd2 --- /dev/null +++ b/src/libvirt_qemu_trace_events @@ -0,0 +1,15 @@ +# file: src/qemu/qemu_monitor.c +# prefix: qemu +# binary: libvirtd +# module: libvirt/connection-driver/libvirt_driver_qemu.so +# Monitor lifecycle +qemu_monitor_new(void *mon, int refs, int fd) "mon=%p refs=%d fd=%d" +qemu_monitor_close(void *mon, int refs) "mon=%p refs=%d" +qemu_monitor_send_msg(void *mon, char *msg, int fd) "mon=%p msg=%s fd=%d" + +qemu_monitor_io_process(void *mon, char *buf, size_t len ) "mon=%p buf=%s len=%zu" +qemu_monitor_io_write(void *mon, char *buf, int len, int ret, int err) "mon=%p buf=%s len=%d ret=%d errno=%d" +qemu_monitor_io_send_fd(void *mon, int fd, int ret, int err) "mon=%p fd=%d ret=%d errno=%d" + +qemu_monitor_recv_event(void *mon, const char *line) "mon=%p event=%s" +qemu_monitor_recv_reply(void *mon, const char *line) "mon=%p reply=%s" diff --git a/src/libvirt_trace_events b/src/libvirt_trace_events new file mode 100644 index 0000000..5b11e62 --- /dev/null +++ b/src/libvirt_trace_events @@ -0,0 +1,70 @@ +# file: src/util/vireventpoll.c +# prefix: event_poll +event_poll_add_handle(int watch, int fd, int events, void * cb, void *opaque, void *ff) "watch=%d fd=%d events=%d cb=%p opaque=%p ff=%p" +event_poll_update_handle( int watch, int events) "watch=%d events=%d" +event_poll_remove_handle(int watch) "watch=%d" +event_poll_dispatch_handle( int watch, int Events) "watch=%d events=%d" +event_poll_purge_handle(int watch) "watch=%d" + +event_poll_add_timeout(int ret, int frequency, void *cb, void *opaque, void *ff) "timer=%d frequency=%d cb=%p opaque=%p ff=%p" +event_poll_update_timeout(int timer, int frequency) "timer=%d frequency=%d" +event_poll_remove_timeout(int timer) "timer=%d" +event_poll_dispatch_timeout(int timer) "timer=%d" +event_poll_purge_timeout(int timer) "timer=%d" + +event_poll_run(int nfds, int timeout) "nhandles=%d timeout=%d" + +# file: src/util/virobject.c +# prefix: object +object_new( void *obj, const char *classname) "obj=%p classname=%s" +object_ref(void *obj) "obj=%p" +object_unref(void *obj) "obj=%p" +object_dispose(void *obj) "obj=%p" + +# file: src/rpc/virnetsocket.c +# prefix: rpc +rpc_socket_new(void *sock, int fd, int errfd, long long pid, const char *localAddr, const char *remoteAddr ) "sock=%p fd=%d errfd=%d pid=%lld localAddr=%s, remoteAddr=%s" +rpc_socket_dispose(void *sock) "sock=%p" +rpc_socket_send_fd(void *sock, int fd) "sock=%p fd=%d" +rpc_socket_recv_fd(void *sock, int fd) "sock=%p fd=%d" + +# file: src/rpc/virnetserverclient.c +# prefix: rpc +rpc_server_client_new(void *client, void *sock) "client=%p sock=%p" +rpc_server_client_dispose(void *client) "client=%p" +rpc_server_client_msg_tx_queue(void *client, size_t len, unsigned int prog, unsigned int vers, unsigned int proc, unsigned int type, unsigned int status, unsigned int serial )"client=%p len=%zu prog=%u vers=%u proc=%u type=%u status=%u serial=%u" +rpc_server_client_msg_rx(void *client, size_t len, unsigned int prog, unsigned int vers, unsigned int proc, unsigned int type, unsigned int status, unsigned int serial ) "client=%p len=%zu prog=%u vers=%u proc=%u type=%u status=%u serial=%u" + +# file: src/rpc/virnetclient.c +# prefix: rpc +rpc_client_new(void *client, void *sock) "client=%p sock=%p" +rpc_client_dispose(void *client) "client=%p" +rpc_client_msg_tx_queue(void *client, size_t len, unsigned int prog, unsigned int vers, unsigned int proc, unsigned int type, unsigned int status, unsigned int serial ) "client=%p len=%zu prog=%u vers=%u proc=%u type=%u status=%u serial=%u" +rpc_client_msg_rx(void *client, size_t len, unsigned int prog, unsigned int vers, unsigned int proc, unsigned int type, unsigned int status, unsigned int serial) "client=%p len=%zu prog=%u vers=%u proc=%u type=%u status=%u serial=%u" + +# file: daemon/libvirtd.c +# prefix: rpc +rpc_server_client_auth_allow(void *client, int auth, const char *identity) "client=%p auth=%d identity=%s" +rpc_server_client_auth_deny(void *client, int auth, const char *identity) "client=%p auth=%d identity=%s" +rpc_server_client_auth_fail(void *client, int auth) "client=%p auth=%d" + +# file: src/rpc/virnettlscontext.c +# prefix: rpc +rpc_tls_context_new(void *ctxt, const char *cacert, const char *cacrl, const char *cert, const char *key, int sanityCheckCert, int requireValidCert, int isServer ) "ctxt=%p cacert=%s cacrl=%s cert=%s key=%s sanityCheckCert=%d requireValidCert=%d isServer=%d" +rpc_tls_context_dispose(void *ctxt) "ctxt=%p" +rpc_tls_context_session_allow(void *ctxt, void *sess, const char *dname) "ctxt=%p sess=%p dname=%s" +rpc_tls_context_session_deny(void *ctxt, void *sess, const char *dname) "ctxt=%p sess=%p dname=%s" +rpc_tls_context_session_fail(void *ctxt, void *sess) "ctxt=%p sess=%p" + +rpc_tls_session_new(void *ctxt, void *sess, const char *hostname, int isServer) "sess=%p ctxt=%p hostname=%s isServer=%d" +rpc_tls_session_dispose(void *sess) "sess=%p" + +# file: src/rpc/virkeepalive.c +# prefix: rpc +rpc_keepalive_new(void *ka, void *client) "ka=%p client=%p" +rpc_keepalive_dispose(void *ka) "ka=%p" +rpc_keepalive_start(void *ka, void *client, int interval, unsigned int count) "ka=%p client=%p interval=%d count=%u" +rpc_keepalive_stop(void *ka, void *client) "ka=%p client=%p" +rpc_keepalive_send(void *ka, void *client, int prog, int vers, int proc ) "ka=%p client=%p prog=%d vers=%d proc=%d" +rpc_keepalive_received(void *ka, void *client, int prog, int vers, int proc) "ka=%p client=%p prog=%d vers=%d proc=%d" +rpc_keepalive_timeout(void *ka, void *client, int countToDeath, int idle) "ka=%p client=%p countToDeath=%d idle=%d" -- 1.8.3.1

From: Xinghai Yu <yuxinghai@cn.fujitsu.com> Using the macro exported by configure.ac to decide which trace backend to build for libvirt. We got 3 trace macros now: WITH_TRACE_PROBES, if --with-ftrace or --with-dtrace option was set, this macro would be true and it tell the codes that we will use trace function, dtrace or ftrace will be supported in libvirt. WITH_DTRACE_PROBES, if --with-dtrace was set this macro would be true and the ftrace will be supported in libvirt. The ftrace backend code turn on the tracing function of deugfs and store fd of the ftrace buffer '/sys/kernel/debug/tracing/trace_marker'. Then let the 'trace_backend_init()' function be called in the initial process of other programs so that the trace info of them can be transfered to the ftrace's buffer. The user can get trace info in interface '/sys/kernel/debug/tracing/trace'. Signed-off-by: Xinghai Yu <yuxinghai@cn.fujitsu.com> Cc: Eiichi Tsukata <eiichi.tsukata.xh@hitachi.com> --- configure.ac | 24 ++++++++++++-- daemon/Makefile.am | 3 ++ src/Makefile.am | 66 ++++++++++++++++++++++++++++++--------- src/ftrace.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ftrace.h | 14 +++++++++ tests/Makefile.am | 3 ++ tools/virsh.c | 3 ++ 7 files changed, 188 insertions(+), 16 deletions(-) create mode 100644 src/ftrace.c create mode 100644 src/ftrace.h diff --git a/configure.ac b/configure.ac index 63744ee..6f0992f 100644 --- a/configure.ac +++ b/configure.ac @@ -1476,6 +1476,25 @@ if test "$with_apparmor" = "no"; then fi AM_CONDITIONAL([WITH_APPARMOR_PROFILES], [test "$with_apparmor_profiles" != "no"]) +dnl FTrace trace +AC_ARG_WITH([ftrace], + [AS_HELP_STRING([--with-ftrace], + [use ftrace for tracing @<:@default=check@:>@])], + [], + [with_ftrace=check]) + +if test "$with_ftrace" != "no" ; then + if test "$with_linux" = "yes"; then + with_ftrace=yes + else + with_ftrace=no + fi + if test "$with_ftrace" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_FTRACE_PROBES], 1, [whether FTrace are available]) + fi +fi +AM_CONDITIONAL([WITH_FTRACE_PROBES], [test "$with_ftrace" != "no"]) + dnl DTrace static probes AC_ARG_WITH([dtrace], [AS_HELP_STRING([--with-dtrace], @@ -1500,10 +1519,10 @@ if test "$with_dtrace" != "no" ; then fi AM_CONDITIONAL([WITH_DTRACE_PROBES], [test "$with_dtrace" != "no"]) -if test "$with_dtrace" = "yes"; then +if test "$with_dtrace" = "yes" || test "$with_ftrace" = "yes"; then AC_DEFINE_UNQUOTED([WITH_TRACE_PROBES], 1, [whether Trace function are available]) fi -AM_CONDITIONAL([WITH_TRACE_PROBES], [test "$with_dtrace" != "no"]) +AM_CONDITIONAL([WITH_TRACE_PROBES], [test "$with_dtrace" != "no" || test "$with_ftrace" != "no"]) dnl numad AC_ARG_WITH([numad], @@ -2856,6 +2875,7 @@ AC_MSG_NOTICE([ Debug: $enable_debug]) AC_MSG_NOTICE([ Use -Werror: $set_werror]) AC_MSG_NOTICE([ Warning Flags: $WARN_CFLAGS]) AC_MSG_NOTICE([ DTrace: $with_dtrace]) +AC_MSG_NOTICE([ FTrace: $with_ftrace]) AC_MSG_NOTICE([ numad: $with_numad]) AC_MSG_NOTICE([ XML Catalog: $XML_CATALOG_FILE]) AC_MSG_NOTICE([ Init script: $with_init_script]) diff --git a/daemon/Makefile.am b/daemon/Makefile.am index bd77623..8637978 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -166,6 +166,9 @@ endif WITH_TRACE_PROBES if WITH_DTRACE_PROBES libvirtd_LDADD += ../src/libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES +if WITH_FTRACE_PROBES +libvirtd_LDADD += ../src/libvirt_ftrace.la +endif WITH_FTRACE_PROBES libvirtd_LDADD += \ libvirtd_conf.la \ diff --git a/src/Makefile.am b/src/Makefile.am index 0e50ebc..6325864 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1979,6 +1979,18 @@ CLEANFILES += libvirt_probes.c libvirt_probes.h libvirt_probes.o libvirt_probes. libvirt_qemu_probes.lo endif +if WITH_FTRACE_PROBES +noinst_LTLIBRARIES += libvirt_ftrace.la +libvirt_la_BUILT_LIBADD += libvirt_ftrace.la +libvirt_ftrace_la_SOURCES = ftrace.c ftrace.h +libvirt_ftrace_la_LDFLAGS = $(AM_LDFLAGS) +libvirt_ftrace_la_CFLAGS = $(AM_CFLAGS) +BUILT_SOURCES += ftrace.c ftrace.h +if WITH_QEMU +libvirt_driver_qemu_impl_la_LIBADD += libvirt_ftrace.la +endif WITH_QEMU +endif WITH_FTRACE_PROBES + if WITH_DTRACE_PROBES libvirt_la_BUILT_LIBADD += libvirt_probes_dtrace.lo libvirt_la_DEPENDENCIES += libvirt_probes_dtrace.o libvirt_probes_dtrace.lo @@ -2171,6 +2183,9 @@ endif WITH_TRACE_PROBES if WITH_DTRACE_PROBES lockd_la_LIBADD += libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES +if WITH_FTRACE_PROBES +lockd_la_LIBADD += libvirt_ftrace.la +endif WITH_FTRACE_PROBES if WITH_QEMU nodist_conf_DATA += locking/qemu-lockd.conf BUILT_SOURCES += locking/qemu-lockd.conf @@ -2203,16 +2218,21 @@ virtlockd_LDFLAGS = \ virtlockd_LDADD = \ libvirt-net-rpc-server.la \ libvirt-net-rpc.la \ - libvirt_util.la \ - ../gnulib/lib/libgnu.la \ - $(CYGWIN_EXTRA_LIBADD) \ - $(NULL) + libvirt_util.la if WITH_TRACE_PROBES virtlockd_LDADD += libvirt_probes.lo endif WITH_TRACE_PROBES if WITH_DTRACE_PROBES virtlockd_LDADD += libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES +if WITH_FTRACE_PROBES +virtlockd_LDADD += libvirt_ftrace.la +endif WITH_FTRACE_PROBES +# Library 'libgnu.la' must be added last, since functions it provides/replaces +# are used by 'libvirt_ftrace.la' library. +virtlockd_LDADD += ../gnulib/lib/libgnu.la \ + $(CYGWIN_EXTRA_LIBADD) \ + $(NULL) else ! WITH_LIBVIRTD EXTRA_DIST += $(LOCK_DAEMON_SOURCES) \ @@ -2489,15 +2509,19 @@ libvirt_iohelper_LDFLAGS = \ $(AM_LDFLAGS) \ $(PIE_LDFLAGS) \ $(NULL) -libvirt_iohelper_LDADD = \ - libvirt_util.la \ - ../gnulib/lib/libgnu.la +libvirt_iohelper_LDADD = libvirt_util.la if WITH_TRACE_PROBES libvirt_iohelper_LDADD += libvirt_probes.lo endif WITH_TRACE_PROBES if WITH_DTRACE_PROBES libvirt_iohelper_LDADD += libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES +if WITH_FTRACE_PROBES +libvirt_iohelper_LDADD += libvirt_ftrace.la +endif WITH_FTRACE_PROBES +# Library 'libgnu.la' must be added last, since functions it provides/replaces +# are used by 'libvirt_ftrace.la' library. +libvirt_iohelper_LDADD += ../gnulib/lib/libgnu.la libvirt_iohelper_CFLAGS = \ $(AM_CFLAGS) \ @@ -2516,14 +2540,19 @@ libvirt_parthelper_LDFLAGS = \ $(NULL) libvirt_parthelper_LDADD = \ $(LIBPARTED_LIBS) \ - libvirt_util.la \ - ../gnulib/lib/libgnu.la + libvirt_util.la if WITH_TRACE_PROBES libvirt_parthelper_LDADD += libvirt_probes.lo endif WITH_TRACE_PROBES if WITH_DTRACE_PROBES libvirt_parthelper_LDADD += libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES +if WITH_FTRACE_PROBES +libvirt_parthelper_LDADD += libvirt_ftrace.la +endif WITH_FTRACE_PROBES +# Library 'libgnu.la' must be added last, since functions it provides/replaces +# are used by 'libvirt_ftrace.la' library. +libvirt_parthelper_LDADD += ../gnulib/lib/libgnu.la libvirt_parthelper_CFLAGS = \ $(LIBPARTED_CFLAGS) \ @@ -2569,15 +2598,19 @@ libvirt_lxc_LDADD = \ libvirt-net-rpc.la \ libvirt_security_manager.la \ libvirt_conf.la \ - libvirt_util.la \ - ../gnulib/lib/libgnu.la + libvirt_util.la if WITH_TRACE_PROBES libvirt_lxc_LDADD += libvirt_probes.lo endif WITH_TRACE_PROBES if WITH_DTRACE_PROBES libvirt_lxc_LDADD += libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES -libvirt_lxc_LDADD += $(SECDRIVER_LIBS) +if WITH_FTRACE_PROBES +libvirt_lxc_LDADD += libvirt_ftrace.la +endif WITH_FTRACE_PROBES +# Library 'libgnu.la' must be added last, since functions it provides/replaces +# are used by 'libvirt_ftrace.la' library. +libvirt_lxc_LDADD += ../gnulib/lib/libgnu.la $(SECDRIVER_LIBS) libvirt_lxc_CFLAGS = \ -I$(top_srcdir)/src/conf \ $(AM_CFLAGS) \ @@ -2607,14 +2640,19 @@ virt_aa_helper_LDFLAGS = \ $(NULL) virt_aa_helper_LDADD = \ libvirt_conf.la \ - libvirt_util.la \ - ../gnulib/lib/libgnu.la + libvirt_util.la if WITH_TRACE_PROBES virt_aa_helper_LDADD += libvirt_probes.lo endif WITH_TRACE_PROBES if WITH_DTRACE_PROBES virt_aa_helper_LDADD += libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES +if WITH_FTRACE_PROBES +virt_aa_helper_LDADD += libvirt_ftrace.la +endif WITH_FTRACE_PROBES +# Library 'libgnu.la' must be added last, since functions it provides/replaces +# are used by 'libvirt_ftrace.la' library. +virt_aa_helper_LDADD += ../gnulib/lib/libgnu.la virt_aa_helper_CFLAGS = \ -I$(top_srcdir)/src/conf \ -I$(top_srcdir)/src/security \ diff --git a/src/ftrace.c b/src/ftrace.c new file mode 100644 index 0000000..a46593f --- /dev/null +++ b/src/ftrace.c @@ -0,0 +1,91 @@ +/* + * Ftrace trace backend + * + * Copyright (C) 2013 Hitachi, Ltd. + * Created by Eiichi Tsukata <eiichi.tsukata.xh@hitachi.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <fcntl.h> +#include <limits.h> +#include <sys/unistd.h> + +#define _STR(x) #x +#define STR(x) _STR(x) + +int trace_marker_fd; +bool trace_backend_init(void); + +static int find_debugfs(char *debugfs) +{ + char type[100]; + FILE *fp; + + fp = fopen("/proc/mounts", "r"); + if (fp == NULL) { + return 0; + } + + while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", + debugfs, type) == 2) { + if (strcmp(type, "debugfs") == 0) { + break; + } + } + fclose(fp); + + if (strcmp(type, "debugfs") != 0) { + return 0; + } + return 1; +} + +bool trace_backend_init(void) +{ + int debugfs_found; + int trace_fd = -1; + bool ret = true; + char *debugfs = malloc(PATH_MAX); + char *path = malloc(PATH_MAX); + + debugfs_found = find_debugfs(debugfs); + if (debugfs_found) { + snprintf(path, PATH_MAX, "%s/tracing/tracing_on", debugfs); + trace_fd = open(path, O_WRONLY); + if (trace_fd < 0) { + perror("Could not open ftrace 'tracing_on' file"); + ret = false; + goto out; + } else { + if (write(trace_fd, "1", 1) < 0) { + perror("Could not write to 'tracing_on' file"); + close(trace_fd); + ret = false; + goto out; + } + close(trace_fd); + } + snprintf(path, PATH_MAX, "%s/tracing/trace_marker", debugfs); + trace_marker_fd = open(path, O_WRONLY); + if (trace_marker_fd < 0) { + perror("Could not open ftrace 'trace_marker' file"); + ret = false; + goto out; + } + } else { + fprintf(stderr, "debugfs is not mounted\n"); + ret = false; + goto out; + } +out: + free(path); + free(debugfs); + return ret; +} diff --git a/src/ftrace.h b/src/ftrace.h new file mode 100644 index 0000000..0fd88d1 --- /dev/null +++ b/src/ftrace.h @@ -0,0 +1,14 @@ +#ifndef TRACE_FTRACE_H +#define TRACE_FTRACE_H + +#include <stdbool.h> +#include <unistd.h> + +/* the buffer size of qemu_monitor is 1024 */ +#define MAX_TRACE_STRLEN 1024 + +bool trace_backend_init(void); + +extern int trace_marker_fd; + +#endif diff --git a/tests/Makefile.am b/tests/Makefile.am index 8d24cd9..2aa26f5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -51,6 +51,9 @@ endif WITH_TRACE_PROBES if WITH_DTRACE_PROBES PROBES_O += ../src/libvirt_probes_dtrace.lo endif WITH_DTRACE_PROBES +if WITH_FTRACE_PROBES +PROBES_O += ../src/libvirt_ftrace.la +endif WITH_FTRACE_PROBES GNULIB_LIBS = \ ../gnulib/lib/libgnu.la diff --git a/tools/virsh.c b/tools/virsh.c index 2d4aaff..edd41aa 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -3276,6 +3276,9 @@ vshShowVersion(vshControl *ctl ATTRIBUTE_UNUSED) #ifdef WITH_DTRACE_PROBES vshPrint(ctl, " DTrace"); #endif +#ifdef WITH_FTRACE_PROBES + vshPrint(ctl, " FTrace"); +#endif #if WITH_READLINE vshPrint(ctl, " Readline"); #endif -- 1.8.3.1

From: Xinghai Yu <yuxinghai@cn.fujitsu.com> Signed-off-by: Xinghai Yu <yuxinghai@cn.fujitsu.com> --- src/storage/parthelper.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/storage/parthelper.c b/src/storage/parthelper.c index c04f1bd..e9b56fe 100644 --- a/src/storage/parthelper.c +++ b/src/storage/parthelper.c @@ -47,6 +47,10 @@ #include "configmake.h" #include "virstring.h" +#ifdef WITH_FTRACE_PROBES +# include "ftrace.h" +#endif + /* we don't need to include the full internal.h just for this */ #define STREQ(a,b) (strcmp(a,b) == 0) @@ -85,6 +89,11 @@ int main(int argc, char **argv) return 1; } +#ifdef WITH_FTRACE_PROBES + if(!trace_backend_init()) + exit(EXIT_FAILURE); +#endif + path = argv[1]; if (virIsDevMapperDevice(path)) { partsep = "p"; -- 1.8.3.1

From: Xinghai Yu <yuxinghai@cn.fujitsu.com> Signed-off-by: Xinghai Yu <yuxinghai@cn.fujitsu.com> --- src/locking/lock_daemon.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c index e047751..2de5331 100644 --- a/src/locking/lock_daemon.c +++ b/src/locking/lock_daemon.c @@ -52,6 +52,10 @@ #include "configmake.h" +#ifdef WITH_FTRACE_PROBES +# include "ftrace.h" +#endif + #define VIR_FROM_THIS VIR_FROM_LOCKING #define VIR_LOCK_DAEMON_NUM_LOCKSPACES 3 @@ -1223,6 +1227,11 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } +#ifdef WITH_FTRACE_PROBES + if(!trace_backend_init()) + exit(EXIT_FAILURE); +#endif + while (1) { int optidx = 0; int c; -- 1.8.3.1

From: Xinghai Yu <yuxinghai@cn.fujitsu.com> Signed-off-by: Xinghai Yu <yuxinghai@cn.fujitsu.com> --- src/util/iohelper.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/util/iohelper.c b/src/util/iohelper.c index 9610063..3b33c07 100644 --- a/src/util/iohelper.c +++ b/src/util/iohelper.c @@ -42,6 +42,10 @@ #include "virrandom.h" #include "virstring.h" +#ifdef WITH_FTRACE_PROBES +# include "ftrace.h" +#endif + #define VIR_FROM_THIS VIR_FROM_STORAGE static int @@ -243,6 +247,11 @@ main(int argc, char **argv) exit(EXIT_FAILURE); } +#ifdef WITH_FTRACE_PROBES + if(!trace_backend_init()) + exit(EXIT_FAILURE); +#endif + path = argv[1]; if (argc > 1 && STREQ(argv[1], "--help")) -- 1.8.3.1

From: Xinghai Yu <yuxinghai@cn.fujitsu.com> Signed-off-by: Xinghai Yu <yuxinghai@cn.fujitsu.com> --- src/libvirt.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libvirt.c b/src/libvirt.c index a385935..5d519d4 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -69,6 +69,10 @@ #include "virutil.h" #include "virtypedparam.h" +#if defined(WITH_TRACE_PROBES) && defined(WITH_FTRACE_PROBES) +# include "ftrace.h" +#endif + #ifdef WITH_TEST # include "test/test_driver.h" #endif @@ -376,6 +380,11 @@ virGlobalInit(void) } #endif +#if defined(WITH_TRACE_PROBES) && defined(WITH_FTRACE_PROBES) + if(!trace_backend_init()) + goto error; +#endif + #ifdef WITH_GNUTLS_GCRYPT /* * This sequence of API calls it copied exactly from -- 1.8.3.1

From: Xinghai Yu <yuxinghai@cn.fujitsu.com> Signed-off-by: Xinghai Yu <yuxinghai@cn.fujitsu.com> --- src/qemu/qemu_driver.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9aad2dc..6c5299f 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -96,6 +96,10 @@ #include "viraccessapicheckqemu.h" #include "storage/storage_driver.h" +#ifdef WITH_FTRACE_PROBES +# include "ftrace.h" +#endif + #define VIR_FROM_THIS VIR_FROM_QEMU #define QEMU_NB_MEM_PARAM 3 @@ -843,6 +847,12 @@ qemuStateInitialize(bool privileged, virObjectUnref(conn); virNWFilterRegisterCallbackDriver(&qemuCallbackDriver); + +#ifdef WITH_FTRACE_PROBES + if(!trace_backend_init()) + goto error; +#endif + return 0; error: -- 1.8.3.1

From: Xinghai Yu <yuxinghai@cn.fujitsu.com> Signed-off-by: Xinghai Yu <yuxinghai@cn.fujitsu.com> --- src/lxc/lxc_controller.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 5ca960f..e726afd 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -68,6 +68,10 @@ #include "rpc/virnetserver.h" #include "virstring.h" +#ifdef WITH_FTRACE_PROBES +# include "ftrace.h" +#endif + #define VIR_FROM_THIS VIR_FROM_LXC typedef struct _virLXCControllerConsole virLXCControllerConsole; @@ -2288,6 +2292,11 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } +#ifdef WITH_FTRACE_PROBES + if(!trace_backend_init()) + exit(EXIT_FAILURE); +#endif + /* Initialize logging */ virLogSetFromEnv(); -- 1.8.3.1

From: Xinghai Yu <yuxinghai@cn.fujitsu.com> Signed-off-by: Xinghai Yu <yuxinghai@cn.fujitsu.com> --- src/security/virt-aa-helper.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index e7f1359..fa8894f 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -56,6 +56,10 @@ #include "virrandom.h" #include "virstring.h" +#ifdef WITH_FTRACE_PROBES +# include "ftrace.h" +#endif + #define VIR_FROM_THIS VIR_FROM_SECURITY static char *progname; @@ -1215,6 +1219,11 @@ main(int argc, char **argv) exit(EXIT_FAILURE); } +#ifdef WITH_FTRACE_PROBES + if(!trace_backend_init()) + exit(EXIT_FAILURE); +#endif + /* clear the environment */ environ = NULL; if (setenv("PATH", "/sbin:/usr/sbin", 1) != 0) { -- 1.8.3.1

On Mon, Mar 10, 2014 at 08:17:21AM +0000, yangzy.fnst@cn.fujitsu.com wrote:
From: Xinghai Yu <yuxinghai@cn.fujitsu.com>
This patch set will let libvirt to support multiple trace backend function and add a new 'ftrace' backend at the same time. Then, libvirt would have 2 trace backend: dtrace, ftrace.They can be used alone or together.
Patchs 1,2,3,4,5 are used for supporting multiple trace backend function. Patch 6 are used for adding ftrace as a new trace backend for libvirt. Patchs 7,8,9,10,11,12,13 add ftrace initial code in programs who use it.
Thanks very much for Stefan Hajnoczi for I have used his scripts in patch 4 which commited in qemu. Thanks very much for Eiichi Tsukata for I have used his ftrace codes in patch 6 which commited in qemu.
Backgroud: The existing trace mechanism in libvirt is dtrace. Although the dtrace can work, it's not work well enough. Every time we want get information from the trace point we must write a systemtap script and run it together with libvirt.
That's really unpractical on some occasion, especially on production server since the systemtap script can't be executed automatically. And some problems may be not easy to reproduce, then it will cost a lot of time to get the trace information again.
So I think it is essential to add supporting for record the trace information automatically in libvirt to satisfy the user's requirement. That's why I implemented multiple trace backend function and ftrace support in libvirt.
FYI, i've put this on my todo list to review. From a quick glance through there's a few things in here that I'm not liking very much, but I'll need to take take to analyse them in more detail Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Mon, Mar 10, 2014 at 08:17:21AM +0000, yangzy.fnst@cn.fujitsu.com wrote:
From: Xinghai Yu <yuxinghai@cn.fujitsu.com>
[...] That's really unpractical on some occasion, especially on production server since the systemtap script can't be executed automatically. [...]
(For what it's worth, there are several different ways of executing systemtap scripts automatically at startup. There is an initscript. With the next version, its docs will move into 'man 8 systemtap', and grows a new 'onboot' option, to modules load even earlier at initramfs time via dracut.) - FChE

On Mon, Mar 10, 2014 at 08:17:21AM +0000, yangzy.fnst@cn.fujitsu.com wrote:
Backgroud: The existing trace mechanism in libvirt is dtrace. Although the dtrace can work, it's not work well enough. Every time we want get information from the trace point we must write a systemtap script and run it together with libvirt.
That's really unpractical on some occasion, especially on production server since the systemtap script can't be executed automatically. And some problems may be not easy to reproduce, then it will cost a lot of time to get the trace information again.
So I think it is essential to add supporting for record the trace information automatically in libvirt to satisfy the user's requirement. That's why I implemented multiple trace backend function and ftrace support in libvirt.
I've looked through what this patchset does and I'm not really happy with any of it. Comparing what we have today with what is proposed. The current code being probed just calls a single macro unconditionally: PROBE(EVENT_POLL_ADD_HANDLE, "watch=%d fd=%d events=%d cb=%p opaque=%p ff=%p", watch, fd, events, cb, opaque, ff); In src/util/virprobe.h this expands to VIR_DEBUG(...fmt string..., ... and args...) if (LIBVIRT_EVENT_POLL_ADD_HANDLE_ENABLED()) LIBVIRT_EVENT_POLL_ADD_HANDLE(....args...) The upshot is that even when probes are compiled into libvirt, the only overhead is a single call to virLogMessage, and a check of a boolean flag to see if that probe point is enabled currently or not. The virLogMessage function only has overhead of 2 integer comparisons unless logging is turned on. So our overhead with probes disabled is 3 integer comparisons and 1 function call. This is about as low as we can practically get, which is a good thing. The inclusion of VIR_DEBUG statement means we can see the probe in normal debug logs too, even if systemtap/dtrace is disabled at compile time which is also a good thing. With this proposed patchset the code being probed now will do a conditional function call #ifdef WITH_TRACE_PROBES trace_event_poll_add_handle(watch, fd, events, cb, opaque, ff); #endif So already we have cluttered up the code with #ifdef conditional checks at every single probe location. It has all lost debug logs when tracing is disabled at compile time which is very bad. Now the generated function implementations are something like this: void trace_event_poll_update_handle(int watch, int events) { #ifdef WITH_FTRACE_PROBES char ftrace_buf[MAX_TRACE_STRLEN]; int unused __attribute__ ((unused)); int trlen; trlen = snprintf(ftrace_buf, MAX_TRACE_STRLEN, "event_poll_update_handle " "watch=%d events=%d" "\n" , watch, events); trlen = MIN(trlen, MAX_TRACE_STRLEN - 1); unused = write(trace_marker_fd, ftrace_buf, trlen); #endif #ifdef WITH_DTRACE_PROBES LIBVIRT_EVENT_POLL_UPDATE_HANDLE(watch, events); #endif } So the ftrace backend is not doing any kind of dynamic tracing at all. It is unconditionally formatting the string + args every single time, then writing it into a file descriptor. This is way more overhead than we have today. I've just got to great lengths to remove all the logging overhead when not in use, and this just goes and does something just as bad as the old logging code we just killed. You've also lost the checks to see if the dtrace/systemtap probes are enabled too. AFAICT the ftrace system has no facility to dyanamically control whether probe points are enabled or not, in userspace and no way to get at structed data as we do with dtrace - a ring buffer of printed strings is all it offers. If all you care about is a printable formatted string for the probe, then libvirt already provides this by just enabling debug logs, with the added advantage that our debug code now has almost no overhead unless explicitly enabled. In addition you've copied a bunch of code out of QEMU which is licensed under GPLv2 only. Libvirt is LGPLv2+ licensed, so this is not compatible. I'm afraid I just don't see any compelling reason to include this ftrace code, at least not in anything like the format it is proposed in here. If you just want the ability to record a printable formatted string for probes, then I'd much rather just see us improve our logging code, so we can request that the libvirt logging system were able to ouput only log statements associated with probe points. That's be far simpler to do and avoid all the problems with this patchset. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

-----Original Message----- From: libvir-list-bounces@redhat.com [mailto:libvir-list-bounces@redhat.com] On Behalf Of Daniel P. Berrange Sent: Saturday, March 22, 2014 12:37 AM To: Yang, Zhiyong/杨 志勇 Cc: libvir-list@redhat.com; Xinghai Yu Subject: Re: [libvirt] [PATCH 00/13] Add multiple trace backend function and add new ftrace backend for libvirt ... If you just want the ability to record a printable formatted string for probes, then I'd much rather just see us improve our logging code, so we can request that the libvirt logging system were able to ouput only log statements associated with probe points. That's be far simpler to do and avoid all the problems with this patchset.
Regards, Daniel
I sincerely appreciate the analysis and feedback from you to my patch. As you have pointed out, there are a few of drawbacks in the realization of ftrace, such as overhead and the loss of check of systemtap/dtrace, which I think are due to technical reasons and which I must contemplate on. It is determined that I take on my precious advices and work out a next version of ftrace. And on that new start point, it might be advisable to re-assess the integration of multi-tracer framework(ftrace including) into libvirt, which I strongly believe will practically benefit libvirt. A big advantage of using ftrace for libvirt is that we can easily merge all trace data of libvirt, QEMU, and kernel into one memory buffer. That makes it really easier for us to investigate a problem. When we worked on a problem, we didn't know in which QEMU or libvirt the root cause resided. we needed to look at logging files of both QEMU and libvirt in parallel, but it was really hard. The time QEMU and libvirt has was different so we can't compare the each line of the log easily. As to the dtrace, which is included in libvirt, is more difficult for average users to configurate the D-script. For developer, maybe trace is a powerful, flexible and dynamical tool, but in average users' actual occasion, something such as ftrace may be more practical. The communication with the original author of ftrace has commenced and it is hopeful that the license will soon be legally permitted to me. I am looking forward to any exchange of view of whether multi-tracer framework(ftrace including) is necessary. Regards Yang Zhiyong

-----Original Message----- From: libvir-list-bounces@redhat.com [mailto:libvir-list-bounces@redhat.com] On Behalf Of yangzy.fnst@cn.fujitsu.com Sent: Tuesday, April 01, 2014 5:28 PM To: libvir-list@redhat.com Subject: Re: [libvirt] [PATCH 00/13] Add multiple trace backend function and add new ftrace backend for libvirt
-----Original Message----- From: libvir-list-bounces@redhat.com [mailto:libvir-list-bounces@redhat.com] On Behalf Of Daniel P. Berrange Sent: Saturday, March 22, 2014 12:37 AM To: Yang, Zhiyong/杨 志勇 Cc: libvir-list@redhat.com; Xinghai Yu Subject: Re: [libvirt] [PATCH 00/13] Add multiple trace backend function and add new ftrace backend for libvirt ... If you just want the ability to record a printable formatted string for probes, then I'd much rather just see us improve our logging code, so we can request that the libvirt logging system were able to ouput only log statements associated with probe points. That's be far simpler to do and avoid all the problems with this patchset.
Regards, Daniel
I sincerely appreciate the analysis and feedback from you to my patch. As you have pointed out, there are a few of drawbacks in the realization of ftrace, such as overhead and the loss of check of systemtap/dtrace, which I think are due to technical reasons and which I must contemplate on. It is determined that I take on my precious advices and work out a next version of ftrace.
And on that new start point, it might be advisable to re-assess the integration of multi-tracer framework(ftrace including) into libvirt, which I strongly believe will practically benefit libvirt.
A big advantage of using ftrace for libvirt is that we can easily merge all trace data of libvirt, QEMU, and kernel into one memory buffer. That makes it really easier for us to investigate a problem. When we worked on a problem, we didn't know in which QEMU or libvirt the root cause resided. we needed to look at logging files of both QEMU and libvirt in parallel, but it was really hard. The time QEMU and libvirt has was different so we can't compare the each line of the log easily.
As to the dtrace, which is included in libvirt, is more difficult for average users to configurate the D-script. For developer, maybe trace is a powerful, flexible and dynamical tool, but in average users' actual occasion, something such as ftrace may be more practical.
The communication with the original author of ftrace has commenced and it is hopeful that the license will soon be legally permitted to me.
I am looking forward to any exchange of view of whether multi-tracer framework(ftrace including) is necessary.
Regards Yang Zhiyong
Ping! Regards Yang Zhiyong
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 04/08/2014 07:45 PM, yangzy.fnst@cn.fujitsu.com wrote:
I am looking forward to any exchange of view of whether multi-tracer framework(ftrace including) is necessary.
Ping! Regards Yang Zhiyong
If you can propose patches that are minimally invasive (no more than ONE additional conditional check when ftrace is disabled), and which do not violate licensing, then we can look at them. But right now, the ball is back in your court; I'm not sure what you are pinging for, because Dan's analysis was pretty fair that the first version you posted is not ready for inclusion, and that you may be fighting an uphill battle. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Tue, Apr 01, 2014 at 09:28:18AM +0000, yangzy.fnst@cn.fujitsu.com wrote:
-----Original Message----- From: libvir-list-bounces@redhat.com [mailto:libvir-list-bounces@redhat.com] On Behalf Of Daniel P. Berrange Sent: Saturday, March 22, 2014 12:37 AM To: Yang, Zhiyong/杨 志勇 Cc: libvir-list@redhat.com; Xinghai Yu Subject: Re: [libvirt] [PATCH 00/13] Add multiple trace backend function and add new ftrace backend for libvirt ... If you just want the ability to record a printable formatted string for probes, then I'd much rather just see us improve our logging code, so we can request that the libvirt logging system were able to ouput only log statements associated with probe points. That's be far simpler to do and avoid all the problems with this patchset.
I sincerely appreciate the analysis and feedback from you to my patch. As you have pointed out, there are a few of drawbacks in the realization of ftrace, such as overhead and the loss of check of systemtap/dtrace, which I think are due to technical reasons and which I must contemplate on. It is determined that I take on my precious advices and work out a next version of ftrace.
And on that new start point, it might be advisable to re-assess the integration of multi-tracer framework(ftrace including) into libvirt, which I strongly believe will practically benefit libvirt.
A big advantage of using ftrace for libvirt is that we can easily merge all trace data of libvirt, QEMU, and kernel into one memory buffer. That makes it really easier for us to investigate a problem. When we worked on a problem, we didn't know in which QEMU or libvirt the root cause resided. we needed to look at logging files of both QEMU and libvirt in parallel, but it was really hard. The time QEMU and libvirt has was different so we can't compare the each line of the log easily.
The timestamp difference is likely to only be related to the timezone which libvirt always records in UTC, since there's no thread safe way to log in localtime. All the comments I had about the proposed ftrace impl in libvirt apply even more to QEMU, since it is more performance critical. I'm rather surprised that QEMU accepted the ftrace impl as it is designed currently since merely turning it on a compile time imposes a permanent performance burden thereafter.
As to the dtrace, which is included in libvirt, is more difficult for average users to configurate the D-script. For developer, maybe trace is a powerful, flexible and dynamical tool, but in average users' actual occasion, something such as ftrace may be more practical.
The communication with the original author of ftrace has commenced and it is hopeful that the license will soon be legally permitted to me.
I am looking forward to any exchange of view of whether multi-tracer framework(ftrace including) is necessary.
At the bare minimum there needs to be an impl which doesn't impose a permanent performance burden once turned on at compile time. There's also the licensing problems I previously explained. I don't think we really want to import any of the QEMU tracetool code generator. The libvirt probe code is already able to generate string format messages for probe points via our logging APIs. Since ftrace is really nothing more than a string logging buffer in the kernel, IMHO, it could easily be done as a libvirt log output. eg so you could turn it on with log_filters="2:probe.marker" log_outputs="3:ftrace" Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (4)
-
Daniel P. Berrange
-
Eric Blake
-
Frank Ch. Eigler
-
yangzy.fnst@cn.fujitsu.com