From patchwork Mon Jun 25 15:01:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 10758571 Return-Path: Received: from mail-wm0-f66.google.com ([74.125.82.66]:53660 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934564AbeFYPCB (ORCPT ); Mon, 25 Jun 2018 11:02:01 -0400 Received: by mail-wm0-f66.google.com with SMTP id x6-v6so9635586wmc.3 for ; Mon, 25 Jun 2018 08:02:01 -0700 (PDT) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 1/7] kernel-shark-qt: Add Cmake build system for the Qt based KernelShark Date: Mon, 25 Jun 2018 18:01:15 +0300 Message-Id: <20180625150121.14291-2-y.karadz@gmail.com> In-Reply-To: <20180625150121.14291-1-y.karadz@gmail.com> References: <20180625150121.14291-1-y.karadz@gmail.com> Sender: linux-trace-devel-owner@vger.kernel.org List-ID: Content-Length: 6177 This patch adds in /kernel-shark-qt a simple CMake building infrastructure, to be used by the new, Qt-based version of KernelShark. Signed-off-by: Yordan Karadzhov (VMware) --- kernel-shark-qt/CMakeLists.txt | 35 ++++++++++++ kernel-shark-qt/build/FindTraceCmd.cmake | 70 ++++++++++++++++++++++++ kernel-shark-qt/build/cmake_clean.sh | 8 +++ kernel-shark-qt/build/deff.h.cmake | 20 +++++++ kernel-shark-qt/src/CMakeLists.txt | 4 ++ 5 files changed, 137 insertions(+) create mode 100644 kernel-shark-qt/CMakeLists.txt create mode 100644 kernel-shark-qt/build/FindTraceCmd.cmake create mode 100755 kernel-shark-qt/build/cmake_clean.sh create mode 100644 kernel-shark-qt/build/deff.h.cmake create mode 100644 kernel-shark-qt/src/CMakeLists.txt diff --git a/kernel-shark-qt/CMakeLists.txt b/kernel-shark-qt/CMakeLists.txt new file mode 100644 index 0000000..56fca44 --- /dev/null +++ b/kernel-shark-qt/CMakeLists.txt @@ -0,0 +1,35 @@ +# Check if cmake has the required version +cmake_minimum_required(VERSION 2.8.11 FATAL_ERROR) + +# Set the name and version of the project +project(kernel-shark-qt) + +set(KS_VERSION_MAJOR 0) +set(KS_VERSION_MINOR 7) +set(KS_VERSION_PATCH 0) +set(KS_VERSION_STRING ${KS_VERSION_MAJOR}.${KS_VERSION_MINOR}.${KS_VERSION_PATCH}) +message("\n project: Kernel Shark: (version: ${KS_VERSION_STRING})\n") + +set(KS_DIR ${CMAKE_SOURCE_DIR}) + +include(${KS_DIR}/build/FindTraceCmd.cmake) + +set(LIBRARY_OUTPUT_PATH "${KS_DIR}/lib") +set(EXECUTABLE_OUTPUT_PATH "${KS_DIR}/bin") + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pthread") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11 -pthread") + +include_directories(${KS_DIR}/src/ + ${KS_DIR}/build/src/ + ${TRACECMD_INCLUDE_DIR} + ${TRACEEVENT_INCLUDE_DIR}) + +message("") +message(STATUS "C flags : " ${CMAKE_C_FLAGS}) +message(STATUS "CXX flags : " ${CMAKE_CXX_FLAGS}) +message(STATUS "Linker flags : " ${CMAKE_EXE_LINKER_FLAGS}) + +add_subdirectory(${KS_DIR}/src) + +message("") diff --git a/kernel-shark-qt/build/FindTraceCmd.cmake b/kernel-shark-qt/build/FindTraceCmd.cmake new file mode 100644 index 0000000..fb2092a --- /dev/null +++ b/kernel-shark-qt/build/FindTraceCmd.cmake @@ -0,0 +1,70 @@ +# Find traceevent and trace-cmd +# This module finds an installed trace-cmd package. +# +# It sets the following variables: +# TRACEEVENT_INCLUDE_DIR, where to find traceevent header. +# TRACEEVENT_LIBRARY_DIR , where to find the traceevent library. +# TRACEEVENT_LIBRARY, traceevent the library. +# TRACEEVENT_FOUND, If false, do not try to use traceevent. +# +# TRACECMD_INCLUDE_DIR, where to find trace-cmd header. +# TRACECMD_LIBRARY_DIR , where to find the trace-cmd library. +# TRACECMD_LIBRARY, the trace-cmd library. +# TRACECMD_FOUND, If false, do not try to use trace-cmd. + +# MESSAGE(" Looking for trace-cmd ...") + +find_path(TRACECMD_BIN_DIR NAMES trace-cmd + PATHS $ENV{TRACE_CMD}/tracecmd/ + ${CMAKE_SOURCE_DIR}/../tracecmd/) + +find_path(TRACECMD_INCLUDE_DIR NAMES trace-cmd.h + PATHS $ENV{TRACE_CMD}/include/trace-cmd/ + ${CMAKE_SOURCE_DIR}/../include/trace-cmd/) + +find_path(TRACECMD_LIBRARY_DIR NAMES libtracecmd.a + PATHS $ENV{TRACE_CMD}/lib/trace-cmd/ + ${CMAKE_SOURCE_DIR}/../lib/trace-cmd/) + +IF (TRACECMD_INCLUDE_DIR AND TRACECMD_LIBRARY_DIR) + + SET(TRACECMD_FOUND TRUE) + SET(TRACECMD_LIBRARY "${TRACECMD_LIBRARY_DIR}/libtracecmd.a") + +ENDIF (TRACECMD_INCLUDE_DIR AND TRACECMD_LIBRARY_DIR) + +IF (TRACECMD_FOUND) + + MESSAGE(STATUS "Found trace-cmd: ${TRACECMD_LIBRARY}") + +ELSE (TRACECMD_FOUND) + + MESSAGE(FATAL_ERROR "\nCould not find trace-cmd!\n") + +ENDIF (TRACECMD_FOUND) + + +find_path(TRACEEVENT_INCLUDE_DIR NAMES event-parse.h + PATHS $ENV{TRACE_CMD}/include/traceevent/ + ${CMAKE_SOURCE_DIR}/../include/traceevent/) + +find_path(TRACEEVENT_LIBRARY_DIR NAMES libtraceevent.a + PATHS $ENV{TRACE_CMD}/lib/traceevent/ + ${CMAKE_SOURCE_DIR}/../lib/traceevent/) + +IF (TRACEEVENT_INCLUDE_DIR AND TRACEEVENT_LIBRARY_DIR) + + SET(TRACEEVENT_FOUND TRUE) + SET(TRACEEVENT_LIBRARY "${TRACEEVENT_LIBRARY_DIR}/libtraceevent.a") + +ENDIF (TRACEEVENT_INCLUDE_DIR AND TRACEEVENT_LIBRARY_DIR) + +IF (TRACEEVENT_FOUND) + + MESSAGE(STATUS "Found traceevent: ${TRACEEVENT_LIBRARY}") + +ELSE (TRACEEVENT_FOUND) + + MESSAGE(FATAL_ERROR "\nCould not find libtraceevent!\n") + +ENDIF (TRACEEVENT_FOUND) diff --git a/kernel-shark-qt/build/cmake_clean.sh b/kernel-shark-qt/build/cmake_clean.sh new file mode 100755 index 0000000..ee0abbb --- /dev/null +++ b/kernel-shark-qt/build/cmake_clean.sh @@ -0,0 +1,8 @@ +make clean +rm CMakeCache.txt +rm cmake_install.cmake +rm Makefile +rm -rf CMakeFiles/ +rm -rf src/ +rm -f ../lib/* +rm -f ../src/KsDeff.h diff --git a/kernel-shark-qt/build/deff.h.cmake b/kernel-shark-qt/build/deff.h.cmake new file mode 100644 index 0000000..62e6b9e --- /dev/null +++ b/kernel-shark-qt/build/deff.h.cmake @@ -0,0 +1,20 @@ + /** + * \file KsDeff.h + * \brief This File is generated by CMAKE + */ + +// !-- Do Not Hand Edit - This File is generated by CMAKE --! + +#ifndef _KS_CONFIG_H +#define _KS_CONFIG_H + +/** KernelShark Version number. */ +#cmakedefine KS_VERSION_STRING "@KS_VERSION_STRING@" + +/** KernelShark source code path. */ +#cmakedefine KS_DIR "@KS_DIR@" + +/** Location of the trace-cmd executable. */ +#cmakedefine TRACECMD_BIN_DIR "@TRACECMD_BIN_DIR@" + +#endif // _KS_CONFIG_H diff --git a/kernel-shark-qt/src/CMakeLists.txt b/kernel-shark-qt/src/CMakeLists.txt new file mode 100644 index 0000000..8c66424 --- /dev/null +++ b/kernel-shark-qt/src/CMakeLists.txt @@ -0,0 +1,4 @@ +message("\n src ...") + +configure_file( ${KS_DIR}/build/deff.h.cmake + ${KS_DIR}/src/KsDeff.h) From patchwork Mon Jun 25 15:01:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 10758573 Return-Path: Received: from mail-wr0-f193.google.com ([209.85.128.193]:46985 "EHLO mail-wr0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934559AbeFYPCQ (ORCPT ); Mon, 25 Jun 2018 11:02:16 -0400 Received: by mail-wr0-f193.google.com with SMTP id l14-v6so8967659wrq.13 for ; Mon, 25 Jun 2018 08:02:15 -0700 (PDT) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 3/7] kernel-shark-qt: Add API for loading trace.dat files Date: Mon, 25 Jun 2018 18:01:17 +0300 Message-Id: <20180625150121.14291-4-y.karadz@gmail.com> In-Reply-To: <20180625150121.14291-1-y.karadz@gmail.com> References: <20180625150121.14291-1-y.karadz@gmail.com> Sender: linux-trace-devel-owner@vger.kernel.org List-ID: Content-Length: 16639 This patch introduces the first component of the C API used by the new Qt-based version of KernelShark. The patch includes only the part of the API responsible for loading data files generated by trace-cmd. The following patch will introduces an example, demonstrating the usage of this part of the API. Signed-off-by: Yordan Karadzhov (VMware) --- kernel-shark-qt/src/CMakeLists.txt | 9 + kernel-shark-qt/src/libkshark.c | 438 +++++++++++++++++++++++++++++ kernel-shark-qt/src/libkshark.h | 157 +++++++++++ 3 files changed, 604 insertions(+) create mode 100644 kernel-shark-qt/src/libkshark.c create mode 100644 kernel-shark-qt/src/libkshark.h diff --git a/kernel-shark-qt/src/CMakeLists.txt b/kernel-shark-qt/src/CMakeLists.txt index 8c66424..ed3c60e 100644 --- a/kernel-shark-qt/src/CMakeLists.txt +++ b/kernel-shark-qt/src/CMakeLists.txt @@ -1,4 +1,13 @@ message("\n src ...") +message(STATUS "libkshark") +add_library(kshark SHARED libkshark.c) + +target_link_libraries(kshark ${CMAKE_DL_LIBS} + ${TRACEEVENT_LIBRARY} + ${TRACECMD_LIBRARY}) + +set_target_properties(kshark PROPERTIES SUFFIX ".so.${KS_VERSION_STRING}") + configure_file( ${KS_DIR}/build/deff.h.cmake ${KS_DIR}/src/KsDeff.h) diff --git a/kernel-shark-qt/src/libkshark.c b/kernel-shark-qt/src/libkshark.c new file mode 100644 index 0000000..f112a50 --- /dev/null +++ b/kernel-shark-qt/src/libkshark.c @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: LGPL-2.1 + +/* + * Copyright (C) 2017 VMware Inc, Yordan Karadzhov + */ + +// C +#define _GNU_SOURCE 1 +#include +#include +#include + +// trace-cmd +#include "trace-filter-hash.h" + +// KernelShark +#include "libkshark.h" + +static __thread struct trace_seq seq; + +static struct kshark_context *kshark_context_handler = NULL; + +static bool kshark_default_context(struct kshark_context **context) +{ + struct kshark_context *kshark_ctx; + + kshark_ctx = calloc(1, sizeof(*kshark_ctx)); + if (!kshark_ctx) + return false; + + /* Free the existing context (if any). */ + if (*context && *context != kshark_context_handler) { + free(*context); + *context = NULL; + } + + if (kshark_context_handler) { + free(kshark_context_handler); + kshark_context_handler = NULL; + } + + kshark_context_handler = kshark_ctx; + *context = kshark_ctx; + + return true; +} + +bool kshark_instance(struct kshark_context **context) +{ + if (!seq.buffer) + trace_seq_init(&seq); + + if (*context == NULL && kshark_context_handler == NULL) { + // No kshark_context exists. Create a default one. + bool status = kshark_default_context(context); + if (status) + return status; + } else if (*context != NULL) { + // Use the context provided by the user. + if (kshark_context_handler) + free(kshark_context_handler); + + kshark_context_handler = *context; + } else { + /* + * No context is provided by the user, but the context handler + * is already set. Use the context handler. + */ + *context = kshark_context_handler; + } + + return true; +} + +static void kshark_free_task_list(struct kshark_context *kshark_ctx) +{ + struct kshark_task_list *task; + + while (kshark_ctx->tasks) { + task = kshark_ctx->tasks; + kshark_ctx->tasks = kshark_ctx->tasks->next; + free(task); + } + + task = kshark_ctx->tasks = NULL; +} + +bool kshark_open(struct kshark_context *kshark_ctx, const char *file) +{ + kshark_free_task_list(kshark_ctx); + struct tracecmd_input *handle = tracecmd_open(file); + if (!handle) + return false; + + pthread_mutex_init(&kshark_ctx->input_mutex, NULL); + + kshark_ctx->handle = handle; + kshark_ctx->pevt = tracecmd_get_pevent(handle); + + /* + * Turn off function trace indent and turn on show parent + * if possible. + */ + trace_util_add_option("ftrace:parent", "1"); + trace_util_add_option("ftrace:indent", "0"); + + return true; +} + +void kshark_close(struct kshark_context *kshark_ctx) +{ + if (!kshark_ctx || !kshark_ctx->handle) + return; + + tracecmd_close(kshark_ctx->handle); + kshark_ctx->handle = NULL; + kshark_ctx->pevt = NULL; + + pthread_mutex_destroy(&kshark_ctx->input_mutex); +} + +void kshark_free(struct kshark_context *kshark_ctx) +{ + if (kshark_ctx == NULL && kshark_context_handler == NULL) + return; + + if (kshark_ctx == NULL) { + kshark_ctx = kshark_context_handler; + kshark_context_handler = NULL; + } + + kshark_free_task_list(kshark_ctx); + + if (seq.buffer) + trace_seq_destroy(&seq); + + free(kshark_ctx); + + if (kshark_ctx == kshark_context_handler) + kshark_context_handler = NULL; + + kshark_ctx = NULL; +} + +static struct kshark_task_list * +kshark_find_task(struct kshark_context *kshark_ctx, int pid) +{ + struct kshark_task_list *list = kshark_ctx->tasks; + while (list) { + if (list->pid == pid) + return list; + + list = list->next; + } + + return NULL; +} + +static struct kshark_task_list * +kshark_add_task(struct kshark_context *kshark_ctx, int pid) +{ + struct kshark_task_list *list = kshark_find_task(kshark_ctx, pid); + if (list) + return list; + + list = malloc(sizeof(*list)); + list->pid = pid; + list->next = kshark_ctx->tasks; + kshark_ctx->tasks = list; + + return list; +} + +static void kshark_set_entry_values(struct kshark_context *kshark_ctx, + struct pevent_record *record, + struct kshark_entry *entry) +{ + // Offset of the record + entry->offset = record->offset; + + // CPU Id of the record + entry->cpu = record->cpu; + + // Time stamp of the record + entry->ts = record->ts; + + // Event Id of the record + entry->event_id = pevent_data_type(kshark_ctx->pevt, record); + + /* + * Is visible mask. This default value means that the entry + * is visible everywhere. + */ + entry->visible = 0xFF; + + // Process Id of the record + entry->pid = pevent_data_pid(kshark_ctx->pevt, record); +} + +size_t kshark_load_data_entries(struct kshark_context *kshark_ctx, + struct kshark_entry ***data_rows) +{ + int n_cpus = tracecmd_cpus(kshark_ctx->handle); + int cpu; + size_t count, total = 0; + struct pevent_record *rec; + + if (*data_rows) + free(*data_rows); + + struct kshark_entry *entry, **next; + struct kshark_entry **cpu_list = calloc(n_cpus, sizeof(struct kshark_entry *)); + + for (cpu = 0; cpu < n_cpus; ++cpu) { + count = 0; + cpu_list[cpu] = NULL; + next = &cpu_list[cpu]; + + rec = tracecmd_read_cpu_first(kshark_ctx->handle, cpu); + while (rec) { + *next = entry = malloc( sizeof(struct kshark_entry) ); + assert(entry != NULL); + + kshark_set_entry_values(kshark_ctx, rec, entry); + kshark_add_task(kshark_ctx, entry->pid); + + entry->next = NULL; + next = &(entry->next); + free_record(rec); + + ++count; + rec = tracecmd_read_data(kshark_ctx->handle, cpu); + } + + total += count; + } + + struct kshark_entry **rows; + rows = calloc(total, sizeof(struct kshark_entry *)); + if(!rows) { + fprintf(stderr, "Failed to allocate memory during data loading.\n"); + return 0; + } + + count = 0; + int next_cpu; + uint64_t ts; + while (count < total) { + ts = 0; + next_cpu = -1; + for (cpu = 0; cpu < n_cpus; ++cpu) { + if (!cpu_list[cpu]) + continue; + + if (!ts || cpu_list[cpu]->ts < ts) { + ts = cpu_list[cpu]->ts; + next_cpu = cpu; + } + } + + if (next_cpu >= 0) { + rows[count] = cpu_list[next_cpu]; + cpu_list[next_cpu] = cpu_list[next_cpu]->next; + } + ++count; + } + + free(cpu_list); + *data_rows = rows; + return total; +} + +size_t kshark_load_data_records(struct kshark_context *kshark_ctx, + struct pevent_record ***data_rows) +{ + int n_cpus = tracecmd_cpus(kshark_ctx->handle); + int cpu; + size_t count, total = 0; + struct pevent_record *data; + + struct temp { + struct pevent_record *rec; + struct temp *next; + } **cpu_list, **temp_next, *temp_rec; + + cpu_list = calloc(n_cpus, sizeof(struct temp *)); + + for (cpu = 0; cpu < n_cpus; ++cpu) { + count = 0; + cpu_list[cpu] = NULL; + temp_next = &cpu_list[cpu]; + + data = tracecmd_read_cpu_first(kshark_ctx->handle, cpu); + while (data) { + *temp_next = temp_rec = malloc(sizeof(*temp_rec)); + assert(temp_rec != NULL); + + kshark_add_task(kshark_ctx, + pevent_data_pid(kshark_ctx->pevt, data)); + temp_rec->rec = data; + temp_rec->next = NULL; + temp_next = &(temp_rec->next); + + ++count; + data = tracecmd_read_data(kshark_ctx->handle, cpu); + } + + total += count; + } + + struct pevent_record **rows; + rows = calloc(total, sizeof(struct pevent_record *)); + if(!rows) { + fprintf(stderr, "Failed to allocate memory during data loading.\n"); + return 0; + } + + count = 0; + int next_cpu; + uint64_t ts; + while (count < total) { + ts = 0; + next_cpu = -1; + for (cpu = 0; cpu < n_cpus; ++cpu) { + if (!cpu_list[cpu]) + continue; + + if (!ts || cpu_list[cpu]->rec->ts < ts) { + ts = cpu_list[cpu]->rec->ts; + next_cpu = cpu; + } + } + + if (next_cpu >= 0) { + rows[count] = cpu_list[next_cpu]->rec; + temp_rec = cpu_list[next_cpu]; + cpu_list[next_cpu] = cpu_list[next_cpu]->next; + free (temp_rec); + } + + ++count; + } + + free(cpu_list); + *data_rows = rows; + return total; +} + +static struct pevent_record *kshark_read_at(struct kshark_context *kshark_ctx, + uint64_t offset) +{ + pthread_mutex_lock(&kshark_ctx->input_mutex); + + struct pevent_record *data = tracecmd_read_at(kshark_ctx->handle, + offset, NULL); + + pthread_mutex_unlock(&kshark_ctx->input_mutex); + + return data; +} + +static const char *kshark_get_latency(struct pevent *pe, + struct pevent_record *record) +{ + if (!record) + return NULL; + + trace_seq_reset(&seq); + pevent_data_lat_fmt(pe, &seq, record); + return seq.buffer; +} + +static const char *kshark_get_info(struct pevent *pe, + struct pevent_record *record, + struct event_format *event) +{ + if (!record || !event) + return NULL; + + trace_seq_reset(&seq); + pevent_event_info(&seq, event, record); + + // Remove the trailing newline from the Info string. + char *pos; + if ((pos = strchr(seq.buffer, '\n')) != NULL) + *pos = '\0'; + + return seq.buffer; +} + +char* kshark_dump_entry(struct kshark_entry *entry) +{ + struct kshark_context *kshark_ctx = NULL; + kshark_instance(&kshark_ctx); + + if (!seq.buffer) + trace_seq_init(&seq); + + trace_seq_reset(&seq); + + char *tmp_str, *entry_str; + int size_tmp, size = 0; + + struct pevent_record *data = kshark_read_at(kshark_ctx, entry->offset); + + int event_id = pevent_data_type(kshark_ctx->pevt, data); + struct event_format *event = + pevent_data_event_from_type(kshark_ctx->pevt, event_id); + + const char *event_name = (event)? event->name : "[UNKNOWN EVENT]"; + const char *task = pevent_data_comm_from_pid(kshark_ctx->pevt, entry->pid); + const char *lat = kshark_get_latency(kshark_ctx->pevt, data); + + size_tmp = asprintf(&tmp_str, "%li %s-%i; CPU %i; %s;", + entry->ts, + task, + entry->pid, + entry->cpu, + lat); + + const char *info = kshark_get_info(kshark_ctx->pevt, data, event); + if (size_tmp) { + size = asprintf(&entry_str, "%s %s; %s; 0x%x", + tmp_str, + event_name, + info, + entry->visible); + + free(tmp_str); + } + + free_record(data); + + if (size > 0) + return entry_str; + + return NULL; +} diff --git a/kernel-shark-qt/src/libkshark.h b/kernel-shark-qt/src/libkshark.h new file mode 100644 index 0000000..d6e41bb --- /dev/null +++ b/kernel-shark-qt/src/libkshark.h @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ + +/* + * Copyright (C) 2017 VMware Inc, Yordan Karadzhov + */ + + /** + * @file libkshark.h + * @brief API for processing of FTRACE (trace-cmd) data. + */ + +#ifndef _LIB_KSHARK_H +#define _LIB_KSHARK_H + +// C +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// trace-cmd +#include "trace-cmd.h" +#include "event-parse.h" + +/** + * Kernel Shark entry contains all information from one trace record, needed in order to + * visualize the time-series of trace records. The part of the data which is not directly + * required for the visualization (latency, record info etc.) is available on-demand via + * the offset into the treace file. + */ +struct kshark_entry { + /** + * A bit mask controlling the visibility of the entry. A value of OxFF would mean + * that the entry is visible everywhere. + */ + uint8_t visible; + + /** The CPU core of the record. */ + uint8_t cpu; + + /** The PID of the task the record was generated. */ + int16_t pid; + + /** Unique Id ot the trace event type. */ + int event_id; + + /** The offset into the treace file, used to find the record. */ + uint64_t offset; + + /** + * The time of the record in nano seconds. The value is taken from the timestamps + * within the trace data file, which are architecture dependent. The time usually + * is the timestamp from when the system started. + */ + uint64_t ts; + + /** Pointer to the next (in time) kshark_entry on the same CPU core. */ + struct kshark_entry *next; +}; + +/** Linked list of tasks. */ +struct kshark_task_list { + /** Pointer to the next task's PID. */ + struct kshark_task_list *next; + + /** PID of a task. */ + int pid; +}; + +/** Structure representing a kshark session. */ +struct kshark_context { + /** Input handle for the trace data file. */ + struct tracecmd_input *handle; + + /** Page event used to parse the page. */ + struct pevent *pevt; + + /** List of task's PIDs. */ + struct kshark_task_list *tasks; + + /** A mutex, used to protect the access to the input file. */ + pthread_mutex_t input_mutex; +}; + +/** + * @brief Initialize a kshark session. This function must be called before calling any + * other kshark function. If the session has been initialized, this function can be used + * to obtain the session's context. + * @param kshark_ctx: Optional input/output location for context pointer. Only valid on + * return true. + * @returns true on success, or false on failure. + + */ +bool kshark_instance(struct kshark_context **kshark_ctx); + +/** + * @brief Open and prepare for reading a trace data file specified by "file". If the + * specified file does not exist, or contains no trace data, the function returns false. + * @param kshark_ctx: Input location for context pointer. + * @param file: The file to load. + * @returns true on success, or false on failure. + */ +bool kshark_open(struct kshark_context *kshark_ctx, const char *file); + +/** + * @brief Load the content of the trace data file into an array of kshark_entries. This + * function provides fast loading, however the "latency" and the "info" fields can be + * accessed only via the offset into the file. This makes the access to these two fields + * much slower. + * @param kshark_ctx: Input location for context pointer. + * @param data_rows: Output location for the trace data. The user is responsible for + * freeing the elements of the outputted array. + * @returns The size of the outputted data. + */ +size_t kshark_load_data_entries(struct kshark_context *kshark_ctx, + struct kshark_entry ***data_rows); + +/** + * @brief Load the content of the trace data file into an array of pevent_records. Use + * this function only if you need fast access to all fields of the record. + * @param kshark_ctx: Input location for the session context pointer. + * @param data_rows: Output location for the trace data. Use free_record() to free + * the elements of the outputted array. + * @returns The size of the outputted data. + */ +size_t kshark_load_data_records(struct kshark_context *kshark_ctx, + struct pevent_record ***data_rows); + +/** + * @brief Close the trace data file and free the trace data handle. + * @param kshark_ctx: Input location for the session context pointer. + */ +void kshark_close(struct kshark_context *kshark_ctx); + +/** + * @brief Deinitialize kshark session. Should be called after closing all open trace data + * files and before your application terminates. + * @param kshark_ctx: Optional input location for session context pointer. + */ +void kshark_free(struct kshark_context *kshark_ctx); + +/** + * @brief Dump into a sting the content of one entry. The function allocates a null + * terminated string and return a pointer to this string. The user has to free the + * returned string. + * @param entry: A Kernel Shark entry to be printed. + * @returns The returned string contains a semicolon-separated list of data fields. + */ +char* kshark_dump_entry(struct kshark_entry *entry); + +#ifdef __cplusplus +} +#endif + +#endif // _LIB_KSHARK_H From patchwork Mon Jun 25 15:01:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 10758575 Return-Path: Received: from mail-wr0-f196.google.com ([209.85.128.196]:38204 "EHLO mail-wr0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934559AbeFYPCV (ORCPT ); Mon, 25 Jun 2018 11:02:21 -0400 Received: by mail-wr0-f196.google.com with SMTP id e18-v6so14034617wrs.5 for ; Mon, 25 Jun 2018 08:02:20 -0700 (PDT) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 4/7] kernel-shark-qt: Add an example showing how to load trace data Date: Mon, 25 Jun 2018 18:01:18 +0300 Message-Id: <20180625150121.14291-5-y.karadz@gmail.com> In-Reply-To: <20180625150121.14291-1-y.karadz@gmail.com> References: <20180625150121.14291-1-y.karadz@gmail.com> Sender: linux-trace-devel-owner@vger.kernel.org List-ID: Content-Length: 3726 This patch introduces a basic example, showing how to use the C API of KernelShark and open a new session, load a trace data file, produced by trace-cmd, print some data to the screen, cleanup and then exit. Signed-off-by: Yordan Karadzhov (VMware) --- kernel-shark-qt/CMakeLists.txt | 1 + kernel-shark-qt/build/cmake_clean.sh | 1 + kernel-shark-qt/examples/CMakeLists.txt | 5 ++ kernel-shark-qt/examples/dataload.c | 80 +++++++++++++++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 kernel-shark-qt/examples/CMakeLists.txt create mode 100644 kernel-shark-qt/examples/dataload.c diff --git a/kernel-shark-qt/CMakeLists.txt b/kernel-shark-qt/CMakeLists.txt index 9929937..9ff12a1 100644 --- a/kernel-shark-qt/CMakeLists.txt +++ b/kernel-shark-qt/CMakeLists.txt @@ -33,6 +33,7 @@ message(STATUS "CXX flags : " ${CMAKE_CXX_FLAGS}) message(STATUS "Linker flags : " ${CMAKE_EXE_LINKER_FLAGS}) add_subdirectory(${KS_DIR}/src) +add_subdirectory(${KS_DIR}/examples) if (_DOXYGEN_DOC AND DOXYGEN_FOUND) diff --git a/kernel-shark-qt/build/cmake_clean.sh b/kernel-shark-qt/build/cmake_clean.sh index 57c40a4..acdbb43 100755 --- a/kernel-shark-qt/build/cmake_clean.sh +++ b/kernel-shark-qt/build/cmake_clean.sh @@ -4,6 +4,7 @@ rm cmake_install.cmake rm Makefile rm -rf CMakeFiles/ rm -rf src/ +rm -rf examples/ rm -f ../lib/* rm -f ../src/KsDeff.h rm -f CMakeDoxyfile.in diff --git a/kernel-shark-qt/examples/CMakeLists.txt b/kernel-shark-qt/examples/CMakeLists.txt new file mode 100644 index 0000000..98df9d8 --- /dev/null +++ b/kernel-shark-qt/examples/CMakeLists.txt @@ -0,0 +1,5 @@ +message("\n examples ...") + +message(STATUS "dataload") +add_executable(dload dataload.c) +target_link_libraries(dload kshark) diff --git a/kernel-shark-qt/examples/dataload.c b/kernel-shark-qt/examples/dataload.c new file mode 100644 index 0000000..a5c0ed3 --- /dev/null +++ b/kernel-shark-qt/examples/dataload.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2018 VMware Inc, Yordan Karadzhov + */ + +// C +#include +#include + +// KernelShark +#include "libkshark.h" + +const char *default_file = "trace.dat"; + +int main(int argc, char **argv) +{ + // Create a new kshark session. + struct kshark_context *kshark_ctx = NULL; + kshark_instance(&kshark_ctx); + + // Open a trace data file produced by trace-cmd. + bool status; + if (argc > 1) + status = kshark_open(kshark_ctx, argv[1]); + else + status = kshark_open(kshark_ctx, default_file); + + if (!status) { + kshark_free(kshark_ctx); + return 1; + } + + // Load the content of the file into an array of entries. + struct kshark_entry **data = NULL; + size_t r, n_rows; + n_rows = kshark_load_data_entries(kshark_ctx, &data); + + // Print to the screen the list of all tasks. + struct kshark_task_list* task = kshark_ctx->tasks; + while (task) { + const char *task_str = pevent_data_comm_from_pid(kshark_ctx->pevt, + task->pid); + printf("task: %s-%i\n", task_str, task->pid); + task = task->next; + } + + puts("\n\n"); + + // Print to the screen the first 10 entries. + char *entry_str; + for (r = 0; r < 10; ++r) { + entry_str = kshark_dump_entry(data[r]); + puts(entry_str); + free(entry_str); + } + + puts("\n...\n"); + + // Print the last 10 entries. + for (r = n_rows - 10; r < n_rows; ++r) { + entry_str = kshark_dump_entry(data[r]); + puts(entry_str); + free(entry_str); + } + + // Free the memory. + for (r = 0; r < n_rows; ++r) + free(data[r]); + + free(data); + + // Close the file. + kshark_close(kshark_ctx); + + // Close the session. + kshark_free(kshark_ctx); + + return 0; +} From patchwork Mon Jun 25 15:01:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 10758577 Return-Path: Received: from mail-wr0-f195.google.com ([209.85.128.195]:40537 "EHLO mail-wr0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934559AbeFYPCY (ORCPT ); Mon, 25 Jun 2018 11:02:24 -0400 Received: by mail-wr0-f195.google.com with SMTP id g18-v6so14025775wro.7 for ; Mon, 25 Jun 2018 08:02:23 -0700 (PDT) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 5/7] kernel-shark-qt: Add a README file to trace-cmd/kernel-shark-qt Date: Mon, 25 Jun 2018 18:01:19 +0300 Message-Id: <20180625150121.14291-6-y.karadz@gmail.com> In-Reply-To: <20180625150121.14291-1-y.karadz@gmail.com> References: <20180625150121.14291-1-y.karadz@gmail.com> Sender: linux-trace-devel-owner@vger.kernel.org List-ID: Content-Length: 1688 The README file contains instructions for building and using the Qt-based version of KernelShark. Signed-off-by: Yordan Karadzhov (VMware) --- kernel-shark-qt/README | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 kernel-shark-qt/README diff --git a/kernel-shark-qt/README b/kernel-shark-qt/README new file mode 100644 index 0000000..7cae9ed --- /dev/null +++ b/kernel-shark-qt/README @@ -0,0 +1,37 @@ + +This directory contains the new Qt-based version of the KernelShark GUI. + + +Third Party Software: +------------------------------------------------------------ +The external dependencies: +1. In order to install the packages on Ubuntu do the following: + sudo apt-get install build-essential git cmake -y + +2. In order to install the packages on Fedora, as root do the following: + dnf install gcc gcc-c++ git cmake -y + + +Building: +------------------------------------------------------------ +1. Follow the instructions given in trace-cmd/README and build +the original trace-cmd end traceevent libraries. + +2. Do: + cd kernel-shark-qt/build + cmake ../ + make + +2.1 In order to create a Doxygen documentation add -D_DOXYGEN_DOC=1 +as a CMake Command-Line option. + cd kernel-shark-qt/build + cmake -D_DOXYGEN_DOC=1 ../ + make + +2.2.1 Use "make clean" if you want to delete all already compiled object. + +2.2.2 Use the script "cmake_clean.sh" if you want to delete all already +compiled object and all files generated by CMake. + +3. After building the code "kernel-shark-qt/lib" will contain all libraries +and "kernel-shark-qt/bin" will contain all executables. From patchwork Mon Jun 25 15:01:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 10758579 Return-Path: Received: from mail-wr0-f196.google.com ([209.85.128.196]:37792 "EHLO mail-wr0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934559AbeFYPC0 (ORCPT ); Mon, 25 Jun 2018 11:02:26 -0400 Received: by mail-wr0-f196.google.com with SMTP id k6-v6so14034519wrp.4 for ; Mon, 25 Jun 2018 08:02:26 -0700 (PDT) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 6/7] kernel-shark-qt: Add filtering to the C API of KernelShark Date: Mon, 25 Jun 2018 18:01:20 +0300 Message-Id: <20180625150121.14291-7-y.karadz@gmail.com> In-Reply-To: <20180625150121.14291-1-y.karadz@gmail.com> References: <20180625150121.14291-1-y.karadz@gmail.com> Sender: linux-trace-devel-owner@vger.kernel.org List-ID: Content-Length: 9452 Instruments for trace data filtering are added to the C API of the Qt-based version of KernelShark. The following patch will introduces an example, demonstrating the usage of this instruments. Signed-off-by: Yordan Karadzhov (VMware) --- kernel-shark-qt/src/libkshark.c | 141 ++++++++++++++++++++++++++++++++ kernel-shark-qt/src/libkshark.h | 75 +++++++++++++++++ 2 files changed, 216 insertions(+) diff --git a/kernel-shark-qt/src/libkshark.c b/kernel-shark-qt/src/libkshark.c index f112a50..c6e03a8 100644 --- a/kernel-shark-qt/src/libkshark.c +++ b/kernel-shark-qt/src/libkshark.c @@ -28,6 +28,14 @@ static bool kshark_default_context(struct kshark_context **context) if (!kshark_ctx) return false; + kshark_ctx->show_task_filter = tracecmd_filter_id_hash_alloc(); + kshark_ctx->hide_task_filter = tracecmd_filter_id_hash_alloc(); + + kshark_ctx->show_event_filter = tracecmd_filter_id_hash_alloc(); + kshark_ctx->hide_event_filter = tracecmd_filter_id_hash_alloc(); + + kshark_ctx->filter_mask = 0x0; + /* Free the existing context (if any). */ if (*context && *context != kshark_context_handler) { free(*context); @@ -112,6 +120,15 @@ void kshark_close(struct kshark_context *kshark_ctx) if (!kshark_ctx || !kshark_ctx->handle) return; + /* + * All Id filters are file specific. Make sure that the Pids and Event Ids + * from this file are not going to be used with another file. + */ + tracecmd_filter_id_clear(kshark_ctx->show_task_filter); + tracecmd_filter_id_clear(kshark_ctx->hide_task_filter); + tracecmd_filter_id_clear(kshark_ctx->show_event_filter); + tracecmd_filter_id_clear(kshark_ctx->hide_event_filter); + tracecmd_close(kshark_ctx->handle); kshark_ctx->handle = NULL; kshark_ctx->pevt = NULL; @@ -129,6 +146,12 @@ void kshark_free(struct kshark_context *kshark_ctx) kshark_context_handler = NULL; } + tracecmd_filter_id_hash_free(kshark_ctx->show_task_filter); + tracecmd_filter_id_hash_free(kshark_ctx->hide_task_filter); + + tracecmd_filter_id_hash_free(kshark_ctx->show_event_filter); + tracecmd_filter_id_hash_free(kshark_ctx->hide_event_filter); + kshark_free_task_list(kshark_ctx); if (seq.buffer) @@ -171,6 +194,113 @@ kshark_add_task(struct kshark_context *kshark_ctx, int pid) return list; } +static bool kshark_show_task(struct kshark_context *kshark_ctx, int pid) +{ + return (!kshark_ctx->show_task_filter || + !kshark_ctx->show_task_filter->count || + tracecmd_filter_id_find(kshark_ctx->show_task_filter, pid)) && + (!kshark_ctx->hide_task_filter || + !kshark_ctx->hide_task_filter->count || + !tracecmd_filter_id_find(kshark_ctx->hide_task_filter, pid)); +} + +static bool kshark_show_event(struct kshark_context *kshark_ctx, int event_id) +{ + return (!kshark_ctx->show_event_filter || + !kshark_ctx->show_event_filter->count || + tracecmd_filter_id_find(kshark_ctx->show_event_filter, event_id)) && + (!kshark_ctx->hide_event_filter || + !kshark_ctx->hide_event_filter->count || + !tracecmd_filter_id_find(kshark_ctx->hide_event_filter, event_id)); +} + +void kshark_filter_add_id(struct kshark_context *kshark_ctx, int filter_id, int id) +{ + switch (filter_id) { + case SHOW_EVENT_FILTER: + tracecmd_filter_id_add(kshark_ctx->show_event_filter, id); + break; + + case HIDE_EVENT_FILTER: + tracecmd_filter_id_add(kshark_ctx->hide_event_filter, id); + break; + + case SHOW_TASK_FILTER: + tracecmd_filter_id_add(kshark_ctx->show_task_filter, id); + break; + + case HIDE_TASK_FILTER: + tracecmd_filter_id_add(kshark_ctx->hide_task_filter, id); + break; + + default: + break; + } +} + +void kshark_filter_clear(struct kshark_context *kshark_ctx, int filter_id) +{ + switch (filter_id) { + case SHOW_EVENT_FILTER: + tracecmd_filter_id_clear(kshark_ctx->show_event_filter); + break; + + case HIDE_EVENT_FILTER: + tracecmd_filter_id_clear(kshark_ctx->hide_event_filter); + break; + + case SHOW_TASK_FILTER: + tracecmd_filter_id_clear(kshark_ctx->show_task_filter); + break; + + case HIDE_TASK_FILTER: + tracecmd_filter_id_clear(kshark_ctx->hide_task_filter); + break; + + default: + break; + } +} + +static bool kshark_filter_is_set(struct kshark_context *kshark_ctx) +{ + if ((kshark_ctx->show_task_filter && + kshark_ctx->show_task_filter->count) || + (kshark_ctx->hide_task_filter && + kshark_ctx->hide_task_filter->count) || + (kshark_ctx->show_event_filter && + kshark_ctx->show_event_filter->count) || + (kshark_ctx->hide_event_filter && + kshark_ctx->hide_event_filter->count)) { + return true; + } + + return false; +} + +void kshark_filter_entries(struct kshark_context *kshark_ctx, + struct kshark_entry **data, + size_t n_entries) +{ + if (!kshark_filter_is_set(kshark_ctx)) + return; + + int i; + for (i = 0; i < n_entries; ++i) { + data[i]->visible = 0xFF; + if (!kshark_show_task(kshark_ctx, data[i]->pid)) { + data[i]->visible &= ~kshark_ctx->filter_mask; + } + + if (!kshark_show_event(kshark_ctx, data[i]->event_id)) { + int mask = kshark_ctx->filter_mask; + mask &= ~KS_GRAPH_VIEW_FILTER_MASK; + mask |= KS_EVENT_VIEW_FILTER_MASK; + data[i]->visible &= ~mask; + } + } +} + static void kshark_set_entry_values(struct kshark_context *kshark_ctx, struct pevent_record *record, struct kshark_entry *entry) @@ -224,6 +354,17 @@ size_t kshark_load_data_entries(struct kshark_context *kshark_ctx, kshark_set_entry_values(kshark_ctx, rec, entry); kshark_add_task(kshark_ctx, entry->pid); + if (!kshark_show_task(kshark_ctx, entry->pid)) { + entry->visible &= ~kshark_ctx->filter_mask; + } + + if (!kshark_show_event(kshark_ctx, entry->event_id)) { + int mask = kshark_ctx->filter_mask; + mask &= ~KS_GRAPH_VIEW_FILTER_MASK; + mask |= KS_EVENT_VIEW_FILTER_MASK; + entry->visible &= ~mask; + } + entry->next = NULL; next = &(entry->next); free_record(rec); diff --git a/kernel-shark-qt/src/libkshark.h b/kernel-shark-qt/src/libkshark.h index d6e41bb..460c0c5 100644 --- a/kernel-shark-qt/src/libkshark.h +++ b/kernel-shark-qt/src/libkshark.h @@ -22,6 +22,7 @@ extern "C" { // trace-cmd #include "trace-cmd.h" +// #include "trace-filter-hash.h" #include "event-parse.h" /** @@ -82,6 +83,25 @@ struct kshark_context { /** A mutex, used to protect the access to the input file. */ pthread_mutex_t input_mutex; + + /** Hash of tasks to filter on. */ + struct tracecmd_filter_id *show_task_filter; + + /** Hash of tasks to not display. */ + struct tracecmd_filter_id *hide_task_filter; + + /** Hash of events to filter on. */ + struct tracecmd_filter_id *show_event_filter; + + /** Hash of events to not display. */ + struct tracecmd_filter_id *hide_event_filter; + + /** + * Bit mask, controlling the visibility of the entries after filtering. If given + * bit is set here, all entries which are filtered-out will have this bit unset + * in their "visible" fields. + */ + uint8_t filter_mask; }; /** @@ -150,6 +170,61 @@ void kshark_free(struct kshark_context *kshark_ctx); */ char* kshark_dump_entry(struct kshark_entry *entry); +/** Bit masks used to control the visibility of the entry after filtering. */ +enum kshark_filter_masks { + /** Use this mask to check the visibility of the entry in the text view. */ + KS_TEXT_VIEW_FILTER_MASK = (1 << 0), + + /** Use this mask to check the visibility of the entry in the graph view. */ + KS_GRAPH_VIEW_FILTER_MASK = (1 << 1), + + /** Special mask used whene filtering events. */ + KS_EVENT_VIEW_FILTER_MASK = (1 << 2), +}; + +/** Filter type identifier. */ +enum kshark_filter_type { + /** Identifier of the filter, used to specified the events to be shown. */ + SHOW_EVENT_FILTER, + + /** Identifier of the filter, used to specified the events to be filtered-out. */ + HIDE_EVENT_FILTER, + + /** Identifier of the filter, used to specified the tasks to be shown. */ + SHOW_TASK_FILTER, + + /** Identifier of the filter, used to specified the tasks to be filtered-out. */ + HIDE_TASK_FILTER, +}; + +/** + * @brief Add an Id value to the filster specified by "filter_id". + * @param kshark_ctx: kshark_ctx: Input location for the session context pointer. + * @param filter_id: Identifier of the filter. + * @param id: Id value to be added to the filter. + */ +void kshark_filter_add_id(struct kshark_context *kshark_ctx, int filter_id, int id); + +/** + * @brief Clear (reset) the filster specified by "filter_id". + * @param kshark_ctx: kshark_ctx: Input location for the session context pointer. + * @param filter_id: Identifier of the filter. + */ +void kshark_filter_clear(struct kshark_context *kshark_ctx, int filter_id); + +/** + * @brief This function loops over the array of entries specified by "data" and "n_entries" + * and sets the "visible" fields of each entry according to the criteria provided by the + * filters of the session's context. The field "filter_mask" of the session's context is + * used to control the level of visibility/invisibility of the entries which are filtered-out. + * @param kshark_ctx: kshark_ctx: Input location for the session context pointer. + * @param data: Input location for the trace data to be filtered. + * @param n_entries: The size of the inputted data. + */ +void kshark_filter_entries(struct kshark_context *kshark_ctx, + struct kshark_entry **data, + size_t n_entries); + #ifdef __cplusplus } #endif From patchwork Mon Jun 25 15:01:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 10758581 Return-Path: Received: from mail-wm0-f68.google.com ([74.125.82.68]:38514 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934559AbeFYPC2 (ORCPT ); Mon, 25 Jun 2018 11:02:28 -0400 Received: by mail-wm0-f68.google.com with SMTP id 69-v6so10385853wmf.3 for ; Mon, 25 Jun 2018 08:02:28 -0700 (PDT) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 7/7] kernel-shark-qt: Add an example showing how to filter trace data Date: Mon, 25 Jun 2018 18:01:21 +0300 Message-Id: <20180625150121.14291-8-y.karadz@gmail.com> In-Reply-To: <20180625150121.14291-1-y.karadz@gmail.com> References: <20180625150121.14291-1-y.karadz@gmail.com> Sender: linux-trace-devel-owner@vger.kernel.org List-ID: Content-Length: 3656 This patch introduces a basic example, showing how to use the C API of KernelShark in order to filter trace data. Signed-off-by: Yordan Karadzhov (VMware) --- kernel-shark-qt/examples/CMakeLists.txt | 4 + kernel-shark-qt/examples/datafilter.c | 114 ++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 kernel-shark-qt/examples/datafilter.c diff --git a/kernel-shark-qt/examples/CMakeLists.txt b/kernel-shark-qt/examples/CMakeLists.txt index 98df9d8..009fd1e 100644 --- a/kernel-shark-qt/examples/CMakeLists.txt +++ b/kernel-shark-qt/examples/CMakeLists.txt @@ -3,3 +3,7 @@ message("\n examples ...") message(STATUS "dataload") add_executable(dload dataload.c) target_link_libraries(dload kshark) + +message(STATUS "datafilter") +add_executable(dfilter datafilter.c) +target_link_libraries(dfilter kshark) diff --git a/kernel-shark-qt/examples/datafilter.c b/kernel-shark-qt/examples/datafilter.c new file mode 100644 index 0000000..e824880 --- /dev/null +++ b/kernel-shark-qt/examples/datafilter.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2018 VMware Inc, Yordan Karadzhov + */ + +// C +#include +#include + +// KernelShark +#include "libkshark.h" + +const char *default_file = "trace.dat"; + +int main(int argc, char **argv) +{ + // Create a new kshark session. + struct kshark_context *kshark_ctx = NULL; + kshark_instance(&kshark_ctx); + + // Open a trace data file produced by trace-cmd. + bool status; + if (argc > 1) + status = kshark_open(kshark_ctx, argv[1]); + else + status = kshark_open(kshark_ctx, default_file); + + if (!status) { + kshark_free(kshark_ctx); + return 1; + } + + // Load the content of the file into an array of entries. + struct kshark_entry **data = NULL; + size_t n_rows; + n_rows = kshark_load_data_entries(kshark_ctx, &data); + + // Filter the trace data coming from trace-cmd. + struct kshark_task_list* task = kshark_ctx->tasks; + while (task) { + const char *task_str = pevent_data_comm_from_pid(kshark_ctx->pevt, + task->pid); + + if (strcmp(task_str, "trace-cmd") == 0) + kshark_filter_add_id(kshark_ctx, HIDE_TASK_FILTER, + task->pid); + + task = task->next; + } + + /* + * Set the Filter Mask. In this case we want to avoid showing the filterd + * entris in text format. + */ + kshark_ctx->filter_mask = KS_TEXT_VIEW_FILTER_MASK; + + kshark_filter_entries(kshark_ctx, data, n_rows); + + // Print to the screen the first 10 visible entries. + char *entry_str; + size_t r = 0, count = 0; + while (count < 10) { + if (data[r]->visible & KS_TEXT_VIEW_FILTER_MASK) { + entry_str = kshark_dump_entry(data[r]); + puts(entry_str); + free(entry_str); + ++count; + } + + ++r; + } + + puts("\n\n"); + + struct event_format *event; + size_t i, n_evts = kshark_ctx->pevt->nr_events; + for (i = 0; i < n_evts; ++i) { + event = kshark_ctx->pevt->events[i]; + if (strcmp(event->system, "sched") == 0) + kshark_filter_add_id(kshark_ctx, SHOW_EVENT_FILTER, + event->id); + } + + kshark_filter_entries(kshark_ctx, data, n_rows); + + // Print to the screen the first 10 visible entries. + count = 0; + r = 0; + while (count < 10) { + if (data[r]->visible & KS_TEXT_VIEW_FILTER_MASK) { + entry_str = kshark_dump_entry(data[r]); + puts(entry_str); + free(entry_str); + ++count; + } + + ++r; + } + + // Free the memory. + for (r = 0; r < n_rows; ++r) + free(data[r]); + + free(data); + + // Close the file. + kshark_close(kshark_ctx); + + // Close the session. + kshark_free(kshark_ctx); + + return 0; +}