From patchwork Fri Jan 17 13:55:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11339237 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D9C16138D for ; Fri, 17 Jan 2020 13:55:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 997D82073A for ; Fri, 17 Jan 2020 13:55:55 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="kpw4FlOq" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727403AbgAQNzz (ORCPT ); Fri, 17 Jan 2020 08:55:55 -0500 Received: from mail-lj1-f169.google.com ([209.85.208.169]:42455 "EHLO mail-lj1-f169.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726885AbgAQNzz (ORCPT ); Fri, 17 Jan 2020 08:55:55 -0500 Received: by mail-lj1-f169.google.com with SMTP id y4so26552151ljj.9 for ; Fri, 17 Jan 2020 05:55:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=W2RIk8YBJEBADt5h9PuMeDLfC/U5RAsMn4okHahcH8Y=; b=kpw4FlOqLbkqXuP0Q/RGbbjEqEeGx/rY34cjm+m+BRf3oqCUs4mkimvreG2V52KGYb A9OyVvBHgUMId+WiWQagi/hLlr47rcbU/pOHPx4LhfBu4Xsv6nGY/0amyI1Or2D9MniY Xp7XSkqsB7UM2W22vC7+myMmgI2tTTYon1mbSqTjXg2PzAM1uLj1Qqptl5KwDu4AJMGb 5UPNOK7iPC/0qfZaWl/RmQaMoCpcUgI3dV67DnSzEg6ammoUbmc306TlfUwzM4Fhv5T8 RCE0Z1qNy5c48km7Uy+g2otO2iljfvl41MnWTDr0RtsyyZIMi0nL9ecw8Y6UR+Ls2pn2 SofQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=W2RIk8YBJEBADt5h9PuMeDLfC/U5RAsMn4okHahcH8Y=; b=hXiY7X4wAt388hV0m0ztaOm+A6p9bKuD1IBVuT+FqdL/FUry/Dsv2JRgMfaFOvj3CX IsMAEMA6WYP6xq6GWVCGvQW5vSuMDBC121C2MjVpmBP8ztoyNQAYTRhdtVHYswxatTBk 48PEclxnGVPFSj4vfOVpUIJszwcWVZz6ot/NS6wzgSGSe/jT65gu9mlleI6hCSqv0y2P bI3oalntCwp2nw1dsDhcvCXEuN/sp/wKJW6BAUDjVtuxnO9SDHjujfv1Q8i6anE1UicF KaDLeXj1U88rDOuQfoD9dzG93lPqCs6SLUGUWuo3hs68i+dgaiR/lpnLjUqDwKMFDywu gwNQ== X-Gm-Message-State: APjAAAVuqa4H3fc8PlJLzvjvDFh9ELISkdoPUbJAbP1642Y8wWXpjnKi 0+BVwxamXjOrmFBrUi2WBXVlIbuT X-Google-Smtp-Source: APXvYqzAD8x9XhsH44zzLNu8YOV0556AEEEjaA8MuwmtNZhOD3WyGNdAHm+26uAKh3C1MOMEPiKzog== X-Received: by 2002:a2e:9e03:: with SMTP id e3mr5847134ljk.186.1579269348814; Fri, 17 Jan 2020 05:55:48 -0800 (PST) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id 21sm12422562ljv.19.2020.01.17.05.55.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jan 2020 05:55:48 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 1/5] trace-cmd,kernel-shark: Introduce libtracefs library Date: Fri, 17 Jan 2020 15:55:40 +0200 Message-Id: <20200117135544.598235-2-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200117135544.598235-1-tz.stoyanov@gmail.com> References: <20200117135544.598235-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Add a skeleton for new library: libtracefs. It provides APIs for accessing files from tracefs. - Added new directories lib/tracefs include/tracefs - Integrated the libtracefs build into the trace-cmd compilation - The library is installed by "make install_libs" in: libtrasefs.so in $(libdir)/tracefs trasefs.h in $(includedir)/tracefs - Added implementation of initial APIs: char *tracefs_get_tracing_file(const char *name); void tracefs_put_tracing_file(char *name); const char *tracefs_get_tracing_dir(void); char *tracefs_find_tracing_dir(void); Link libtracefs to kernel-shark and use its API: tracefs_get_tracing_dir() Signed-off-by: Tzvetomir Stoyanov (VMware) --- Makefile | 27 +++- include/trace-cmd/trace-cmd.h | 9 -- include/tracefs/tracefs.h | 20 +++ kernel-shark/CMakeLists.txt | 3 +- kernel-shark/build/FindTraceCmd.cmake | 30 +++++ kernel-shark/src/CMakeLists.txt | 2 + kernel-shark/src/KsCaptureDialog.cpp | 4 +- kernel-shark/src/libkshark.h | 1 + lib/trace-cmd/trace-output.c | 3 +- lib/trace-cmd/trace-recorder.c | 7 +- lib/trace-cmd/trace-util.c | 136 ------------------- lib/tracefs/Makefile | 46 +++++++ lib/tracefs/include/tracefs-local.h | 12 ++ lib/tracefs/tracefs-utils.c | 183 ++++++++++++++++++++++++++ tracecmd/Makefile | 2 +- tracecmd/trace-check-events.c | 3 +- tracecmd/trace-list.c | 19 +-- tracecmd/trace-record.c | 127 +++++++++--------- tracecmd/trace-show.c | 5 +- tracecmd/trace-snapshot.c | 9 +- tracecmd/trace-stack.c | 9 +- tracecmd/trace-stat.c | 17 +-- 22 files changed, 427 insertions(+), 247 deletions(-) create mode 100644 include/tracefs/tracefs.h create mode 100644 lib/tracefs/Makefile create mode 100644 lib/tracefs/include/tracefs-local.h create mode 100644 lib/tracefs/tracefs-utils.c diff --git a/Makefile b/Makefile index 48d88e7..aa803ba 100644 --- a/Makefile +++ b/Makefile @@ -183,12 +183,19 @@ LIBTRACECMD_DIR = $(obj)/lib/trace-cmd LIBTRACECMD_STATIC = $(LIBTRACECMD_DIR)/libtracecmd.a LIBTRACECMD_SHARED = $(LIBTRACECMD_DIR)/libtracecmd.so -TRACE_LIBS = -L$(LIBTRACECMD_DIR) -ltracecmd -L$(LIBTRACEEVENT_DIR) -ltraceevent +LIBTRACEFS_DIR = $(obj)/lib/tracefs +LIBTRACEFS_STATIC = $(LIBTRACEFS_DIR)/libtracefs.a +LIBTRACEFS_SHARED = $(LIBTRACEFS_DIR)/libtracefs.so + +TRACE_LIBS = -L$(LIBTRACECMD_DIR) -ltracecmd \ + -L$(LIBTRACEEVENT_DIR) -ltraceevent \ + -L$(LIBTRACEFS_DIR) -ltracefs export LIBS TRACE_LIBS export LIBTRACEEVENT_DIR LIBTRACECMD_DIR export LIBTRACECMD_STATIC LIBTRACECMD_SHARED export LIBTRACEEVENT_STATIC LIBTRACEEVENT_SHARED +export LIBTRACEFS_STATIC LIBTRACEFS_SHARED export Q SILENT VERBOSE EXT @@ -198,8 +205,10 @@ include scripts/utils.mk INCLUDES = -I$(src)/include -I$(src)/../../include INCLUDES += -I$(src)/include/traceevent INCLUDES += -I$(src)/include/trace-cmd +INCLUDES += -I$(src)/include/tracefs INCLUDES += -I$(src)/lib/traceevent/include INCLUDES += -I$(src)/lib/trace-cmd/include +INCLUDES += -I$(src)/lib/tracefs/include INCLUDES += -I$(src)/tracecmd/include INCLUDES += -I$(obj)/tracecmd/include @@ -277,7 +286,7 @@ gui: force $(CMD_TARGETS) $(kshark-dir)/build/Makefile @echo "gui build complete" @echo " kernelshark located at $(kshark-dir)/bin" -trace-cmd: force $(LIBTRACEEVENT_STATIC) $(LIBTRACECMD_STATIC) +trace-cmd: force $(LIBTRACEEVENT_STATIC) $(LIBTRACECMD_STATIC) $(LIBTRACEFS_STATIC) $(Q)$(MAKE) -C $(src)/tracecmd $(obj)/tracecmd/$@ $(LIBTRACEEVENT_SHARED): force $(obj)/lib/traceevent/plugins/traceevent_plugin_dir @@ -292,12 +301,21 @@ $(LIBTRACECMD_STATIC): force $(LIBTRACECMD_SHARED): force $(Q)$(MAKE) -C $(src)/lib/trace-cmd $@ +$(LIBTRACEFS_STATIC): force + $(Q)$(MAKE) -C $(src)/lib/tracefs $@ + +$(LIBTRACEFS_SHARED): force + $(Q)$(MAKE) -C $(src)/lib/tracefs $@ + + libtraceevent.so: $(LIBTRACEEVENT_SHARED) libtraceevent.a: $(LIBTRACEEVENT_STATIC) libtracecmd.a: $(LIBTRACECMD_STATIC) libtracecmd.so: $(LIBTRACECMD_SHARED) +libtracefs.a: $(LIBTRACEFS_STATIC) +libtracefs.so: $(LIBTRACEFS_SHARED) -libs: $(LIBTRACECMD_SHARED) $(LIBTRACEEVENT_SHARED) +libs: $(LIBTRACECMD_SHARED) $(LIBTRACEEVENT_SHARED) $(LIBTRACEFS_SHARED) plugins: force $(obj)/lib/traceevent/plugins/traceevent_plugin_dir $(obj)/lib/traceevent/plugins/trace_python_dir $(Q)$(MAKE) -C $(src)/lib/traceevent/plugins @@ -353,10 +371,12 @@ install_gui: install_cmd gui install_libs: libs $(Q)$(call do_install,$(LIBTRACECMD_SHARED),$(libdir_SQ)/trace-cmd) $(Q)$(call do_install,$(LIBTRACEEVENT_SHARED),$(libdir_SQ)/traceevent) + $(Q)$(call do_install,$(LIBTRACEFS_SHARED),$(libdir_SQ)/tracefs) $(Q)$(call do_install,$(src)/include/traceevent/event-parse.h,$(includedir_SQ)/traceevent) $(Q)$(call do_install,$(src)/include/traceevent/trace-seq.h,$(includedir_SQ)/traceevent) $(Q)$(call do_install,$(src)/include/trace-cmd/trace-cmd.h,$(includedir_SQ)/trace-cmd) $(Q)$(call do_install,$(src)/include/trace-cmd/trace-filter-hash.h,$(includedir_SQ)/trace-cmd) + $(Q)$(call do_install,$(src)/include/tracefs/tracefs.h,$(includedir_SQ)/tracefs) doc: $(MAKE) -C $(src)/Documentation all @@ -379,6 +399,7 @@ clean: $(RM) tags TAGS cscope* $(MAKE) -C $(src)/lib/traceevent clean $(MAKE) -C $(src)/lib/trace-cmd clean + $(MAKE) -C $(src)/lib/tracefs clean $(MAKE) -C $(src)/lib/traceevent/plugins clean $(MAKE) -C $(src)/python clean $(MAKE) -C $(src)/tracecmd clean diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index 13afce7..66736ae 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -64,12 +64,6 @@ static inline int tracecmd_host_bigendian(void) return *ptr == 0x01020304; } -/* tracecmd_get_tracing_dir must *not* be freed */ -const char *tracecmd_get_tracing_dir(void); - -/* tracecmd_find_tracing_dir must be freed */ -char *tracecmd_find_tracing_dir(void); - /* --- Opening and Reading the trace.dat file --- */ enum { @@ -208,9 +202,6 @@ tracecmd_get_show_data_func(struct tracecmd_input *handle); void tracecmd_set_show_data_func(struct tracecmd_input *handle, tracecmd_show_data_func func); -char *tracecmd_get_tracing_file(const char *name); -void tracecmd_put_tracing_file(char *name); - int tracecmd_record_at_buffer_start(struct tracecmd_input *handle, struct tep_record *record); unsigned long long tracecmd_page_ts(struct tracecmd_input *handle, struct tep_record *record); diff --git a/include/tracefs/tracefs.h b/include/tracefs/tracefs.h new file mode 100644 index 0000000..e844c75 --- /dev/null +++ b/include/tracefs/tracefs.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ +/* + * Copyright (C) 2019, VMware, Tzvetomir Stoyanov + * + */ +#ifndef _TRACE_FS_H +#define _TRACE_FS_H + +#include "traceevent/event-parse.h" + +char *tracefs_get_tracing_file(const char *name); +void tracefs_put_tracing_file(char *name); + +/* tracefs_get_tracing_dir must *not* be freed */ +const char *tracefs_get_tracing_dir(void); + +/* tracefs_find_tracing_dir must be freed */ +char *tracefs_find_tracing_dir(void); + +#endif /* _TRACE_FS_H */ diff --git a/kernel-shark/CMakeLists.txt b/kernel-shark/CMakeLists.txt index 20478b9..8786b83 100644 --- a/kernel-shark/CMakeLists.txt +++ b/kernel-shark/CMakeLists.txt @@ -76,7 +76,8 @@ endif (CMAKE_BUILD_TYPE MATCHES Package) include_directories(${KS_DIR}/src/ ${KS_DIR}/build/src/ ${JSONC_INCLUDE_DIR} - ${TRACECMD_INCLUDE_DIR}) + ${TRACECMD_INCLUDE_DIR} + ${TRACEFS_INCLUDE_DIR}) message("") message(STATUS "C flags : " ${CMAKE_C_FLAGS}) diff --git a/kernel-shark/build/FindTraceCmd.cmake b/kernel-shark/build/FindTraceCmd.cmake index d3e145c..f27fafe 100644 --- a/kernel-shark/build/FindTraceCmd.cmake +++ b/kernel-shark/build/FindTraceCmd.cmake @@ -6,6 +6,8 @@ # TRACEEVENT_FOUND, If false, do not try to use traceevent. # # TRACECMD_INCLUDE_DIR, where to find trace-cmd header. +# TRACEFS_INCLUDE_DIR, where to find tracefs header. +# TRACEFS_LIBRARY, the tracefs library. # TRACECMD_LIBRARY, the trace-cmd library. # TRACECMD_FOUND, If false, do not try to use trace-cmd. @@ -31,12 +33,21 @@ find_path(TRACECMD_INCLUDE_DIR NAMES trace-cmd/trace-cmd.h PATHS $ENV{TRACE_CMD}/include/ ${CMAKE_SOURCE_DIR}/../include/ NO_DEFAULT_PATH) +find_path(TRACEFS_INCLUDE_DIR NAMES tracefs/tracefs.h + PATHS $ENV{TRACE_CMD}/include/ + ${CMAKE_SOURCE_DIR}/../include/ + NO_DEFAULT_PATH) find_library(TRACECMD_LIBRARY NAMES trace-cmd/libtracecmd.a PATHS $ENV{TRACE_CMD}/lib/ ${CMAKE_SOURCE_DIR}/../lib/ NO_DEFAULT_PATH) +find_library(TRACEFS_LIBRARY NAMES trace-cmd/libtracefs.a + PATHS $ENV{TRACE_CMD}/lib/ + ${CMAKE_SOURCE_DIR}/../lib/ + NO_DEFAULT_PATH) + find_library(TRACEEVENT_LIBRARY NAMES traceevent/libtraceevent.a PATHS $ENV{TRACE_CMD}/lib/ ${CMAKE_SOURCE_DIR}/../lib/ @@ -46,7 +57,9 @@ find_library(TRACEEVENT_LIBRARY NAMES traceevent/libtraceevent.a # search was successful "find_path" will do nothing this time. find_program(TRACECMD_EXECUTABLE NAMES trace-cmd) find_path(TRACECMD_INCLUDE_DIR NAMES trace-cmd/trace-cmd.h) +find_path(TRACEFS_INCLUDE_DIR NAMES tracefs/tracefs.h) find_library(TRACECMD_LIBRARY NAMES trace-cmd/libtracecmd.so) +find_library(TRACEFS_LIBRARY NAMES tracefs/libtracefs.so) find_library(TRACEEVENT_LIBRARY NAMES traceevent/libtraceevent.so) IF (TRACECMD_INCLUDE_DIR AND TRACECMD_LIBRARY) @@ -65,6 +78,23 @@ ELSE (TRACECMD_FOUND) ENDIF (TRACECMD_FOUND) +IF (TRACEFS_INCLUDE_DIR AND TRACEFS_LIBRARY) + + SET(TRACEFS_FOUND TRUE) + +ENDIF (TRACEFS_INCLUDE_DIR AND TRACEFS_LIBRARY) + +IF (TRACEFS_FOUND) + + MESSAGE(STATUS "Found tracefs: ${TRACEFS_LIBRARY}") + +ELSE (TRACEFS_FOUND) + + MESSAGE(FATAL_ERROR "\nCould not find tracefs!\n") + +ENDIF (TRACEFS_FOUND) + + IF (TRACEEVENT_LIBRARY) SET(TRACEEVENT_FOUND TRUE) diff --git a/kernel-shark/src/CMakeLists.txt b/kernel-shark/src/CMakeLists.txt index e20a030..33b5db8 100644 --- a/kernel-shark/src/CMakeLists.txt +++ b/kernel-shark/src/CMakeLists.txt @@ -9,6 +9,7 @@ add_library(kshark SHARED libkshark.c target_link_libraries(kshark ${TRACEEVENT_LIBRARY} ${TRACECMD_LIBRARY} + ${TRACEFS_LIBRARY} ${JSONC_LIBRARY} ${CMAKE_DL_LIBS}) @@ -69,6 +70,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) Qt5::Network ${TRACEEVENT_LIBRARY} ${TRACECMD_LIBRARY} + ${TRACEFS_LIBRARY} ${CMAKE_DL_LIBS}) set_target_properties(kshark-gui PROPERTIES SUFFIX ".so.${KS_VERSION_STRING}") diff --git a/kernel-shark/src/KsCaptureDialog.cpp b/kernel-shark/src/KsCaptureDialog.cpp index ad05917..548b6fb 100644 --- a/kernel-shark/src/KsCaptureDialog.cpp +++ b/kernel-shark/src/KsCaptureDialog.cpp @@ -26,7 +26,7 @@ extern "C" { static inline tep_handle *local_events() { - return tracecmd_local_events(tracecmd_get_tracing_dir()); + return tracecmd_local_events(tracefs_get_tracing_dir()); } /** @@ -204,7 +204,7 @@ QStringList KsCaptureControl::_getPlugins() QStringList pluginList; char **all_plugins; - all_plugins = tracecmd_local_plugins(tracecmd_get_tracing_dir()); + all_plugins = tracecmd_local_plugins(tracefs_get_tracing_dir()); if (!all_plugins) return pluginList; diff --git a/kernel-shark/src/libkshark.h b/kernel-shark/src/libkshark.h index 3407db1..b05aa90 100644 --- a/kernel-shark/src/libkshark.h +++ b/kernel-shark/src/libkshark.h @@ -28,6 +28,7 @@ extern "C" { #include "trace-cmd/trace-cmd.h" #include "trace-cmd/trace-filter-hash.h" #include "traceevent/event-parse.h" +#include "tracefs/tracefs.h" // KernelShark #include "libkshark-plugin.h" diff --git a/lib/trace-cmd/trace-output.c b/lib/trace-cmd/trace-output.c index be4d3f5..a3dda27 100644 --- a/lib/trace-cmd/trace-output.c +++ b/lib/trace-cmd/trace-output.c @@ -20,6 +20,7 @@ #include #include +#include "tracefs.h" #include "trace-cmd-local.h" #include "list.h" #include "trace-msg.h" @@ -238,7 +239,7 @@ static tsize_t copy_file(struct tracecmd_output *handle, static const char *find_tracing_dir(struct tracecmd_output *handle) { if (!handle->tracing_dir) - handle->tracing_dir = tracecmd_find_tracing_dir(); + handle->tracing_dir = tracefs_find_tracing_dir(); return handle->tracing_dir; } diff --git a/lib/trace-cmd/trace-recorder.c b/lib/trace-cmd/trace-recorder.c index 36c9a96..2a6e2b6 100644 --- a/lib/trace-cmd/trace-recorder.c +++ b/lib/trace-cmd/trace-recorder.c @@ -12,6 +12,7 @@ #include #include +#include "tracefs.h" #include "trace-cmd.h" #include "event-utils.h" @@ -306,7 +307,7 @@ struct tracecmd_recorder *tracecmd_create_recorder_fd(int fd, int cpu, unsigned { const char *tracing; - tracing = tracecmd_get_tracing_dir(); + tracing = tracefs_get_tracing_dir(); if (!tracing) { errno = ENODEV; return NULL; @@ -319,7 +320,7 @@ struct tracecmd_recorder *tracecmd_create_recorder(const char *file, int cpu, un { const char *tracing; - tracing = tracecmd_get_tracing_dir(); + tracing = tracefs_get_tracing_dir(); if (!tracing) { errno = ENODEV; return NULL; @@ -333,7 +334,7 @@ tracecmd_create_recorder_maxkb(const char *file, int cpu, unsigned flags, int ma { const char *tracing; - tracing = tracecmd_get_tracing_dir(); + tracing = tracefs_get_tracing_dir(); if (!tracing) { errno = ENODEV; return NULL; diff --git a/lib/trace-cmd/trace-util.c b/lib/trace-cmd/trace-util.c index b5bb0d5..1394469 100644 --- a/lib/trace-cmd/trace-util.c +++ b/lib/trace-cmd/trace-util.c @@ -23,8 +23,6 @@ #include "event-utils.h" #define LOCAL_PLUGIN_DIR ".trace-cmd/plugins" -#define TRACEFS_PATH "/sys/kernel/tracing" -#define DEBUGFS_PATH "/sys/kernel/debug" #define PROC_STACK_FILE "/proc/sys/kernel/stack_tracer_enabled" int tracecmd_disable_sys_plugins; @@ -33,9 +31,6 @@ static bool debug; static FILE *logfp; -#define _STR(x) #x -#define STR(x) _STR(x) - /** * tracecmd_set_debug - Set debug mode of the tracecmd library * @set_debug: The new "debug" mode. If true, the tracecmd library is @@ -147,113 +142,6 @@ void tracecmd_parse_ftrace_printk(struct tep_handle *pevent, } } -static int mount_debugfs(void) -{ - struct stat st; - int ret; - - /* make sure debugfs exists */ - ret = stat(DEBUGFS_PATH, &st); - if (ret < 0) - return -1; - - ret = mount("nodev", DEBUGFS_PATH, - "debugfs", 0, NULL); - - return ret; -} - -static int mount_tracefs(void) -{ - struct stat st; - int ret; - - /* make sure debugfs exists */ - ret = stat(TRACEFS_PATH, &st); - if (ret < 0) - return -1; - - ret = mount("nodev", TRACEFS_PATH, - "tracefs", 0, NULL); - - return ret; -} - -char *tracecmd_find_tracing_dir(void) -{ - char *debug_str = NULL; - char fspath[PATH_MAX+1]; - char *tracing_dir; - char type[100]; - int use_debug = 0; - FILE *fp; - - if ((fp = fopen("/proc/mounts","r")) == NULL) { - warning("Can't open /proc/mounts for read"); - return NULL; - } - - while (fscanf(fp, "%*s %" - STR(PATH_MAX) - "s %99s %*s %*d %*d\n", - fspath, type) == 2) { - if (strcmp(type, "tracefs") == 0) - break; - if (!debug_str && strcmp(type, "debugfs") == 0) { - debug_str = strdup(fspath); - if (!debug_str) { - fclose(fp); - return NULL; - } - } - } - fclose(fp); - - if (strcmp(type, "tracefs") != 0) { - if (mount_tracefs() < 0) { - if (debug_str) { - strncpy(fspath, debug_str, PATH_MAX); - fspath[PATH_MAX] = 0; - } else { - if (mount_debugfs() < 0) { - warning("debugfs not mounted, please mount"); - free(debug_str); - return NULL; - } - strcpy(fspath, DEBUGFS_PATH); - } - use_debug = 1; - } else - strcpy(fspath, TRACEFS_PATH); - } - free(debug_str); - - if (use_debug) { - int ret; - - ret = asprintf(&tracing_dir, "%s/tracing", fspath); - if (ret < 0) - return NULL; - } else { - tracing_dir = strdup(fspath); - if (!tracing_dir) - return NULL; - } - - return tracing_dir; -} - -const char *tracecmd_get_tracing_dir(void) -{ - static const char *tracing_dir; - - if (tracing_dir) - return tracing_dir; - - tracing_dir = tracecmd_find_tracing_dir(); - return tracing_dir; -} - /* FIXME: append_file() is duplicated and could be consolidated */ static char *append_file(const char *dir, const char *name) { @@ -863,30 +751,6 @@ void trace_util_free_plugin_files(char **files) free(files); } -char *tracecmd_get_tracing_file(const char *name) -{ - static const char *tracing; - char *file; - int ret; - - if (!tracing) { - tracing = tracecmd_find_tracing_dir(); - if (!tracing) - return NULL; - } - - ret = asprintf(&file, "%s/%s", tracing, name); - if (ret < 0) - return NULL; - - return file; -} - -void tracecmd_put_tracing_file(char *name) -{ - free(name); -} - void __noreturn __vdie(const char *fmt, va_list ap) { int ret = errno; diff --git a/lib/tracefs/Makefile b/lib/tracefs/Makefile new file mode 100644 index 0000000..86d7845 --- /dev/null +++ b/lib/tracefs/Makefile @@ -0,0 +1,46 @@ + + +include $(src)/scripts/utils.mk + +bdir:=$(obj)/lib/tracefs + +DEFAULT_TARGET = $(bdir)/libtracefs.a + +OBJS = +OBJS += tracefs-utils.o + +OBJS := $(OBJS:%.o=$(bdir)/%.o) +DEPS := $(OBJS:$(bdir)/%.o=$(bdir)/.%.d) + +all: $(DEFAULT_TARGET) + +$(bdir): + @mkdir -p $(bdir) + +$(OBJS): | $(bdir) +$(DEPS): | $(bdir) + +$(bdir)/libtracefs.a: $(OBJS) + $(Q)$(call do_build_static_lib) + +$(bdir)/libtracefs.so: $(OBJS) + $(Q)$(call do_compile_shared_library) + +$(bdir)/%.o: %.c + $(Q)$(call do_fpic_compile) + +$(DEPS): $(bdir)/.%.d: %.c + $(Q)$(CC) -M $(CPPFLAGS) $(CFLAGS) $< > $@ + +$(OBJS): $(bdir)/%.o : $(bdir)/.%.d + +dep_includes := $(wildcard $(DEPS)) + +ifneq ($(dep_includes),) + include $(dep_includes) +endif + +clean: + $(RM) $(bdir)/*.a $(bdir)/*.so $(bdir)/*.o $(bdir)/.*.d + +.PHONY: clean diff --git a/lib/tracefs/include/tracefs-local.h b/lib/tracefs/include/tracefs-local.h new file mode 100644 index 0000000..231edd1 --- /dev/null +++ b/lib/tracefs/include/tracefs-local.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ +/* + * Copyright (C) 2019, VMware, Tzvetomir Stoyanov + * + */ +#ifndef _TRACE_FS_LOCAL_H +#define _TRACE_FS_LOCAL_H + +/* Can be overridden */ +void warning(const char *fmt, ...); + +#endif /* _TRACE_FS_LOCAL_H */ diff --git a/lib/tracefs/tracefs-utils.c b/lib/tracefs/tracefs-utils.c new file mode 100644 index 0000000..0ef16fc --- /dev/null +++ b/lib/tracefs/tracefs-utils.c @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2008, 2009, 2010 Red Hat Inc, Steven Rostedt + * + * Updates: + * Copyright (C) 2019, VMware, Tzvetomir Stoyanov + * + */ +#include +#include +#include +#include + +#include "tracefs.h" + +#define TRACEFS_PATH "/sys/kernel/tracing" +#define DEBUGFS_PATH "/sys/kernel/debug" + +#define _STR(x) #x +#define STR(x) _STR(x) + +void __attribute__((weak)) warning(const char *fmt, ...) +{ +} + +static int mount_tracefs(void) +{ + struct stat st; + int ret; + + /* make sure debugfs exists */ + ret = stat(TRACEFS_PATH, &st); + if (ret < 0) + return -1; + + ret = mount("nodev", TRACEFS_PATH, + "tracefs", 0, NULL); + + return ret; +} + +static int mount_debugfs(void) +{ + struct stat st; + int ret; + + /* make sure debugfs exists */ + ret = stat(DEBUGFS_PATH, &st); + if (ret < 0) + return -1; + + ret = mount("nodev", DEBUGFS_PATH, + "debugfs", 0, NULL); + + return ret; +} + +/** + * tracefs_find_tracing_dir - Find tracing directory + * + * Returns string containing the full path to the system's tracing directory. + * The string must be freed by free() + */ +char *tracefs_find_tracing_dir(void) +{ + char *debug_str = NULL; + char fspath[PATH_MAX+1]; + char *tracing_dir; + char type[100]; + int use_debug = 0; + FILE *fp; + + fp = fopen("/proc/mounts", "r"); + if (!fp) { + warning("Can't open /proc/mounts for read"); + return NULL; + } + + while (fscanf(fp, "%*s %" + STR(PATH_MAX) + "s %99s %*s %*d %*d\n", + fspath, type) == 2) { + if (strcmp(type, "tracefs") == 0) + break; + if (!debug_str && strcmp(type, "debugfs") == 0) { + debug_str = strdup(fspath); + if (!debug_str) { + fclose(fp); + return NULL; + } + } + } + fclose(fp); + + if (strcmp(type, "tracefs") != 0) { + if (mount_tracefs() < 0) { + if (debug_str) { + strncpy(fspath, debug_str, PATH_MAX); + fspath[PATH_MAX] = 0; + } else { + if (mount_debugfs() < 0) { + warning("debugfs not mounted, please mount"); + free(debug_str); + return NULL; + } + strcpy(fspath, DEBUGFS_PATH); + } + use_debug = 1; + } else + strcpy(fspath, TRACEFS_PATH); + } + free(debug_str); + + if (use_debug) { + int ret; + + ret = asprintf(&tracing_dir, "%s/tracing", fspath); + if (ret < 0) + return NULL; + } else { + tracing_dir = strdup(fspath); + if (!tracing_dir) + return NULL; + } + + return tracing_dir; +} + +/** + * tracefs_get_tracing_dir - Get tracing directory + * + * Returns string containing the full path to the system's tracing directory. + * Must use tracefs_put_tracing_file() to free the returned string. + */ +const char *tracefs_get_tracing_dir(void) +{ + static const char *tracing_dir; + + if (tracing_dir) + return tracing_dir; + + tracing_dir = tracefs_find_tracing_dir(); + return tracing_dir; +} + +/** + * tracefs_get_tracing_file - Get tracing file + * @name: tracing file name + * + * Returns string containing the full path to a tracing file in + * the system's tracing directory. + * + * Must use tracefs_put_tracing_file() to free the returned string. + */ +char *tracefs_get_tracing_file(const char *name) +{ + static const char *tracing; + char *file; + int ret; + + if (!tracing) { + tracing = tracefs_find_tracing_dir(); + if (!tracing) + return NULL; + } + + ret = asprintf(&file, "%s/%s", tracing, name); + if (ret < 0) + return NULL; + + return file; +} + +/** + * tracefs_put_tracing_file - Free tracing file or directory name + * + * Frees tracing file or directory, returned by + * tracefs_get_tracing_file() or tracefs_get_tracing_dir() APIs + */ +void tracefs_put_tracing_file(char *name) +{ + free(name); +} diff --git a/tracecmd/Makefile b/tracecmd/Makefile index 29a623b..d00d8e0 100644 --- a/tracecmd/Makefile +++ b/tracecmd/Makefile @@ -62,7 +62,7 @@ $(all_objs): | $(bdir) $(bdir)/trace-cmd: $(ALL_OBJS) $(Q)$(do_app_build) -$(bdir)/trace-cmd: $(LIBTRACECMD_STATIC) $(LIBTRACEEVENT_STATIC) +$(bdir)/trace-cmd: $(LIBTRACECMD_STATIC) $(LIBTRACEEVENT_STATIC) $(LIBTRACEFS_STATIC) $(bdir)/%.o: %.c $(Q)$(call do_compile) diff --git a/tracecmd/trace-check-events.c b/tracecmd/trace-check-events.c index b09fcd0..a8ee60a 100644 --- a/tracecmd/trace-check-events.c +++ b/tracecmd/trace-check-events.c @@ -7,6 +7,7 @@ #include #include +#include "tracefs.h" #include "trace-local.h" void trace_check_events(int argc, char **argv) @@ -28,7 +29,7 @@ void trace_check_events(int argc, char **argv) break; } } - tracing = tracecmd_get_tracing_dir(); + tracing = tracefs_get_tracing_dir(); if (!tracing) { printf("Can not find or mount tracing directory!\n" diff --git a/tracecmd/trace-list.c b/tracecmd/trace-list.c index 65099a5..86e3358 100644 --- a/tracecmd/trace-list.c +++ b/tracecmd/trace-list.c @@ -6,6 +6,7 @@ #include +#include "tracefs.h" #include "trace-local.h" @@ -35,7 +36,7 @@ void show_instance_file(struct buffer_instance *instance, const char *name) path = get_instance_file(instance, name); dump_file_content(path); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); } enum { @@ -49,9 +50,9 @@ void show_file(const char *name) { char *path; - path = tracecmd_get_tracing_file(name); + path = tracefs_get_tracing_file(name); dump_file_content(path); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); } typedef int (*process_file_func)(char *buf, int len); @@ -86,11 +87,11 @@ static void process_file_re(process_file_func func, free(str); - path = tracecmd_get_tracing_file(name); + path = tracefs_get_tracing_file(name); fp = fopen(path, "r"); if (!fp) die("reading %s", path); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); do { n = getline(&buf, &l, fp); @@ -132,12 +133,12 @@ static char *get_event_file(const char *type, char *buf, int len) if (!event) die("no event found in %s\n", buf); - path = tracecmd_get_tracing_file("events"); + path = tracefs_get_tracing_file("events"); ret = asprintf(&file, "%s/%s/%s/%s", path, system, event, type); if (ret < 0) die("Failed to allocate event file %s %s", system, event); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); return file; } @@ -282,9 +283,9 @@ static void show_buffers(void) char *path; int printed = 0; - path = tracecmd_get_tracing_file("instances"); + path = tracefs_get_tracing_file("instances"); dir = opendir(path); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); if (!dir) die("Can not read instance directory"); diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index 80b2234..5355813 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -39,6 +39,7 @@ #include #endif +#include "tracefs.h" #include "version.h" #include "trace-local.h" #include "trace-msg.h" @@ -337,21 +338,21 @@ static void test_set_event_pid(void) if (tested) return; - path = tracecmd_get_tracing_file("set_event_pid"); + path = tracefs_get_tracing_file("set_event_pid"); ret = stat(path, &st); if (!ret) { have_set_event_pid = 1; reset_save_file(path, RESET_DEFAULT_PRIO); } - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); - path = tracecmd_get_tracing_file("options/event-fork"); + path = tracefs_get_tracing_file("options/event-fork"); ret = stat(path, &st); if (!ret) { have_event_fork = 1; reset_save_file(path, RESET_DEFAULT_PRIO); } - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); tested = 1; } @@ -442,13 +443,13 @@ static int __add_all_instances(const char *tracing_dir) */ void add_all_instances(void) { - char *tracing_dir = tracecmd_find_tracing_dir(); + char *tracing_dir = tracefs_find_tracing_dir(); if (!tracing_dir) die("malloc"); __add_all_instances(tracing_dir); - tracecmd_put_tracing_file(tracing_dir); + tracefs_put_tracing_file(tracing_dir); } /** @@ -474,7 +475,7 @@ void tracecmd_stat_cpu_instance(struct buffer_instance *instance, path = get_instance_file(instance, file); free(file); fd = open(path, O_RDONLY); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); if (fd < 0) return; @@ -772,9 +773,9 @@ static int set_ftrace(int set, int use_proc) int ret; /* First check if the function-trace option exists */ - path = tracecmd_get_tracing_file("options/function-trace"); + path = tracefs_get_tracing_file("options/function-trace"); ret = set_ftrace_enable(path, set); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); /* Always enable ftrace_enable proc file when set is true */ if (ret < 0 || set || use_proc) @@ -790,7 +791,7 @@ static int set_ftrace(int set, int use_proc) * * Returns the path name of the @file for the given @instance. * - * Must use tracecmd_put_tracing_file() to free the returned string. + * Must use tracefs_put_tracing_file() to free the returned string. */ char * get_instance_file(struct buffer_instance *instance, const char *file) @@ -803,10 +804,10 @@ get_instance_file(struct buffer_instance *instance, const char *file) ret = asprintf(&buf, "instances/%s/%s", instance->name, file); if (ret < 0) die("Failed to allocate name for %s/%s", instance->name, file); - path = tracecmd_get_tracing_file(buf); + path = tracefs_get_tracing_file(buf); free(buf); } else - path = tracecmd_get_tracing_file(file); + path = tracefs_get_tracing_file(file); return path; } @@ -825,7 +826,7 @@ get_instance_dir(struct buffer_instance *instance) ret = asprintf(&buf, "instances/%s", instance->name); if (ret < 0) die("Failed to allocate for instance %s", instance->name); - path = tracecmd_get_tracing_file(buf); + path = tracefs_get_tracing_file(buf); free(buf); return path; @@ -868,7 +869,7 @@ write_instance_file(struct buffer_instance *instance, ret = stat(path, &st); if (ret == 0) ret = write_file(path, str, type); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); return ret; } @@ -886,7 +887,7 @@ static void __clear_trace(struct buffer_instance *instance) fp = fopen(path, "w"); if (!fp) die("writing to '%s'", path); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); fwrite("0", 1, 1, fp); fclose(fp); } @@ -905,11 +906,11 @@ static void clear_trace(void) char *path; /* reset the trace */ - path = tracecmd_get_tracing_file("trace"); + path = tracefs_get_tracing_file("trace"); fp = fopen(path, "w"); if (!fp) die("writing to '%s'", path); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); fwrite("0", 1, 1, fp); fclose(fp); } @@ -956,7 +957,7 @@ static void update_ftrace_pid(const char *pid, int reset) if (fd >= 0) close(fd); if (path) - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); fd = -1; path = NULL; return; @@ -970,7 +971,7 @@ static void update_ftrace_pid(const char *pid, int reset) if (fd < 0) { if (!path) - path = tracecmd_get_tracing_file("set_ftrace_pid"); + path = tracefs_get_tracing_file("set_ftrace_pid"); if (!path) return; ret = stat(path, &st); @@ -1601,12 +1602,12 @@ set_plugin_instance(struct buffer_instance *instance, const char *name) * plugin for those if name is "nop". */ if (!strncmp(name, "nop", 3)) { - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); return; } die("writing to '%s'", path); } - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); fwrite(name, 1, strlen(name), fp); fclose(fp); @@ -1619,11 +1620,11 @@ set_plugin_instance(struct buffer_instance *instance, const char *name) path = get_instance_file(instance, "options/func_stack_trace"); fp = fopen(path, "w"); if (!fp) { - tracecmd_put_tracing_file(path); - path = tracecmd_get_tracing_file("options/func_stack_trace"); + tracefs_put_tracing_file(path); + path = tracefs_get_tracing_file("options/func_stack_trace"); fp = fopen(path, "w"); if (!fp) { - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); return; } } @@ -1632,7 +1633,7 @@ set_plugin_instance(struct buffer_instance *instance, const char *name) * the original content. */ add_reset_file(path, "0", RESET_HIGH_PRIO); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); fwrite(&zero, 1, 1, fp); fclose(fp); } @@ -1662,11 +1663,11 @@ static int set_option(const char *option) FILE *fp; char *path; - path = tracecmd_get_tracing_file("trace_options"); + path = tracefs_get_tracing_file("trace_options"); fp = fopen(path, "w"); if (!fp) warning("writing to '%s'", path); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); if (!fp) return -1; @@ -1693,7 +1694,7 @@ static void disable_func_stack_trace_instance(struct buffer_instance *instance) path = get_instance_file(instance, "current_tracer"); ret = stat(path, &st); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); if (ret < 0) return; @@ -1727,7 +1728,7 @@ static void add_reset_options(void) if (keep) return; - path = tracecmd_get_tracing_file("trace_options"); + path = tracefs_get_tracing_file("trace_options"); content = get_file_content(path); for (opt = options; opt; opt = opt->next) { @@ -1790,7 +1791,7 @@ static void add_reset_options(void) add_reset_file(path, option, RESET_DEFAULT_PRIO); } - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); free(content); } @@ -1819,14 +1820,14 @@ static void set_saved_cmdlines_size(struct common_record_context *ctx) if (!ctx->saved_cmdlines_size) return; - path = tracecmd_get_tracing_file("saved_cmdlines_size"); + path = tracefs_get_tracing_file("saved_cmdlines_size"); if (!path) goto err; reset_save_file(path, RESET_DEFAULT_PRIO); fd = open(path, O_WRONLY); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); if (fd < 0) goto err; @@ -1852,7 +1853,7 @@ static int trace_check_file_exists(struct buffer_instance *instance, char *file) path = get_instance_file(instance, file); ret = stat(path, &st); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); return ret < 0 ? 0 : 1; } @@ -1884,11 +1885,11 @@ static void old_update_events(const char *name, char update) name = "*:*"; /* need to use old way */ - path = tracecmd_get_tracing_file("set_event"); + path = tracefs_get_tracing_file("set_event"); fp = fopen(path, "w"); if (!fp) die("opening '%s'", path); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); /* Disable the event with "!" */ if (update == '0') @@ -1935,12 +1936,12 @@ reset_events_instance(struct buffer_instance *instance) die("opening to '%s'", path); ret = write(fd, &c, 1); close(fd); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); path = get_instance_file(instance, "events/*/filter"); globbuf.gl_offs = 0; ret = glob(path, 0, NULL, &globbuf); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); if (ret < 0) return; @@ -2182,9 +2183,9 @@ static void check_tracing_enabled(void) char *path; if (fd < 0) { - path = tracecmd_get_tracing_file("tracing_enabled"); + path = tracefs_get_tracing_file("tracing_enabled"); fd = open(path, O_WRONLY | O_CLOEXEC); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); if (fd < 0) return; @@ -2205,7 +2206,7 @@ static int open_instance_fd(struct buffer_instance *instance, if (is_top_instance(instance)) die("opening '%s'", path); } - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); return fd; } @@ -2526,7 +2527,7 @@ static void set_mask(struct buffer_instance *instance) close(fd); out: - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); free(instance->cpumask); instance->cpumask = NULL; } @@ -2583,7 +2584,7 @@ static void set_clock(struct buffer_instance *instance) add_reset_file(path, str, RESET_DEFAULT_PRIO); free(content); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); write_instance_file(instance, "trace_clock", instance->clock, "clock"); } @@ -2598,7 +2599,7 @@ static void set_max_graph_depth(struct buffer_instance *instance, char *max_grap path = get_instance_file(instance, "max_graph_depth"); reset_save_file(path, RESET_DEFAULT_PRIO); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); ret = write_instance_file(instance, "max_graph_depth", max_graph_depth, NULL); if (ret < 0) @@ -2721,7 +2722,7 @@ static int expand_event_files(struct buffer_instance *instance, globbuf.gl_offs = 0; ret = glob(path, 0, NULL, &globbuf); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); free(p); if (ret < 0) @@ -3182,7 +3183,7 @@ create_recorder_instance_pipe(struct buffer_instance *instance, if (instance->name) path = get_instance_dir(instance); else - path = tracecmd_find_tracing_dir(); + path = tracefs_find_tracing_dir(); if (!path) die("malloc"); @@ -3193,7 +3194,7 @@ create_recorder_instance_pipe(struct buffer_instance *instance, recorder = tracecmd_create_buffer_recorder_fd(brass[1], cpu, flags, path); if (instance->name) - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); return recorder; } @@ -3234,7 +3235,7 @@ create_recorder_instance(struct buffer_instance *instance, const char *file, int record = tracecmd_create_buffer_recorder_maxkb(file, cpu, recorder_flags, path, max_kb); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); return record; } @@ -3287,9 +3288,9 @@ static int create_recorder(struct buffer_instance *instance, int cpu, if (instance->name && !is_agent(instance)) path = get_instance_dir(instance); else - path = tracecmd_find_tracing_dir(); + path = tracefs_find_tracing_dir(); recorder = tracecmd_create_buffer_recorder_fd(fd, cpu, flags, path); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); } else { file = get_temp_file(instance, cpu); recorder = create_recorder_instance(instance, file, cpu, brass); @@ -4124,7 +4125,7 @@ static int write_func_file(struct buffer_instance *instance, close(fd); ret = 0; free: - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); return ret; failed: die("Failed to write %s to %s.\n" @@ -4142,7 +4143,7 @@ static int functions_filtered(struct buffer_instance *instance) path = get_instance_file(instance, "set_ftrace_filter"); fd = open(path, O_RDONLY); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); if (fd < 0) { if (is_top_instance(instance)) warning("Can not set set_ftrace_filter"); @@ -4265,7 +4266,7 @@ static unsigned long long find_time_stamp(struct tep_handle *pevent) int fd; int r; - path = tracecmd_get_tracing_file("per_cpu"); + path = tracefs_get_tracing_file("per_cpu"); if (!path) return 0; @@ -4304,7 +4305,7 @@ static unsigned long long find_time_stamp(struct tep_handle *pevent) closedir(dir); out: - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); return ts; } @@ -4319,7 +4320,7 @@ static char *read_instance_file(struct buffer_instance *instance, char *file, in path = get_instance_file(instance, file); fd = open(path, O_RDONLY); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); if (fd < 0) { warning("%s not found, --date ignored", file); return NULL; @@ -4400,9 +4401,9 @@ static char *get_date_to_ts(void) goto out_pevent; } - path = tracecmd_get_tracing_file("trace_marker"); + path = tracefs_get_tracing_file("trace_marker"); tfd = open(path, O_WRONLY); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); if (tfd < 0) { warning("Can not open 'trace_marker', --date ignored"); goto out_pevent; @@ -4491,7 +4492,7 @@ static void set_buffer_size_instance(struct buffer_instance *instance) warning("Can't write to %s", path); close(fd); out: - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); } void set_buffer_size(void) @@ -4560,7 +4561,7 @@ static void clear_instance_triggers(struct buffer_instance *instance) trace_event_iter_free(iter); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); } static void @@ -4621,7 +4622,7 @@ static void clear_instance_filters(struct buffer_instance *instance) trace_event_iter_free(iter); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); } static void clear_filters(void) @@ -4687,7 +4688,7 @@ static void clear_func_filters(void) for (i = 0; files[i]; i++) { path = get_instance_file(instance, files[i]); clear_func_filter(path); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); } } } @@ -4712,7 +4713,7 @@ static void make_instances(void) } else /* Don't delete instances that already exist */ instance->flags |= BUFFER_FL_KEEP; - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); } } @@ -4734,7 +4735,7 @@ void tracecmd_remove_instances(void) ret = rmdir(path); if (ret < 0) die("rmdir %s", path); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); } } @@ -5043,7 +5044,7 @@ static int test_stacktrace_trigger(struct buffer_instance *instance) ret = 1; close(fd); out: - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); return ret; } diff --git a/tracecmd/trace-show.c b/tracecmd/trace-show.c index 96bfe77..391d329 100644 --- a/tracecmd/trace-show.c +++ b/tracecmd/trace-show.c @@ -7,6 +7,7 @@ #include #include +#include "tracefs.h" #include "trace-local.h" enum { @@ -157,9 +158,9 @@ void trace_show(int argc, char **argv) if (show_name) { char *name; - name = tracecmd_get_tracing_file(file); + name = tracefs_get_tracing_file(file); printf("%s\n", name); - tracecmd_put_tracing_file(name); + tracefs_put_tracing_file(name); } show_file(file); if (buffer) diff --git a/tracecmd/trace-snapshot.c b/tracecmd/trace-snapshot.c index a9a512a..34630b4 100644 --- a/tracecmd/trace-snapshot.c +++ b/tracecmd/trace-snapshot.c @@ -12,6 +12,7 @@ #include #include +#include "tracefs.h" #include "trace-local.h" static void write_file(const char *name, char *val) @@ -20,7 +21,7 @@ static void write_file(const char *name, char *val) int fd; ssize_t n; - path = tracecmd_get_tracing_file(name); + path = tracefs_get_tracing_file(name); fd = open(path, O_WRONLY); if (fd < 0) die("writing %s", path); @@ -29,7 +30,7 @@ static void write_file(const char *name, char *val) if (n < 0) die("failed to write to %s\n", path); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); close(fd); } @@ -91,11 +92,11 @@ void trace_snapshot (int argc, char **argv) file = cpu_path; } - name = tracecmd_get_tracing_file(file); + name = tracefs_get_tracing_file(file); ret = stat(name, &st); if (ret < 0) die("Snapshot feature is not supported by this kernel"); - tracecmd_put_tracing_file(name); + tracefs_put_tracing_file(name); if (!reset_snap && !take_snap && !free_snap) { show_file(file); diff --git a/tracecmd/trace-stack.c b/tracecmd/trace-stack.c index bb002c0..5e88b36 100644 --- a/tracecmd/trace-stack.c +++ b/tracecmd/trace-stack.c @@ -15,6 +15,7 @@ #include #include +#include "tracefs.h" #include "trace-local.h" #define PROC_FILE "/proc/sys/kernel/stack_tracer_enabled" @@ -86,7 +87,7 @@ static void reset_trace(void) int fd; int n; - path = tracecmd_get_tracing_file("stack_max_size"); + path = tracefs_get_tracing_file("stack_max_size"); fd = open(path, O_WRONLY); if (fd < 0) die("writing %s", path); @@ -95,7 +96,7 @@ static void reset_trace(void) n = write(fd, buf, 1); if (n < 0) die("writing into %s", path); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); close(fd); } @@ -116,11 +117,11 @@ static void read_trace(void) else printf("(stack tracer not running)\n"); - path = tracecmd_get_tracing_file("stack_trace"); + path = tracefs_get_tracing_file("stack_trace"); fp = fopen(path, "r"); if (!fp) die("reading to '%s'", path); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); while ((r = getline(&buf, &n, fp)) >= 0) { /* diff --git a/tracecmd/trace-stat.c b/tracecmd/trace-stat.c index 538f4ad..7a1d9bb 100644 --- a/tracecmd/trace-stat.c +++ b/tracecmd/trace-stat.c @@ -13,6 +13,7 @@ #include #include +#include "tracefs.h" #include "trace-local.h" #ifndef BUFSIZ @@ -32,7 +33,7 @@ static int get_instance_file_fd(struct buffer_instance *instance, path = get_instance_file(instance, file); fd = open(path, O_RDONLY); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); return fd; } @@ -383,7 +384,7 @@ static void report_events(struct buffer_instance *instance) if (!processed && !processed_part) printf(" (none enabled)\n"); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); } static void @@ -456,7 +457,7 @@ static void report_event_filters(struct buffer_instance *instance) trace_event_iter_free(iter); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); } static void @@ -529,7 +530,7 @@ static void report_event_triggers(struct buffer_instance *instance) trace_event_iter_free(iter); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); } enum func_states { @@ -604,7 +605,7 @@ static void report_graph_funcs(struct buffer_instance *instance) list_functions(path, "Function Graph Filter"); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); path = get_instance_file(instance, "set_graph_notrace"); if (!path) @@ -612,7 +613,7 @@ static void report_graph_funcs(struct buffer_instance *instance) list_functions(path, "Function Graph No Trace"); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); } static void report_ftrace_filters(struct buffer_instance *instance) @@ -625,7 +626,7 @@ static void report_ftrace_filters(struct buffer_instance *instance) list_functions(path, "Function Filter"); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); path = get_instance_file(instance, "set_ftrace_notrace"); if (!path) @@ -633,7 +634,7 @@ static void report_ftrace_filters(struct buffer_instance *instance) list_functions(path, "Function No Trace"); - tracecmd_put_tracing_file(path); + tracefs_put_tracing_file(path); } static void report_buffers(struct buffer_instance *instance) From patchwork Fri Jan 17 13:55:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11339233 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E34D013A0 for ; Fri, 17 Jan 2020 13:55:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A4EC82073A for ; Fri, 17 Jan 2020 13:55:54 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="NFFAblqa" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727243AbgAQNzy (ORCPT ); Fri, 17 Jan 2020 08:55:54 -0500 Received: from mail-lj1-f196.google.com ([209.85.208.196]:38434 "EHLO mail-lj1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727033AbgAQNzy (ORCPT ); Fri, 17 Jan 2020 08:55:54 -0500 Received: by mail-lj1-f196.google.com with SMTP id w1so26584594ljh.5 for ; Fri, 17 Jan 2020 05:55:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=RQyANBpx880aFoTIItmHlRiFt3LAUsqIALUJNACFVpM=; b=NFFAblqaHyPJmM0HeGqdsoZWPyw1OY9MSUNMzPCH7Ux0dvmdRD9V00WJFs29s9AuPz g+LoKSKjbFSIP4A1jMOsTIoWxqMDD3icZKtGQiLFPj69mYd00GvwnpWlB2KtV9g+ccIo lGNlHeA05ldTK4l98WcSJSTVn1hpWWZCk6h1/WppX+ZXWIox4UiVEqo9WwJi9ptt9cuB lSLEA6podmW36mjfEo33BHJPniMSfjif7VaTtg+Es/sZvXbP2qc+9htVEL3IyR4ylI4A d5WLC247K8T27+wT0jBMCt4Xj/SEI2A6I00ySeYG8ioT0k5CLriEus9lFQ5jlYvCjk+q zcRA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=RQyANBpx880aFoTIItmHlRiFt3LAUsqIALUJNACFVpM=; b=uOnci7pjluPE74KpMP4UinSpjFTNcTXzOs4BxhL6WYrr2C6C/CHFlbGjEFd2z583yy +9Qo99mbLjyPaKvY9qfnjT7nxLbYN20fyJ8dvfAn0xUfR7yh/xmc0rV+uwEw6pwj4afu nvDSSwovXORu+XoNMRRPGnzs8N7j4ESgvOWM43ojbZpkX5V2cKKP648gGTHGZCe5+FTq NhllPDxVuisKHdTyNH5svkp6u1CjgTnD1MtLiQC8u111aVtxhVTNHbE1lAma3KY86iY8 1fYv8RVfBM0n2ywGzKvNE6PRBAw43ZF1iI1fmTU+29hFBII9Jo4ogZ6Q+o7A5ML3G0q/ HIJA== X-Gm-Message-State: APjAAAWRBrl5JsyvBZnsl2G/e1C4z+VVzzqLEkEZ24qyP4tvLi+2373q 4ObpVE6kZEBO9e1m6hlCU64= X-Google-Smtp-Source: APXvYqzoEhI6+gy7hMtzJemqM1bk2xkSIoKDMvBtT6EK9gnk6KaViqUTKI8J4mQ2vMLdiFdyPsHMxg== X-Received: by 2002:a2e:3514:: with SMTP id z20mr5378075ljz.261.1579269350055; Fri, 17 Jan 2020 05:55:50 -0800 (PST) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id 21sm12422562ljv.19.2020.01.17.05.55.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jan 2020 05:55:49 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 2/5] trace-cmd: New libtracefs APIs for ftrace instances Date: Fri, 17 Jan 2020 15:55:41 +0200 Message-Id: <20200117135544.598235-3-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200117135544.598235-1-tz.stoyanov@gmail.com> References: <20200117135544.598235-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The functionality related to ftrace instances is moved from trace-cmd application to libtracefs. The following new library APIs are introduced: struct tracefs_instance; struct tracefs_instance *tracefs_alloc_instance(const char *name); int tracefs_free_instance(struct tracefs_instance *instance); int tracefs_make_instance(struct tracefs_instance *instance); int tracefs_remove_instance(struct tracefs_instance *instance); char *tracefs_get_instance_name(struct tracefs_instance *instance); char *tracefs_get_instance_file(struct tracefs_instance *instance, const char *file); char *tracefs_get_instance_dir(struct tracefs_instance *instance); int tracefs_write_instance_file(struct tracefs_instance *instance, const char *file, const char *str, const char *type); char *tracefs_read_instance_file(struct tracefs_instance *instance, char *file, int *psize); Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/tracefs/tracefs.h | 16 ++ lib/tracefs/Makefile | 1 + lib/tracefs/include/tracefs-local.h | 1 + lib/tracefs/tracefs-instance.c | 249 ++++++++++++++++++++++++++ lib/tracefs/tracefs-utils.c | 43 +++++ tracecmd/include/trace-local.h | 5 +- tracecmd/trace-list.c | 2 +- tracecmd/trace-record.c | 264 +++++++++------------------- tracecmd/trace-show.c | 2 + tracecmd/trace-stat.c | 21 ++- 10 files changed, 412 insertions(+), 192 deletions(-) create mode 100644 lib/tracefs/tracefs-instance.c diff --git a/include/tracefs/tracefs.h b/include/tracefs/tracefs.h index e844c75..bdeb8e8 100644 --- a/include/tracefs/tracefs.h +++ b/include/tracefs/tracefs.h @@ -17,4 +17,20 @@ const char *tracefs_get_tracing_dir(void); /* tracefs_find_tracing_dir must be freed */ char *tracefs_find_tracing_dir(void); +/* ftarce instances */ +struct tracefs_instance; + +struct tracefs_instance *tracefs_instance_alloc(const char *name); +void tracefs_instance_free(struct tracefs_instance *instance); +int tracefs_instance_create(struct tracefs_instance *instance); +int tracefs_instance_destroy(struct tracefs_instance *instance); +char *tracefs_instance_get_name(struct tracefs_instance *instance); +char * +tracefs_instance_get_file(struct tracefs_instance *instance, const char *file); +char *tracefs_instance_get_dir(struct tracefs_instance *instance); +int tracefs_instance_file_write(struct tracefs_instance *instance, + const char *file, const char *str); +char *tracefs_instance_file_read(struct tracefs_instance *instance, + char *file, int *psize); + #endif /* _TRACE_FS_H */ diff --git a/lib/tracefs/Makefile b/lib/tracefs/Makefile index 86d7845..4030272 100644 --- a/lib/tracefs/Makefile +++ b/lib/tracefs/Makefile @@ -8,6 +8,7 @@ DEFAULT_TARGET = $(bdir)/libtracefs.a OBJS = OBJS += tracefs-utils.o +OBJS += tracefs-instance.o OBJS := $(OBJS:%.o=$(bdir)/%.o) DEPS := $(OBJS:$(bdir)/%.o=$(bdir)/.%.d) diff --git a/lib/tracefs/include/tracefs-local.h b/lib/tracefs/include/tracefs-local.h index 231edd1..fe327a0 100644 --- a/lib/tracefs/include/tracefs-local.h +++ b/lib/tracefs/include/tracefs-local.h @@ -8,5 +8,6 @@ /* Can be overridden */ void warning(const char *fmt, ...); +int str_read_file(const char *file, char **buffer); #endif /* _TRACE_FS_LOCAL_H */ diff --git a/lib/tracefs/tracefs-instance.c b/lib/tracefs/tracefs-instance.c new file mode 100644 index 0000000..b96ab61 --- /dev/null +++ b/lib/tracefs/tracefs-instance.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2008, 2009, 2010 Red Hat Inc, Steven Rostedt + * + * Updates: + * Copyright (C) 2019, VMware, Tzvetomir Stoyanov + * + */ + +#include +#include +#include +#include +#include +#include + +#include "tracefs.h" +#include "tracefs-local.h" + +struct tracefs_instance { + char *name; +}; + +/** + * tracefs_instance_alloc - allocate a new ftrace instance + * @name: The name of the instance (instance will point to this) + * + * Returns a newly allocated instance, or NULL in case of an error. + */ +struct tracefs_instance *tracefs_instance_alloc(const char *name) +{ + struct tracefs_instance *instance; + + instance = calloc(1, sizeof(*instance)); + if (instance && name) { + instance->name = strdup(name); + if (!instance->name) { + free(instance); + instance = NULL; + } + } + + return instance; +} + +/** + * tracefs_instance_free - Free an instance, previously allocated by + tracefs_instance_alloc() + * @instance: Pointer to the instance to be freed + * + */ +void tracefs_instance_free(struct tracefs_instance *instance) +{ + if (!instance) + return; + free(instance->name); + free(instance); +} + +/** + * tracefs_instance_create - Create a new ftrace instance + * @instance: Pointer to the instance to be created + * + * Returns 1 if the instance already exist, 0 if the instance + * is created successful or -1 in case of an error + */ +int tracefs_instance_create(struct tracefs_instance *instance) +{ + struct stat st; + char *path; + int ret; + + path = tracefs_instance_get_dir(instance); + ret = stat(path, &st); + if (ret < 0) + ret = mkdir(path, 0777); + else + ret = 1; + tracefs_put_tracing_file(path); + return ret; +} + +/** + * tracefs_instance_destroy - Remove a ftrace instance + * @instance: Pointer to the instance to be removed + * + * Returns -1 in case of an error, or 0 otherwise. + */ +int tracefs_instance_destroy(struct tracefs_instance *instance) +{ + char *path; + int ret = -1; + + if (!instance || !instance->name) { + warning("Cannot remove top instance"); + return -1; + } + + path = tracefs_instance_get_dir(instance); + if (path) + ret = rmdir(path); + tracefs_put_tracing_file(path); + + return ret; +} + +/** + * tracefs_instance_get_file - return the path to an instance file. + * @instance: ftrace instance, can be NULL for the top instance + * @file: name of file to return + * + * Returns the path of the @file for the given @instance, or NULL in + * case of an error. + * + * Must use tracefs_put_tracing_file() to free the returned string. + */ +char * +tracefs_instance_get_file(struct tracefs_instance *instance, const char *file) +{ + char *path; + char *buf; + int ret; + + if (instance && instance->name) { + ret = asprintf(&buf, "instances/%s/%s", instance->name, file); + if (ret < 0) + return NULL; + path = tracefs_get_tracing_file(buf); + free(buf); + } else + path = tracefs_get_tracing_file(file); + + return path; +} + +/** + * tracefs_instance_get_dir - return the path to the instance directory. + * @instance: ftrace instance, can be NULL for the top instance + * + * Returns the full path to the instance directory + * + * Must use tracefs_put_tracing_file() to free the returned string. + */ +char *tracefs_instance_get_dir(struct tracefs_instance *instance) +{ + char *buf; + char *path; + int ret; + + if (instance && instance->name) { + ret = asprintf(&buf, "instances/%s", instance->name); + if (ret < 0) { + warning("Failed to allocate path for instance %s", + instance->name); + return NULL; + } + path = tracefs_get_tracing_file(buf); + free(buf); + } else + path = tracefs_find_tracing_dir(); + + return path; +} + +/** + * tracefs_instance_get_name - return the name of an instance + * @instance: ftrace instance + * + * Returns the name of the given @instance. + * The returned string must *not* be freed. + */ +char *tracefs_instance_get_name(struct tracefs_instance *instance) +{ + if (instance) + return instance->name; + return NULL; +} + +static int write_file(const char *file, const char *str) +{ + int ret; + int fd; + + fd = open(file, O_WRONLY | O_TRUNC); + if (fd < 0) { + warning("Failed to open '%s'", file); + return -1; + } + ret = write(fd, str, strlen(str)); + close(fd); + return ret; +} + + +/** + * tracefs_instance_file_write - Write in trace file of specific instance. + * @instance: ftrace instance, can be NULL for the top instance + * @file: name of the file + * @str: nul terminated string, that will be written in the file. + * + * Returns the number of written bytes, or -1 in case of an error + */ +int tracefs_instance_file_write(struct tracefs_instance *instance, + const char *file, const char *str) +{ + struct stat st; + char *path; + int ret; + + path = tracefs_instance_get_file(instance, file); + if (!path) + return -1; + ret = stat(path, &st); + if (ret == 0) + ret = write_file(path, str); + tracefs_put_tracing_file(path); + + return ret; +} + +/** + * tracefs_instance_file_read - Read from a trace file of specific instance. + * @instance: ftrace instance, can be NULL for the top instance + * @file: name of the file + * @psize: returns the number of bytes read + * + * Returns a pointer to a nul terminated string, read from the file, or NULL in + * case of an error. + * The return string must be freed by free() + */ +char *tracefs_instance_file_read(struct tracefs_instance *instance, + char *file, int *psize) +{ + char *buf = NULL; + int size = 0; + char *path; + + path = tracefs_instance_get_file(instance, file); + if (!path) + return NULL; + + size = str_read_file(path, &buf); + + tracefs_put_tracing_file(path); + if (buf && psize) + *psize = size; + + return buf; +} diff --git a/lib/tracefs/tracefs-utils.c b/lib/tracefs/tracefs-utils.c index 0ef16fc..658c852 100644 --- a/lib/tracefs/tracefs-utils.c +++ b/lib/tracefs/tracefs-utils.c @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include #include "tracefs.h" @@ -181,3 +184,43 @@ void tracefs_put_tracing_file(char *name) { free(name); } + +int str_read_file(const char *file, char **buffer) +{ + char stbuf[BUFSIZ]; + char *buf = NULL; + int size = 0; + char *nbuf; + int fd; + int r; + + fd = open(file, O_RDONLY); + if (fd < 0) { + warning("File %s not found", file); + return -1; + } + + do { + r = read(fd, stbuf, BUFSIZ); + if (r <= 0) + continue; + nbuf = realloc(buf, size+r+1); + if (!nbuf) { + warning("Failed to allocate file buffer"); + size = -1; + break; + } + buf = nbuf; + memcpy(buf+size, stbuf, r); + size += r; + } while (r > 0); + + close(fd); + if (r == 0 && size > 0) { + buf[size] = '\0'; + *buffer = buf; + } else + free(buf); + + return size; +} diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index fedc0b7..c7310e5 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -181,7 +181,7 @@ struct pid_addr_maps { struct buffer_instance { struct buffer_instance *next; - const char *name; + struct tracefs_instance *tracefs; char *cpumask; struct event_list *events; struct event_list **event_next; @@ -225,6 +225,8 @@ struct buffer_instance { bool use_fifos; }; +void init_top_instance(void); + extern struct buffer_instance top_instance; extern struct buffer_instance *buffer_instances; extern struct buffer_instance *first_instance; @@ -238,7 +240,6 @@ extern struct buffer_instance *first_instance; struct buffer_instance *create_instance(const char *name); void add_instance(struct buffer_instance *instance, int cpu_count); -char *get_instance_file(struct buffer_instance *instance, const char *file); void update_first_instance(struct buffer_instance *instance, int topt); void show_instance_file(struct buffer_instance *instance, const char *name); diff --git a/tracecmd/trace-list.c b/tracecmd/trace-list.c index 86e3358..7b3b9df 100644 --- a/tracecmd/trace-list.c +++ b/tracecmd/trace-list.c @@ -34,7 +34,7 @@ void show_instance_file(struct buffer_instance *instance, const char *name) { char *path; - path = get_instance_file(instance, name); + path = tracefs_instance_get_file(instance->tracefs, name); dump_file_content(path); tracefs_put_tracing_file(path); } diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index 5355813..80ca03f 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -174,7 +174,7 @@ static struct reset_file *reset_files; /* Triggers need to be cleared in a special way */ static struct reset_file *reset_triggers; -struct buffer_instance top_instance = { .flags = BUFFER_FL_KEEP }; +struct buffer_instance top_instance; struct buffer_instance *buffer_instances; struct buffer_instance *first_instance; @@ -372,7 +372,11 @@ struct buffer_instance *create_instance(const char *name) if (!instance) return NULL; memset(instance, 0, sizeof(*instance)); - instance->name = name; + instance->tracefs = tracefs_instance_alloc(name); + if (!instance->tracefs) { + free(instance); + return NULL; + } return instance; } @@ -472,7 +476,7 @@ void tracecmd_stat_cpu_instance(struct buffer_instance *instance, return; snprintf(file, 40, "per_cpu/cpu%d/stats", cpu); - path = get_instance_file(instance, file); + path = tracefs_instance_get_file(instance->tracefs, file); free(file); fd = open(path, O_RDONLY); tracefs_put_tracing_file(path); @@ -511,10 +515,11 @@ static void reset_event_list(struct buffer_instance *instance) static char *get_temp_file(struct buffer_instance *instance, int cpu) { - const char *name = instance->name; + const char *name; char *file = NULL; int size; + name = tracefs_instance_get_name(instance->tracefs); if (name) { size = snprintf(file, 0, "%s.%s.cpu%d", output_file, name, cpu); file = malloc(size + 1); @@ -558,9 +563,10 @@ static void put_temp_file(char *file) static void delete_temp_file(struct buffer_instance *instance, int cpu) { - const char *name = instance->name; + const char *name; char file[PATH_MAX]; + name = tracefs_instance_get_name(instance->tracefs); if (name) snprintf(file, PATH_MAX, "%s.%s.cpu%d", output_file, name, cpu); else @@ -784,54 +790,6 @@ static int set_ftrace(int set, int use_proc) return 0; } -/** - * get_instance_file - return the path to a instance file. - * @instance: buffer instance for the file - * @file: name of file to return - * - * Returns the path name of the @file for the given @instance. - * - * Must use tracefs_put_tracing_file() to free the returned string. - */ -char * -get_instance_file(struct buffer_instance *instance, const char *file) -{ - char *buf; - char *path; - int ret; - - if (instance->name) { - ret = asprintf(&buf, "instances/%s/%s", instance->name, file); - if (ret < 0) - die("Failed to allocate name for %s/%s", instance->name, file); - path = tracefs_get_tracing_file(buf); - free(buf); - } else - path = tracefs_get_tracing_file(file); - - return path; -} - -static char * -get_instance_dir(struct buffer_instance *instance) -{ - char *buf; - char *path; - int ret; - - /* only works for instances */ - if (!instance->name) - return NULL; - - ret = asprintf(&buf, "instances/%s", instance->name); - if (ret < 0) - die("Failed to allocate for instance %s", instance->name); - path = tracefs_get_tracing_file(buf); - free(buf); - - return path; -} - static int write_file(const char *file, const char *str, const char *type) { char buf[BUFSIZ]; @@ -857,23 +815,6 @@ static int write_file(const char *file, const char *str, const char *type) return ret; } -static int -write_instance_file(struct buffer_instance *instance, - const char *file, const char *str, const char *type) -{ - struct stat st; - char *path; - int ret; - - path = get_instance_file(instance, file); - ret = stat(path, &st); - if (ret == 0) - ret = write_file(path, str, type); - tracefs_put_tracing_file(path); - - return ret; -} - static void __clear_trace(struct buffer_instance *instance) { FILE *fp; @@ -883,7 +824,7 @@ static void __clear_trace(struct buffer_instance *instance) return; /* reset the trace */ - path = get_instance_file(instance, "trace"); + path = tracefs_instance_get_file(instance->tracefs, "trace"); fp = fopen(path, "w"); if (!fp) die("writing to '%s'", path); @@ -917,8 +858,8 @@ static void clear_trace(void) static void reset_max_latency(struct buffer_instance *instance) { - write_instance_file(instance, - "tracing_max_latency", "0", "max_latency"); + tracefs_instance_file_write(instance->tracefs, + "tracing_max_latency", "0"); } static void add_filter_pid(int pid, int exclude) @@ -1364,7 +1305,8 @@ static void add_event_pid(const char *buf) struct buffer_instance *instance; for_all_instances(instance) - write_instance_file(instance, "set_event_pid", buf, "event_pid"); + tracefs_instance_file_write(instance->tracefs, + "set_event_pid", buf); } static void add_new_filter_pid(int pid) @@ -1593,7 +1535,7 @@ set_plugin_instance(struct buffer_instance *instance, const char *name) if (is_guest(instance)) return; - path = get_instance_file(instance, "current_tracer"); + path = tracefs_instance_get_file(instance->tracefs, "current_tracer"); fp = fopen(path, "w"); if (!fp) { /* @@ -1617,7 +1559,7 @@ set_plugin_instance(struct buffer_instance *instance, const char *name) /* Make sure func_stack_trace option is disabled */ /* First try instance file, then top level */ - path = get_instance_file(instance, "options/func_stack_trace"); + path = tracefs_instance_get_file(instance->tracefs, "options/func_stack_trace"); fp = fopen(path, "w"); if (!fp) { tracefs_put_tracing_file(path); @@ -1678,8 +1620,6 @@ static int set_option(const char *option) return 0; } -static char *read_instance_file(struct buffer_instance *instance, char *file, int *psize); - static void disable_func_stack_trace_instance(struct buffer_instance *instance) { struct stat st; @@ -1692,13 +1632,14 @@ static void disable_func_stack_trace_instance(struct buffer_instance *instance) if (is_guest(instance)) return; - path = get_instance_file(instance, "current_tracer"); + path = tracefs_instance_get_file(instance->tracefs, "current_tracer"); ret = stat(path, &st); tracefs_put_tracing_file(path); if (ret < 0) return; - content = read_instance_file(instance, "current_tracer", &size); + content = tracefs_instance_file_read(instance->tracefs, + "current_tracer", &size); cond = strstrip(content); if (memcmp(cond, "function", size - (cond - content)) !=0) goto out; @@ -1851,7 +1792,7 @@ static int trace_check_file_exists(struct buffer_instance *instance, char *file) char *path; int ret; - path = get_instance_file(instance, file); + path = tracefs_instance_get_file(instance->tracefs, file); ret = stat(path, &st); tracefs_put_tracing_file(path); @@ -1930,7 +1871,7 @@ reset_events_instance(struct buffer_instance *instance) } c = '0'; - path = get_instance_file(instance, "events/enable"); + path = tracefs_instance_get_file(instance->tracefs, "events/enable"); fd = open(path, O_WRONLY); if (fd < 0) die("opening to '%s'", path); @@ -1938,7 +1879,7 @@ reset_events_instance(struct buffer_instance *instance) close(fd); tracefs_put_tracing_file(path); - path = get_instance_file(instance, "events/*/filter"); + path = tracefs_instance_get_file(instance->tracefs, "events/*/filter"); globbuf.gl_offs = 0; ret = glob(path, 0, NULL, &globbuf); tracefs_put_tracing_file(path); @@ -2199,7 +2140,7 @@ static int open_instance_fd(struct buffer_instance *instance, int fd; char *path; - path = get_instance_file(instance, file); + path = tracefs_instance_get_file(instance->tracefs, file); fd = open(path, flags); if (fd < 0) { /* instances may not be created yet */ @@ -2508,7 +2449,7 @@ static void set_mask(struct buffer_instance *instance) if (!instance->cpumask) return; - path = get_instance_file(instance, "tracing_cpumask"); + path = tracefs_instance_get_file(instance->tracefs, "tracing_cpumask"); if (!path) die("could not allocate path"); reset_save_file(path, RESET_DEFAULT_PRIO); @@ -2569,7 +2510,8 @@ static void set_clock(struct buffer_instance *instance) return; /* The current clock is in brackets, reset it when we are done */ - content = read_instance_file(instance, "trace_clock", NULL); + content = tracefs_instance_file_read(instance->tracefs, + "trace_clock", NULL); /* check if first clock is set */ if (*content == '[') @@ -2580,13 +2522,14 @@ static void set_clock(struct buffer_instance *instance) die("Can not find clock in trace_clock"); str = strtok(NULL, "]"); } - path = get_instance_file(instance, "trace_clock"); + path = tracefs_instance_get_file(instance->tracefs, "trace_clock"); add_reset_file(path, str, RESET_DEFAULT_PRIO); free(content); tracefs_put_tracing_file(path); - write_instance_file(instance, "trace_clock", instance->clock, "clock"); + tracefs_instance_file_write(instance->tracefs, + "trace_clock", instance->clock); } static void set_max_graph_depth(struct buffer_instance *instance, char *max_graph_depth) @@ -2597,11 +2540,11 @@ static void set_max_graph_depth(struct buffer_instance *instance, char *max_grap if (is_guest(instance)) return; - path = get_instance_file(instance, "max_graph_depth"); + path = tracefs_instance_get_file(instance->tracefs, "max_graph_depth"); reset_save_file(path, RESET_DEFAULT_PRIO); tracefs_put_tracing_file(path); - ret = write_instance_file(instance, "max_graph_depth", max_graph_depth, - NULL); + ret = tracefs_instance_file_write(instance->tracefs, "max_graph_depth", + max_graph_depth); if (ret < 0) die("could not write to max_graph_depth"); } @@ -2718,7 +2661,7 @@ static int expand_event_files(struct buffer_instance *instance, if (ret < 0) die("Failed to allocate event filter path for %s", file); - path = get_instance_file(instance, p); + path = tracefs_instance_get_file(instance->tracefs, p); globbuf.gl_offs = 0; ret = glob(path, 0, NULL, &globbuf); @@ -3180,10 +3123,7 @@ create_recorder_instance_pipe(struct buffer_instance *instance, unsigned flags = recorder_flags | TRACECMD_RECORD_BLOCK; char *path; - if (instance->name) - path = get_instance_dir(instance); - else - path = tracefs_find_tracing_dir(); + path = tracefs_instance_get_dir(instance->tracefs); if (!path) die("malloc"); @@ -3193,8 +3133,7 @@ create_recorder_instance_pipe(struct buffer_instance *instance, recorder = tracecmd_create_buffer_recorder_fd(brass[1], cpu, flags, path); - if (instance->name) - tracefs_put_tracing_file(path); + tracefs_put_tracing_file(path); return recorder; } @@ -3228,10 +3167,10 @@ create_recorder_instance(struct buffer_instance *instance, const char *file, int if (brass) return create_recorder_instance_pipe(instance, cpu, brass); - if (!instance->name) + if (!tracefs_instance_get_name(instance->tracefs)) return tracecmd_create_recorder_maxkb(file, cpu, recorder_flags, max_kb); - path = get_instance_dir(instance); + path = tracefs_instance_get_dir(instance->tracefs); record = tracecmd_create_buffer_recorder_maxkb(file, cpu, recorder_flags, path, max_kb); @@ -3285,8 +3224,8 @@ static int create_recorder(struct buffer_instance *instance, int cpu, } if (fd < 0) die("Failed connecting to client"); - if (instance->name && !is_agent(instance)) - path = get_instance_dir(instance); + if (tracefs_instance_get_name(instance->tracefs) && !is_agent(instance)) + path = tracefs_instance_get_dir(instance->tracefs); else path = tracefs_find_tracing_dir(); recorder = tracecmd_create_buffer_recorder_fd(fd, cpu, flags, path); @@ -3597,9 +3536,11 @@ static void connect_to_agent(struct buffer_instance *instance) unsigned int *ports; int i, *fds = NULL; bool use_fifos = false; + char *name; + name = tracefs_instance_get_name(instance->tracefs); if (!no_fifos) { - nr_fifos = open_guest_fifos(instance->name, &fds); + nr_fifos = open_guest_fifos(name, &fds); use_fifos = nr_fifos > 0; } @@ -3626,7 +3567,7 @@ static void connect_to_agent(struct buffer_instance *instance) if (nr_cpus != nr_fifos) { warning("number of FIFOs (%d) for guest %s differs " "from number of virtual CPUs (%d)", - nr_fifos, instance->name, nr_cpus); + nr_fifos, name, nr_cpus); nr_cpus = nr_cpus < nr_fifos ? nr_cpus : nr_fifos; } free(ports); @@ -3652,7 +3593,8 @@ static void setup_guest(struct buffer_instance *instance) int fd; /* Create a place to store the guest meta data */ - file = get_guest_file(output_file, instance->name); + file = get_guest_file(output_file, + tracefs_instance_get_name(instance->tracefs)); if (!file) die("Failed to allocate memory"); @@ -3828,7 +3770,8 @@ add_buffer_stat(struct tracecmd_output *handle, struct buffer_instance *instance int i; trace_seq_init(&s); - trace_seq_printf(&s, "\nBuffer: %s\n\n", instance->name); + trace_seq_printf(&s, "\nBuffer: %s\n\n", + tracefs_instance_get_name(instance->tracefs)); tracecmd_add_option(handle, TRACECMD_OPTION_CPUSTAT, s.len+1, s.buffer); trace_seq_destroy(&s); @@ -3894,7 +3837,8 @@ static void print_stat(struct buffer_instance *instance) return; if (!is_top_instance(instance)) - printf("\nBuffer: %s\n\n", instance->name); + printf("\nBuffer: %s\n\n", + tracefs_instance_get_name(instance->tracefs)); for (cpu = 0; cpu < instance->cpu_count; cpu++) trace_seq_do_printf(&instance->s_print[cpu]); @@ -3934,7 +3878,8 @@ static void write_guest_file(struct buffer_instance *instance) char **temp_files; int i, fd; - file = get_guest_file(output_file, instance->name); + file = get_guest_file(output_file, + tracefs_instance_get_name(instance->tracefs)); if (!file) die("Failed to allocate memory"); @@ -4050,7 +3995,7 @@ static void record_data(struct common_record_context *ctx) continue; buffer_options[i++] = tracecmd_add_buffer_option(handle, - instance->name, + tracefs_instance_get_name(instance->tracefs), cpus); add_buffer_stat(handle, instance); } @@ -4097,7 +4042,7 @@ static int write_func_file(struct buffer_instance *instance, if (!*list) return 0; - path = get_instance_file(instance, file); + path = tracefs_instance_get_file(instance->tracefs, file); fd = open(path, O_WRONLY | O_TRUNC); if (fd < 0) @@ -4141,7 +4086,7 @@ static int functions_filtered(struct buffer_instance *instance) char *path; int fd; - path = get_instance_file(instance, "set_ftrace_filter"); + path = tracefs_instance_get_file(instance->tracefs, "set_ftrace_filter"); fd = open(path, O_RDONLY); tracefs_put_tracing_file(path); if (fd < 0) { @@ -4149,7 +4094,7 @@ static int functions_filtered(struct buffer_instance *instance) warning("Can not set set_ftrace_filter"); else warning("Can not set set_ftrace_filter for %s", - instance->name); + tracefs_instance_get_name(instance->tracefs)); return 0; } @@ -4309,45 +4254,9 @@ static unsigned long long find_time_stamp(struct tep_handle *pevent) return ts; } -static char *read_instance_file(struct buffer_instance *instance, char *file, int *psize) -{ - char buffer[BUFSIZ]; - char *path; - char *buf; - int size = 0; - int fd; - int r; - - path = get_instance_file(instance, file); - fd = open(path, O_RDONLY); - tracefs_put_tracing_file(path); - if (fd < 0) { - warning("%s not found, --date ignored", file); - return NULL; - } - do { - r = read(fd, buffer, BUFSIZ); - if (r <= 0) - continue; - if (size) - buf = realloc(buf, size+r+1); - else - buf = malloc(r+1); - if (!buf) - die("Failed to allocate instance file buffer"); - memcpy(buf+size, buffer, r); - size += r; - } while (r); - - buf[size] = '\0'; - if (psize) - *psize = size; - return buf; -} - static char *read_file(char *file, int *psize) { - return read_instance_file(&top_instance, file, psize); + return tracefs_instance_file_read(top_instance.tracefs, file, psize); } /* @@ -4480,7 +4389,7 @@ static void set_buffer_size_instance(struct buffer_instance *instance) snprintf(buf, BUFSIZ, "%d", buffer_size); - path = get_instance_file(instance, "buffer_size_kb"); + path = tracefs_instance_get_file(instance->tracefs, "buffer_size_kb"); fd = open(path, O_WRONLY); if (fd < 0) { warning("can't open %s", path); @@ -4541,7 +4450,7 @@ static void clear_instance_triggers(struct buffer_instance *instance) enum event_iter_type type; enum event_process processed = PROCESSED_NONE; - path = get_instance_file(instance, "events"); + path = tracefs_instance_get_file(instance->tracefs, "events"); if (!path) die("malloc"); @@ -4602,7 +4511,7 @@ static void clear_instance_filters(struct buffer_instance *instance) enum event_iter_type type; enum event_process processed = PROCESSED_NONE; - path = get_instance_file(instance, "events"); + path = tracefs_instance_get_file(instance->tracefs, "events"); if (!path) die("malloc"); @@ -4638,7 +4547,8 @@ static void reset_clock(void) struct buffer_instance *instance; for_all_instances(instance) - write_instance_file(instance, "trace_clock", "local", "clock"); + tracefs_instance_file_write(instance->tracefs, + "trace_clock", "local"); } static void reset_cpu_mask(void) @@ -4657,7 +4567,8 @@ static void reset_cpu_mask(void) strcat(buf, ",ffffffff"); for_all_instances(instance) - write_instance_file(instance, "tracing_cpumask", buf, "cpumask"); + tracefs_instance_file_write(instance->tracefs, + "tracing_cpumask", buf); } static void reset_event_pid(void) @@ -4686,7 +4597,7 @@ static void clear_func_filters(void) for_all_instances(instance) { for (i = 0; files[i]; i++) { - path = get_instance_file(instance, files[i]); + path = tracefs_instance_get_file(instance->tracefs, files[i]); clear_func_filter(path); tracefs_put_tracing_file(path); } @@ -4696,32 +4607,20 @@ static void clear_func_filters(void) static void make_instances(void) { struct buffer_instance *instance; - struct stat st; - char *path; - int ret; for_each_instance(instance) { if (is_guest(instance)) continue; - - path = get_instance_dir(instance); - ret = stat(path, &st); - if (ret < 0) { - ret = mkdir(path, 0777); - if (ret < 0) - die("mkdir %s", path); - } else + if (tracefs_instance_create(instance->tracefs) > 0) { /* Don't delete instances that already exist */ instance->flags |= BUFFER_FL_KEEP; - tracefs_put_tracing_file(path); + } } } void tracecmd_remove_instances(void) { struct buffer_instance *instance; - char *path; - int ret; for_each_instance(instance) { /* Only delete what we created */ @@ -4731,11 +4630,7 @@ void tracecmd_remove_instances(void) close(instance->tracing_on_fd); instance->tracing_on_fd = 0; } - path = get_instance_dir(instance); - ret = rmdir(path); - if (ret < 0) - die("rmdir %s", path); - tracefs_put_tracing_file(path); + tracefs_instance_destroy(instance->tracefs); } } @@ -5029,7 +4924,8 @@ static int test_stacktrace_trigger(struct buffer_instance *instance) int ret = 0; int fd; - path = get_instance_file(instance, "events/sched/sched_switch/trigger"); + path = tracefs_instance_get_file(instance->tracefs, + "events/sched/sched_switch/trigger"); clear_trigger(path); @@ -5211,6 +5107,15 @@ void update_first_instance(struct buffer_instance *instance, int topt) first_instance = buffer_instances; } +void init_top_instance(void) +{ + if (!top_instance.tracefs) + top_instance.tracefs = tracefs_instance_alloc(NULL); + top_instance.cpu_count = count_cpus(); + top_instance.flags = BUFFER_FL_KEEP; + init_instance(&top_instance); +} + enum { OPT_user = 243, OPT_procmap = 244, @@ -5235,7 +5140,7 @@ void trace_stop(int argc, char **argv) int topt = 0; struct buffer_instance *instance = &top_instance; - init_instance(instance); + init_top_instance(); for (;;) { int c; @@ -5276,7 +5181,7 @@ void trace_restart(int argc, char **argv) int topt = 0; struct buffer_instance *instance = &top_instance; - init_instance(instance); + init_top_instance(); for (;;) { int c; @@ -5318,7 +5223,7 @@ void trace_reset(int argc, char **argv) int topt = 0; struct buffer_instance *instance = &top_instance; - init_instance(instance); + init_top_instance(); /* if last arg is -a, then -b and -d apply to all instances */ int last_specified_all = 0; @@ -5403,9 +5308,8 @@ static void init_common_record_context(struct common_record_context *ctx, memset(ctx, 0, sizeof(*ctx)); ctx->instance = &top_instance; ctx->curr_cmd = curr_cmd; - init_instance(ctx->instance); local_cpu_count = count_cpus(); - ctx->instance->cpu_count = local_cpu_count; + init_top_instance(); } #define IS_EXTRACT(ctx) ((ctx)->curr_cmd == CMD_extract) diff --git a/tracecmd/trace-show.c b/tracecmd/trace-show.c index 391d329..a6f2102 100644 --- a/tracecmd/trace-show.c +++ b/tracecmd/trace-show.c @@ -52,6 +52,8 @@ void trace_show(int argc, char **argv) {NULL, 0, NULL, 0} }; + init_top_instance(); + while ((c = getopt_long(argc-1, argv+1, "B:c:fsp", long_options, &option_index)) >= 0) { switch (c) { diff --git a/tracecmd/trace-stat.c b/tracecmd/trace-stat.c index 7a1d9bb..0db3bac 100644 --- a/tracecmd/trace-stat.c +++ b/tracecmd/trace-stat.c @@ -31,7 +31,7 @@ static int get_instance_file_fd(struct buffer_instance *instance, char *path; int fd; - path = get_instance_file(instance, file); + path = tracefs_instance_get_file(instance->tracefs, file); fd = open(path, O_RDONLY); tracefs_put_tracing_file(path); @@ -348,7 +348,7 @@ static void report_events(struct buffer_instance *instance) free(str); - path = get_instance_file(instance, "events"); + path = tracefs_instance_get_file(instance->tracefs, "events"); if (!path) die("malloc"); @@ -437,7 +437,7 @@ static void report_event_filters(struct buffer_instance *instance) enum event_iter_type type; enum event_process processed = PROCESSED_NONE; - path = get_instance_file(instance, "events"); + path = tracefs_instance_get_file(instance->tracefs, "events"); if (!path) die("malloc"); @@ -510,7 +510,7 @@ static void report_event_triggers(struct buffer_instance *instance) enum event_iter_type type; enum event_process processed = PROCESSED_NONE; - path = get_instance_file(instance, "events"); + path = tracefs_instance_get_file(instance->tracefs, "events"); if (!path) die("malloc"); @@ -599,7 +599,7 @@ static void report_graph_funcs(struct buffer_instance *instance) { char *path; - path = get_instance_file(instance, "set_graph_function"); + path = tracefs_instance_get_file(instance->tracefs, "set_graph_function"); if (!path) die("malloc"); @@ -607,7 +607,7 @@ static void report_graph_funcs(struct buffer_instance *instance) tracefs_put_tracing_file(path); - path = get_instance_file(instance, "set_graph_notrace"); + path = tracefs_instance_get_file(instance->tracefs, "set_graph_notrace"); if (!path) die("malloc"); @@ -620,7 +620,7 @@ static void report_ftrace_filters(struct buffer_instance *instance) { char *path; - path = get_instance_file(instance, "set_ftrace_filter"); + path = tracefs_instance_get_file(instance->tracefs, "set_ftrace_filter"); if (!path) die("malloc"); @@ -628,7 +628,7 @@ static void report_ftrace_filters(struct buffer_instance *instance) tracefs_put_tracing_file(path); - path = get_instance_file(instance, "set_ftrace_notrace"); + path = tracefs_instance_get_file(instance->tracefs, "set_ftrace_notrace"); if (!path) die("malloc"); @@ -858,7 +858,8 @@ static void stat_instance(struct buffer_instance *instance) if (instance != &top_instance) { if (instance != first_instance) printf("---------------\n"); - printf("Instance: %s\n", instance->name); + printf("Instance: %s\n", + tracefs_instance_get_name(instance->tracefs)); } report_plugin(instance); @@ -883,6 +884,8 @@ void trace_stat (int argc, char **argv) int status; int c; + init_top_instance(); + for (;;) { c = getopt(argc-1, argv+1, "tB:"); if (c == -1) From patchwork Fri Jan 17 13:55:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11339235 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1B19E1820 for ; Fri, 17 Jan 2020 13:55:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id EE0362073A for ; Fri, 17 Jan 2020 13:55:54 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ucTBfowe" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727033AbgAQNzy (ORCPT ); Fri, 17 Jan 2020 08:55:54 -0500 Received: from mail-lj1-f176.google.com ([209.85.208.176]:36728 "EHLO mail-lj1-f176.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727403AbgAQNzy (ORCPT ); Fri, 17 Jan 2020 08:55:54 -0500 Received: by mail-lj1-f176.google.com with SMTP id r19so26565344ljg.3 for ; Fri, 17 Jan 2020 05:55:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=21WzK31KLgIoTmE5fsUo1wFfOIx2PiWLYUX3LC88q9o=; b=ucTBfoweC/koZNpKSTQ61+B4NxzWBValrkbEbyjeUWs5KWjZ/M8okRxYCk5UP7HqiJ 4sVnsjkIQrbfuiTS1ml9jhndSDVT4Q+RN8VatovsKZ2j5OhodY/UwwvFhANGrJpUM/Xd FsOCuWkkscTig7tOtklXCGD0GBYgA1pq9xEKz+tiXjmEVlLAmz87txT3giimGGk9b71b sCeQmtY/HYY9MSxjTzdxlZrVSfFLWyea+PTr05zKCliBwIdGAn11Hx5qgT/rcCgEgupx roieQ0HEmCz383gMFhk2nhZlkm8IuZqkQlixtWFB4VHCPI/oNmhpUISpiqct0vZ18pUA Z0nA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=21WzK31KLgIoTmE5fsUo1wFfOIx2PiWLYUX3LC88q9o=; b=DfX3+439Q+2fmTGlMqRuVjwCY6XsOuUl3DWMnkMrV94nkC80lVeFYqClymapMOh5eN 7vX+f2kyEeXMcux+liUnC9xNvr9ODvpPGMYt5IMDRA1GDL2dEwszN10dqea00W0OUa26 bbdpZ6YqrKYU/TIxDNjth4ZttnabxYr/0DehocLoYLVokZk02tjDY15NN2kX4vPtewGM 7hj1xKXFkV7pegLvZlmeiFE/QIqcXR9wr9dvgNIM0RLASrdLuh6kC2hqyFIdncq/qTkP jt/k0jHDofBqPvxTjNxgbpSeT6rw16AV7GMkJraTIlco4Kkg4+4JizZbwLRJ7TqbYOQ2 lwmA== X-Gm-Message-State: APjAAAVfgNnxZngI/UFl39I9DTud+X9/0yq9iD7SdgBebauqgYGoWxwv ywTW11l3I05aipbnfForPDvM2vpg X-Google-Smtp-Source: APXvYqyokWJPFuiXR7X2R8arNwQUg27KwjWACj5RFXb66qpUCc7ieC/1/Q2v2V7f91dLkZoVH4iH4w== X-Received: by 2002:a2e:9804:: with SMTP id a4mr5535183ljj.10.1579269351270; Fri, 17 Jan 2020 05:55:51 -0800 (PST) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id 21sm12422562ljv.19.2020.01.17.05.55.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jan 2020 05:55:50 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 3/5] trace-cmd,kernel-shark: New libtracefs APIs for ftrace events and systems Date: Fri, 17 Jan 2020 15:55:42 +0200 Message-Id: <20200117135544.598235-4-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200117135544.598235-1-tz.stoyanov@gmail.com> References: <20200117135544.598235-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The functionality related to ftrace events and systems is moved from trace-cmd application and libtracecmd to libtracefs. The following libtracecmd APIs are removed: tracecmd_read_page_record(); tracecmd_event_systems(); tracecmd_system_events(); tracecmd_local_plugins(); tracecmd_add_list(); tracecmd_free_list(); The following new library APIs are introduced: tracefs_read_page_record(); tracefs_event_systems(); tracefs_system_events(); tracefs_local_plugins(); tracefs_iterate_raw_events(); tracefs_list_free(); Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/trace-cmd/trace-cmd.h | 8 - include/tracefs/tracefs.h | 16 + kernel-shark/src/KsCaptureDialog.cpp | 2 +- lib/trace-cmd/trace-input.c | 95 ------ lib/trace-cmd/trace-util.c | 265 ---------------- lib/tracefs/Makefile | 1 + lib/tracefs/tracefs-events.c | 442 +++++++++++++++++++++++++++ tracecmd/trace-record.c | 107 ++----- 8 files changed, 484 insertions(+), 452 deletions(-) create mode 100644 lib/tracefs/tracefs-events.c diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index 66736ae..30bb144 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -24,15 +24,10 @@ void tracecmd_parse_ftrace_printk(struct tep_handle *pevent, char *file, unsigne extern int tracecmd_disable_sys_plugins; extern int tracecmd_disable_plugins; -char **tracecmd_event_systems(const char *tracing_dir); -char **tracecmd_system_events(const char *tracing_dir, const char *system); struct tep_handle *tracecmd_local_events(const char *tracing_dir); int tracecmd_fill_local_events(const char *tracing_dir, struct tep_handle *pevent, int *parsing_failures); -char **tracecmd_local_plugins(const char *tracing_dir); -char **tracecmd_add_list(char **list, const char *name, int len); -void tracecmd_free_list(char **list); int *tracecmd_add_id(int *list, int id, int len); enum { @@ -143,9 +138,6 @@ void tracecmd_print_stats(struct tracecmd_input *handle); void tracecmd_print_uname(struct tracecmd_input *handle); void tracecmd_print_version(struct tracecmd_input *handle); -struct tep_record * -tracecmd_read_page_record(struct tep_handle *pevent, void *page, int size, - struct tep_record *last_record); struct tep_record * tracecmd_peek_data(struct tracecmd_input *handle, int cpu); diff --git a/include/tracefs/tracefs.h b/include/tracefs/tracefs.h index bdeb8e8..d86482b 100644 --- a/include/tracefs/tracefs.h +++ b/include/tracefs/tracefs.h @@ -33,4 +33,20 @@ int tracefs_instance_file_write(struct tracefs_instance *instance, char *tracefs_instance_file_read(struct tracefs_instance *instance, char *file, int *psize); +/* events */ +struct tep_record * +tracefs_read_page_record(struct tep_handle *tep, void *page, int size, + struct tep_record *last_record); +void tracefs_list_free(char **list); +char **tracefs_event_systems(const char *tracing_dir); +char **tracefs_system_events(const char *tracing_dir, const char *system); +int tracefs_iterate_raw_events(struct tep_handle *tep, + struct tracefs_instance *instance, + int (*callback)(struct tep_event *, + struct tep_record *, + int, void *), + void *callback_context); + +char **tracefs_tracers(const char *tracing_dir); + #endif /* _TRACE_FS_H */ diff --git a/kernel-shark/src/KsCaptureDialog.cpp b/kernel-shark/src/KsCaptureDialog.cpp index 548b6fb..529fa77 100644 --- a/kernel-shark/src/KsCaptureDialog.cpp +++ b/kernel-shark/src/KsCaptureDialog.cpp @@ -204,7 +204,7 @@ QStringList KsCaptureControl::_getPlugins() QStringList pluginList; char **all_plugins; - all_plugins = tracecmd_local_plugins(tracefs_get_tracing_dir()); + all_plugins = tracefs_tracers(tracefs_get_tracing_dir()); if (!all_plugins) return pluginList; diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c index 3b187e3..67c7236 100644 --- a/lib/trace-cmd/trace-input.c +++ b/lib/trace-cmd/trace-input.c @@ -1663,101 +1663,6 @@ tracecmd_translate_data(struct tracecmd_input *handle, return record; } -/** - * tracecmd_read_page_record - read a record off of a page - * @pevent: pevent used to parse the page - * @page: the page to read - * @size: the size of the page - * @last_record: last record read from this page. - * - * If a ring buffer page is available, and the need to parse it - * without having a handle, then this function can be used. - * - * The @pevent needs to be initialized to have the page header information - * already available. - * - * The @last_record is used to know where to read the next record from. - * If @last_record is NULL, the first record on the page will be read. - * - * Returns: - * A newly allocated record that must be freed with free_record() if - * a record is found. Otherwise NULL is returned if the record is bad - * or no more records exist. - */ -struct tep_record * -tracecmd_read_page_record(struct tep_handle *pevent, void *page, int size, - struct tep_record *last_record) -{ - unsigned long long ts; - struct kbuffer *kbuf; - struct tep_record *record = NULL; - enum kbuffer_long_size long_size; - enum kbuffer_endian endian; - void *ptr; - - if (tep_is_file_bigendian(pevent)) - endian = KBUFFER_ENDIAN_BIG; - else - endian = KBUFFER_ENDIAN_LITTLE; - - if (tep_get_header_page_size(pevent) == 8) - long_size = KBUFFER_LSIZE_8; - else - long_size = KBUFFER_LSIZE_4; - - kbuf = kbuffer_alloc(long_size, endian); - if (!kbuf) - return NULL; - - kbuffer_load_subbuffer(kbuf, page); - if (kbuffer_subbuffer_size(kbuf) > size) { - warning("tracecmd_read_page_record: page_size > size"); - goto out_free; - } - - if (last_record) { - if (last_record->data < page || last_record->data >= (page + size)) { - warning("tracecmd_read_page_record: bad last record (size=%u)", - last_record->size); - goto out_free; - } - - ptr = kbuffer_read_event(kbuf, &ts); - while (ptr < last_record->data) { - ptr = kbuffer_next_event(kbuf, NULL); - if (!ptr) - break; - if (ptr == last_record->data) - break; - } - if (ptr != last_record->data) { - warning("tracecmd_read_page_record: could not find last_record"); - goto out_free; - } - ptr = kbuffer_next_event(kbuf, &ts); - } else - ptr = kbuffer_read_event(kbuf, &ts); - - if (!ptr) - goto out_free; - - record = malloc(sizeof(*record)); - if (!record) - return NULL; - memset(record, 0, sizeof(*record)); - - record->ts = ts; - record->size = kbuffer_event_size(kbuf); - record->record_size = kbuffer_curr_size(kbuf); - record->cpu = 0; - record->data = ptr; - record->ref_count = 1; - - out_free: - kbuffer_free(kbuf); - return record; -} - /** * tracecmd_peek_data - return the record at the current location. * @handle: input handle for the trace.dat file diff --git a/lib/trace-cmd/trace-util.c b/lib/trace-cmd/trace-util.c index 1394469..1554e88 100644 --- a/lib/trace-cmd/trace-util.c +++ b/lib/trace-cmd/trace-util.c @@ -153,56 +153,6 @@ static char *append_file(const char *dir, const char *name) return ret < 0 ? NULL : file; } -/** - * tracecmd_add_list - add an new string to a string list. - * @list: list to add the string to (may be NULL) - * @name: the string to add - * @len: current length of list of strings. - * - * The typical usage is: - * - * systems = tracecmd_add_list(systems, name, len++); - * - * Returns the new allocated list with an allocated name added. - * The list will end with NULL. - */ -char **tracecmd_add_list(char **list, const char *name, int len) -{ - if (!list) - list = malloc(sizeof(*list) * 2); - else - list = realloc(list, sizeof(*list) * (len + 2)); - if (!list) - return NULL; - - list[len] = strdup(name); - if (!list[len]) - return NULL; - - list[len + 1] = NULL; - - return list; -} - -/** - * tracecmd_free_list - free a list created with tracecmd_add_list. - * @list: The list to free. - * - * Frees the list as well as the names within the list. - */ -void tracecmd_free_list(char **list) -{ - int i; - - if (!list) - return; - - for (i = 0; list[i]; i++) - free(list[i]); - - free(list); -} - /** * tracecmd_add_id - add an int to the event id list * @list: list to add the id to @@ -233,160 +183,6 @@ int *tracecmd_add_id(int *list, int id, int len) return list; } -/** - * tracecmd_event_systems - return list of systems for tracing - * @tracing_dir: directory holding the "events" directory - * - * Returns an allocated list of system names. Both the names and - * the list must be freed with free(). - * The list returned ends with a "NULL" pointer. - */ -char **tracecmd_event_systems(const char *tracing_dir) -{ - struct dirent *dent; - char **systems = NULL; - char *events_dir; - struct stat st; - DIR *dir; - int len = 0; - int ret; - - if (!tracing_dir) - return NULL; - - events_dir = append_file(tracing_dir, "events"); - if (!events_dir) - return NULL; - - /* - * Search all the directories in the events directory, - * and collect the ones that have the "enable" file. - */ - ret = stat(events_dir, &st); - if (ret < 0 || !S_ISDIR(st.st_mode)) - goto out_free; - - dir = opendir(events_dir); - if (!dir) - goto out_free; - - while ((dent = readdir(dir))) { - const char *name = dent->d_name; - char *enable; - char *sys; - - if (strcmp(name, ".") == 0 || - strcmp(name, "..") == 0) - continue; - - sys = append_file(events_dir, name); - ret = stat(sys, &st); - if (ret < 0 || !S_ISDIR(st.st_mode)) { - free(sys); - continue; - } - - enable = append_file(sys, "enable"); - - ret = stat(enable, &st); - if (ret >= 0) - systems = tracecmd_add_list(systems, name, len++); - - free(enable); - free(sys); - } - - closedir(dir); - - out_free: - free(events_dir); - return systems; -} - -/** - * tracecmd_system_events - return list of events for system - * @tracing_dir: directory holding the "events" directory - * @system: the system to return the events for - * - * Returns an allocated list of event names. Both the names and - * the list must be freed with free(). - * The list returned ends with a "NULL" pointer. - */ -char **tracecmd_system_events(const char *tracing_dir, const char *system) -{ - struct dirent *dent; - char **events = NULL; - char *events_dir; - char *system_dir; - struct stat st; - DIR *dir; - int len = 0; - int ret; - - if (!tracing_dir || !system) - return NULL; - - events_dir = append_file(tracing_dir, "events"); - if (!events_dir) - return NULL; - - /* - * Search all the directories in the systems directory, - * and collect the ones that have the "enable" file. - */ - ret = stat(events_dir, &st); - if (ret < 0 || !S_ISDIR(st.st_mode)) - goto out_free; - - system_dir = append_file(events_dir, system); - if (!system_dir) - goto out_free; - - ret = stat(system_dir, &st); - if (ret < 0 || !S_ISDIR(st.st_mode)) - goto out_free_sys; - - dir = opendir(system_dir); - if (!dir) - goto out_free_sys; - - while ((dent = readdir(dir))) { - const char *name = dent->d_name; - char *enable; - char *event; - - if (strcmp(name, ".") == 0 || - strcmp(name, "..") == 0) - continue; - - event = append_file(system_dir, name); - ret = stat(event, &st); - if (ret < 0 || !S_ISDIR(st.st_mode)) { - free(event); - continue; - } - - enable = append_file(event, "enable"); - - ret = stat(enable, &st); - if (ret >= 0) - events = tracecmd_add_list(events, name, len++); - - free(enable); - free(event); - } - - closedir(dir); - - out_free_sys: - free(system_dir); - - out_free: - free(events_dir); - - return events; -} - static int read_file(const char *file, char **buffer) { char *buf; @@ -604,67 +400,6 @@ int tracecmd_fill_local_events(const char *tracing_dir, return ret; } -/** - * tracecmd_local_plugins - returns an array of available tracer plugins - * @tracing_dir: The directory that contains the tracing directory - * - * Returns an allocate list of plugins. The array ends with NULL. - * Both the plugin names and array must be freed with free(). - */ -char **tracecmd_local_plugins(const char *tracing_dir) -{ - char *available_tracers; - struct stat st; - char **plugins = NULL; - char *buf; - char *str, *saveptr; - char *plugin; - int slen; - int len; - int ret; - - if (!tracing_dir) - return NULL; - - available_tracers = append_file(tracing_dir, "available_tracers"); - if (!available_tracers) - return NULL; - - ret = stat(available_tracers, &st); - if (ret < 0) - goto out_free; - - len = read_file(available_tracers, &buf); - if (len < 0) - goto out_free; - - len = 0; - for (str = buf; ; str = NULL) { - plugin = strtok_r(str, " ", &saveptr); - if (!plugin) - break; - if (!(slen = strlen(plugin))) - continue; - - /* chop off any newlines */ - if (plugin[slen - 1] == '\n') - plugin[slen - 1] = '\0'; - - /* Skip the non tracers */ - if (strcmp(plugin, "nop") == 0 || - strcmp(plugin, "none") == 0) - continue; - - plugins = tracecmd_add_list(plugins, plugin, len++); - } - free(buf); - - out_free: - free(available_tracers); - - return plugins; -} - struct add_plugin_data { int ret; int index; diff --git a/lib/tracefs/Makefile b/lib/tracefs/Makefile index 4030272..5763e06 100644 --- a/lib/tracefs/Makefile +++ b/lib/tracefs/Makefile @@ -9,6 +9,7 @@ DEFAULT_TARGET = $(bdir)/libtracefs.a OBJS = OBJS += tracefs-utils.o OBJS += tracefs-instance.o +OBJS += tracefs-events.o OBJS := $(OBJS:%.o=$(bdir)/%.o) DEPS := $(OBJS:$(bdir)/%.o=$(bdir)/.%.d) diff --git a/lib/tracefs/tracefs-events.c b/lib/tracefs/tracefs-events.c new file mode 100644 index 0000000..3469431 --- /dev/null +++ b/lib/tracefs/tracefs-events.c @@ -0,0 +1,442 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2008, 2009, 2010 Red Hat Inc, Steven Rostedt + * + * Updates: + * Copyright (C) 2019, VMware, Tzvetomir Stoyanov + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include "kbuffer.h" +#include "tracefs.h" +#include "tracefs-local.h" + +static struct kbuffer * +page_to_kbuf(struct tep_handle *tep, void *page, int size) +{ + enum kbuffer_long_size long_size; + enum kbuffer_endian endian; + struct kbuffer *kbuf; + + if (tep_is_file_bigendian(tep)) + endian = KBUFFER_ENDIAN_BIG; + else + endian = KBUFFER_ENDIAN_LITTLE; + + if (tep_get_header_page_size(tep) == 8) + long_size = KBUFFER_LSIZE_8; + else + long_size = KBUFFER_LSIZE_4; + + kbuf = kbuffer_alloc(long_size, endian); + if (!kbuf) + return NULL; + + kbuffer_load_subbuffer(kbuf, page); + if (kbuffer_subbuffer_size(kbuf) > size) { + warning("%s: page_size > size", __func__); + kbuffer_free(kbuf); + kbuf = NULL; + } + + return kbuf; +} + +static int read_kbuf_record(struct kbuffer *kbuf, struct tep_record *record) +{ + unsigned long long ts; + void *ptr; + + ptr = kbuffer_read_event(kbuf, &ts); + if (!ptr || !record) + return -1; + + memset(record, 0, sizeof(*record)); + record->ts = ts; + record->size = kbuffer_event_size(kbuf); + record->record_size = kbuffer_curr_size(kbuf); + record->cpu = 0; + record->data = ptr; + record->ref_count = 1; + + kbuffer_next_event(kbuf, NULL); + + return 0; +} + +static int +get_events_in_page(struct tep_handle *tep, void *page, + int size, int cpu, + int (*callback)(struct tep_event *, + struct tep_record *, + int, void *), + void *callback_context) +{ + struct tep_record record; + struct tep_event *event; + struct kbuffer *kbuf; + int id, cnt = 0; + int ret; + + if (size <= 0) + return 0; + + kbuf = page_to_kbuf(tep, page, size); + if (!kbuf) + return 0; + + ret = read_kbuf_record(kbuf, &record); + while (!ret) { + id = tep_data_type(tep, &record); + event = tep_find_event(tep, id); + if (event) { + cnt++; + if (callback && + callback(event, &record, cpu, callback_context)) + break; + } + ret = read_kbuf_record(kbuf, &record); + } + + kbuffer_free(kbuf); + + return cnt; +} + +/* + * tracefs_iterate_raw_events - Iterate through events in trace_pipe_raw, + * per CPU trace buffers + * @tep: a handle to the trace event parser context + * @instance: ftrace instance, can be NULL for the top instance + * @callback: A user function, called for each record from the file + * @callback_context: A custom context, passed to the user callback function + * + * If the @callback returns non-zero, the iteration stops - in that case all + * records from the current page will be lost from future reads + * + * Returns -1 in case of an error, or 0 otherwise + */ +int tracefs_iterate_raw_events(struct tep_handle *tep, + struct tracefs_instance *instance, + int (*callback)(struct tep_event *, + struct tep_record *, + int, void *), + void *callback_context) +{ + unsigned int p_size; + struct dirent *dent; + char file[PATH_MAX]; + void *page = NULL; + struct stat st; + char *path; + DIR *dir; + int ret; + int cpu; + int fd; + int r; + + if (!tep || !callback) + return -1; + + p_size = getpagesize(); + path = tracefs_instance_get_file(instance, "per_cpu"); + if (!path) + return -1; + dir = opendir(path); + if (!dir) { + ret = -1; + goto error; + } + page = malloc(p_size); + if (!page) { + ret = -1; + goto error; + } + while ((dent = readdir(dir))) { + const char *name = dent->d_name; + + if (strlen(name) < 4 || strncmp(name, "cpu", 3) != 0) + continue; + cpu = atoi(name + 3); + sprintf(file, "%s/%s", path, name); + ret = stat(file, &st); + if (ret < 0 || !S_ISDIR(st.st_mode)) + continue; + + sprintf(file, "%s/%s/trace_pipe_raw", path, name); + fd = open(file, O_RDONLY | O_NONBLOCK); + if (fd < 0) + continue; + do { + r = read(fd, page, p_size); + if (r > 0) + get_events_in_page(tep, page, r, cpu, + callback, callback_context); + } while (r > 0); + close(fd); + } + ret = 0; + +error: + if (dir) + closedir(dir); + free(page); + tracefs_put_tracing_file(path); + return ret; +} + +static char **add_list_string(char **list, const char *name, int len) +{ + if (!list) + list = malloc(sizeof(*list) * 2); + else + list = realloc(list, sizeof(*list) * (len + 2)); + if (!list) + return NULL; + + list[len] = strdup(name); + if (!list[len]) + return NULL; + + list[len + 1] = NULL; + + return list; +} + +static char *append_file(const char *dir, const char *name) +{ + char *file; + int ret; + + ret = asprintf(&file, "%s/%s", dir, name); + + return ret < 0 ? NULL : file; +} + +/** + * tracefs_list_free - free list if strings, returned by APIs + * tracefs_event_systems() + * tracefs_system_events() + * + *@list pointer to a list of strings, the last one must be NULL + */ +void tracefs_list_free(char **list) +{ + int i; + + if (!list) + return; + + for (i = 0; list[i]; i++) + free(list[i]); + + free(list); +} + +/** + * tracefs_event_systems - return list of systems for tracing + * @tracing_dir: directory holding the "events" directory + * if NULL, top tracing directory is used + * + * Returns an allocated list of system names. Both the names and + * the list must be freed with tracefs_list_free() + * The list returned ends with a "NULL" pointer + */ +char **tracefs_event_systems(const char *tracing_dir) +{ + struct dirent *dent; + char **systems = NULL; + char *events_dir; + struct stat st; + DIR *dir; + int len = 0; + int ret; + + if (!tracing_dir) + tracing_dir = tracefs_get_tracing_dir(); + + if (!tracing_dir) + return NULL; + + events_dir = append_file(tracing_dir, "events"); + if (!events_dir) + return NULL; + + /* + * Search all the directories in the events directory, + * and collect the ones that have the "enable" file. + */ + ret = stat(events_dir, &st); + if (ret < 0 || !S_ISDIR(st.st_mode)) + goto out_free; + + dir = opendir(events_dir); + if (!dir) + goto out_free; + + while ((dent = readdir(dir))) { + const char *name = dent->d_name; + char *enable; + char *sys; + + if (strcmp(name, ".") == 0 || + strcmp(name, "..") == 0) + continue; + + sys = append_file(events_dir, name); + ret = stat(sys, &st); + if (ret < 0 || !S_ISDIR(st.st_mode)) { + free(sys); + continue; + } + + enable = append_file(sys, "enable"); + + ret = stat(enable, &st); + if (ret >= 0) + systems = add_list_string(systems, name, len++); + + free(enable); + free(sys); + } + + closedir(dir); + + out_free: + free(events_dir); + return systems; +} + +/** + * tracefs_system_events - return list of events for system + * @tracing_dir: directory holding the "events" directory + * @system: the system to return the events for + * + * Returns an allocated list of event names. Both the names and + * the list must be freed with tracefs_list_free() + * The list returned ends with a "NULL" pointer + */ +char **tracefs_system_events(const char *tracing_dir, const char *system) +{ + struct dirent *dent; + char **events = NULL; + char *system_dir = NULL; + struct stat st; + DIR *dir; + int len = 0; + int ret; + + if (!tracing_dir) + tracing_dir = tracefs_get_tracing_dir(); + + if (!tracing_dir || !system) + return NULL; + + asprintf(&system_dir, "%s/events/%s", tracing_dir, system); + if (!system_dir) + return NULL; + + ret = stat(system_dir, &st); + if (ret < 0 || !S_ISDIR(st.st_mode)) + goto out_free; + + dir = opendir(system_dir); + if (!dir) + goto out_free; + + while ((dent = readdir(dir))) { + const char *name = dent->d_name; + char *event; + + if (strcmp(name, ".") == 0 || + strcmp(name, "..") == 0) + continue; + + event = append_file(system_dir, name); + ret = stat(event, &st); + if (ret < 0 || !S_ISDIR(st.st_mode)) { + free(event); + continue; + } + + events = add_list_string(events, name, len++); + + free(event); + } + + closedir(dir); + + out_free: + free(system_dir); + + return events; +} + +/** + * tracefs_tracers - returns an array of available tracers + * @tracing_dir: The directory that contains the tracing directory + * + * Returns an allocate list of plugins. The array ends with NULL + * Both the plugin names and array must be freed with free() + */ +char **tracefs_tracers(const char *tracing_dir) +{ + char *available_tracers; + struct stat st; + char **plugins = NULL; + char *buf; + char *str, *saveptr; + char *plugin; + int slen; + int len; + int ret; + + if (!tracing_dir) + return NULL; + + available_tracers = append_file(tracing_dir, "available_tracers"); + if (!available_tracers) + return NULL; + + ret = stat(available_tracers, &st); + if (ret < 0) + goto out_free; + + len = str_read_file(available_tracers, &buf); + if (len < 0) + goto out_free; + + len = 0; + for (str = buf; ; str = NULL) { + plugin = strtok_r(str, " ", &saveptr); + if (!plugin) + break; + slen = strlen(plugin); + if (!slen) + continue; + + /* chop off any newlines */ + if (plugin[slen - 1] == '\n') + plugin[slen - 1] = '\0'; + + /* Skip the non tracers */ + if (strcmp(plugin, "nop") == 0 || + strcmp(plugin, "none") == 0) + continue; + + plugins = add_list_string(plugins, plugin, len++); + } + free(buf); + + out_free: + free(available_tracers); + + return plugins; +} diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index 80ca03f..f7d3017 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -4164,96 +4164,35 @@ static void add_func(struct func_list **list, const char *mod, const char *func) *list = item; } -static unsigned long long -find_ts_in_page(struct tep_handle *pevent, void *page, int size) +static int find_ts(struct tep_event *event, struct tep_record *record, + int cpu, void *context) { + unsigned long long *ts = (unsigned long long *)context; struct tep_format_field *field; - struct tep_record *last_record = NULL; - struct tep_record *record; - struct tep_event *event; - unsigned long long ts = 0; - int id; - if (size <= 0) - return 0; + if (!ts) + return -1; - while (!ts) { - record = tracecmd_read_page_record(pevent, page, size, - last_record); - if (!record) - break; - free_record(last_record); - id = tep_data_type(pevent, record); - event = tep_find_event(pevent, id); - if (event) { - /* Make sure this is our event */ - field = tep_find_field(event, "buf"); - /* the trace_marker adds a '\n' */ - if (field && strcmp(STAMP"\n", record->data + field->offset) == 0) - ts = record->ts; - } - last_record = record; + field = tep_find_field(event, "buf"); + if (field && strcmp(STAMP"\n", record->data + field->offset) == 0) { + *ts = record->ts; + return 1; } - free_record(last_record); - return ts; + return 0; } -static unsigned long long find_time_stamp(struct tep_handle *pevent) +static unsigned long long find_time_stamp(struct tep_handle *tep) { - struct dirent *dent; unsigned long long ts = 0; - void *page; - char *path; - char *file; - DIR *dir; - int len; - int fd; - int r; - - path = tracefs_get_tracing_file("per_cpu"); - if (!path) - return 0; - - dir = opendir(path); - if (!dir) - goto out; - len = strlen(path); - file = malloc(len + strlen("trace_pipe_raw") + 32); - page = malloc(page_size); - if (!file || !page) - die("Failed to allocate time_stamp info"); + if (!tracefs_iterate_raw_events(tep, NULL, find_ts, &ts)) + return ts; - while ((dent = readdir(dir))) { - const char *name = dent->d_name; - - if (strncmp(name, "cpu", 3) != 0) - continue; - - sprintf(file, "%s/%s/trace_pipe_raw", path, name); - fd = open(file, O_RDONLY | O_NONBLOCK); - if (fd < 0) - continue; - do { - r = read(fd, page, page_size); - ts = find_ts_in_page(pevent, page, r); - if (ts) - break; - } while (r > 0); - close(fd); - if (ts) - break; - } - free(file); - free(page); - closedir(dir); - - out: - tracefs_put_tracing_file(path); - return ts; + return 0; } + static char *read_file(char *file, int *psize) { return tracefs_instance_file_read(top_instance.tracefs, file, psize); @@ -4271,7 +4210,7 @@ static char *get_date_to_ts(void) unsigned long long min_stamp; unsigned long long min_ts; unsigned long long ts; - struct tep_handle *pevent; + struct tep_handle *tep; struct timespec start; struct timespec end; char *date2ts = NULL; @@ -4283,16 +4222,18 @@ static char *get_date_to_ts(void) int i; /* Set up a pevent to read the raw format */ - pevent = tep_alloc(); - if (!pevent) { + tep = tep_alloc(); + if (!tep) { warning("failed to alloc pevent, --date ignored"); return NULL; } + tep_set_file_bigendian(tep, tracecmd_host_bigendian()); + buf = read_file("events/header_page", &size); if (!buf) goto out_pevent; - ret = tep_parse_header_page(pevent, buf, size, sizeof(unsigned long)); + ret = tep_parse_header_page(tep, buf, size, sizeof(unsigned long)); free(buf); if (ret < 0) { warning("Can't parse header page, --date ignored"); @@ -4303,7 +4244,7 @@ static char *get_date_to_ts(void) buf = read_file("events/ftrace/print/format", &size); if (!buf) goto out_pevent; - ret = tep_parse_event(pevent, buf, size, "ftrace"); + ret = tep_parse_event(tep, buf, size, "ftrace"); free(buf); if (ret < 0) { warning("Can't parse print event, --date ignored"); @@ -4328,7 +4269,7 @@ static char *get_date_to_ts(void) clock_gettime(CLOCK_REALTIME, &end); tracecmd_disable_tracing(); - ts = find_time_stamp(pevent); + ts = find_time_stamp(tep); if (!ts) continue; @@ -4365,7 +4306,7 @@ static char *get_date_to_ts(void) snprintf(date2ts, 19, "0x%llx", diff/1000); out_pevent: - tep_free(pevent); + tep_free(tep); return date2ts; } From patchwork Fri Jan 17 13:55:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11339241 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 060B013A0 for ; Fri, 17 Jan 2020 13:55:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C5302206E6 for ; Fri, 17 Jan 2020 13:55:58 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="skK6e2Tn" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727580AbgAQNz6 (ORCPT ); Fri, 17 Jan 2020 08:55:58 -0500 Received: from mail-lf1-f54.google.com ([209.85.167.54]:46180 "EHLO mail-lf1-f54.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726885AbgAQNz6 (ORCPT ); Fri, 17 Jan 2020 08:55:58 -0500 Received: by mail-lf1-f54.google.com with SMTP id f15so18382555lfl.13 for ; Fri, 17 Jan 2020 05:55:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=zEE3UfH/5aNQw08/T6tbQeZzNt5wetud4hlt9/McDOc=; b=skK6e2Tn9fuMRgCn6dyz0GoiInzBRL+KceoX/s8zsul5GeqP/5A/Wpqc7jj0jXpEB7 XnbMv5bQ38oqJdJV+Gnpit7XxaS3HxQdXRbJRncQyZePpEXNdOm8pf7RMJjEuDf5pShg LZVyIvrGAev5V2KMuZfP8or9RyqBGCoJmmx8bnMmf9BxiFd91DV5RvwynztStDPQwNvh hK7oJ+Jy2WRxbSXUsCp/26Oblzt1NcwCWOdgNiq/Fzb5zCJij/xgQhtYwTtyBa60ZWvC 4Hb88RbOPt9o4Yo+6ahoXxdANTCqkx0MoxfEfspsiuqvOh2QUffDUBak1QQe0oilAw4b dU/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=zEE3UfH/5aNQw08/T6tbQeZzNt5wetud4hlt9/McDOc=; b=IyMzfqPLnEAidDzizdiTjDOlBOdV6dcIaEElZGMo6AA+IlQ93SVm5DKRKb8913tlte X477Ew2KDHrjheMSq3FlIa8Yu4kHYa762pnFnSB7uU48LrNBaJzrl7TEmyTMj9aENIh1 6rPhRIums3D1c+wGgfDMR2ziOmw1HSKY4XXkIxFVLF8Ef20ae617QkFcyTWQAlEl09Ji MRlRN2oGsQLJLJvNcu+lEu+ZOjc6Dz7HE2p4z9MNOGPFfzaZfd/es8rP0QTZnYJVSISd iWxZkZ/2ZBo3FQFHRFqSinXKRtVfDn0Clt9BFYDBdF82lE3jsQWHJRTi3T1R3i3FeDTj Klgw== X-Gm-Message-State: APjAAAWvwRHtpgxjvexYgGQH+Ij4n2iC6w7Qo348WdFehxsDg4GPE1rf zcpGnZ3WA1mzvEpJ2RIOpk0= X-Google-Smtp-Source: APXvYqyCwWUYlXDXYbQlmQq+Euvwyxirh+Jk4Y1plyLki6H+1oEnuKhIsLeJuAqChsHGJJn7SVjatA== X-Received: by 2002:a19:114:: with SMTP id 20mr4980948lfb.25.1579269352371; Fri, 17 Jan 2020 05:55:52 -0800 (PST) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id 21sm12422562ljv.19.2020.01.17.05.55.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jan 2020 05:55:51 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 4/5] trace-cmd,kernel-shark: New libtracefs APIs for loading ftrace events Date: Fri, 17 Jan 2020 15:55:43 +0200 Message-Id: <20200117135544.598235-5-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200117135544.598235-1-tz.stoyanov@gmail.com> References: <20200117135544.598235-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The functionality related to loading local ftrace events to a pet handler is moved from libtracecmd to libtracefs. The following libtracecmd APIs are removed: tracecmd_local_events(); tracecmd_fill_local_events(); The following new library APIs are introduced: tracefs_local_events(); tracefs_fill_local_events(); tracefs_local_events_system(); The APIs are reimplemented to reuse functionality from tracefs_event_systems() and tracefs_system_events() Signed-off-by: Tzvetomir Stoyanov (VMware) --- include/trace-cmd/trace-cmd.h | 4 - include/tracefs/tracefs.h | 6 + kernel-shark/src/KsCaptureDialog.cpp | 2 +- lib/trace-cmd/trace-util.c | 228 --------------------------- lib/tracefs/tracefs-events.c | 185 ++++++++++++++++++++++ tracecmd/trace-check-events.c | 2 +- tracecmd/trace-record.c | 19 +-- 7 files changed, 197 insertions(+), 249 deletions(-) diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h index 30bb144..da5bd2d 100644 --- a/include/trace-cmd/trace-cmd.h +++ b/include/trace-cmd/trace-cmd.h @@ -24,10 +24,6 @@ void tracecmd_parse_ftrace_printk(struct tep_handle *pevent, char *file, unsigne extern int tracecmd_disable_sys_plugins; extern int tracecmd_disable_plugins; -struct tep_handle *tracecmd_local_events(const char *tracing_dir); -int tracecmd_fill_local_events(const char *tracing_dir, - struct tep_handle *pevent, int *parsing_failures); - int *tracecmd_add_id(int *list, int id, int len); enum { diff --git a/include/tracefs/tracefs.h b/include/tracefs/tracefs.h index d86482b..bd3f732 100644 --- a/include/tracefs/tracefs.h +++ b/include/tracefs/tracefs.h @@ -49,4 +49,10 @@ int tracefs_iterate_raw_events(struct tep_handle *tep, char **tracefs_tracers(const char *tracing_dir); +struct tep_handle *tracefs_local_events(const char *tracing_dir); +struct tep_handle *tracefs_local_events_system(const char *tracing_dir, + const char * const *sys_names); +int tracefs_fill_local_events(const char *tracing_dir, + struct tep_handle *tep, int *parsing_failures); + #endif /* _TRACE_FS_H */ diff --git a/kernel-shark/src/KsCaptureDialog.cpp b/kernel-shark/src/KsCaptureDialog.cpp index 529fa77..69b9944 100644 --- a/kernel-shark/src/KsCaptureDialog.cpp +++ b/kernel-shark/src/KsCaptureDialog.cpp @@ -26,7 +26,7 @@ extern "C" { static inline tep_handle *local_events() { - return tracecmd_local_events(tracefs_get_tracing_dir()); + return tracefs_local_events(tracefs_get_tracing_dir()); } /** diff --git a/lib/trace-cmd/trace-util.c b/lib/trace-cmd/trace-util.c index 1554e88..795e83d 100644 --- a/lib/trace-cmd/trace-util.c +++ b/lib/trace-cmd/trace-util.c @@ -142,17 +142,6 @@ void tracecmd_parse_ftrace_printk(struct tep_handle *pevent, } } -/* FIXME: append_file() is duplicated and could be consolidated */ -static char *append_file(const char *dir, const char *name) -{ - char *file; - int ret; - - ret = asprintf(&file, "%s/%s", dir, name); - - return ret < 0 ? NULL : file; -} - /** * tracecmd_add_id - add an int to the event id list * @list: list to add the id to @@ -183,223 +172,6 @@ int *tracecmd_add_id(int *list, int id, int len) return list; } -static int read_file(const char *file, char **buffer) -{ - char *buf; - int len = 0; - int fd; - int r; - - fd = open(file, O_RDONLY); - if (fd < 0) - return -1; - - buf = malloc(BUFSIZ + 1); - if (!buf) { - len = -1; - goto out; - } - - while ((r = read(fd, buf + len, BUFSIZ)) > 0) { - len += r; - buf = realloc(buf, len + BUFSIZ + 1); - if (!buf) { - len = -1; - goto out; - } - } - - *buffer = buf; - buf[len] = 0; - out: - close(fd); - - return len; -} - -static int load_events(struct tep_handle *pevent, const char *system, - const char *sys_dir) -{ - struct dirent *dent; - struct stat st; - DIR *dir; - int len = 0; - int ret = 0, failure = 0; - - ret = stat(sys_dir, &st); - if (ret < 0 || !S_ISDIR(st.st_mode)) - return EINVAL; - - dir = opendir(sys_dir); - if (!dir) - return errno; - - while ((dent = readdir(dir))) { - const char *name = dent->d_name; - char *event; - char *format; - char *buf; - - if (strcmp(name, ".") == 0 || - strcmp(name, "..") == 0) - continue; - - event = append_file(sys_dir, name); - ret = stat(event, &st); - if (ret < 0 || !S_ISDIR(st.st_mode)) - goto free_event; - - format = append_file(event, "format"); - ret = stat(format, &st); - if (ret < 0) - goto free_format; - - len = read_file(format, &buf); - if (len < 0) - goto free_format; - - ret = tep_parse_event(pevent, buf, len, system); - free(buf); - free_format: - free(format); - free_event: - free(event); - if (ret) - failure = ret; - } - - closedir(dir); - return failure; -} - -static int read_header(struct tep_handle *pevent, const char *events_dir) -{ - struct stat st; - char *header; - char *buf; - int len; - int ret = -1; - - header = append_file(events_dir, "header_page"); - - ret = stat(header, &st); - if (ret < 0) - goto out; - - len = read_file(header, &buf); - if (len < 0) - goto out; - - tep_parse_header_page(pevent, buf, len, sizeof(long)); - - free(buf); - - ret = 0; - out: - free(header); - return ret; -} - -/** - * tracecmd_local_events - create a pevent from the events on system - * @tracing_dir: The directory that contains the events. - * - * Returns a pevent structure that contains the pevents local to - * the system. - */ -struct tep_handle *tracecmd_local_events(const char *tracing_dir) -{ - struct tep_handle *pevent = NULL; - - pevent = tep_alloc(); - if (!pevent) - return NULL; - - if (tracecmd_fill_local_events(tracing_dir, pevent, NULL)) { - tep_free(pevent); - pevent = NULL; - } - - return pevent; -} - -/** - * tracecmd_fill_local_events - Fill a pevent with the events on system - * @tracing_dir: The directory that contains the events. - * @pevent: Allocated pevent which will be filled - * @parsing_failures: return number of failures while parsing the event files - * - * Returns whether the operation succeeded - */ -int tracecmd_fill_local_events(const char *tracing_dir, - struct tep_handle *pevent, int *parsing_failures) -{ - struct dirent *dent; - char *events_dir; - struct stat st; - DIR *dir; - int ret; - - if (!tracing_dir) - return -1; - if (parsing_failures) - *parsing_failures = 0; - - events_dir = append_file(tracing_dir, "events"); - if (!events_dir) - return -1; - - ret = stat(events_dir, &st); - if (ret < 0 || !S_ISDIR(st.st_mode)) { - ret = -1; - goto out_free; - } - - dir = opendir(events_dir); - if (!dir) { - ret = -1; - goto out_free; - } - - ret = read_header(pevent, events_dir); - if (ret < 0) { - ret = -1; - goto out_free; - } - - while ((dent = readdir(dir))) { - const char *name = dent->d_name; - char *sys; - - if (strcmp(name, ".") == 0 || - strcmp(name, "..") == 0) - continue; - - sys = append_file(events_dir, name); - ret = stat(sys, &st); - if (ret < 0 || !S_ISDIR(st.st_mode)) { - free(sys); - continue; - } - - ret = load_events(pevent, name, sys); - - free(sys); - - if (ret && parsing_failures) - (*parsing_failures)++; - } - - closedir(dir); - /* always succeed because parsing failures are not critical */ - ret = 0; - - out_free: - free(events_dir); - - return ret; -} - struct add_plugin_data { int ret; int index; diff --git a/lib/tracefs/tracefs-events.c b/lib/tracefs/tracefs-events.c index 3469431..8e825f5 100644 --- a/lib/tracefs/tracefs-events.c +++ b/lib/tracefs/tracefs-events.c @@ -440,3 +440,188 @@ char **tracefs_tracers(const char *tracing_dir) return plugins; } + +static int load_events(struct tep_handle *tep, + const char *tracing_dir, const char *system) +{ + int ret = 0, failure = 0; + char **events = NULL; + struct stat st; + int len = 0; + int i; + + events = tracefs_system_events(tracing_dir, system); + if (!events) + return -ENOENT; + + for (i = 0; events[i]; i++) { + char *format; + char *buf; + + ret = asprintf(&format, "%s/events/%s/%s/format", + tracing_dir, system, events[i]); + if (ret < 0) { + failure = -ENOMEM; + break; + } + + ret = stat(format, &st); + if (ret < 0) + goto next_event; + + len = str_read_file(format, &buf); + if (len < 0) + goto next_event; + + ret = tep_parse_event(tep, buf, len, system); + free(buf); +next_event: + free(format); + if (ret) + failure = ret; + } + + if (events) { + for (i = 0; events[i]; i++) + free(events[i]); + free(events); + } + return failure; +} + +static int read_header(struct tep_handle *tep, const char *tracing_dir) +{ + struct stat st; + char *header; + char *buf; + int len; + int ret = -1; + + header = append_file(tracing_dir, "events/header_page"); + + ret = stat(header, &st); + if (ret < 0) + goto out; + + len = str_read_file(header, &buf); + if (len < 0) + goto out; + + tep_parse_header_page(tep, buf, len, sizeof(long)); + + free(buf); + + ret = 0; + out: + free(header); + return ret; +} + +static bool contains(const char *name, const char * const *names) +{ + if (!names) + return false; + for (; *names; names++) + if (strcmp(name, *names) == 0) + return true; + return false; +} + +static int fill_local_events_system(const char *tracing_dir, + struct tep_handle *tep, + const char * const *sys_names, + int *parsing_failures) +{ + char **systems = NULL; + int ret; + int i; + + if (!tracing_dir) + tracing_dir = tracefs_get_tracing_dir(); + if (!tracing_dir) + return -1; + + systems = tracefs_event_systems(tracing_dir); + if (!systems) + return -1; + + ret = read_header(tep, tracing_dir); + if (ret < 0) { + ret = -1; + goto out; + } + + if (parsing_failures) + *parsing_failures = 0; + + for (i = 0; systems[i]; i++) { + if (sys_names && !contains(systems[i], sys_names)) + continue; + ret = load_events(tep, tracing_dir, systems[i]); + if (ret && parsing_failures) + (*parsing_failures)++; + } + /* always succeed because parsing failures are not critical */ + ret = 0; +out: + if (systems) { + for (i = 0; systems[i]; i++) + free(systems[i]); + free(systems); + } + return ret; +} + +/** + * tracefs_local_events_system - create a tep from the events of the specified subsystem. + * + * @tracing_dir: The directory that contains the events. + * @sys_name: Array of system names, to load the events from. + * The last element from the array must be NULL + * + * Returns a tep structure that contains the tep local to + * the system. + */ +struct tep_handle *tracefs_local_events_system(const char *tracing_dir, + const char * const *sys_names) +{ + struct tep_handle *tep = NULL; + + tep = tep_alloc(); + if (!tep) + return NULL; + + if (fill_local_events_system(tracing_dir, tep, sys_names, NULL)) { + tep_free(tep); + tep = NULL; + } + + return tep; +} + +/** + * tracefs_local_events - create a tep from the events on system + * @tracing_dir: The directory that contains the events. + * + * Returns a tep structure that contains the teps local to + * the system. + */ +struct tep_handle *tracefs_local_events(const char *tracing_dir) +{ + return tracefs_local_events_system(tracing_dir, NULL); +} + +/** + * tracefs_fill_local_events - Fill a tep with the events on system + * @tracing_dir: The directory that contains the events. + * @tep: Allocated tep handler which will be filled + * @parsing_failures: return number of failures while parsing the event files + * + * Returns whether the operation succeeded + */ +int tracefs_fill_local_events(const char *tracing_dir, + struct tep_handle *tep, int *parsing_failures) +{ + return fill_local_events_system(tracing_dir, tep, + NULL, parsing_failures); +} diff --git a/tracecmd/trace-check-events.c b/tracecmd/trace-check-events.c index a8ee60a..d37af67 100644 --- a/tracecmd/trace-check-events.c +++ b/tracecmd/trace-check-events.c @@ -50,7 +50,7 @@ void trace_check_events(int argc, char **argv) tep_set_flag(pevent, TEP_DISABLE_SYS_PLUGINS); list = tep_load_plugins(pevent); - ret = tracecmd_fill_local_events(tracing, pevent, &parsing_failures); + ret = tracefs_fill_local_events(tracing, pevent, &parsing_failures); if (ret || parsing_failures) ret = EINVAL; tep_unload_plugins(list, pevent); diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index f7d3017..85291d9 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -4204,6 +4204,7 @@ static char *read_file(char *file, int *psize) */ static char *get_date_to_ts(void) { + const char *systems[] = {"ftrace", NULL}; unsigned long long min = -1ULL; unsigned long long diff; unsigned long long stamp; @@ -4221,10 +4222,10 @@ static char *get_date_to_ts(void) int ret; int i; - /* Set up a pevent to read the raw format */ - tep = tep_alloc(); + /* Set up a tep to read the raw format */ + tep = tracefs_local_events_system(NULL, systems); if (!tep) { - warning("failed to alloc pevent, --date ignored"); + warning("failed to alloc tep, --date ignored"); return NULL; } @@ -4240,17 +4241,6 @@ static char *get_date_to_ts(void) goto out_pevent; } - /* Find the format for ftrace:print. */ - buf = read_file("events/ftrace/print/format", &size); - if (!buf) - goto out_pevent; - ret = tep_parse_event(tep, buf, size, "ftrace"); - free(buf); - if (ret < 0) { - warning("Can't parse print event, --date ignored"); - goto out_pevent; - } - path = tracefs_get_tracing_file("trace_marker"); tfd = open(path, O_WRONLY); tracefs_put_tracing_file(path); @@ -4304,7 +4294,6 @@ static char *get_date_to_ts(void) */ diff = min_stamp - min_ts; snprintf(date2ts, 19, "0x%llx", diff/1000); - out_pevent: tep_free(tep); From patchwork Fri Jan 17 13:55:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tzvetomir Stoyanov (VMware)" X-Patchwork-Id: 11339239 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C7352138D for ; Fri, 17 Jan 2020 13:55:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9B9712072E for ; Fri, 17 Jan 2020 13:55:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="iiGYuhYI" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727667AbgAQNz5 (ORCPT ); Fri, 17 Jan 2020 08:55:57 -0500 Received: from mail-lf1-f49.google.com ([209.85.167.49]:44479 "EHLO mail-lf1-f49.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727580AbgAQNz5 (ORCPT ); Fri, 17 Jan 2020 08:55:57 -0500 Received: by mail-lf1-f49.google.com with SMTP id v201so18390654lfa.11 for ; Fri, 17 Jan 2020 05:55:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=VB49kJVd8Q9Gk0gcELo+Yv7q3l/GoBnq1uPhDRPAXm0=; b=iiGYuhYIUyarTFL/ElVdV1sPqOEdTaFMwuBNLjdoN96LTI6ZAfo0L4vRrzoZSyiekl 2xqfVQnJseX2xVwM+6I9E0EvLsNicxUhyGSSH96MmlwBH+9XoxV+8XERbFuycXciZyBF S4a2FGwUfWDs8E28iGPExhiSY1QNMOaVsjZD+1+VeCrtLw3Hu5ypZz5Lo3QkQ7n7VExN 2HPpbkGfjMslxgxkmT1SKo94ST6Uz3I8v7Ag0DXzOQvCu44iqa9XAqOX3l0+TiIAQGwM AFxBXLzh/mmriERurd7unp7PZlq2NAZvFYCih+w7WQ68LU3culVnyqfqQePWC6hoxY6J jNcA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=VB49kJVd8Q9Gk0gcELo+Yv7q3l/GoBnq1uPhDRPAXm0=; b=nr2G7d6MtY/+h2LNg8a70A1FTErLcBgFALhyvfR5hBnZpbASPjjd0HQp8pbteZNaLd kflyvJ1/q5c9H8hgoofsqowYdsmuGZh2xS2QVYVDmyuJoKYIgceoYLtO4oN6e+3jQH4X GuHZVMepUsW/WoGaJd9ley/SuPKgnG+sAG7dN6lMCwkt9M1EmCcPkqBgir4f4tfUy8eP hdbafG6+XKiQBDHYf9AWjdpM33hqi30uuqd492NRcvlgQsCXToYe8Tncrb1pRN+nD2+u FAGpN80nVroaeYSiBREyzDH4aHYqs/p7mYstTFvyXhc6B+g+QsUw3PkiFG9YgogyhqiQ 1BfA== X-Gm-Message-State: APjAAAUG+hfOV8U62FXAl9pHn9V7Jmo3MLs5lGa8jhiiDdnmjfgsv6R3 pWJjizUqD9B7xESPLth/51M= X-Google-Smtp-Source: APXvYqx9z5MHtYV9U/xCSXU8sKqJW8W6Riz4Gy0SWhLAiUuYR/EwzK5hXBB3GzajnGiKG1xZNxt+/Q== X-Received: by 2002:a19:4f46:: with SMTP id a6mr5473088lfk.143.1579269353453; Fri, 17 Jan 2020 05:55:53 -0800 (PST) Received: from oberon.eng.vmware.com ([146.247.46.5]) by smtp.gmail.com with ESMTPSA id 21sm12422562ljv.19.2020.01.17.05.55.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jan 2020 05:55:52 -0800 (PST) From: "Tzvetomir Stoyanov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org Subject: [PATCH v3 5/5] trace-cmd: Unit test for libtracefs Date: Fri, 17 Jan 2020 15:55:44 +0200 Message-Id: <20200117135544.598235-6-tz.stoyanov@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200117135544.598235-1-tz.stoyanov@gmail.com> References: <20200117135544.598235-1-tz.stoyanov@gmail.com> MIME-Version: 1.0 Sender: linux-trace-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The CUnit test infrastructure is integrated in trace-cmd. http://cunit.sourceforge.net/ The library and its headers must be installed on the machine, in order to build the trace-cmd unit tests. For Fedora, these packages must be installed: CUnit, CUnit-devel A new directory is added: lib/utest containing unit tests implementation. Added new target to trace-cmd top Makefile: make test which builds the unit test binary: lib/utest/trace-utest The goal of this patch is not to provide full unit test coverage of libtracefs, but to be a POC for adding test infrastructure to trace-cmd. The first API, covered be the test is: tracefs_iterate_raw_events() Signed-off-by: Tzvetomir Stoyanov (VMware) --- Makefile | 13 +++- lib/utest/Makefile | 43 +++++++++++++ lib/utest/trace-utest.c | 83 ++++++++++++++++++++++++ lib/utest/trace-utest.h | 11 ++++ lib/utest/tracefs-utest.c | 132 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 280 insertions(+), 2 deletions(-) create mode 100644 lib/utest/Makefile create mode 100644 lib/utest/trace-utest.c create mode 100644 lib/utest/trace-utest.h create mode 100644 lib/utest/tracefs-utest.c diff --git a/Makefile b/Makefile index aa803ba..a67dd67 100644 --- a/Makefile +++ b/Makefile @@ -192,7 +192,7 @@ TRACE_LIBS = -L$(LIBTRACECMD_DIR) -ltracecmd \ -L$(LIBTRACEFS_DIR) -ltracefs export LIBS TRACE_LIBS -export LIBTRACEEVENT_DIR LIBTRACECMD_DIR +export LIBTRACEEVENT_DIR LIBTRACECMD_DIR LIBTRACEFS_DIR export LIBTRACECMD_STATIC LIBTRACECMD_SHARED export LIBTRACEEVENT_STATIC LIBTRACEEVENT_SHARED export LIBTRACEFS_STATIC LIBTRACEFS_SHARED @@ -226,6 +226,9 @@ ifeq ($(VSOCK_DEFINED), 1) CFLAGS += -DVSOCK endif +CUNIT_INSTALLED := $(shell if (echo -e "\#include \n void main(){CU_initialize_registry();}" | $(CC) -x c -lcunit - >/dev/null 2>&1) ; then echo 1; else echo 0 ; fi) +export CUNIT_INSTALLED + export CFLAGS export INCLUDES @@ -307,7 +310,6 @@ $(LIBTRACEFS_STATIC): force $(LIBTRACEFS_SHARED): force $(Q)$(MAKE) -C $(src)/lib/tracefs $@ - libtraceevent.so: $(LIBTRACEEVENT_SHARED) libtraceevent.a: $(LIBTRACEEVENT_STATIC) libtracecmd.a: $(LIBTRACECMD_STATIC) @@ -317,6 +319,12 @@ libtracefs.so: $(LIBTRACEFS_SHARED) libs: $(LIBTRACECMD_SHARED) $(LIBTRACEEVENT_SHARED) $(LIBTRACEFS_SHARED) +test: force $(LIBTRACEEVENT_STATIC) $(LIBTRACEFS_STATIC) $(LIBTRACECMD_STATIC) +ifneq ($(CUNIT_INSTALLED),1) + $(error CUnit framework not installed, cannot build unit tests)) +endif + $(Q)$(MAKE) -C $(src)/lib/utest $@ + plugins: force $(obj)/lib/traceevent/plugins/traceevent_plugin_dir $(obj)/lib/traceevent/plugins/trace_python_dir $(Q)$(MAKE) -C $(src)/lib/traceevent/plugins @@ -401,6 +409,7 @@ clean: $(MAKE) -C $(src)/lib/trace-cmd clean $(MAKE) -C $(src)/lib/tracefs clean $(MAKE) -C $(src)/lib/traceevent/plugins clean + $(MAKE) -C $(src)/lib/utest clean $(MAKE) -C $(src)/python clean $(MAKE) -C $(src)/tracecmd clean if [ -f $(kshark-dir)/build/Makefile ]; then $(MAKE) -C $(kshark-dir)/build clean; fi diff --git a/lib/utest/Makefile b/lib/utest/Makefile new file mode 100644 index 0000000..577b07f --- /dev/null +++ b/lib/utest/Makefile @@ -0,0 +1,43 @@ + +include $(src)/scripts/utils.mk + +bdir:=$(obj)/lib/utest + +TARGETS = $(bdir)/trace-utest + +OBJS = +OBJS += trace-utest.o +OBJS += tracefs-utest.o + +LIBS += -lcunit \ + -L$(LIBTRACEFS_DIR) -ltracefs \ + -L$(LIBTRACEEVENT_DIR) -ltraceevent + +OBJS := $(OBJS:%.o=$(bdir)/%.o) +DEPS := $(OBJS:$(bdir)/%.o=$(bdir)/.%.d) + +$(bdir): + @mkdir -p $(bdir) + +$(OBJS): | $(bdir) +$(DEPS): | $(bdir) + +$(bdir)/trace-utest: $(OBJS) + $(Q)$(do_app_build) + +#$(bdir)/trace-utest: $(LIBUTEST) + +$(bdir)/%.o: %.c + $(Q)$(call do_fpic_compile) + +$(DEPS): $(bdir)/.%.d: %.c + $(Q)$(CC) -M $(CPPFLAGS) $(CFLAGS) $< > $@ + +$(OBJS): $(bdir)/%.o : $(bdir)/.%.d + +dep_includes := $(wildcard $(DEPS)) + +test: $(TARGETS) + +clean: + $(RM) $(TARGETS) $(bdir)/*.o $(bdir)/.*.d diff --git a/lib/utest/trace-utest.c b/lib/utest/trace-utest.c new file mode 100644 index 0000000..58d4d4e --- /dev/null +++ b/lib/utest/trace-utest.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2020, VMware, Tzvetomir Stoyanov + * + */ +#include +#include +#include +#include + +#include +#include + +#include "trace-utest.h" + +enum unit_tests { + RUN_NONE = 0, + RUN_TRACEFS = (1 << 0), + RUN_ALL = 0xFFFF +}; + +static void print_help(char **argv) +{ + printf("Usage: %s [OPTIONS]\n", basename(argv[0])); + printf("\t-s, --silent\tPrint test summary\n"); + printf("\t-r, --run test\tRun specific test:\n"); + printf("\t\t tracefs run libtracefs tests\n"); + printf("\t-h, --help\tPrint usage information\n"); + exit(0); +} + +int main(int argc, char **argv) +{ + CU_BasicRunMode verbose = CU_BRM_VERBOSE; + enum unit_tests tests = RUN_NONE; + + for (;;) { + int c; + int index = 0; + const char *opts = "+hsr:"; + static struct option long_options[] = { + {"silent", no_argument, NULL, 's'}, + {"run", required_argument, NULL, 'r'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + c = getopt_long (argc, argv, opts, long_options, &index); + if (c == -1) + break; + switch (c) { + case 'r': + if (strcmp(optarg, "tracefs") == 0) + tests |= RUN_TRACEFS; + else + print_help(argv); + break; + case 's': + verbose = CU_BRM_SILENT; + break; + case 'h': + default: + print_help(argv); + break; + } + } + + if (tests == RUN_NONE) + tests = RUN_ALL; + + if (CU_initialize_registry() != CUE_SUCCESS) { + printf("Test registry cannot be initialized\n"); + return -1; + } + + if (tests & RUN_TRACEFS) + test_tracefs_lib(); + + CU_basic_set_mode(verbose); + CU_basic_run_tests(); + CU_cleanup_registry(); + return 0; +} diff --git a/lib/utest/trace-utest.h b/lib/utest/trace-utest.h new file mode 100644 index 0000000..917c0e7 --- /dev/null +++ b/lib/utest/trace-utest.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ +/* + * Copyright (C) 2020, VMware, Tzvetomir Stoyanov + * + */ +#ifndef _TRACE_UTEST_H_ +#define _TRACE_UTEST_H_ + +void test_tracefs_lib(void); + +#endif /* _TRACE_UTEST_H_ */ diff --git a/lib/utest/tracefs-utest.c b/lib/utest/tracefs-utest.c new file mode 100644 index 0000000..97bb087 --- /dev/null +++ b/lib/utest/tracefs-utest.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2020, VMware, Tzvetomir Stoyanov + * + */ +#include +#include +#include +#include +#include + +#include +#include + +#include "tracefs.h" + +#define TRACEFS_SUITE "trasefs library" +#define TEST_INSTANCE_NAME "cunit_test_iter" +#define TEST_ARRAY_SIZE 50 + +static struct tracefs_instance *test_instance; +static struct tep_handle *test_tep; +static int test_array[TEST_ARRAY_SIZE]; +static int test_found; + +static int test_callback(struct tep_event *event, struct tep_record *record, + int cpu, void *context) +{ + struct tep_format_field *field; + int val, i; + + field = tep_find_field(event, "buf"); + if (field) { + val = *((int *)(record->data + field->offset)); + for (i = 0; i < TEST_ARRAY_SIZE; i++) { + if (test_array[i] == val) { + test_array[i] = 0; + test_found++; + break; + } + } + } + + return 0; +} + +static void test_iter_write(void) +{ + char *path; + int i, fd; + int ret; + + path = tracefs_instance_get_file(test_instance, "trace_marker"); + CU_TEST(path != NULL); + fd = open(path, O_WRONLY); + CU_TEST(fd >= 0); + + for (i = 0; i < TEST_ARRAY_SIZE; i++) { + test_array[i] = random(); + ret = write(fd, test_array + i, sizeof(int)); + CU_TEST(ret == sizeof(int)); + } + + tracefs_put_tracing_file(path); + close(fd); +} + + +static void test_iter_read(void) +{ + int ret; + + test_found = 0; + test_iter_write(); + ret = tracefs_iterate_raw_events(test_tep, test_instance, + test_callback, NULL); + CU_TEST(ret == 0); + CU_TEST(test_found == TEST_ARRAY_SIZE); +} + +static void test_iter_in_params(void) +{ + int ret; + + ret = tracefs_iterate_raw_events(NULL, test_instance, test_callback, NULL); + CU_TEST(ret < 0); + ret = tracefs_iterate_raw_events(test_tep, NULL, test_callback, NULL); + CU_TEST(ret == 0); + ret = tracefs_iterate_raw_events(test_tep, test_instance, NULL, NULL); + CU_TEST(ret < 0); +} + +static int test_suite_destroy(void) +{ + tracefs_instance_destroy(test_instance); + tracefs_instance_free(test_instance); + tep_free(test_tep); + return 0; +} + +static int test_suite_init(void) +{ + const char *systems[] = {"ftrace", NULL}; + + test_tep = tracefs_local_events_system(NULL, systems); + if (test_tep == NULL) + return 1; + + test_instance = tracefs_instance_alloc(TEST_INSTANCE_NAME); + if (test_instance == NULL) + return 1; + + if (tracefs_instance_create(test_instance) < 0) + return 1; + + return 0; +} + +void test_tracefs_lib(void) +{ + CU_pSuite suite = NULL; + + suite = CU_add_suite(TRACEFS_SUITE, test_suite_init, test_suite_destroy); + if (suite == NULL) { + fprintf(stderr, "Suite \"%s\" cannot be ceated\n", TRACEFS_SUITE); + return; + } + CU_add_test(suite, "tracefs_iterate_raw_events: Wrong input parameters", + test_iter_in_params); + CU_add_test(suite, "tracefs_iterate_raw_events: Regular operation", + test_iter_read); +}