From patchwork Wed Jan 6 16:11:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12001931 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 31549C433E6 for ; Wed, 6 Jan 2021 16:12:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DCD1A23130 for ; Wed, 6 Jan 2021 16:12:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727022AbhAFQMQ (ORCPT ); Wed, 6 Jan 2021 11:12:16 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44820 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725800AbhAFQMQ (ORCPT ); Wed, 6 Jan 2021 11:12:16 -0500 Received: from mail-ej1-x632.google.com (mail-ej1-x632.google.com [IPv6:2a00:1450:4864:20::632]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 210F0C061357 for ; Wed, 6 Jan 2021 08:11:36 -0800 (PST) Received: by mail-ej1-x632.google.com with SMTP id g20so5825921ejb.1 for ; Wed, 06 Jan 2021 08:11:36 -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=Y+k8neNdzORKAr1XPD79IEi+kxR+kKWu+FozF4tcoT8=; b=NJ0gT6pJu33+F15iQqucjeMIu5QMf5GgWnzPn0k+lZJnd3136mpdji6id0Eqt8BI07 uLAlzCU0ayTDcxI9qs2dOc5YGVAewnw7snXBp2TE4kpgVl3vCNNZXt4RNK4bqvvYWilp xLDNAtjESrZ9XxWQghOTgXuSg7dQt1RTZkJbJ+vtGp+oHn6nnmEJ9yd56TpCgwL4JR+w hLqUIaUIpZtFeOP+/jt5wNYZoXxlZj8mgPa0mJ3LoC0PO09ZN1gkty/6Fgk6y76+vP4D v5fiwJNm6ig92fpwb0/g2rMql8LAe/GJdHUvNY3jq/VzK+HzowH6m//SVZ3yhOFGN45y UeGg== 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=Y+k8neNdzORKAr1XPD79IEi+kxR+kKWu+FozF4tcoT8=; b=FP81fMMQsdwue2/7gSSWxPOY2m8UgilEcczqyE373yKgrlcTqc4V/Wc2X5tywRpDUv efugIzX5G6mN8LXjZRibcQtFnV3rYPIcAatTZBDkZ0wirpAH96czHj1vKqxavlavRgfZ zvhK3tV4/cyc/gzjrCEM/aMUeX+PEjr9enDjrKeDansO6cdN8iI5k7HoTjd1yxG7gEe8 Hh527xl/mBbl+ZFFwaH81seqrwa0hScpEHeM+eh8ztIG7GN/e9/+MfgbwONN/lcVX/U9 Jx49PKLkxotzmFhyK7vOM4bpjpGNUva16dIS00YXPT8G/rv9JyScgQSV86k4Pt4KXUmz mdXQ== X-Gm-Message-State: AOAM530Rodbc/U7bSGlC0B1MTE6e2olqvBDchSypbp0XFdQu0VqytLZ/ E5R/tA/oq5Khfn9rD4HAE0k= X-Google-Smtp-Source: ABdhPJybKUrrQ8l9bnJdNg74y64HJSA/P6z331hjTutovAgmLl+PcseCqMhR65kvX92TNmoulLmiUw== X-Received: by 2002:a17:906:5043:: with SMTP id e3mr3380251ejk.260.1609949494867; Wed, 06 Jan 2021 08:11:34 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id q25sm1570041eds.85.2021.01.06.08.11.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 06 Jan 2021 08:11:34 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 1/6] kernel-shark: Add KS_DOUBLE_SIZE macro Date: Wed, 6 Jan 2021 18:11:15 +0200 Message-Id: <20210106161120.119085-2-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210106161120.119085-1-y.karadz@gmail.com> References: <20210106161120.119085-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 | 14 ++++++++++++++ src/libkshark.c | 15 +++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/libkshark-plugin.h b/src/libkshark-plugin.h index 1a642ad..f3c724f 100644 --- a/src/libkshark-plugin.h +++ b/src/libkshark-plugin.h @@ -346,6 +346,20 @@ 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(type, array, size, ok) \ +{ \ + ssize_t n = *size; \ + *ok = false; \ + type *tmp = (type *) realloc(array, 2 * n * sizeof(*tmp)); \ + if (tmp) { \ + memset(tmp + n, 0, n * sizeof(*tmp)); \ + *size = 2 * n; \ + array = tmp; \ + *ok = true; \ + } \ +} \ + #ifdef __cplusplus } #endif // __cplusplus diff --git a/src/libkshark.c b/src/libkshark.c index 315c24f..3aa3fa2 100644 --- a/src/libkshark.c +++ b/src/libkshark.c @@ -234,16 +234,15 @@ 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; + bool ok; - streams_tmp = realloc(kshark_ctx->stream, - new_size * sizeof(*kshark_ctx->stream)); - if (!streams_tmp) - return -ENOMEM; + KS_DOUBLE_SIZE(struct kshark_data_stream *, + kshark_ctx->stream, + &kshark_ctx->stream_info.array_size, + &ok); - kshark_ctx->stream = streams_tmp; - kshark_ctx->stream_info.array_size = new_size; + if (!ok) + return -ENOMEM; } stream = kshark_stream_alloc(); From patchwork Wed Jan 6 16:11:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12001935 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 51FDDC433DB for ; Wed, 6 Jan 2021 16:12:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 14A5323131 for ; Wed, 6 Jan 2021 16:12:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727162AbhAFQMS (ORCPT ); Wed, 6 Jan 2021 11:12:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44824 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725800AbhAFQMR (ORCPT ); Wed, 6 Jan 2021 11:12:17 -0500 Received: from mail-ej1-x634.google.com (mail-ej1-x634.google.com [IPv6:2a00:1450:4864:20::634]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2152CC061358 for ; Wed, 6 Jan 2021 08:11:37 -0800 (PST) Received: by mail-ej1-x634.google.com with SMTP id b9so5842139ejy.0 for ; Wed, 06 Jan 2021 08:11:37 -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=Pw4SkXIOP3gYsrfkXUMDmrfWVE+b+YR/QHYLmcMcDkw=; b=aefvSY2I8SlfJfl71rmVQu4eVxkFN80UyYTt6TW3O/2heX7AUbWt3SVLnxiQ2wWVPv MDxiI4374crCU8QmsDjw9AXCgWa4oqgzUQGm0ii5FMi2R+1lRYjl/P4Lln9IuyZqS03e T+QbPsRILi63jUf86fY4OaadFMrzGP2gh3BLccOu2bwaHU5S69sHW1u+1kl5UDy7L1ZN awUGekt/KDn1Q4HJh11m9NEjWSCdsBJOGgtb57kWvr7Phr1dkSmlCyM0gZI076HKeQgM CA6PNocPImwPfaaW1oEMQMjjOUZ8FQlDYlgrB2sHd4V6wZaVjsHQxhoeZzRtEDZkX/mR ZUoA== 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=Pw4SkXIOP3gYsrfkXUMDmrfWVE+b+YR/QHYLmcMcDkw=; b=ob+yO7KGYKboJAy905zpBGVPJgS7tX++hLYhMz0bT5ghJa4eICX9ATp7xl2FqvnOXK TYLrJRqSw8+KH1+7vAK9ZtD8Y8KMPeTLVO9rU0t/CclbRdBOvkArWo+wTdWBuHqG47q1 qUsKIThBm+Najea/7j8Ouc8ovXO7ClRRQ2epl2nUYS/M5b88VkagIqlVAO81G8xtIrsx XrXV+c0spRGVmAU64dpgAFtRz+Ud5koEoH8tTkUlII65PgWqJ04mp4Mf23Y+S5ohyKBj dnz7Cd82TQ2QqDYhoy85TLuX+d628WbaBCZuZZEZ7LfagO9ImMhX4sxzLRib1wxkK9h3 axww== X-Gm-Message-State: AOAM533M9IG/LoF2UpzbKCooDEftFOTPqWftU8xRH8H+f871t9umvM01 tv6HcmTNYlV8zt191jevNxOVCvL6kR+WZA== X-Google-Smtp-Source: ABdhPJxdDC9LYjuVMNMAILLoOIdHmTMNfNEBfLK4h2aMwNAporMoU1m+Zz2Tn4odK0CYTtP/Dvwejg== X-Received: by 2002:a17:906:4348:: with SMTP id z8mr3326230ejm.371.1609949495817; Wed, 06 Jan 2021 08:11:35 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id q25sm1570041eds.85.2021.01.06.08.11.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 06 Jan 2021 08:11:35 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 2/6] kernel-shark: Add kshark_data_container to libkshark Date: Wed, 6 Jan 2021 18:11:16 +0200 Message-Id: <20210106161120.119085-3-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210106161120.119085-1-y.karadz@gmail.com> References: <20210106161120.119085-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 a plugins for example). Signed-off-by: Yordan Karadzhov (VMware) --- src/libkshark.c | 147 ++++++++++++++++++++++++++++++++++++++ src/libkshark.h | 43 +++++++++++ tests/libkshark-tests.cpp | 34 +++++++++ 3 files changed, 224 insertions(+) diff --git a/src/libkshark.c b/src/libkshark.c index 3aa3fa2..8722794 100644 --- a/src/libkshark.c +++ b/src/libkshark.c @@ -2116,3 +2116,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) +{ + 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: Intput 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) +{ + if (container->capacity == container->size) { + bool ok; + + KS_DOUBLE_SIZE(struct kshark_data_field_int64 *, + container->data, + &container->capacity, + &ok); + + if (!ok) + return -ENOMEM; + } + + container->data[container->size] = malloc(sizeof(container->data)); + container->data[container->size]->entry = entry; + container->data[container->size++]->field = 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 27c1171..06fdf62 100644 --- a/tests/libkshark-tests.cpp +++ b/tests/libkshark-tests.cpp @@ -46,3 +46,37 @@ BOOST_AUTO_TEST_CASE(add_remove_streams) kshark_close_all(kshark_ctx); } + +#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], i); + } + + 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); + 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 Wed Jan 6 16:11:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12001933 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 6C19DC433E9 for ; Wed, 6 Jan 2021 16:12:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3EBD52312F for ; Wed, 6 Jan 2021 16:12:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727169AbhAFQMT (ORCPT ); Wed, 6 Jan 2021 11:12:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44830 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725800AbhAFQMS (ORCPT ); Wed, 6 Jan 2021 11:12:18 -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 2ADCDC061359 for ; Wed, 6 Jan 2021 08:11:38 -0800 (PST) Received: by mail-ej1-x62a.google.com with SMTP id b9so5842208ejy.0 for ; Wed, 06 Jan 2021 08:11:38 -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=AMfZqfEwANLhFci9bin94vClMQu8eTUomp2FFIpnm+w=; b=CoNhvOs2qisMQQcmUN+0IQ6D7s4o1GyxwWdhge2M8n+nz9sGsFIkOHuO3p/OQSOM8H nyg2z7tabIQj/CZXm37L/UQhB2XyPEvhwdg9cL8Hn3Jn3YyxX6gpHy4g18sl9CP4IYv9 GUWSdU3BR4qAN1jXfpio6z2jnS9uDcVxHTbq7hLZiVaF2QYVNldRDRaUzpVCRmBbl5H3 4FuLorQEx6AYQAMjSUi2nWEuqOEzNpLCIbkDIwTA+opGgKdEiGOnKh5qWfpN6xVe9t2/ EoMsqS3fW0wbI2hPM4WIlDCsvABH1WVYVFCMwNAaEj1LU4EQBVpm0VEUg9WIi3iv6zju Av+w== 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=AMfZqfEwANLhFci9bin94vClMQu8eTUomp2FFIpnm+w=; b=EI6ON3i40axjckmM5jOnZhWC1k5BrJw9EzA8ZGVZMXoxKbo+7YiafAEWHuG4077+D+ 1aSbkflvMg9imMHaDkX8O1LDEUIV5Gm47OanWHkkANb2gnPgwMDuPou9BzFqNOI9D5rx j2gQ9uLcaPTiMGBB8YERatS1tfgEMmI+gmBVt4aWkSmZmbnC08+FpfAWqHIA2RTZI1ol aihNj1ArVbdKiexVuqJyf1OUAvPHFvq3Pr/0iQqHW0LsLVkiF1AOMtof7cpgTMhRH2Ly eXQ0n+qThC1O9mDKu7+3PhGQEpPNPdt9tVlowPq6NeKNRi0SYhfNdsg8k/PpeDGiJn7D v5uw== X-Gm-Message-State: AOAM531BGdE0ZxgoH9DjXaJZiXDK85Z8viLPlMhlntTec/lb4lddncxz TXbf+LENRoXsTxUQXFUcDFQ= X-Google-Smtp-Source: ABdhPJwkQk4Km23xbgqWhYn2ueCNAKryjYuAdZjwSEU4fpXK6SNw6IF/hRfjLyHXmjBVSbDgqWv+Rg== X-Received: by 2002:a17:906:a192:: with SMTP id s18mr3149405ejy.249.1609949496895; Wed, 06 Jan 2021 08:11:36 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id q25sm1570041eds.85.2021.01.06.08.11.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 06 Jan 2021 08:11:36 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 3/6] kernel-shark: Add KS_DEFINE_PLUGIN_CONTEXT macro Date: Wed, 6 Jan 2021 18:11:17 +0200 Message-Id: <20210106161120.119085-4-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210106161120.119085-1-y.karadz@gmail.com> References: <20210106161120.119085-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 | 43 +++++++++++++++++++++++++++++++++++++++ tests/libkshark-tests.cpp | 32 +++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/src/libkshark-plugin.h b/src/libkshark-plugin.h index f3c724f..e58d658 100644 --- a/src/libkshark-plugin.h +++ b/src/libkshark-plugin.h @@ -360,6 +360,49 @@ int kshark_handle_all_dpis(struct kshark_data_stream *stream, } \ } \ +/** 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 bool ok; \ +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) { \ + KS_DOUBLE_SIZE(type *, __context_handler, \ + &__n_streams, &ok) \ + if (!ok) \ + 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 06fdf62..4990cdb 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 @@ -80,3 +81,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 Wed Jan 6 16:11:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12001937 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 5C33EC433E0 for ; Wed, 6 Jan 2021 16:12:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 240BB2312F for ; Wed, 6 Jan 2021 16:12:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727270AbhAFQMo (ORCPT ); Wed, 6 Jan 2021 11:12:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44896 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726682AbhAFQMo (ORCPT ); Wed, 6 Jan 2021 11:12:44 -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 11765C06135A for ; Wed, 6 Jan 2021 08:11:39 -0800 (PST) Received: by mail-ed1-x532.google.com with SMTP id h16so4866501edt.7 for ; Wed, 06 Jan 2021 08:11:38 -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=RyEOAPgyFNfnfTut6h3hzXp0fb8WNmpylfxVeIc2l5Jz+azg0X8TCkmDqcS7J+xLxP ybDv1uDJvoKnEDhaPECruh/wn07cDRtg3x1BDXMEtoVUjzh46VyMM5EMdV/ysOb9t2bI rmIqMnfo7sUUUaNDiJgUPrBw/I7vDNGz9SON8YN5sIxWrY0J2INRRwhCeTV8nF/u+eH4 /EDV+QyuSnaMFA8X9ebFvtZqWc7hdibVvbGVjKjz0vZdIf+4JLb9HrjAYjheH0jsbFVC e4KKB3ZtaZmrkkTq1KgCLCCzWcSDj8zRdvQg84lEIvtPms1ABme7lmRkIdyFH+HRC3B2 J2ug== 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=WubS5r9PnTEVSWMz7/hSTgE/JL73dzA4DsGkZ1NuC7t23+Yyji0lgJT0YEwOt2yO8z tzw8Rvl+0MAXsTG5j2cu+8bh5oavIEhrAGgRizCTQqYptUAQmnCJcoVO9u7rAPT3cbte 9M6Fe3DYVIygiGVWXFHZfzsanfOm0jjyof+RyMezy7+PXn1eCJRQwPHI4kpg59HFX2w2 6+AY1EjQ4/HHyz3KEAjQUC8Odhy6XUINAHHt6ZvSPwTGT6DZgQFxzmRiPYA+NIOx7FdQ S65fN5spUVm6pSwrZK3SzfvRG+OuD7MjYINSGeIdet+m2kInMffBUMQdelnhQfYUXkwy 11bA== X-Gm-Message-State: AOAM533BI8kEa2mTJ0KBrhaVpMaGGqbSQaaBlkG0uM8C6e76G2RNv/QU h7SMQaKYcOC2mWjp5F4xj+s= X-Google-Smtp-Source: ABdhPJxUpk0EC4EQwLJSGcSq+azYAbxrXEw/dlmLKXhRF7DJJyCqpwV4FgWqpHzp79yZPiryK61+hw== X-Received: by 2002:a05:6402:41:: with SMTP id f1mr4365333edu.286.1609949497873; Wed, 06 Jan 2021 08:11:37 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id q25sm1570041eds.85.2021.01.06.08.11.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 06 Jan 2021 08:11:37 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 4/6] kernel-shark: Start using C++17 Date: Wed, 6 Jan 2021 18:11:18 +0200 Message-Id: <20210106161120.119085-5-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210106161120.119085-1-y.karadz@gmail.com> References: <20210106161120.119085-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 Wed Jan 6 16:11:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12001939 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 C26C2C433DB for ; Wed, 6 Jan 2021 16:12:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6266B23130 for ; Wed, 6 Jan 2021 16:12:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726682AbhAFQMp (ORCPT ); Wed, 6 Jan 2021 11:12:45 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44898 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727269AbhAFQMo (ORCPT ); Wed, 6 Jan 2021 11:12:44 -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 094A2C06135B for ; Wed, 6 Jan 2021 08:11:40 -0800 (PST) Received: by mail-ej1-x629.google.com with SMTP id x16so5730287ejj.7 for ; Wed, 06 Jan 2021 08:11:39 -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=RbwWHgkJ3OZLIO3087guw+dE2tjqJkSp9hoWKThJWvPA0zx2mkRXJrmRyaiGPDHrLI 79/AcaGdphJgomjBMUVdEXzaATx2W+ZHZpSXmX+uhLp7u+Y1vjpt7TjHUb6sNbMH7Bl5 5MeIT5X4szNdmsyRMjkfYayYvVPEm1XIAfaVAkIrkMjt7XM8qmIeK3beGZ+Bs9LiptE1 rDg2FilaQ9TmvgcYaFlimjejceWc2yp6IhzyyNuGGEpxJXwwtyPOIoOQssZ/7vCSwJ76 OIJWSYG9mHJcf+BZFdsEFkxp80XeUYAuAodn2ep0yjflDu+yEySjkY9ZtV0KdQeVJtUy mvVw== 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=FlgCW8spCp6m51ERLCO+00fh+0iVwnpLFMfz/iIYUrLiMq0DwljQlsCErRWZR0fDBU RgD9TN2v8MOKFm31A9jWDgRNqPqFyU4sH5Q99KXkiHtVHIfWDPSgIiKb8A9RCU1v12dD IgDWEUvXdaY9iik8G9bK/DhhhnJKj5wUPbzYzO171MYLNJUD08pccrpl1ixtCEVEKaBa ZUBuXRWoQCg9E9S+4JHWBRCQYEQTYOCI7X74tTectNXXm3U+tbMPpvL3Pl97fM7o7+55 k4jDvaulODgaUmTJzc4MIGPerorqHfxhUYASmCkDgrGf/e2AaGoDJ3cNwyhCT6ZjvUSr 5s0w== X-Gm-Message-State: AOAM533XCGbAkO8e7cqMufxPQksNbiMPHFmZP46e0OmGDebt5/GTs8zO 1Ew88artrv3Xh8js/QWD2xzJbmxgjCxang== X-Google-Smtp-Source: ABdhPJxDQ01b4a7gBoPL0m7zZrIsbcIX3JqbLhnrQ3RlUozvNNQ9DWTp1wyMU0P0tom5zjD2ptP11Q== X-Received: by 2002:a17:906:578e:: with SMTP id k14mr3385636ejq.90.1609949498706; Wed, 06 Jan 2021 08:11:38 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id q25sm1570041eds.85.2021.01.06.08.11.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 06 Jan 2021 08:11:38 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 5/6] kernel-shark: Add plotting methods to KsPlugins Date: Wed, 6 Jan 2021 18:11:19 +0200 Message-Id: <20210106161120.119085-6-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210106161120.119085-1-y.karadz@gmail.com> References: <20210106161120.119085-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 Wed Jan 6 16:11:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12001941 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 161A5C433DB for ; Wed, 6 Jan 2021 16:12:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A8C4F2251F for ; Wed, 6 Jan 2021 16:12:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727269AbhAFQM4 (ORCPT ); Wed, 6 Jan 2021 11:12:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44930 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726768AbhAFQM4 (ORCPT ); Wed, 6 Jan 2021 11:12:56 -0500 Received: from mail-ej1-x633.google.com (mail-ej1-x633.google.com [IPv6:2a00:1450:4864:20::633]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 10643C06135C for ; Wed, 6 Jan 2021 08:11:41 -0800 (PST) Received: by mail-ej1-x633.google.com with SMTP id ga15so5772752ejb.4 for ; Wed, 06 Jan 2021 08:11:40 -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=NG2mRAXtUBlAi8ykl78rrf26sxKUhOMMWmLTIp4Nn04=; b=LjpEPJhnGBjfNJivcx1t/neYz+ajOR7OkPfZqkmxK91iaxHF9WIimvBSouGAnEVcD/ XhIKwOSDA1qW8oCwdnPl/wUq23Vyfz0IJ0Hf4u/tPgn0L4JEDsgtUAKKTM6uLvKmKjIO ODZQZIO86jL+naKK+qCc4QdRArZEMZdndRqUULD0DCsj1/ewg5tJM8S4Jojx5tG0cLsi wH5yhVVkh8CAo5R31yw8rHA/U2r80qHCP0k49xe8kLJJrvXUgMZOyZQonkXeDKzM3cYk 6MY5JcaKZQ7veIvp6rj+jSRpOOQgFgz1ovfZJFwJlkNmxPky9gkjiQJgKb8V51jF9N8+ oSYg== 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=NG2mRAXtUBlAi8ykl78rrf26sxKUhOMMWmLTIp4Nn04=; b=KF1VFHYaZABPnnH06IzCM4OyF+mTDQFX73KTFN505LKPG1ZKoRrm/YnjuPnmguTq0/ cRexBKhNz7z2boY3AUkKI5NFo5ZDnuIv1db/lMLQAHRzmx8JF/GvdiCLjE5f97pl07M1 144xK8Pj7f+07fd6Dr/gloNju8zAPtkNc+i2Rj2MiqRWs1E2850efxxWwaWa4ILwCa/f EEevCbuXZ8FvTltaR9xMItTLrSNpCyAputQ2uDpiG2qFpeMCTAzvOUQ2cWWI4x5uk5sA irABwKSUgDPNADN2dUr6ytT2AaoHmSe038nzJPis8yQ206D9vEqlXHb25jIIEqxU8oDf FTjA== X-Gm-Message-State: AOAM532DbFAfTPeEQANJ37ZZZIceac8B0gPUW+sF93ZWoZt8trsMadOx PI+087HmcnptvYKtZYb4sPM= X-Google-Smtp-Source: ABdhPJw7OUe7Mpj7FvTJnslbSAnWtGIJGqebNvVpm+LgvMF3Fe1JYtlaoxzpSes/PWUTnbXFN5KBQg== X-Received: by 2002:a17:907:4126:: with SMTP id mx6mr3334081ejb.91.1609949499466; Wed, 06 Jan 2021 08:11:39 -0800 (PST) Received: from localhost.localdomain ([95.87.199.238]) by smtp.gmail.com with ESMTPSA id q25sm1570041eds.85.2021.01.06.08.11.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 06 Jan 2021 08:11:39 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 6/6] kernel-shark: Speed-up the sched_events plugin Date: Wed, 6 Jan 2021 18:11:20 +0200 Message-Id: <20210106161120.119085-7-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210106161120.119085-1-y.karadz@gmail.com> References: <20210106161120.119085-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 e58d658..77887e5 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 }