From patchwork Thu Jan 7 16:15:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12004403 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3EBABC433E0 for ; Thu, 7 Jan 2021 16:16:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 070E423118 for ; Thu, 7 Jan 2021 16:16:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728088AbhAGQQp (ORCPT ); Thu, 7 Jan 2021 11:16:45 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44728 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727327AbhAGQQp (ORCPT ); Thu, 7 Jan 2021 11:16:45 -0500 Received: from mail-ed1-x52e.google.com (mail-ed1-x52e.google.com [IPv6:2a00:1450:4864:20::52e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E278DC0612F5 for ; Thu, 7 Jan 2021 08:16:04 -0800 (PST) Received: by mail-ed1-x52e.google.com with SMTP id cw27so8288400edb.5 for ; Thu, 07 Jan 2021 08:16:04 -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=PMw4L2ve2WxqUYu8kFltnlB64JiUbb7s0LJmU4h7gPk=; b=Nom3bQSraGJR+y1ktvSMAEeBTpXAWP0c66TQJR8O/PZF1/By8+uuF0xjDHHNbBFo2W WIr/znP6N27sBBXeRQ6Y/Pai7ogc9rPwEcrkQt3xW1ScV4Zn6WMuFlFdAx2IIF+foSJ9 3RhZaY7V7HYHG9i8y6yuWpwCWR33K/eBnEBZhtqvtVXVhUpwNY9B/dPZMuPw35InCKxj 61kJx9LrLzLQpUpRDvrBDB8bI3/6OuTbNkoEHyWn9ZwwdNVpmVNFbUAhsBh4nP/rQMXQ 1l3VAma7eCQybDKpOtMZvb1bjejXxIe5uPn4lO2gJ2v7wmNNiGfguPoDKw6UFuR08LyV WwcQ== 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=PMw4L2ve2WxqUYu8kFltnlB64JiUbb7s0LJmU4h7gPk=; b=HUaoESgq13fYTE8UlPiumMQ5EJj8A+c/CWthocDnojdruA5LXfbemGEeibIM+FFGkJ g6PLO3LNT3Rm/B4kRf6uLKxxikfCnFIYoNrWnl6CNPDkMTFoDryryDHE1gL8bL6zlOJ+ TlMESQX/lo0pLlGFdk27bpcGUAsEm82GzJ6mid0+V2yYH21bsfXv+8hZ+tZHqbkEY+Kr 6pV5xJMDcZOtTA5JapY5aOqg80YdAmSHZY8TFHm3KgNNVONu6Tc52C2+Dn2ZJsDkzv9H U01PrfRWGEgnjTOgUFWIP+LRTDSr9Mp/DKzpHbF4Z5ferZjeME0d2PqrzrsCLPll2y0D tJhw== X-Gm-Message-State: AOAM532wj+/Cc4hDgOvzNy95GMCLSyDFyHP0+6gUM6pa+rQp2dzg6Izs 0Gogah4Lu7UD5lAtHzGCyZah0lKlayIaTg== X-Google-Smtp-Source: ABdhPJz3ylAF8w5pEsLdkME9BPi/dpEClCa0F3W0UX2OPCCWRQYUftgQMnxaJkXoHCEiUVBXFQFugQ== X-Received: by 2002:a05:6402:17cb:: with SMTP id s11mr2130147edy.119.1610036163672; Thu, 07 Jan 2021 08:16:03 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id j23sm2846212edv.45.2021.01.07.08.16.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jan 2021 08:16:03 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 1/6] kernel-shark: Add KS_DOUBLE_SIZE macro Date: Thu, 7 Jan 2021 18:15:42 +0200 Message-Id: <20210107161547.207270-2-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210107161547.207270-1-y.karadz@gmail.com> References: <20210107161547.207270-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The macro is useful for resizing of dynamic arrays. It is currently used to resize the Data stream descriptor array, owned by the session context. We will later use the macro with the arrays of data fields and plugin contexts. Signed-off-by: Yordan Karadzhov (VMware) --- src/libkshark-plugin.h | 17 +++++++++++++++++ src/libkshark.c | 11 ++--------- tests/libkshark-tests.cpp | 20 ++++++++++++++++++++ 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/libkshark-plugin.h b/src/libkshark-plugin.h index 1a642ad..4104357 100644 --- a/src/libkshark-plugin.h +++ b/src/libkshark-plugin.h @@ -346,6 +346,23 @@ int kshark_handle_dpi(struct kshark_data_stream *stream, int kshark_handle_all_dpis(struct kshark_data_stream *stream, enum kshark_plugin_actions task_id); +/** General purpose macro for resizing dynamic arrays. */ +#define KS_DOUBLE_SIZE(array, size) \ +({ \ + ssize_t __n = size; \ + bool __ok = false; \ + __typeof__(array) __tmp = \ + (__typeof__(array)) realloc(array, \ + 2 * __n * sizeof(*__tmp)); \ + if (__tmp) { \ + memset(__tmp + __n, 0, __n * sizeof(*__tmp)); \ + size = 2 * __n; \ + array = __tmp; \ + __ok = true; \ + } \ + __ok; \ +}) \ + #ifdef __cplusplus } #endif // __cplusplus diff --git a/src/libkshark.c b/src/libkshark.c index 315c24f..0e2ce7a 100644 --- a/src/libkshark.c +++ b/src/libkshark.c @@ -234,16 +234,9 @@ int kshark_add_stream(struct kshark_context *kshark_ctx) if (kshark_ctx->stream_info.next_free_stream_id == kshark_ctx->stream_info.array_size) { - size_t new_size = 2 * kshark_ctx->stream_info.array_size; - struct kshark_data_stream **streams_tmp; - - streams_tmp = realloc(kshark_ctx->stream, - new_size * sizeof(*kshark_ctx->stream)); - if (!streams_tmp) + if (!KS_DOUBLE_SIZE(kshark_ctx->stream, + kshark_ctx->stream_info.array_size)) return -ENOMEM; - - kshark_ctx->stream = streams_tmp; - kshark_ctx->stream_info.array_size = new_size; } stream = kshark_stream_alloc(); diff --git a/tests/libkshark-tests.cpp b/tests/libkshark-tests.cpp index 27c1171..d0a3594 100644 --- a/tests/libkshark-tests.cpp +++ b/tests/libkshark-tests.cpp @@ -46,3 +46,23 @@ BOOST_AUTO_TEST_CASE(add_remove_streams) kshark_close_all(kshark_ctx); } + +#define ARRAY_DEFAULT_SIZE 1000 +BOOST_AUTO_TEST_CASE(doule_size_macro) +{ + int i, n = ARRAY_DEFAULT_SIZE; + int *arr = (int *) malloc(n * sizeof(*arr)); + bool ok; + + for (i = 0; i < n; ++i) + arr[i] = i; + + ok = KS_DOUBLE_SIZE(arr, n); + BOOST_CHECK_EQUAL(ok, true); + BOOST_CHECK_EQUAL(n, ARRAY_DEFAULT_SIZE * 2); + + for (i = 0; i < ARRAY_DEFAULT_SIZE; ++i) + BOOST_CHECK_EQUAL(arr[i], i); + for (; i < n; ++i) + BOOST_CHECK_EQUAL(arr[i], 0); +} From patchwork Thu Jan 7 16:15:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12004405 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6E87CC433E6 for ; Thu, 7 Jan 2021 16:16:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 368C123118 for ; Thu, 7 Jan 2021 16:16:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728246AbhAGQQr (ORCPT ); Thu, 7 Jan 2021 11:16:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44730 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727327AbhAGQQq (ORCPT ); Thu, 7 Jan 2021 11:16:46 -0500 Received: from mail-ej1-x629.google.com (mail-ej1-x629.google.com [IPv6:2a00:1450:4864:20::629]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 20D36C0612F6 for ; Thu, 7 Jan 2021 08:16:06 -0800 (PST) Received: by mail-ej1-x629.google.com with SMTP id 6so10461872ejz.5 for ; Thu, 07 Jan 2021 08:16:06 -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=bpYByy6xxf6EZQ35P6Jo81Zh0mOC5DoQ7VSTCF7bKok=; b=ARp0tLRABwsI3Wg30CuWlqzx/a50E4WOdjmW3Kxj25/Id+sW0d+8BjTICUeEAhvqlU OP1HxWEQfZmxbWdUwj0w4b6uH/szqDzQkhn9SGR9fkYGjhITcYlDVex4pE7Qv0uF02/G QW0R8m7I3zXgDiQJ2QcmmTlklrbhJEPjZowkjd66oRDRUgdJEHYDopHZ4PWerNL3Ec4B 4qV2JToZOHOwiF3eJ0OKPO8b8jFeb9QwubZdOI7dn15Pfw1tC4M51EgLFkpl/2Bf8mI4 IZDe3ZzgBCioua73EutCpTdZRW7GJ7B1dQrhbrWHnuNDdKEzBGuYygLoX39ZIWUMqgeP TX7A== 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=bpYByy6xxf6EZQ35P6Jo81Zh0mOC5DoQ7VSTCF7bKok=; b=sdyLM1cGS+eM0OLJ9xYN6Mw8Jl2uHY6jB5LqWGkvw9nXoBRnv85IqMMQmxuMNhD3wL rSqNCMaK7AA4dDWk4EFMVY3puZnCCkgDMfOFWR4/0fKDVzAjO4MTvlwAubNZUYEDJ1No Nl9zkQMV5glwjeA3WHaBf25m5ajS8L+64Mmsol0QkGMU35y12HIjEoorVicRj89KBfRC vJzSRkLHk2W1p7iRxl98BKtPU+388f6gUY8uo1Sj1jxZXH3M3HMgGtokddQDYokURunB CxO5kiXdihF6Po7mcbKzD6R24B1ARsNw2MfMYbAXmNG4SxQVrKBnKVcvsyOIGJoo/71P rTUg== X-Gm-Message-State: AOAM533nYd60i1hzURmMJ9AGUIGmx07qAhyrUpV+/Icmm3R0pNyNkEAh aJI3MP6icQjSGaJwzBpiH8E= X-Google-Smtp-Source: ABdhPJzjjybgXECGY3rBtGnUDjmpoqMMHurDKPsHl2o5tMXDT+ElffyKKzodsOTy4CoaY0HWxyJGlA== X-Received: by 2002:a17:906:55d0:: with SMTP id z16mr6759782ejp.466.1610036164882; Thu, 07 Jan 2021 08:16:04 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id j23sm2846212edv.45.2021.01.07.08.16.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jan 2021 08:16:04 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 2/6] kernel-shark: Add kshark_data_container to libkshark Date: Thu, 7 Jan 2021 18:15:43 +0200 Message-Id: <20210107161547.207270-3-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210107161547.207270-1-y.karadz@gmail.com> References: <20210107161547.207270-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org We add an infrastructure for recording the data from a particular trace event field during data loading. The goal is to avoid the use of the expensive "read_event_field" operation in the case when the value of the field is needed during the visualization processing (in plugins for example). Signed-off-by: Yordan Karadzhov (VMware) --- src/libkshark.c | 147 ++++++++++++++++++++++++++++++++++++++ src/libkshark.h | 43 +++++++++++ tests/libkshark-tests.cpp | 37 ++++++++++ 3 files changed, 227 insertions(+) diff --git a/src/libkshark.c b/src/libkshark.c index 0e2ce7a..f73e1da 100644 --- a/src/libkshark.c +++ b/src/libkshark.c @@ -2110,3 +2110,150 @@ kshark_merge_data_matrices(struct kshark_matrix_data_set *buffers, int n_buffers end: return merged_data; } + +/** @brief Allocate memory for kshark_data_container. */ +struct kshark_data_container *kshark_init_data_container() +{ + struct kshark_data_container *container; + + container = calloc(1, sizeof(*container)); + if (!container) + goto fail; + + container->data = calloc(KS_CONTAINER_DEFAULT_SIZE, + sizeof(*container->data)); + + if (!container->data) + goto fail; + + container->capacity = KS_CONTAINER_DEFAULT_SIZE; + container->sorted = false; + + return container; + + fail: + fprintf(stderr, "Failed to allocate memory for data container.\n"); + kshark_free_data_container(container); + return NULL; +} + +/** + * @brief Free the memory allocated for a kshark_data_container + * @param container: Intput location for the kshark_data_container object. + */ +void kshark_free_data_container(struct kshark_data_container *container) +{ + if (!container) + return; + + for (ssize_t i = 0; i < container->size; ++i) + free(container->data[i]); + + free(container->data); + free(container); +} + +/** + * @brief Append data field value to a kshark_data_container + * @param container: Input location for the kshark_data_container object. + * @param entry: The entry that needs addition data field value. + * @param field: The value of data field to be added. + * + * @returns The size of the container after the addition. + */ +ssize_t kshark_data_container_append(struct kshark_data_container *container, + struct kshark_entry *entry, int64_t field) +{ + struct kshark_data_field_int64 *data_field; + + if (container->capacity == container->size) { + if (!KS_DOUBLE_SIZE(container->data, + container->capacity)) + return -ENOMEM; + } + + data_field = malloc(sizeof(*data_field)); + data_field->entry = entry; + data_field->field = field; + container->data[container->size++] = data_field; + + return container->size; +} + +static int compare_time_dc(const void* a, const void* b) +{ + const struct kshark_data_field_int64 *field_a, *field_b; + + field_a = *(const struct kshark_data_field_int64 **) a; + field_b = *(const struct kshark_data_field_int64 **) b; + + if (field_a->entry->ts > field_b->entry->ts) + return 1; + + if (field_a->entry->ts < field_b->entry->ts) + return -1; + + return 0; +} + +/** + * @brief Sort in time the records in kshark_data_container. The container is + * resized in order to free the unused memory capacity. + * + * @param container: Intput location for the kshark_data_container object. + */ +void kshark_data_container_sort(struct kshark_data_container *container) +{ + struct kshark_data_field_int64 **data_tmp; + + qsort(container->data, container->size, + sizeof(struct kshark_data_field_int64 *), + compare_time_dc); + + container->sorted = true; + + data_tmp = realloc(container->data, + container->size * sizeof(*container->data)); + + if (!data_tmp) + return; + + container->data = data_tmp; + container->capacity = container->size; +} + +/** + * @brief Binary search inside a time-sorted array of kshark_data_field_int64. + * + * @param time: The value of time to search for. + * @param data: Input location for the data. + * @param l: Array index specifying the lower edge of the range to search in. + * @param h: Array index specifying the upper edge of the range to search in. + * + * @returns On success, the index of the first kshark_data_field_int64 inside + * the range, having a timestamp equal or bigger than "time". + * If all fields inside the range have timestamps greater than "time" + * the function returns BSEARCH_ALL_GREATER (negative value). + * If all fields inside the range have timestamps smaller than "time" + * the function returns BSEARCH_ALL_SMALLER (negative value). + */ +ssize_t kshark_find_entry_field_by_time(int64_t time, + struct kshark_data_field_int64 **data, + size_t l, size_t h) +{ + size_t mid; + + if (data[l]->entry->ts > time) + return BSEARCH_ALL_GREATER; + + if (data[h]->entry->ts < time) + return BSEARCH_ALL_SMALLER; + + /* + * After executing the BSEARCH macro, "l" will be the index of the last + * entry having timestamp < time and "h" will be the index of the first + * entry having timestamp >= time. + */ + BSEARCH(h, l, data[mid]->entry->ts < time); + return h; +} diff --git a/src/libkshark.h b/src/libkshark.h index dd4f2b7..aa4b3ca 100644 --- a/src/libkshark.h +++ b/src/libkshark.h @@ -1105,6 +1105,49 @@ struct kshark_matrix_data_set kshark_merge_data_matrices(struct kshark_matrix_data_set *buffers, int n_buffers); +/** + * Structure used to store the data of a kshark_entry plus one additional + * 64 bit integer data field. + */ +struct kshark_data_field_int64 { + /** The entry object holding the basic data of the trace record. */ + struct kshark_entry *entry; + + /** Additional 64 bit integer data field. */ + int64_t field; +}; + +/** The capacity of the kshark_data_container object after initialization. */ +#define KS_CONTAINER_DEFAULT_SIZE 1024 + +/** Structure used to store an array of entries and data fields. */ +struct kshark_data_container { + /** An array of kshark_data_field_int64 objects. */ + struct kshark_data_field_int64 **data; + + /** The total number of kshark_data_field_int64 objects stored. */ + ssize_t size; + + /** The memory capacity of the container. */ + ssize_t capacity; + + /** Is sorted in time. */ + bool sorted; +}; + +struct kshark_data_container *kshark_init_data_container(); + +void kshark_free_data_container(struct kshark_data_container *container); + +ssize_t kshark_data_container_append(struct kshark_data_container *container, + struct kshark_entry *entry, int64_t field); + +void kshark_data_container_sort(struct kshark_data_container *container); + +ssize_t kshark_find_entry_field_by_time(int64_t time, + struct kshark_data_field_int64 **data, + size_t l, size_t h); + #ifdef __cplusplus } #endif diff --git a/tests/libkshark-tests.cpp b/tests/libkshark-tests.cpp index d0a3594..8a5dcf1 100644 --- a/tests/libkshark-tests.cpp +++ b/tests/libkshark-tests.cpp @@ -66,3 +66,40 @@ BOOST_AUTO_TEST_CASE(doule_size_macro) for (; i < n; ++i) BOOST_CHECK_EQUAL(arr[i], 0); } + +#define N_VALUES 2 * KS_CONTAINER_DEFAULT_SIZE + 1 +#define MAX_TS 100000 +BOOST_AUTO_TEST_CASE(fill_data_container) +{ + struct kshark_data_container *data = kshark_init_data_container(); + struct kshark_entry entries[N_VALUES]; + int64_t i, ts_last(0); + + BOOST_CHECK_EQUAL(data->capacity, KS_CONTAINER_DEFAULT_SIZE); + + for (i = 0; i < N_VALUES; ++i) { + entries[i].ts = rand() % MAX_TS; + kshark_data_container_append(data, &entries[i], 10 - entries[i].ts); + } + + BOOST_CHECK_EQUAL(data->size, N_VALUES); + BOOST_CHECK_EQUAL(data->capacity, 4 * KS_CONTAINER_DEFAULT_SIZE); + + kshark_data_container_sort(data); + BOOST_CHECK_EQUAL(data->capacity, N_VALUES); + for (i = 0; i < N_VALUES; ++i) { + BOOST_REQUIRE(data->data[i]->entry->ts >= ts_last); + BOOST_CHECK_EQUAL(data->data[i]->entry->ts, + 10 - data->data[i]->field); + + ts_last = data->data[i]->entry->ts; + } + + i = kshark_find_entry_field_by_time(MAX_TS / 2, data->data, + 0, N_VALUES - 1); + + BOOST_REQUIRE(data->data[i - 1]->entry->ts < MAX_TS / 2); + BOOST_REQUIRE(data->data[i]->entry->ts >= MAX_TS / 2); + + kshark_free_data_container(data); +} From patchwork Thu Jan 7 16:15:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12004407 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE, SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 90D2EC433E0 for ; Thu, 7 Jan 2021 16:16:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5AEFE23118 for ; Thu, 7 Jan 2021 16:16:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728282AbhAGQQs (ORCPT ); Thu, 7 Jan 2021 11:16:48 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44736 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727327AbhAGQQr (ORCPT ); Thu, 7 Jan 2021 11:16:47 -0500 Received: from mail-ej1-x635.google.com (mail-ej1-x635.google.com [IPv6:2a00:1450:4864:20::635]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 57892C0612F8 for ; Thu, 7 Jan 2021 08:16:07 -0800 (PST) Received: by mail-ej1-x635.google.com with SMTP id 6so10461966ejz.5 for ; Thu, 07 Jan 2021 08:16:07 -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=jmkMu/QYHXmGG1seImCzj9Y70IrC/yFLNCWMankBDtA=; b=f2O982BB4k4CKUOGjrbE/2HUj6bj5MCpcojolL4HKWn9cXNVFl4s568ytveCgbWkqy 0AHyq07MYC2Bw1eFS2sLTl+vIuSi55Ob+8E3LC4yT11mzlX6u/BsgKul55VP2mMFmL5f +CuAcHrc3oaIeYKkbTHIj3BB0d88EdYQ2SdEHUSerW6gPAslUPSRWf7xlBdC+5IMm59Z 83CKeKFe6kpssrnLmmcPxIG14irnS1YKLF8wfKQj+oPxBYU+uOF4AshwQKBcF7DnSx6p g7htqJyL9K1fmv4/J6ZdhTCIIzk7Uh3U3id+rwp3lFx1lxo5SDdAhfWr2TqcOcprCXad vtWA== 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=jmkMu/QYHXmGG1seImCzj9Y70IrC/yFLNCWMankBDtA=; b=bVwZ3/8e6TxsEyUkIgK+nWybHebpRxR44oD3cNLKhT2JCU9kEWgIS/PseG27Ik776f MNwuijSPY7em9l46OGak0BMgUSvz10nW7fNOfVnMmFFct7xryHiFE9vC67W/R+P9IIGi wIXMo5W0tPRV0lzbUMpg7pspM43/bqez4TmFT4/NxS1uKkN0K2XjlI8liYPB5bVxcfN/ mR+EOBg7fdvRqVrN6jqkeUDCHlYdQhQKa0Lsu/fFhraUv5t2AagvG8CE/6Po12N6vwp+ 7dpR1kpuQl6YJDObpqho05iVvg9kQ7xnvntgAgiLk1Mshtb7GRbIu5zFxig3ZDxVTOB8 4f/g== X-Gm-Message-State: AOAM532gsSvdtWpHTE+NgksvOlA4GE/neQ4BoFmHopZqwUlLP/1uhCRI Cyn+Z3mprnG4DstxWE+1SIM= X-Google-Smtp-Source: ABdhPJzySOy6u/O/4VWh0YV/QtWgX/tfECW0potYWHnOJo2el3Bc4jupJ2bFc/Ck6GinYfKx8Z3Ekg== X-Received: by 2002:a17:906:3fc4:: with SMTP id k4mr6628770ejj.137.1610036166111; Thu, 07 Jan 2021 08:16:06 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id j23sm2846212edv.45.2021.01.07.08.16.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jan 2021 08:16:05 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 3/6] kernel-shark: Add KS_DEFINE_PLUGIN_CONTEXT macro Date: Thu, 7 Jan 2021 18:15:44 +0200 Message-Id: <20210107161547.207270-4-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210107161547.207270-1-y.karadz@gmail.com> References: <20210107161547.207270-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org When we implement a KernelShark plugins, we often need a way to define a structure that can hold context data that is visible only inside the plugin and that has specific values for each data stream. The tricky part here is that the total number of data streams and the IDs of the active streams are dynamic quantities that can change as the user adds or removes data streams. The macro defines an interface of functions that will be useful for the plugin developer, helping to directly use context objects, without caring for the complications due to the dynamic configuration of active data streams. --- src/libkshark-plugin.h | 41 +++++++++++++++++++++++++++++++++++++++ tests/libkshark-tests.cpp | 32 ++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/src/libkshark-plugin.h b/src/libkshark-plugin.h index 4104357..c62086f 100644 --- a/src/libkshark-plugin.h +++ b/src/libkshark-plugin.h @@ -363,6 +363,47 @@ int kshark_handle_all_dpis(struct kshark_data_stream *stream, __ok; \ }) \ +/** General purpose macro defining methods for adding plugin context. */ +#define KS_DEFINE_PLUGIN_CONTEXT(type) \ +static type **__context_handler; \ +static ssize_t __n_streams = -1; \ +static inline type *__init(int sd) \ +{ \ + type *obj; \ + if (__n_streams < 0 && sd < KS_DEFAULT_NUM_STREAMS) { \ + __context_handler = \ + (type **) calloc(KS_DEFAULT_NUM_STREAMS, \ + sizeof(*__context_handler)); \ + if (!__context_handler) \ + return NULL; \ + __n_streams = KS_DEFAULT_NUM_STREAMS; \ + } else if (sd >= __n_streams) { \ + if (!KS_DOUBLE_SIZE(__context_handler, \ + __n_streams)) \ + return NULL; \ + } \ + assert(__context_handler[sd] == NULL); \ + obj = (type *) calloc(1, sizeof(*obj)); \ + __context_handler[sd] = obj; \ + return obj; \ +} \ +static inline void __close(int sd) \ +{ \ + if (sd < 0) { \ + free(__context_handler); \ + __n_streams = -1; \ + return; \ + } \ + free(__context_handler[sd]); \ + __context_handler[sd] = NULL; \ +} \ +static inline type *__get_context(int sd) \ +{ \ + if (sd < 0 || sd >= __n_streams) \ + return NULL; \ + return __context_handler[sd]; \ +} \ + #ifdef __cplusplus } #endif // __cplusplus diff --git a/tests/libkshark-tests.cpp b/tests/libkshark-tests.cpp index 8a5dcf1..780a3fa 100644 --- a/tests/libkshark-tests.cpp +++ b/tests/libkshark-tests.cpp @@ -10,6 +10,7 @@ // KernelShark #include "libkshark.h" +#include "libkshark-plugin.h" #define N_TEST_STREAMS 1000 @@ -103,3 +104,34 @@ BOOST_AUTO_TEST_CASE(fill_data_container) kshark_free_data_container(data); } + +struct test_context { + int a; + char b; +}; + +KS_DEFINE_PLUGIN_CONTEXT(struct test_context); + +BOOST_AUTO_TEST_CASE(init_close_plugin) +{ + struct test_context *ctx; + int i; + + for (i = 0; i < N_TEST_STREAMS; ++i) { + ctx = __init(i); + ctx->a = i * 10; + ctx->b = 'z'; + } + + for (i = 0; i < N_TEST_STREAMS; ++i) { + ctx = __get_context(i); + BOOST_REQUIRE(ctx != NULL); + BOOST_CHECK_EQUAL(ctx->a, i * 10); + BOOST_CHECK_EQUAL(ctx->b, 'z'); + + __close(i); + BOOST_REQUIRE(__get_context(i) == NULL); + } + + __close(-1); +} From patchwork Thu Jan 7 16:15:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12004409 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE, SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E9A5EC433DB for ; Thu, 7 Jan 2021 16:16:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C758C23118 for ; Thu, 7 Jan 2021 16:16:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728296AbhAGQQt (ORCPT ); Thu, 7 Jan 2021 11:16:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44744 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728292AbhAGQQt (ORCPT ); Thu, 7 Jan 2021 11:16:49 -0500 Received: from mail-ej1-x62a.google.com (mail-ej1-x62a.google.com [IPv6:2a00:1450:4864:20::62a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CC536C0612F9 for ; Thu, 7 Jan 2021 08:16:08 -0800 (PST) Received: by mail-ej1-x62a.google.com with SMTP id x16so10436239ejj.7 for ; Thu, 07 Jan 2021 08:16:08 -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=6jo+XK2A5ZjaTMZ0pG8VBbZT5SAXfAyjI5CCbxG2kVk=; b=VjmhkPOGSzA0apaVGJGw7A7VovnSh2H16vf+YLs+LmlBchgMPHWhtcfj50glfBvPqB kKU2+sNI7NjYuQVXPIuH6X0vwuNxoUBYliuJ/q3qX+zcb/lQWkTtto4vyQ7zRiR7913E BoyJAWDOHrHz+Lbjtnz5TSk/kDEpYqcOBTcgrx5vojp5r+4qEB7DprFE26/KW9RZ8uB+ 3rAqEVFyFUWOZiJsEwtd0WBH6NsG3AB18LE9HWZmBNr7XIy+GdQ9gtWSuKqiVIybDaIh fctqAJh7tqlnfhotWwd+zUt2Y9wMOkOYS4XOz/aWtFVOizZ8VX2BJRvIaeMijMrT058x CpIw== 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=6jo+XK2A5ZjaTMZ0pG8VBbZT5SAXfAyjI5CCbxG2kVk=; b=P64rQGwgi3jrkbPXpcHtRy+MdjFo5eTeokEbSGiDh/4jRkyW57/hxs0sanlYpl3TDi bMDixmoet/c9sFeSXAfyVQujbEgyRkLIrdeIlPFNAQlTLJy6HEG1ZHcrlX6K7GpmoMsb d83gh7Q1GFB3IE9nTIExLKjxDMKiqsWMNq49JFXF/iRpa11q+TZPPNRFlIGbnOm1jw6F 1bDmb16kxqIPPrDDEijlF5LdcSpgf140+xrd++E3Bxv5c64QAYrz2vV1VHDYeVx2ookl ikwOtEcU+wG8YDXWI25rPY2aLO4mxETBrtX0UaV0EhsaHLclH3B8bLM/9YAwAptOgm9U mHEg== X-Gm-Message-State: AOAM533Oe6Ac8olhZd91d1R/Wvz/atotGtEZcWY29s///LzuSP84zsZ3 8TC7aNl9xFMkd1fR6+4uEiJ1yRWp8eU/5w== X-Google-Smtp-Source: ABdhPJz++kaJ4WKYXi0QWpFLVirXXBgOhvNb/Tr0ubUDXIaXFKXSXVnfTvvCswzIVrJPAV4af9mzkg== X-Received: by 2002:a17:906:589:: with SMTP id 9mr7032786ejn.229.1610036167506; Thu, 07 Jan 2021 08:16:07 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id j23sm2846212edv.45.2021.01.07.08.16.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jan 2021 08:16:06 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 4/6] kernel-shark: Start using C++17 Date: Thu, 7 Jan 2021 18:15:45 +0200 Message-Id: <20210107161547.207270-5-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210107161547.207270-1-y.karadz@gmail.com> References: <20210107161547.207270-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Update to a more recent version of the C++ standard. The particular motivation to do this change now is because, we would like to use "auto" as a function parameter type for lambda functions. Signen-off-by: Yordan Karadzhov (VMware) --- CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9abacd0..dd62091 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,8 +62,12 @@ find_package (Boost COMPONENTS unit_test_framework) set(LIBRARY_OUTPUT_PATH "${KS_DIR}/lib") set(EXECUTABLE_OUTPUT_PATH "${KS_DIR}/bin") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pthread -fPIC") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11 -pthread -fPIC") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pthread -fPIC -fno-common") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pthread -fPIC -fno-common") + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo) From patchwork Thu Jan 7 16:15:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12004411 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 77A7FC433E0 for ; Thu, 7 Jan 2021 16:17:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3D93C23428 for ; Thu, 7 Jan 2021 16:17:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728112AbhAGQRZ (ORCPT ); Thu, 7 Jan 2021 11:17:25 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44832 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727753AbhAGQRY (ORCPT ); Thu, 7 Jan 2021 11:17:24 -0500 Received: from mail-ed1-x52e.google.com (mail-ed1-x52e.google.com [IPv6:2a00:1450:4864:20::52e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DB619C0612FA for ; Thu, 7 Jan 2021 08:16:09 -0800 (PST) Received: by mail-ed1-x52e.google.com with SMTP id r5so8211366eda.12 for ; Thu, 07 Jan 2021 08:16:09 -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=xGd/Y7DJSDuSVCgPE4Mf12P9D9WMnhPsjFd8eKdwpe4=; b=OifyYe2pijcNLbKLeo8v+/dNDJ8w4lCowbT8ayZHvY1ooC/sPdD3t8BC51U85rqZrP OZV9LZ4QR1feXxHq5BQFtcrAsDf5Kx2eeUl9mV6sRjJOZIeCN70z7NyDKMOFWasLXjP8 fuP4a33tstQUkVRhDpPOn6J5mkM/y5bTvPwDPWLiFVtoHXMElIVS1zFmiDlocVIyQWj0 lD2Z/Pkb+FVKZ0JNX3dwsTUxIVf09rdBoKX0G3CflyYe8A+rlPQHIteuF+HrPRYe4ZHA T6UcApA0gVb8YnIt8XhT6ABxHduyXbmc5FDWnqSVGH2a8BMgh5RoZ1MlaENKe2aMRK6P E7Mg== 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=xGd/Y7DJSDuSVCgPE4Mf12P9D9WMnhPsjFd8eKdwpe4=; b=tw0fUnd0/6nog7H1y7sFvIfmTLAXq/hgdPzSdY9i74K988NxPIFZhv+9zsk2CQeDyy Nl5awiT2jKEkCWrc+m7u6cynWBk+XWT41FeYz1mJFj8I86LO2Ypt5tOo0XRS6sE6AgpG swUHXqflFx94d9dzKRUw6xrwnrQ1BpIY8AuiMFb37Qwr1nFq2YBWYPuEASaGGu1tl49h OuPvEUTbaUt1HuZ0xqHPbZSmSquuSIeq50JYtlA3f4CqL8yAB7kOv3B5MfvsReZ+gH+A Fk3J6uZvc9QOo5/s0KyPrBDWsrIgKkaTwUgXuSdZwM2rcEEjn7cjLaTlzOpquYAJKl6o aNkQ== X-Gm-Message-State: AOAM531NQ/ur4o5KmR+VHwD80EzEt97OIJlEegTxsaMpp+eIac+tnD0I 0MPKHHF7G6axXUYdkEIgp2NSCN4udnZRxA== X-Google-Smtp-Source: ABdhPJz7rDBR9pG63AIcbx3Seaqh6x4DBi6WQTKEdI95j2BzIIUgOEBxwxUNoFhGQot62Xhr85cSVg== X-Received: by 2002:a50:d888:: with SMTP id p8mr2228563edj.147.1610036168534; Thu, 07 Jan 2021 08:16:08 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id j23sm2846212edv.45.2021.01.07.08.16.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jan 2021 08:16:08 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 5/6] kernel-shark: Add plotting methods to KsPlugins Date: Thu, 7 Jan 2021 18:15:46 +0200 Message-Id: <20210107161547.207270-6-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210107161547.207270-1-y.karadz@gmail.com> References: <20210107161547.207270-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org We add generic methods for visualizing the value of a given trace event field or the relation between two given trace event field. Those methods are taking advantage of the stored values of the event fields in kshark_data_container objects and allow the visualization plugin to process the data orders of magnitude faster. Signed-off-by: Yordan Karadzhov (VMware) --- src/CMakeLists.txt | 3 +- src/KsPlugins.cpp | 416 +++++++++++++++++++++++++++++++++++++++++++++ src/KsPlugins.hpp | 48 ++++++ 3 files changed, 466 insertions(+), 1 deletion(-) create mode 100644 src/KsPlugins.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e35b436..588cccd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,7 +41,8 @@ if (OPENGL_FOUND) message(STATUS "libkshark-plot") add_library(kshark-plot SHARED libkshark-plot.c - KsPlotTools.cpp) + KsPlotTools.cpp + KsPlugins.cpp) target_link_libraries(kshark-plot kshark ${GLUT_LIBRARY} diff --git a/src/KsPlugins.cpp b/src/KsPlugins.cpp new file mode 100644 index 0000000..ad9f478 --- /dev/null +++ b/src/KsPlugins.cpp @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: LGPL-2.1 + +/* + * Copyright (C) 2019 VMware Inc, Yordan Karadzhov (VMware) + */ + +/** + * @file KsPlugins.cpp + * @brief KernelShark C++ plugin declarations. + */ + +// C++ +#include + +// KernelShark +#include "KsPlugins.hpp" + +using namespace KsPlot; + +/** + * A pair of Bin Id and a trace event data field in this bin, that needs to be + * plotted. + */ +typedef std::forward_list> PlotPointList; + +//! @cond Doxygen_Suppress + +typedef std::function pushFunc; + +typedef std::function resolveFunc; + +//! @endcond + +static void pointPlot(KsCppArgV *argvCpp, IsApplicableFunc isApplicable, + pluginShapeFunc makeShape, Color col, float size) +{ + int nBins = argvCpp->_graph->size(); + + for (int bin = 0; bin < nBins; ++bin) + if (isApplicable(nullptr, bin)) + argvCpp->_shapes->push_front(makeShape({argvCpp->_graph}, + {bin}, {}, + col, size)); +} + +static std::pair +getRange(kshark_trace_histo *histo, kshark_data_container *data) +{ + ssize_t firstEntry, lastEntry; + std::pair err(-1, -2); + + firstEntry = kshark_find_entry_field_by_time(histo->min, + data->data, + 0, + data->size - 1); + + if (firstEntry == BSEARCH_ALL_SMALLER) + return err; + + if (firstEntry == BSEARCH_ALL_GREATER) + firstEntry = 0; + + lastEntry = kshark_find_entry_field_by_time(histo->max, + data->data, + firstEntry, + data->size - 1); + + if (lastEntry == BSEARCH_ALL_GREATER) + return err; + + if (lastEntry == BSEARCH_ALL_SMALLER) + lastEntry = data->size - 1; + + return {firstEntry, lastEntry}; +} + +static PlotPointList +getInBinEvents(kshark_trace_histo *histo, + kshark_data_container *data, + IsApplicableFunc isApplicable, + pushFunc push, + resolveFunc resolve) +{ + int bin, lastBin(-1); + PlotPointList buffer; + + auto lamIsOverflow = [] (int bin) { + return (bin == UPPER_OVERFLOW_BIN || + bin == LOWER_OVERFLOW_BIN) ? true : false; + }; + + auto range = getRange(histo, data); + + for (ssize_t i = range.second; i >= range.first; --i) { + if (isApplicable(data, i)) { + bin = ksmodel_get_bin(histo, data->data[i]->entry); + if (lamIsOverflow(bin)) + continue; + + if (bin != lastBin) { + push(bin, data, i, &buffer); + lastBin = bin; + } else { + resolve(data, i, &buffer); + } + } + } + + return buffer; +} + +static PlotPointList +getLastInBinEvents(kshark_trace_histo *histo, kshark_data_container *data, + IsApplicableFunc isApplicable) +{ + pushFunc push = [] (int bin, kshark_data_container *data, ssize_t i, + PlotPointList *list) { + list->push_front({bin, data->data[i]}); + }; + + /* + * Do not resolve. This means that only the very last (in time) + * appearance of the event in the bin will be visualized. + */ + resolveFunc resolve = [] (kshark_data_container *data, ssize_t i, + PlotPointList *list) {}; + + return getInBinEvents(histo, data, isApplicable, push, resolve); +} + +static PlotPointList +getMaxInBinEvents(kshark_trace_histo *histo, kshark_data_container *data, + IsApplicableFunc isApplicable) +{ + pushFunc push = [] (int bin, kshark_data_container *data, ssize_t i, + PlotPointList *list) { + list->push_front({bin, data->data[i]}); + }; + + /* Overwrite if bigger. */ + resolveFunc resolve = [] (kshark_data_container *data, ssize_t i, + PlotPointList *list) { + if (list->front().second < data->data[i]) + list->front().second = data->data[i]; + }; + + return getInBinEvents(histo, data, isApplicable, push, resolve); +} + + +static PlotPointList +getMinInBinEvents(kshark_trace_histo *histo, kshark_data_container *data, + IsApplicableFunc isApplicable) +{ + pushFunc push = [] (int bin, kshark_data_container *data, ssize_t i, + PlotPointList *list) { + list->push_front({bin, data->data[i]}); + }; + + /* Overwrite if smaller. */ + resolveFunc resolve = [] (kshark_data_container *data, ssize_t i, + PlotPointList *list) { + if (list->front().second > data->data[i]) + list->front().second = data->data[i]; + }; + + return getInBinEvents(histo, data, isApplicable, push, resolve); +} + +//! @cond Doxygen_Suppress + +#define PLUGIN_MIN_BOX_SIZE 4 + +//! @endcond + +static void intervalPlot(kshark_trace_histo *histo, + kshark_data_container *dataEvtA, + IsApplicableFunc checkFieldA, + kshark_data_container *dataEvtB, + IsApplicableFunc checkFieldB, + Graph *graph, + PlotObjList *shapes, + pluginShapeFunc makeShape, + Color col, + float size) +{ + kshark_data_field_int64 *dataA, *dataB; + PlotPointList bufferA, bufferB; + int binA, binB; + int64_t tsB; + + auto lamGetBin = [] (auto it) {return (*it).first;}; + + auto lamGetTime = [] (auto it) {return (*it).second->entry->ts;}; + + auto lamGetData = [] (auto it) {return (*it).second;}; + + bufferA = getLastInBinEvents(histo, + dataEvtA, + checkFieldA); + + bufferB = getLastInBinEvents(histo, + dataEvtB, + checkFieldB); + + if (bufferA.empty() || bufferB.empty()) + return; + + auto itA = bufferA.cbegin(); + auto itB = bufferB.cbegin(); + while (itA != bufferA.cend() && itB != bufferB.cend()) { + binA = lamGetBin(itA); + dataA = lamGetData(itA); + + /* + * We will draw a shape between "Event A" and "Event B". + * Because the shape starts with "Event A", we will skip all + * "Event B" entries before the "Event A" entry. + */ + do { + dataB = lamGetData(itB); + tsB = lamGetTime(itB); + binB = lamGetBin(itB); + itB++; + } while (itB != bufferB.cend() && tsB < lamGetTime(itA)); + + /* + * The shape ends with "Event B" and we already have this + * event. However, we have to make sure that we will start the + * shape from the very last "Event A" entry, which is rigth + * before the "Event B" entry, which we already selected. + */ + while (itA != bufferA.cend() && lamGetTime(itA) < tsB) { + dataA = lamGetData(itA); + binA = lamGetBin(itA); + itA++; + } + + if (binB - binA >= PLUGIN_MIN_BOX_SIZE) + shapes->push_front(makeShape({graph}, + {binA, binB}, + {dataA, dataB}, + col, size)); + } +} + +/** + * @brief Generic plotting method for plugins. To be used for visualizing + * a trace events. + * + * @param argvCpp: The C++ arguments of the drawing function of the plugin. + * @param isApplicable: Check function used to select events from data + * container A. + * @param makeShape: Input location for a function pointer used to generate + * the shape to be plotted. + * @param col: The color of the shape to be plotted. + * @param size: The size of the shape to be plotted. + */ +void eventPlot(KsCppArgV *argvCpp, + IsApplicableFunc isApplicable, + pluginShapeFunc makeShape, + Color col, + float size) +{ + try { + pointPlot(argvCpp, isApplicable, makeShape, col, size); + } catch (const std::exception &exc) { + std::cerr << "Exception in eventPlot\n" + << exc.what() << std::endl; + } +} + +//! @cond Doxygen_Suppress + +enum class PlotWath { + Maximum, + Minimum, +}; + +//! @endcond + +static void eventFieldPlot(KsCppArgV *argvCpp, + kshark_data_container *dataEvt, + IsApplicableFunc checkField, + PlotWath s, + pluginShapeFunc makeShape, + KsPlot::Color col, + float size) +{ + PlotPointList buffer; + + if (dataEvt->size == 0) + return; + + if (!dataEvt->sorted) + kshark_data_container_sort(dataEvt); + + try { + if (s == PlotWath::Maximum) + buffer = getMaxInBinEvents(argvCpp->_histo, + dataEvt, checkField); + + if (s == PlotWath::Minimum) + buffer = getMinInBinEvents(argvCpp->_histo, + dataEvt, checkField); + + for (auto const &i: buffer) { + argvCpp->_shapes->push_front(makeShape({argvCpp->_graph}, + {i.first}, + {i.second}, + col, size)); + } + } catch (const std::exception &exc) { + std::cerr << "Exception in eventFieldPlot\n" + << exc.what() << std::endl; + } +} + +/** + * @brief Generic plotting method for plugins. To be used for visualizing + * the value of a data fiels trace events. + * + * @param argvCpp: The C++ arguments of the drawing function of the plugin. + * @param dataEvt: Input location for the container of the Evant's data. + * @param checkField: Check function used to select events from data + * container. + * @param makeShape: Input location for a function pointer used to generate + * the shape to be plotted. + * @param col: The color of the shape to be plotted. + * @param size: The size of the shape to be plotted. + */ +void eventFieldPlotMax(KsCppArgV *argvCpp, + kshark_data_container *dataEvt, + IsApplicableFunc checkField, + pluginShapeFunc makeShape, + KsPlot::Color col, + float size) +{ + eventFieldPlot(argvCpp, dataEvt, checkField, + PlotWath::Maximum, + makeShape, col, size); +} + +/** + * @brief Generic plotting method for plugins. To be used for visualizing + * the value of a data fiels trace events. + * + * @param argvCpp: The C++ arguments of the drawing function of the plugin. + * @param dataEvt: Input location for the container of the Evant's data. + * @param checkField: check function used to select events from data + * container. + * @param makeShape: Input location for a function pointer used to generate + * the shape to be plotted. + * @param col: The color of the shape to be plotted. + * @param size: The size of the shape to be plotted. + */ +void eventFieldPlotMin(KsCppArgV *argvCpp, + kshark_data_container *dataEvt, + IsApplicableFunc checkField, + pluginShapeFunc makeShape, + KsPlot::Color col, + float size) +{ + eventFieldPlot(argvCpp, dataEvt, checkField, + PlotWath::Minimum, + makeShape, col, size); +} + +/** + * @brief Generic plotting method for plugins. To be used for visualizing + * the correlation between two trace events. + * + * @param argvCpp: The C++ arguments of the drawing function of the plugin. + * @param dataEvtA: Input location for the container of the Evant A data. + * @param checkFieldA: Check function used to select events from data + * container A. + * @param dataEvtB: Input location for the container of the Evant B data. + * @param checkFieldB: Check function used to select events from data + * container B. + * @param makeShape: Input location for a function pointer used to generate + * the shape to be plotted. + * @param col: The color of the shape to be plotted. + * @param size: The size of the shape to be plotted. + */ +void eventFieldIntervalPlot(KsCppArgV *argvCpp, + kshark_data_container *dataEvtA, + IsApplicableFunc checkFieldA, + kshark_data_container *dataEvtB, + IsApplicableFunc checkFieldB, + pluginShapeFunc makeShape, + KsPlot::Color col, + float size) +{ + if (dataEvtA->size == 0 || dataEvtB->size == 0) + return; + + if (!dataEvtA->sorted) + kshark_data_container_sort(dataEvtA); + + if (!dataEvtB->sorted) + kshark_data_container_sort(dataEvtB); + + try { + intervalPlot(argvCpp->_histo, + dataEvtA, checkFieldA, + dataEvtB, checkFieldB, + argvCpp->_graph, + argvCpp->_shapes, + makeShape, col, size); + } catch (const std::exception &exc) { + std::cerr << "Exception in eventFieldIntervalPlot\n" + << exc.what() << std::endl; + } +} diff --git a/src/KsPlugins.hpp b/src/KsPlugins.hpp index 3955cdf..a19bb9d 100644 --- a/src/KsPlugins.hpp +++ b/src/KsPlugins.hpp @@ -12,6 +12,9 @@ #ifndef _KS_PLUGINS_H #define _KS_PLUGINS_H +// C++ +#include + // KernelShark #include "libkshark-model.h" #include "KsPlotTools.hpp" @@ -48,4 +51,49 @@ struct KsCppArgV { */ #define KS_ARGV_TO_CPP(a) (reinterpret_cast(a)) +/** + * Function of this type has to be implemented by the user in order to use + * some of the Generic plotting method. The returned shape will be plotted + * by KernelShark on top of the existing Graph generated by the model. + */ +typedef std::function graph, + std::vector bin, + std::vector data, + KsPlot::Color col, + float size)> pluginShapeFunc; + +/** + * Function of this type has to be implemented by the user in order to use + * some of the Generic plotting method. The user must implement a logic + * deciding if the record, having a given index inside the data container has + * to be visualized. + */ +typedef std::function IsApplicableFunc; + +void eventPlot(KsCppArgV *argvCpp, IsApplicableFunc isApplicable, + pluginShapeFunc makeShape, KsPlot::Color col, float size); + +void eventFieldPlotMax(KsCppArgV *argvCpp, + kshark_data_container *dataEvt, + IsApplicableFunc checkField, + pluginShapeFunc makeShape, + KsPlot::Color col, + float size); + +void eventFieldPlotMin(KsCppArgV *argvCpp, + kshark_data_container *dataEvt, + IsApplicableFunc checkField, + pluginShapeFunc makeShape, + KsPlot::Color col, + float size); + +void eventFieldIntervalPlot(KsCppArgV *argvCpp, + kshark_data_container *dataEvtA, + IsApplicableFunc checkFieldA, + kshark_data_container *dataEvtB, + IsApplicableFunc checkFieldB, + pluginShapeFunc makeShape, + KsPlot::Color col, + float size); + #endif From patchwork Thu Jan 7 16:15:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12004413 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5A86FC433DB for ; Thu, 7 Jan 2021 16:17:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 122C723118 for ; Thu, 7 Jan 2021 16:17:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728130AbhAGQRY (ORCPT ); Thu, 7 Jan 2021 11:17:24 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44834 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728112AbhAGQRY (ORCPT ); Thu, 7 Jan 2021 11:17:24 -0500 Received: from mail-ed1-x536.google.com (mail-ed1-x536.google.com [IPv6:2a00:1450:4864:20::536]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F2DA5C0612FB for ; Thu, 7 Jan 2021 08:16:10 -0800 (PST) Received: by mail-ed1-x536.google.com with SMTP id i24so8247558edj.8 for ; Thu, 07 Jan 2021 08:16:10 -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=l+pnpTuSPoHD23d+V3lh4bAJ6Y6ptXfyA94q6daMcaM=; b=ezVPcLK8hhN5WaqdqrobQoQsJRRRkvZ8f0vVYvxb1IEZ7QW0VmeGshZevL8lM/ijaf u5wyYNpmp/pZTlvxM5fbcmxZfGO3Q3fY6L6pgQ0weg4nwrDjYm5WhfSKPNWPpIPA3/UN 95p/y0bsB9tpqnpIG9t/4wfwjY8v4XHoreQoj8db1sEXrfN+WL2MN8NhehFUyRkuXTQ7 tfGtR4yRFC4VwoJ6pD6g8ZcOpNBySdYKIEXfmz3GCsfbH1XCik+THuYkvNuijfMOTleQ E/dDOndTbuZ7KQWW7Eq2P4DMkMZqzpbip5PxsUd18C45GQsQHUlSgBI5hLdbQZhD2Yrn aNiA== 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=l+pnpTuSPoHD23d+V3lh4bAJ6Y6ptXfyA94q6daMcaM=; b=LeQTe6vlowrjM/2hD9zFdgd6TanDsiDJ9+ewDjempiwaRS8m/3KUXz8JhGyROGsmTR TpNQpRtiZS6TLN/iUb6yMfsJBssu1fYjNy5WPmQSALCPe4Qx8QzqO64N0T23gB0EpXCb wwPNRPW/pGx89rBS22hMNQMdgTCiWsOgX4r7mUUmjcXc73sNoPXQc0AYeuAMAZ5dpAfL p7D/hC8ksAk18x+ltt/X6gWcrNnkUG9UVLFEe+CheO8BjSBF0RtwhKvLTfN3bgy27mea uVL+M4UjfH6s6yb+rqf4paOpovxsMRF0NkA1JmvCwwMl1uUuv0qe6d6B9KCQJvlobD4x 0z6Q== X-Gm-Message-State: AOAM530ny4CY6PQfgFX9sEZOlvu2Qyrpb1OVBwgZMRlLbxptHpx0Q4r1 cScHiDNvi8m/qsIYZx4c41M= X-Google-Smtp-Source: ABdhPJyDGyDFH884Dr6qmmIy23Z+r8KURF+SDwWL8v5Xdf+x65x/CkjcP+qf5L0pYpttm4PgL1576Q== X-Received: by 2002:a50:8e19:: with SMTP id 25mr2177147edw.263.1610036169382; Thu, 07 Jan 2021 08:16:09 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id j23sm2846212edv.45.2021.01.07.08.16.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Jan 2021 08:16:08 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 6/6] kernel-shark: Speed-up the sched_events plugin Date: Thu, 7 Jan 2021 18:15:47 +0200 Message-Id: <20210107161547.207270-7-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210107161547.207270-1-y.karadz@gmail.com> References: <20210107161547.207270-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org General revision of the sched_events plugin that achieves much faster processing of the wake-up latency, by using the new generic methods for visualization of event's data field. Signed-off-by: Yordan Karadzhov (VMware) --- src/CMakeLists.txt | 2 +- src/libkshark-plugin.h | 1 + src/libkshark-tepdata.c | 34 ++++ src/libkshark-tepdata.h | 7 + src/plugins/CMakeLists.txt | 11 +- src/plugins/SchedEvents.cpp | 310 +++++++--------------------- src/plugins/sched_events.c | 393 +++++++++++------------------------- src/plugins/sched_events.h | 50 ++--- 8 files changed, 260 insertions(+), 548 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 588cccd..980e802 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -135,7 +135,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) endif (Qt5Widgets_FOUND AND Qt5Network_FOUND) -# add_subdirectory(plugins) +add_subdirectory(plugins) find_program(DO_AS_ROOT pkexec) diff --git a/src/libkshark-plugin.h b/src/libkshark-plugin.h index c62086f..c110616 100644 --- a/src/libkshark-plugin.h +++ b/src/libkshark-plugin.h @@ -19,6 +19,7 @@ extern "C" { // C #include #include +#include /* Quiet warnings over documenting simple structures */ //! @cond Doxygen_Suppress diff --git a/src/libkshark-tepdata.c b/src/libkshark-tepdata.c index 724cff2..d4be052 100644 --- a/src/libkshark-tepdata.c +++ b/src/libkshark-tepdata.c @@ -1912,3 +1912,37 @@ int kshark_tep_find_top_stream(struct kshark_context *kshark_ctx, return top_stream->stream_id; } + +static bool find_wakeup_event(struct tep_handle *tep, const char *wakeup_name, + struct tep_event **waking_event_ptr) +{ + *waking_event_ptr = tep_find_event_by_name(tep, "sched", wakeup_name); + + return (*waking_event_ptr)? true : false; +} + +/** + * @brief Search the available trace events and retrieve a definition of + * a waking_event. + * + * @param tep: Input location for the the Page event object. + * @param waking_event_ptr: Output location for the the waking_event object. + * + * @returns True on success, otherwise False. + */ +bool define_wakeup_event(struct tep_handle *tep, + struct tep_event **waking_event_ptr) +{ + bool wakeup_found; + + wakeup_found = find_wakeup_event(tep, "sched_wakeup", + waking_event_ptr); + + wakeup_found |= find_wakeup_event(tep, "sched_wakeup_new", + waking_event_ptr); + + wakeup_found |= find_wakeup_event(tep, "sched_waking", + waking_event_ptr); + + return wakeup_found; +} diff --git a/src/libkshark-tepdata.h b/src/libkshark-tepdata.h index 46b18c8..1b955be 100644 --- a/src/libkshark-tepdata.h +++ b/src/libkshark-tepdata.h @@ -105,6 +105,13 @@ int kshark_tep_find_top_stream(struct kshark_context *kshark_ctx, bool kshark_tep_is_top_stream(struct kshark_data_stream *stream); +struct tep_event; + +struct tep_format_field; + +bool define_wakeup_event(struct tep_handle *tep, + struct tep_event **wakeup_event); + #ifdef __cplusplus } #endif diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 2da73f8..108bc5f 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -20,14 +20,13 @@ endfunction() set(PLUGIN_LIST "") BUILD_PLUGIN(NAME sched_events SOURCE sched_events.c SchedEvents.cpp) -list(APPEND PLUGIN_LIST "sched_events default") # This plugin will be loaded by default -# list(APPEND PLUGIN_LIST "sched_events") # This plugin isn't loaded by default +list(APPEND PLUGIN_LIST "sched_events") -BUILD_PLUGIN(NAME missed_events - SOURCE missed_events.c MissedEvents.cpp) -list(APPEND PLUGIN_LIST "missed_events default") # This plugin will be loaded by default +# BUILD_PLUGIN(NAME missed_events +# SOURCE missed_events.c MissedEvents.cpp) +# list(APPEND PLUGIN_LIST "missed_events") -install(TARGETS sched_events missed_events +install(TARGETS ${PLUGIN_LIST} LIBRARY DESTINATION ${KS_PLUGIN_INSTALL_PREFIX} COMPONENT kernelshark) diff --git a/src/plugins/SchedEvents.cpp b/src/plugins/SchedEvents.cpp index 8408657..c85a059 100644 --- a/src/plugins/SchedEvents.cpp +++ b/src/plugins/SchedEvents.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * Copyright (C) 2018 VMware Inc, Yordan Karadzhov + * Copyright (C) 2018 VMware Inc, Yordan Karadzhov (VMware) */ /** @@ -12,180 +12,39 @@ */ // C++ -#include - -// C++ 11 -#include -#include +#include // KernelShark #include "libkshark.h" +#include "libkshark-plugin.h" #include "plugins/sched_events.h" #include "KsPlotTools.hpp" #include "KsPlugins.hpp" -//! @cond Doxygen_Suppress - -#define PLUGIN_MIN_BOX_SIZE 4 - -#define KS_TASK_COLLECTION_MARGIN 25 - -//! @endcond - -extern struct plugin_sched_context *plugin_sched_context_handler; - -/** Sched Event identifier. */ -enum class SchedEvent { - /** Sched Switch Event. */ - Switch, +using namespace KsPlot; - /** Sched Wakeup Event. */ - Wakeup, -}; - -static void pluginDraw(plugin_sched_context *plugin_ctx, - kshark_context *kshark_ctx, - kshark_trace_histo *histo, - kshark_entry_collection *col, - SchedEvent e, - int pid, - KsPlot::Graph *graph, - KsPlot::PlotObjList *shapes) +static PlotObject *makeShape(std::vector graph, + std::vector bins, + std::vector, + Color col, float size) { - const kshark_entry *entryClose, *entryOpen, *entryME; - ssize_t indexClose(0), indexOpen(0), indexME(0); - std::function ifSchedBack; - KsPlot::Rectangle *rec = nullptr; - int height = graph->getHeight() * .3; - - auto openBox = [&] (const KsPlot::Point &p) - { - /* - * First check if we already have an open box. If we don't - * have, open a new one. - */ - if (!rec) - rec = new KsPlot::Rectangle; - - if (e == SchedEvent::Switch) { - /* Red box. */ - rec->_color = KsPlot::Color(255, 0, 0); - } else { - /* Green box. */ - rec->_color = KsPlot::Color(0, 255, 0); - } - - rec->setFill(false); - - rec->setPoint(0, p.x() - 1, p.y() - height); - rec->setPoint(1, p.x() - 1, p.y() - 1); - }; - - auto closeBox = [&] (const KsPlot::Point &p) - { - if (rec == nullptr) - return; - - int boxSize = p.x() - rec->getPoint(0)->x; - if (boxSize < PLUGIN_MIN_BOX_SIZE) { - /* This box is too small. Don't try to plot it. */ - delete rec; - rec = nullptr; - return; - } - - rec->setPoint(3, p.x() - 1, p.y() - height); - rec->setPoint(2, p.x() - 1, p.y() - 1); - - shapes->push_front(rec); - rec = nullptr; - }; - - for (int bin = 0; bin < graph->size(); ++bin) { - /* - * Starting from the first element in this bin, go forward - * in time until you find a trace entry that satisfies the - * condition defined by kshark_match_pid. - */ - entryClose = ksmodel_get_entry_back(histo, bin, false, - plugin_switch_match_entry_pid, - pid, col, &indexClose); - - entryME = ksmodel_get_task_missed_events(histo, - bin, pid, - col, - &indexME); - - if (e == SchedEvent::Switch) { - /* - * Starting from the last element in this bin, go backward - * in time until you find a trace entry that satisfies the - * condition defined by plugin_switch_match_rec_pid. - */ - entryOpen = - ksmodel_get_entry_back(histo, bin, false, - plugin_switch_match_rec_pid, - pid, col, &indexOpen); + Rectangle *rec = new KsPlot::Rectangle; + Point p0 = graph[0]->bin(bins[0])._base; + Point p1 = graph[0]->bin(bins[1])._base; + int height = graph[0]->height() * .3; - } else { - /* - * Starting from the last element in this bin, go backward - * in time until you find a trace entry that satisfies the - * condition defined by plugin_wakeup_match_rec_pid. - */ - entryOpen = - ksmodel_get_entry_back(histo, bin, false, - plugin_wakeup_match_rec_pid, - pid, - col, - &indexOpen); + rec->setFill(false); + rec->setPoint(0, p0.x() - 1, p0.y() - height); + rec->setPoint(1, p0.x() - 1, p0.y() - 1); - if (entryOpen) { - int cpu = ksmodel_get_cpu_back(histo, bin, - pid, - false, - col, - nullptr); - if (cpu >= 0) { - /* - * The task is already running. Ignore - * this wakeup event. - */ - entryOpen = nullptr; - } - } - } - - if (rec) { - if (entryME || entryClose) { - /* Close the box in this bin. */ - closeBox(graph->getBin(bin)._base); - if (entryOpen && - indexME < indexOpen && - indexClose < indexOpen) { - /* - * We have a Sched switch entry that - * comes after (in time) the closure of - * the previous box. We have to open a - * new box in this bin. - */ - openBox(graph->getBin(bin)._base); - } - } - } else { - if (entryOpen && - (!entryClose || indexClose < indexOpen)) { - /* Open a new box in this bin. */ - openBox(graph->getBin(bin)._base); - } - } - } + rec->setPoint(3, p1.x() - 1, p1.y() - height); + rec->setPoint(2, p1.x() - 1, p1.y() - 1); - if (rec) - delete rec; + rec->_size = size; + rec->_color = col; - return; -} + return rec; +}; /* * Ideally, the sched_switch has to be the last trace event recorded before the @@ -199,49 +58,32 @@ static void pluginDraw(plugin_sched_context *plugin_ctx, * of the entry (this field is set during the first pass) to search for trailing * events after the "sched_switch". */ -static void secondPass(kshark_entry **data, - kshark_entry_collection *col, - int pid) +static void secondPass(plugin_sched_context *plugin_ctx) { - if (!col) - return; - - const kshark_entry *e; - kshark_entry *last; - int first, n; - ssize_t index; - - /* Loop over the intervals of the data collection. */ - for (size_t i = 0; i < col->size; ++i) { - first = col->break_points[i]; - n = first - col->resume_points[i]; - - kshark_entry_request *req = - kshark_entry_request_alloc(first, n, - plugin_switch_match_rec_pid, - pid, - false, - KS_GRAPH_VIEW_FILTER_MASK); - - e = kshark_get_entry_back(req, data, &index); - free(req); - - if (!e || index < 0) { - /* No sched_switch event in this interval. */ + kshark_data_container *cSS; + kshark_entry *e; + int pid_rec; + + cSS = plugin_ctx->ss_data; + for (ssize_t i = 0; i < cSS->size; ++i) { + pid_rec = plugin_sched_get_pid(cSS->data[i]->field); + e = cSS->data[i]->entry; + if (!e->next || e->pid == 0 || + e->event_id == e->next->event_id || + pid_rec != e->next->pid) continue; - } /* Find the very last trailing event. */ - for (last = data[index]; last->next; last = last->next) { - if (last->next->pid != pid) { + for (; e->next; e = e->next) { + if (e->next->pid != plugin_sched_get_pid(cSS->data[i]->field)) { /* * This is the last trailing event. Change the * "pid" to be equal to the "next pid" of the * sched_switch event and leave a sign that you * edited this entry. */ - last->pid = data[index]->pid; - last->visible &= ~KS_PLUGIN_UNTOUCHED_MASK; + e->pid = cSS->data[i]->entry->pid; + e->visible &= ~KS_PLUGIN_UNTOUCHED_MASK; break; } } @@ -252,62 +94,56 @@ static void secondPass(kshark_entry **data, * @brief Plugin's draw function. * * @param argv_c: A C pointer to be converted to KsCppArgV (C++ struct). + * @param sd: Data stream identifier. * @param pid: Process Id. * @param draw_action: Draw action identifier. */ -void plugin_draw(kshark_cpp_argv *argv_c, int pid, int draw_action) +void plugin_draw(kshark_cpp_argv *argv_c, int sd, int pid, int draw_action) { plugin_sched_context *plugin_ctx; - kshark_context *kshark_ctx(NULL); - kshark_entry_collection *col; - if (draw_action != KSHARK_PLUGIN_TASK_DRAW || pid == 0) + if (!(draw_action & KSHARK_TASK_DRAW) || pid == 0) return; - plugin_ctx = plugin_sched_context_handler; - if (!plugin_ctx || !kshark_instance(&kshark_ctx)) + plugin_ctx = __get_context(sd); + if (!plugin_ctx) return; KsCppArgV *argvCpp = KS_ARGV_TO_CPP(argv_c); - /* - * Try to find a collections for this task. It is OK if - * coll = NULL. - */ - col = kshark_find_data_collection(plugin_ctx->collections, - plugin_match_pid, pid); - if (!col) { - /* - * If a data collection for this task does not exist, - * register a new one. - */ - kshark_entry **data = argvCpp->_histo->data; - int size = argvCpp->_histo->data_size; - - col = kshark_add_collection_to_list(kshark_ctx, - &plugin_ctx->collections, - data, size, - plugin_match_pid, pid, - KS_TASK_COLLECTION_MARGIN); + if (!plugin_ctx->second_pass_done) { + /* The second pass is not done yet. */ + secondPass(plugin_ctx); + plugin_ctx->second_pass_done = true; } - if (!tracecmd_filter_id_find(plugin_ctx->second_pass_hash, pid)) { - /* The second pass for this task is not done yet. */ - secondPass(argvCpp->_histo->data, col, pid); - tracecmd_filter_id_add(plugin_ctx->second_pass_hash, pid); - } + IsApplicableFunc checkFieldSW = [=] (kshark_data_container *d, + ssize_t i) { + return d->data[i]->field == pid; + }; - try { - pluginDraw(plugin_ctx, kshark_ctx, - argvCpp->_histo, col, - SchedEvent::Wakeup, pid, - argvCpp->_graph, argvCpp->_shapes); + IsApplicableFunc checkFieldSS = [=] (kshark_data_container *d, + ssize_t i) { + return !(plugin_sched_get_prev_state(d->data[i]->field) & 0x7f) && + plugin_sched_get_pid(d->data[i]->field) == pid; + }; - pluginDraw(plugin_ctx, kshark_ctx, - argvCpp->_histo, col, - SchedEvent::Switch, pid, - argvCpp->_graph, argvCpp->_shapes); - } catch (const std::exception &exc) { - std::cerr << "Exception in SchedEvents\n" << exc.what(); - } + IsApplicableFunc checkEntryPid = [=] (kshark_data_container *d, + ssize_t i) { + return d->data[i]->entry->pid == pid; + }; + + eventFieldIntervalPlot(argvCpp, + plugin_ctx->sw_data, checkFieldSW, + plugin_ctx->ss_data, checkEntryPid, + makeShape, + {0, 255, 0}, // Green + -1); // Default size + + eventFieldIntervalPlot(argvCpp, + plugin_ctx->ss_data, checkFieldSS, + plugin_ctx->ss_data, checkEntryPid, + makeShape, + {255, 0, 0}, // Red + -1); // Default size } diff --git a/src/plugins/sched_events.c b/src/plugins/sched_events.c index d0fd15e..1596880 100644 --- a/src/plugins/sched_events.c +++ b/src/plugins/sched_events.c @@ -1,85 +1,92 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * Copyright (C) 2018 VMware Inc, Yordan Karadzhov + * Copyright (C) 2018 VMware Inc, Yordan Karadzhov (VMware) */ /** * @file sched_events.c - * @brief Defines a callback function for Sched events used to registers the - * "next" task (if not registered already) and to changes the value - * of the "pid" field of the "sched_switch" entries such that, it - * will be ploted as part of the "next" task. + * @brief */ // C #include #include -#include + +// trace-cmd +#include "trace-cmd/trace-cmd.h" // KernelShark #include "plugins/sched_events.h" +#include "libkshark-tepdata.h" /** Plugin context instance. */ -struct plugin_sched_context *plugin_sched_context_handler = NULL; -static bool define_wakeup_event(struct tep_handle *tep, const char *wakeup_name, - struct tep_event **wakeup_event, - struct tep_format_field **pid_field) -{ - struct tep_event *event; +//! @cond Doxygen_Suppress - event = tep_find_event_by_name(tep, "sched", wakeup_name); - if (!event) - return false; +typedef unsigned long long tep_num_field_t; - *wakeup_event = event; - *pid_field = tep_find_any_field(event, "pid"); +#define PREV_STATE_SHIFT ((int) ((sizeof(ks_num_field_t) - 1) * 8)) - return true; +#define PREV_STATE_MASK (((ks_num_field_t) 1 << 8) - 1) + +#define PID_MASK (((ks_num_field_t) 1 << PREV_STATE_SHIFT) - 1) + +//! @endcond + +static void plugin_sched_set_pid(ks_num_field_t *field, + tep_num_field_t pid) +{ + *field &= ~PID_MASK; + *field = pid & PID_MASK; } -static void plugin_free_context(struct plugin_sched_context *plugin_ctx) +/** + * @brief Retrieve the PID value from the data field stored in the + * kshark_data_container object. + * + * @param field: Input location for the data field. + */ +int plugin_sched_get_pid(ks_num_field_t field) { - if (!plugin_ctx) - return; + return field & PID_MASK; +} - tracecmd_filter_id_hash_free(plugin_ctx->second_pass_hash); - kshark_free_collection_list(plugin_ctx->collections); +/* Use the most significant byte to store the value of "prev_state". */ +static void plugin_sched_set_prev_state(ks_num_field_t *field, + tep_num_field_t prev_state) +{ + tep_num_field_t mask = PREV_STATE_MASK << PREV_STATE_SHIFT; + *field &= ~mask; + *field |= (prev_state & PREV_STATE_MASK) << PREV_STATE_SHIFT; +} - free(plugin_ctx); +/** + * @brief Retrieve the "prev_state" value from the data field stored in the + * kshark_data_container object. + * + * @param field: Input location for the data field. + */ +int plugin_sched_get_prev_state(ks_num_field_t field) +{ + tep_num_field_t mask = PREV_STATE_MASK << PREV_STATE_SHIFT; + return (field & mask) >> PREV_STATE_SHIFT; } -static bool plugin_sched_init_context(struct kshark_context *kshark_ctx) +static bool plugin_sched_init_context(struct kshark_data_stream *stream, + struct plugin_sched_context *plugin_ctx) { - struct plugin_sched_context *plugin_ctx; struct tep_event *event; bool wakeup_found; - /* No context should exist when we initialize the plugin. */ - assert(plugin_sched_context_handler == NULL); - - plugin_sched_context_handler = - calloc(1, sizeof(*plugin_sched_context_handler)); - if (!plugin_sched_context_handler) { - fprintf(stderr, - "Failed to allocate memory for plugin_sched_context.\n"); + if (!kshark_is_tep(stream)) return false; - } - plugin_ctx = plugin_sched_context_handler; - plugin_ctx->handle = kshark_ctx->handle; - plugin_ctx->pevent = kshark_ctx->pevent; - plugin_ctx->collections = NULL; - - event = tep_find_event_by_name(plugin_ctx->pevent, + plugin_ctx->tep = kshark_get_tep(stream); + event = tep_find_event_by_name(plugin_ctx->tep, "sched", "sched_switch"); - if (!event) { - plugin_free_context(plugin_ctx); - plugin_sched_context_handler = NULL; - + if (!event) return false; - } plugin_ctx->sched_switch_event = event; plugin_ctx->sched_switch_next_field = @@ -91,277 +98,121 @@ static bool plugin_sched_init_context(struct kshark_context *kshark_ctx) plugin_ctx->sched_switch_prev_state_field = tep_find_field(event, "prev_state"); + wakeup_found = define_wakeup_event(plugin_ctx->tep, + &plugin_ctx->sched_waking_event); - wakeup_found = define_wakeup_event(kshark_ctx->pevent, "sched_wakeup", - &plugin_ctx->sched_wakeup_event, - &plugin_ctx->sched_wakeup_pid_field); - - wakeup_found |= define_wakeup_event(kshark_ctx->pevent, "sched_wakeup_new", - &plugin_ctx->sched_wakeup_new_event, - &plugin_ctx->sched_wakeup_new_pid_field); + if (wakeup_found) { + plugin_ctx->sched_waking_pid_field = + tep_find_any_field(plugin_ctx->sched_waking_event, "pid"); + } - wakeup_found |= define_wakeup_event(kshark_ctx->pevent, "sched_waking", - &plugin_ctx->sched_waking_event, - &plugin_ctx->sched_waking_pid_field); + plugin_ctx->second_pass_done = false; - plugin_ctx->second_pass_hash = tracecmd_filter_id_hash_alloc(); + plugin_ctx->ss_data = kshark_init_data_container(); + plugin_ctx->sw_data = kshark_init_data_container(); + if (!plugin_ctx->ss_data || + !plugin_ctx->sw_data) + return false; return true; } -/** - * @brief Get the Process Id of the next scheduled task. - * - * @param record: Input location for a sched_switch record. - */ -int plugin_get_next_pid(struct tep_record *record) +static void plugin_sched_swith_action(struct kshark_data_stream *stream, + void *rec, struct kshark_entry *entry) { - struct plugin_sched_context *plugin_ctx = - plugin_sched_context_handler; - unsigned long long val; + struct tep_record *record = (struct tep_record *) rec; + struct plugin_sched_context *plugin_ctx; + unsigned long long next_pid, prev_state; + ks_num_field_t ks_field; int ret; - ret = tep_read_number_field(plugin_ctx->sched_switch_next_field, - record->data, &val); - - return ret ? : val; -} - -static void plugin_register_command(struct kshark_context *kshark_ctx, - struct tep_record *record, - int pid) -{ - struct plugin_sched_context *plugin_ctx = - plugin_sched_context_handler; - const char *comm; - - if (!plugin_ctx->sched_switch_comm_field) + plugin_ctx = __get_context(stream->stream_id); + if (!plugin_ctx) return; - comm = record->data + plugin_ctx->sched_switch_comm_field->offset; - /* - * TODO: The retrieve of the name of the command above needs to be - * implemented as a wrapper function in libtracevent. - */ - - if (!tep_is_pid_registered(kshark_ctx->pevent, pid)) - tep_register_comm(kshark_ctx->pevent, comm, pid); -} - -static int find_wakeup_pid(struct kshark_context *kshark_ctx, struct kshark_entry *e, - struct tep_event *wakeup_event, struct tep_format_field *pid_field) -{ - struct tep_record *record; - unsigned long long val; - int ret; - - if (!wakeup_event || e->event_id != wakeup_event->id) - return -1; + ret = tep_read_number_field(plugin_ctx->sched_switch_next_field, + record->data, &next_pid); - record = tracecmd_read_at(kshark_ctx->handle, e->offset, NULL); - ret = tep_read_number_field(pid_field, record->data, &val); - free_record(record); + if (ret == 0 && next_pid >= 0) { + plugin_sched_set_pid(&ks_field, entry->pid); - if (ret) - return -1; + ret = tep_read_number_field(plugin_ctx->sched_switch_prev_state_field, + record->data, &prev_state); - return val; -} + if (ret == 0) + plugin_sched_set_prev_state(&ks_field, prev_state); -static bool wakeup_match_rec_pid(struct plugin_sched_context *plugin_ctx, - struct kshark_context *kshark_ctx, - struct kshark_entry *e, - int pid) -{ - struct tep_event *wakeup_events[] = { - plugin_ctx->sched_waking_event, - plugin_ctx->sched_wakeup_event, - plugin_ctx->sched_wakeup_new_event, - }; - struct tep_format_field *wakeup_fields[] = { - plugin_ctx->sched_waking_pid_field, - plugin_ctx->sched_wakeup_pid_field, - plugin_ctx->sched_wakeup_new_pid_field, - }; - int i, wakeup_pid = -1; - - for (i = 0; i < sizeof(wakeup_events) / sizeof(wakeup_events[0]); i++) { - wakeup_pid = find_wakeup_pid(kshark_ctx, e, wakeup_events[i], wakeup_fields[i]); - if (wakeup_pid >= 0) - break; + kshark_data_container_append(plugin_ctx->ss_data, entry, ks_field); + entry->pid = next_pid; } - - if (wakeup_pid >= 0 && wakeup_pid == pid) - return true; - - return false; -} - -/** - * @brief Process Id matching function adapted for sched_wakeup and - * sched_wakeup_new events. - * - * @param kshark_ctx: Input location for the session context pointer. - * @param e: kshark_entry to be checked. - * @param pid: Matching condition value. - * - * @returns True if the Pid of the record matches the value of "pid". - * Otherwise false. - */ -bool plugin_wakeup_match_rec_pid(struct kshark_context *kshark_ctx, - struct kshark_entry *e, - int pid) -{ - struct plugin_sched_context *plugin_ctx; - - plugin_ctx = plugin_sched_context_handler; - if (!plugin_ctx) - return false; - - return wakeup_match_rec_pid(plugin_ctx, kshark_ctx, e, pid); } -/** - * @brief Process Id matching function adapted for sched_switch events. - * - * @param kshark_ctx: Input location for the session context pointer. - * @param e: kshark_entry to be checked. - * @param pid: Matching condition value. - * - * @returns True if the Pid of the record matches the value of "pid". - * Otherwise false. - */ -bool plugin_switch_match_rec_pid(struct kshark_context *kshark_ctx, - struct kshark_entry *e, - int pid) +static void plugin_sched_wakeup_action(struct kshark_data_stream *stream, + void *rec, struct kshark_entry *entry) { + struct tep_record *record = (struct tep_record *) rec; struct plugin_sched_context *plugin_ctx; unsigned long long val; - int ret, switch_pid = -1; - - plugin_ctx = plugin_sched_context_handler; - - if (plugin_ctx->sched_switch_event && - e->event_id == plugin_ctx->sched_switch_event->id) { - struct tep_record *record; - - record = tracecmd_read_at(kshark_ctx->handle, e->offset, NULL); - ret = tep_read_number_field(plugin_ctx->sched_switch_prev_state_field, - record->data, &val); - - if (ret == 0 && !(val & 0x7f)) - switch_pid = tep_data_pid(plugin_ctx->pevent, record); + int ret; - free_record(record); - } + plugin_ctx = __get_context(stream->stream_id); + if (!plugin_ctx) + return; - if (switch_pid >= 0 && switch_pid == pid) - return true; + ret = tep_read_number_field(plugin_ctx->sched_waking_pid_field, + record->data, &val); - return false; + if (ret == 0) + kshark_data_container_append(plugin_ctx->sw_data, entry, val); } -/** - * @brief Process Id matching function adapted for sched_switch events. - * - * @param kshark_ctx: Input location for the session context pointer. - * @param e: kshark_entry to be checked. - * @param pid: Matching condition value. - * - * @returns True if the Pid of the entry matches the value of "pid". - * Otherwise false. - */ -bool plugin_switch_match_entry_pid(struct kshark_context *kshark_ctx, - struct kshark_entry *e, - int pid) +/** Load this plugin. */ +int KSHARK_PLOT_PLUGIN_INITIALIZER(struct kshark_data_stream *stream) { + printf("--> sched init %i\n", stream->stream_id); struct plugin_sched_context *plugin_ctx; - plugin_ctx = plugin_sched_context_handler; - - if (plugin_ctx->sched_switch_event && - e->event_id == plugin_ctx->sched_switch_event->id && - e->pid == pid) - return true; - - return false; -} - -/** - * @brief A match function to be used to process a data collections for - * the Sched events plugin. - * - * @param kshark_ctx: Input location for the session context pointer. - * @param e: kshark_entry to be checked. - * @param pid: Matching condition value. - * - * @returns True if the entry is relevant for the Sched events plugin. - * Otherwise false. - */ -bool plugin_match_pid(struct kshark_context *kshark_ctx, - struct kshark_entry *e, int pid) -{ - return plugin_switch_match_entry_pid(kshark_ctx, e, pid) || - plugin_switch_match_rec_pid(kshark_ctx, e, pid) || - plugin_wakeup_match_rec_pid(kshark_ctx, e, pid); -} - -static void plugin_sched_action(struct kshark_context *kshark_ctx, - struct tep_record *rec, - struct kshark_entry *entry) -{ - int pid = plugin_get_next_pid(rec); - if (pid >= 0) { - entry->pid = pid; - plugin_register_command(kshark_ctx, rec, entry->pid); + plugin_ctx = __init(stream->stream_id); + if (!plugin_ctx || !plugin_sched_init_context(stream, plugin_ctx)) { + __close(stream->stream_id); + return 0; } -} - -static int plugin_sched_init(struct kshark_context *kshark_ctx) -{ - struct plugin_sched_context *plugin_ctx; - if (!plugin_sched_init_context(kshark_ctx)) - return 0; + kshark_register_event_handler(stream, + plugin_ctx->sched_switch_event->id, + plugin_sched_swith_action); - plugin_ctx = plugin_sched_context_handler; + kshark_register_event_handler(stream, + plugin_ctx->sched_waking_event->id, + plugin_sched_wakeup_action); - kshark_register_event_handler(&kshark_ctx->event_handlers, - plugin_ctx->sched_switch_event->id, - plugin_sched_action, - plugin_draw); + kshark_register_draw_handler(stream, plugin_draw); return 1; } -static int plugin_sched_close(struct kshark_context *kshark_ctx) +/** Unload this plugin. */ +int KSHARK_PLOT_PLUGIN_DEINITIALIZER(struct kshark_data_stream *stream) { + printf("<-- sched close %i\n", stream->stream_id); struct plugin_sched_context *plugin_ctx; + int sd = stream->stream_id; - if (!plugin_sched_context_handler) + plugin_ctx = __get_context(sd); + if (!plugin_ctx) return 0; - plugin_ctx = plugin_sched_context_handler; - - kshark_unregister_event_handler(&kshark_ctx->event_handlers, + kshark_unregister_event_handler(stream, plugin_ctx->sched_switch_event->id, - plugin_sched_action, - plugin_draw); + plugin_sched_swith_action); - plugin_free_context(plugin_ctx); - plugin_sched_context_handler = NULL; + kshark_unregister_event_handler(stream, + plugin_ctx->sched_waking_event->id, + plugin_sched_wakeup_action); - return 1; -} + kshark_unregister_draw_handler(stream, plugin_draw); -/** Load this plugin. */ -int KSHARK_PLUGIN_INITIALIZER(struct kshark_context *kshark_ctx) -{ - return plugin_sched_init(kshark_ctx); -} + __close(sd); -/** Unload this plugin. */ -int KSHARK_PLUGIN_DEINITIALIZER(struct kshark_context *kshark_ctx) -{ - return plugin_sched_close(kshark_ctx); + return 1; } diff --git a/src/plugins/sched_events.h b/src/plugins/sched_events.h index dbc9963..4c57606 100644 --- a/src/plugins/sched_events.h +++ b/src/plugins/sched_events.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * Copyright (C) 2017 VMware Inc, Yordan Karadzhov + * Copyright (C) 2017 VMware Inc, Yordan Karadzhov (VMware) */ /** @@ -14,6 +14,7 @@ // KernelShark #include "libkshark.h" +#include "libkshark-plugin.h" #ifdef __cplusplus extern "C" { @@ -21,11 +22,8 @@ extern "C" { /** Structure representing a plugin-specific context. */ struct plugin_sched_context { - /** Input handle for the trace data file. */ - struct tracecmd_input *handle; - /** Page event used to parse the page. */ - struct tep_handle *pevent; + struct tep_handle *tep; /** Pointer to the sched_switch_event object. */ struct tep_event *sched_switch_event; @@ -39,47 +37,33 @@ struct plugin_sched_context { /** Pointer to the sched_switch_prev_state_field format descriptor. */ struct tep_format_field *sched_switch_prev_state_field; - /** Pointer to the sched_wakeup_event object. */ - struct tep_event *sched_wakeup_event; - - /** Pointer to the sched_wakeup_pid_field format descriptor. */ - struct tep_format_field *sched_wakeup_pid_field; - - /** Pointer to the sched_wakeup_new_event object. */ - struct tep_event *sched_wakeup_new_event; - - /** Pointer to the sched_wakeup_new_pid_field format descriptor. */ - struct tep_format_field *sched_wakeup_new_pid_field; - /** Pointer to the sched_waking_event object. */ struct tep_event *sched_waking_event; /** Pointer to the sched_waking_pid_field format descriptor. */ struct tep_format_field *sched_waking_pid_field; - /** List of Data collections used by this plugin. */ - struct kshark_entry_collection *collections; + /** True if the second pass is already done. */ + bool second_pass_done; - /** Hash of the tasks for which the second pass is already done. */ - struct tracecmd_filter_id *second_pass_hash; -}; + /** Data container for sched_switch data. */ + struct kshark_data_container *ss_data; -int plugin_get_next_pid(struct tep_record *record); + /** Data container for sched_waking data. */ + struct kshark_data_container *sw_data; +}; -bool plugin_wakeup_match_rec_pid(struct kshark_context *kshark_ctx, - struct kshark_entry *e, int pid); +KS_DEFINE_PLUGIN_CONTEXT(struct plugin_sched_context); -bool plugin_switch_match_rec_pid(struct kshark_context *kshark_ctx, - struct kshark_entry *e, int pid); +/** The type of the data field stored in the kshark_data_container object. */ +typedef int64_t ks_num_field_t; -bool plugin_switch_match_entry_pid(struct kshark_context *kshark_ctx, - struct kshark_entry *e, - int pid); +int plugin_sched_get_pid(ks_num_field_t field); -bool plugin_match_pid(struct kshark_context *kshark_ctx, - struct kshark_entry *e, int pid); +int plugin_sched_get_prev_state(ks_num_field_t field); -void plugin_draw(struct kshark_cpp_argv *argv, int pid, int draw_action); +void plugin_draw(struct kshark_cpp_argv *argv, int sd, int pid, + int draw_action); #ifdef __cplusplus }