From patchwork Fri Jan 8 14:31:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12006699 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 3BF00C433E6 for ; Fri, 8 Jan 2021 14:32:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0DA9C238A1 for ; Fri, 8 Jan 2021 14:32:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727242AbhAHOcg (ORCPT ); Fri, 8 Jan 2021 09:32:36 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55262 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726476AbhAHOcg (ORCPT ); Fri, 8 Jan 2021 09:32:36 -0500 Received: from mail-ej1-x62d.google.com (mail-ej1-x62d.google.com [IPv6:2a00:1450:4864:20::62d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 10212C061381 for ; Fri, 8 Jan 2021 06:31:56 -0800 (PST) Received: by mail-ej1-x62d.google.com with SMTP id w1so14665328ejf.11 for ; Fri, 08 Jan 2021 06:31:55 -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=ium9RnzF9mAjGSsdhhVB0NggOeRlvQ45ZdvB10rIv69siIhSnZF/MdEd1hI0sM+DDs zDfnx2Uoro7vH6umLdldipXHpm9q3HfMQl9M75KugVf6JVnlNjfCxdI1YxpUvlibqc7L SNUWOp0V4CxF4NHZJ0Q6A52NKjJzKr+pV5s6P5LW2gWUF4yhm5MSiebAPAi9AaDShSg7 gweNlFvfanH3zJ/3u5AVxIf52pfAA371T93FwuQx07hJ5fcSRFr5/vYqzq3xkiIfXfkH kLIpUzaxYzB8hqszkYXmvsehdY4reX3FtKzUdfl6Wcjq37BIboK+/LEEJkrktxQy/lIK KS0w== 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=QrWbeNJ8qQTMaJsCC0hLSvtIqOXZwPoRWfDRG0nkYOXxrKVebVAzYtdsuyyuOKONGI YlEGRUJsgVsPXpWM+JQLID6YBwzt82MiV4qjdAt8iA/iz0yh7pKQ0qHZaA8GODdfoEMv py2iJ7rnHaoZZTlwAaXs5/0/zIFrzqiacrQ8G5vlRodmbov3Nicy/wW1AXRlc+bLkcHb 3kvIuVz5IX9TM6Sh0MoDrXaji+Z1ywf/kSST5MzJXGk94cL/ncrTvkYd77OwFzbLS2VQ +lS7hTl2AmOUMo35KEvPsNEaKTPtIrjAGdAWhqF9c1KZKD7Og8BmQgPaK1L/YjEGUdl4 5jFg== X-Gm-Message-State: AOAM530xiadADonTILT8Y6HQXt8P42/JwoY5JlbO1LGlRZhQ0SHPSMRn kYJMMMsTqSdKdoypYMFkw3Q= X-Google-Smtp-Source: ABdhPJztcPyyMp0Jrpzm1S9LRioeBR2vEN4LFktyXd9Jymo0LQhkq0NfVhIP8tZOpdZfPyErQc8Zww== X-Received: by 2002:a17:906:b2da:: with SMTP id cf26mr2918000ejb.176.1610116314785; Fri, 08 Jan 2021 06:31:54 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id d13sm3588120ejc.44.2021.01.08.06.31.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 08 Jan 2021 06:31:54 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v3 1/6] kernel-shark: Add KS_DOUBLE_SIZE macro Date: Fri, 8 Jan 2021 16:31:35 +0200 Message-Id: <20210108143140.285037-2-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210108143140.285037-1-y.karadz@gmail.com> References: <20210108143140.285037-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 Fri Jan 8 14:31:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12006701 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 57908C433E9 for ; Fri, 8 Jan 2021 14:32:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2E8E1238A1 for ; Fri, 8 Jan 2021 14:32:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726858AbhAHOch (ORCPT ); Fri, 8 Jan 2021 09:32:37 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55266 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726476AbhAHOch (ORCPT ); Fri, 8 Jan 2021 09:32:37 -0500 Received: from mail-ej1-x62e.google.com (mail-ej1-x62e.google.com [IPv6:2a00:1450:4864:20::62e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 10277C0612EA for ; Fri, 8 Jan 2021 06:31:57 -0800 (PST) Received: by mail-ej1-x62e.google.com with SMTP id ce23so14752264ejb.8 for ; Fri, 08 Jan 2021 06:31:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=N4sAK+nbuIDNs3UACy8J6ZxsWYC8FLKSUqCZzS2tC1w=; b=T/3fY4f2HJqxRcQ7IxD5oIsI4MFF1hOmlezStoJqb7WUp3QiJyBA2HIE66a9rceUS9 kGKNwRN4syI6hxD3/Xlbgyk5CcTeGNaRInZ+B5zdVQRY0LPsNSiMSMg3mKfXD0enc5S4 fhzzq5zjbROET+BRjBbNeEexDdAilQpUO0E4XBeueB8ymlilZ5N2AHgsLZ1zIFDK4+wG keItlnlakcGgwRCndiq2AH08c9YiNhjkXY8AO/PQE3bLA3vEf9b+a3EfOW9aVANfH2pq xBu/PBRqxZY+ySvEXxHnAA9zG0PrN1GfReER3qxKofre3ZktWweYZNQZno9vqk8nePNV EPCQ== 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=N4sAK+nbuIDNs3UACy8J6ZxsWYC8FLKSUqCZzS2tC1w=; b=EffQuOkPU8ZQuRaD3SG4h+OT8tLTNQx+J5m6m7maT/RSN7+Mhkiaa+e4EpJGI9qUdr b/mzyGy5ZTRXy92GWNfbrol79dHYL5xY06vgHs3Bx9qy15k0Uc4f+saBiCigurg1Xop7 COQ74kXrWpkcuVJvBbgAHWhDWTS+L0/bvrj/2EjWEkNvc1uSO1D0yBYoN5s/onWlZe5s 1T0D7bVHM/2ZgSnQxrGBf9k78IZd9rClML9q7xvfDC+eRMtaZ+MxeTWKEqUx+ob5QHyk AVaSDMXdUH9rZTDXt4BWenq/ZZtBznzksFNo3b+JGmp4sjLYIjijwVCKaoew+OM1eMm4 ACLQ== X-Gm-Message-State: AOAM5327gLmF6ZI6mah8t+XHVEvJcLXc2MlP3903clYT/XSWHcDRliRq k+IKLs6MruoiVKZT498SygQ= X-Google-Smtp-Source: ABdhPJyWZKKaqwG/qFvX7bQeSkD7JAhFYEqNMGs3Ya+8rS1wPlUZr6s8kbsVCBY+xMqldS73NW/Cyw== X-Received: by 2002:a17:906:c097:: with SMTP id f23mr2952403ejz.136.1610116315794; Fri, 08 Jan 2021 06:31:55 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id d13sm3588120ejc.44.2021.01.08.06.31.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 08 Jan 2021 06:31:55 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v3 2/6] kernel-shark: Add kshark_data_container to libkshark Date: Fri, 8 Jan 2021 16:31:36 +0200 Message-Id: <20210108143140.285037-3-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210108143140.285037-1-y.karadz@gmail.com> References: <20210108143140.285037-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..a54fdd5 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: Input 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: Input 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 Fri Jan 8 14:31:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12006703 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 163FEC433DB for ; Fri, 8 Jan 2021 14:32:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E1470238A1 for ; Fri, 8 Jan 2021 14:32:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727252AbhAHOci (ORCPT ); Fri, 8 Jan 2021 09:32:38 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55272 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726476AbhAHOci (ORCPT ); Fri, 8 Jan 2021 09:32:38 -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 E2849C0612FD for ; Fri, 8 Jan 2021 06:31:57 -0800 (PST) Received: by mail-ej1-x635.google.com with SMTP id g20so14854699ejb.1 for ; Fri, 08 Jan 2021 06:31:57 -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=Yg4a6WHkBJ0hMjF08qLfqPtBOBjR46qQKfEisVK0WdU=; b=gVAdrSQU3CMcolZncpzjW/IcY5zgHj0UMbv7AC/1Hae61kb0IqfEEYqx3NfjUgtJaS 5Nhvh4ilzTnhNe1zuV33z8pV7tEMrp/RjFZhBbGN7FoutdX8ZsDiK3Cao9cPLoZskOlB Q2Fos/iSyVrenw5U5XE63T99SUneB9ku04i8S+tuuay1E6pn3+wcn1B06YnAcHSDD3ki 9ca3mkCDahoXBo2YHPrt3FnVcUWxLo2+J8w+EAMoeIaOXjgzEIcMTfbidC1lmL/ayvyL SlaEfwiV2uPctpozW76J1zFVBSGUz8tii2Kn50sPktKgwIpnxaMnmrVsMr/J4N7WLw3E SSNg== 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=Yg4a6WHkBJ0hMjF08qLfqPtBOBjR46qQKfEisVK0WdU=; b=aUoF01FLPwJdMyglECmoTQVqdPn3WAPIQiL1SyY4fJlBo1lHryw1XhGPKw42NlO62H yUEkfq6s+2Qu8FaPdRb1qPLLpT/zTYktKFF3OFIa6OpIgLhov8L9sKt6sLpvT1FQIHza k+jPbd/GOyjq3o4OZjw4OYyn7FzvdHZ921Z/3c9uTvPEVJD5/NclNs1WWwa/s1NbL2VI NlkOtuqy7WDCyCvZSDeQY7oWcW7nAvBWH/l49aso1WM3GorOVn9gzBg7uuElJBvau3p8 nvis075qSxMNLuhcThjeLbGh89B8LeJRtgEzktFhd4fteE0sEspGB+/Uvm/JuD1pnoIr hNLQ== X-Gm-Message-State: AOAM530yr9zJPbZvNpnK5X7VUrWaY4leA/hzUE28NkhwfdhXfObs8GzL 6K8B4My4HeaAW86Xj/Qd0F96HhfnaV8wDw== X-Google-Smtp-Source: ABdhPJyeNIHtR+jbYYNtkmSJBWELaXN0fgNDOd0SoFkYj5xon0V5E0Ii2zj3Vj2d2WWIJa0uAUAaqw== X-Received: by 2002:a17:906:358e:: with SMTP id o14mr2765986ejb.526.1610116316707; Fri, 08 Jan 2021 06:31:56 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id d13sm3588120ejc.44.2021.01.08.06.31.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 08 Jan 2021 06:31:56 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v3 3/6] kernel-shark: Add KS_DEFINE_PLUGIN_CONTEXT macro Date: Fri, 8 Jan 2021 16:31:37 +0200 Message-Id: <20210108143140.285037-4-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210108143140.285037-1-y.karadz@gmail.com> References: <20210108143140.285037-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. Signed-off-by: Yordan Karadzhov (VMware) --- 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 Fri Jan 8 14:31:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12006705 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 34215C433E6 for ; Fri, 8 Jan 2021 14:32:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 03988238A1 for ; Fri, 8 Jan 2021 14:32:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727256AbhAHOcj (ORCPT ); Fri, 8 Jan 2021 09:32:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55274 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726476AbhAHOcj (ORCPT ); Fri, 8 Jan 2021 09:32:39 -0500 Received: from mail-ed1-x532.google.com (mail-ed1-x532.google.com [IPv6:2a00:1450:4864:20::532]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 15079C0612FE for ; Fri, 8 Jan 2021 06:31:59 -0800 (PST) Received: by mail-ed1-x532.google.com with SMTP id p22so11309775edu.11 for ; Fri, 08 Jan 2021 06:31:59 -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=JWduVzasZxft8iKzPuYzzrnytO3r8eukytsk5t47TvEo0HwaC7sRN4frxE9FAS04DF kEUjnRcSh7d1kfpUy4uAMAy3C/Ju+OTh5PNgIWIZvzlIqltt4IxTuRAvBKc+Pr0B6SKh PItEsM1xFdhRrm+RHeYiJPfnI9ureqkLdijqkh1+cqAxMJ3VGMH7EDnj6dxkkvqs0yoA FhEbEE3wW5Gp+gXQCPkUkfcUjbjX0LHstbKkz7NwZ4mO2zrlugp+tviucgXc18J1Fmrn N68+kdKbXAUVMB8sBvUPmC2Szncb1321A2s2iyRYA8x3wvdZLP5EYzzpUtt14eocJJpD baug== 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=Xs+FpuCFPPTnKACyo3b9NnoOzcdCHLhBYV3SblKC2OA3WiRVXfRE//OQv/dTxlwd63 mfbHZuLJZVOUUbezGTr1OzgzjNrjZMwKFcaSThquMapRUGDA65Q6C3lIBdV6vBQoHAJS yxgRHDrny/d0VrB5tmpFLzYJG1hddrfzksC8/92QwkLEKa2gKztNCbsbhRL6CKM/miVc Vlh6ZY8m/0hIOJG/RbCtvFtRDIBfr3ythy+qerdNpxq0yE2TEWcmAJOPN0tpohC4oJyw +yeZgGszyNWjwNocHiNruQ8jyZN0hZfqxNAUWNZbfUqwDc3r5l3i8fSpg6M7tZCVtKFA LPXA== X-Gm-Message-State: AOAM5314nx5/HiiC3asAHTyNMm6k3lo/MfTAfxsYbZc0Ursc8UwL2oFP EkfN3LVX0b1W0wTO46RQL368lTmKRwlXig== X-Google-Smtp-Source: ABdhPJxhKUxYqPiu4G7NS8AGXsI9jyfTmILQeQXH5uTb4D+VkVZBWw1hS3oFFf5WUz6Xy5iwvwGZog== X-Received: by 2002:aa7:cd06:: with SMTP id b6mr5425912edw.43.1610116317872; Fri, 08 Jan 2021 06:31:57 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id d13sm3588120ejc.44.2021.01.08.06.31.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 08 Jan 2021 06:31:57 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v3 4/6] kernel-shark: Start using C++17 Date: Fri, 8 Jan 2021 16:31:38 +0200 Message-Id: <20210108143140.285037-5-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210108143140.285037-1-y.karadz@gmail.com> References: <20210108143140.285037-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 Fri Jan 8 14:31:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12006707 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 6F53BC433DB for ; Fri, 8 Jan 2021 14:33:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 18102238A1 for ; Fri, 8 Jan 2021 14:33:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727119AbhAHOdP (ORCPT ); Fri, 8 Jan 2021 09:33:15 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55366 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726875AbhAHOdP (ORCPT ); Fri, 8 Jan 2021 09:33:15 -0500 Received: from mail-ed1-x535.google.com (mail-ed1-x535.google.com [IPv6:2a00:1450:4864:20::535]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2EA08C0612FF for ; Fri, 8 Jan 2021 06:32:00 -0800 (PST) Received: by mail-ed1-x535.google.com with SMTP id u19so11435945edx.2 for ; Fri, 08 Jan 2021 06:32:00 -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=Nr8WWz0EsTn2dLu+osRphqPz7AwjuOH38pkw/wkCebf+CxPB5L9vFq42Gwmu6vywJL lwPTZg/F8W6EGpd5hj/5xiWcvCLpJh4JhLtzLYpp63AjQnlrcm4XTJRzKUx27270eIYP bUMCK5i+0mANzzvKv3VmIDy9A2o/WuW8tTnVcpJbZ6V++cF/hA9bX/UkHYC6VLzyCYuk uTlHh53fgsAyMljSTb6PfyrViF//RXKjlg2vJhYuGl4YDvtiuv5F9VY9OkOZCeIneHap groZa9sg9rS4qK57X8Xl7sFXA/L2EGhWry4GhDPqSvbC1R+9UfZxJ8Yt4JuAv9liL0Bb o4cQ== 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=kn4tkR5aEQucVpap9t1r0gLEJjfWur3qdMnK+uracst06LWOPf1CxxDdUuxovJJNsd IOvVLCPOW02xhel63pDHjH/eoLNyNSIByVqITZQqcI0f+E8UFUagM0zeZAb37mW3fZKh Yik7mcgj2UyIIfQf6M+wI8NjlExVWvzXvl3O+vK5eqH6PBYDi7Ze+iQtBjuBB0SZVS0l qJ81c9jWxMg7wx0/iWgL/ZPig/CXpYSsza9vxIc67Pa10MEAntejDQvGVomqoX3ldzFY gblQVMBq5dK3JuBWMi5DCAKhMR+uvZfOdby30EgQS0zzGY+gXdbiqaiUSR8KBltlzPAJ +TGA== X-Gm-Message-State: AOAM532adCXzdRQqGYLthkokW0fWwsz/FE5xQHEYCMXSBvcPNU+X64nE IC28ARa9EN3hpnveZKb7b2LHA4XL1PFB5A== X-Google-Smtp-Source: ABdhPJwfDceGxT55gmFSKX6EFo9nN0fAI6K8UyITltEYCgPL1ug+9IV9WNhdn0McWsDuNOyL2F9Mgg== X-Received: by 2002:aa7:d642:: with SMTP id v2mr5635897edr.305.1610116318850; Fri, 08 Jan 2021 06:31:58 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id d13sm3588120ejc.44.2021.01.08.06.31.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 08 Jan 2021 06:31:58 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v3 5/6] kernel-shark: Add plotting methods to KsPlugins Date: Fri, 8 Jan 2021 16:31:39 +0200 Message-Id: <20210108143140.285037-6-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210108143140.285037-1-y.karadz@gmail.com> References: <20210108143140.285037-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 Fri Jan 8 14:31:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12006709 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 7C97AC433E0 for ; Fri, 8 Jan 2021 14:33:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 47D0B23A00 for ; Fri, 8 Jan 2021 14:33:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726875AbhAHOdQ (ORCPT ); Fri, 8 Jan 2021 09:33:16 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55368 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726876AbhAHOdP (ORCPT ); Fri, 8 Jan 2021 09:33:15 -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 C01E0C06129C for ; Fri, 8 Jan 2021 06:32:01 -0800 (PST) Received: by mail-ej1-x635.google.com with SMTP id lt17so14823191ejb.3 for ; Fri, 08 Jan 2021 06:32:01 -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=ULLGjPFinUnvw4NGTlGOdQGjlGe5aqzdHRcHWoXmDYwpx3HmrbfxiVioe5gw1hh9SC 94YGg51Zqrnwj3FGnTLQRgroahSLiEoj/j4BQNM3CY9HwAIrZJJmJLuTzAIaAjrNdDn8 SFHRXD86xpiyaZdWDOXWupnha3QtgK4qMEPPeu4rYD7kvS20DrrjD4+WkaesKKRzUGUi k0IL/knprUHXbCQqHd6RM3frvVHU3lGw0laHHPF1B6XEG+ndHLvO8V1AU+OJXT4SNLsb nSTn36cbjnD45oCdJ4GQp57fQ0ByO5FwE916MkOlB/32HPC0PmNF0wl9Pk4aDouGuS9k rmog== 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=VVlQpKPfFxQ1QgtjTR4sIYkGSUsIjgOlNwup3olEM63403gq/q0wNiXtl89fN2XGwn U89dAoJ8uGxVO7t2EwBMQ2gEUUMz/t2SG/MiEL6Oh4TR+ahkoqUezkX9ezK4XRjLKORD bavgz4w0bCFYCKcmaeEcKrKK547geeP5JBVpUmJaxBUiF0SbxbtCQxM2JzeoFBIZVryd yjDYmC1V2uaeWi0j/bi5LPDD6+i1yyEYI1+oVtZGEPKHyIxur85c1MFp1e9N+lTAUeSa V1wvEYoKFd7loOoeFW1LCf855CucWR/wuxZ05FLaOAFALMXRSW1CPNSgBLW1r6J6nAvT O1Jw== X-Gm-Message-State: AOAM530jk/m/lah9PCGdoKonlvJoPBzIFAGrSdayi/tIQmCHPbV79RbL WVPqc8M+cA+FAp9fb5964x8Ek0at9R2nHA== X-Google-Smtp-Source: ABdhPJx52ZTjUjTXJ+6Ct/LMoCmvuBazg3rKRo3fO79OB2MnRyNvG6AvKlwZUyVjXCj9NXwJxrQjKg== X-Received: by 2002:a17:906:8301:: with SMTP id j1mr2802789ejx.397.1610116320192; Fri, 08 Jan 2021 06:32:00 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id d13sm3588120ejc.44.2021.01.08.06.31.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 08 Jan 2021 06:31:59 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v3 6/6] kernel-shark: Speed-up the sched_events plugin Date: Fri, 8 Jan 2021 16:31:40 +0200 Message-Id: <20210108143140.285037-7-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210108143140.285037-1-y.karadz@gmail.com> References: <20210108143140.285037-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 }