From patchwork Thu Feb 11 10: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: 12082705 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.7 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 5009BC433E0 for ; Thu, 11 Feb 2021 10:35:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id ED96664E92 for ; Thu, 11 Feb 2021 10:35:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230046AbhBKKfQ (ORCPT ); Thu, 11 Feb 2021 05:35:16 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45816 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229882AbhBKKdD (ORCPT ); Thu, 11 Feb 2021 05:33:03 -0500 Received: from mail-ej1-x62c.google.com (mail-ej1-x62c.google.com [IPv6:2a00:1450:4864:20::62c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BB392C0613D6 for ; Thu, 11 Feb 2021 02:32:22 -0800 (PST) Received: by mail-ej1-x62c.google.com with SMTP id p20so9278137ejb.6 for ; Thu, 11 Feb 2021 02:32:22 -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=cVWQshYHmRecjva6Hux0++8NiD47FE2oRBIZvYkMseM=; b=fT6pzhRQVY5BK2ZUGvL6pdA0PrWaZyFUiOaor9fzwTAT4DbpfADyt9+ho4zJUJzGIs yain+ic3MSTDhmWyzKBFdW1jcAb801x8Enujj/1SYIa9TnSOOu2Iu79Nq2nEL5lhL12r n7NWXRqcbF+7CrYSLZ6EvdGhvgOpcLABHSzOgPJE+rg9i+H90+JT/rgPtNWiSvzBkYSw 46lhlvRpA6sNuCS1ZJntV7YLYALqlK3LAjbFTimJ9bxT7On9ZS3c84OK25AWQKvnP+Bm qz3tPEIp702x8wnddZ2skUB9tRjHVHmpVJtI5FUoENoW0Vw+L6Hi94QIGv9JmVuYMPwk 9yMw== 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=cVWQshYHmRecjva6Hux0++8NiD47FE2oRBIZvYkMseM=; b=ZbJy2bfwmh6+t39fjU042ZTkkSUKRI7ldg2KDc2aJmJKcOAxjRxp2GV1KoMhDBG8Fo VZog3WzEy61/vzNCic4utg/YnDBZZiEHU0uVboiRWV0NfbldybfQca4XZAS8Ht4sTlNl A62a7AKkSSXxubEVq4FwJ66PKRtwSSjy7fUr3dvtJTx+mtr2bubVPa+GgxHXoG6SeVsI Y2OFzsjkm7SIULuauzflnatNSV+X/KTzeM98DNd+QOFE7VRGdHvTtf4M9/ZNlVF4IaMb r0itqV/pIuE3ms6UtiiO/YoKigdilNdQwAPAQHy9dWSxxInzHiIezeFk/k2kqen78vXD WRkA== X-Gm-Message-State: AOAM530Gwy/DwyYq+nE8czwLrA9l8Fogq6Wq8UCRE/CknmjeayWeBa/4 eDNnYM/TlOqzftq0PAcMijRr16P3YFQ= X-Google-Smtp-Source: ABdhPJwmZwG/gNhm0E514gQDWCg28Lx1cZ0nBkolzFWnCGyYi+9gJcnhYDyqLokavBWlUHJQkAkSKg== X-Received: by 2002:a17:906:3acc:: with SMTP id z12mr8097240ejd.494.1613039541454; Thu, 11 Feb 2021 02:32:21 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:21 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 01/27] kernel-shark: Add get_stream_object() Date: Thu, 11 Feb 2021 12:31:39 +0200 Message-Id: <20210211103205.418588-2-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org In a previous patch we modified kshark_get_data_stream() to return NULL in the case when the kshark_data_stream object does not own a data processing interface. This was motivated by the idea that kshark_get_data_stream() is supposed to be used to access only successfully loaded data streams, which is not possible in the case when the data processing interface is not initialized. However, this creates a contradiction with the definition of the public method kshark_add_stream(). This method adds a stream without initializing its data processing interface. In this patch we add a static function that returns the Data stream object, regardless of the existence of the interface and we use this static function in all cases when the existence of the interface is not guaranteed. Signed-off-by: Yordan Karadzhov (VMware) --- src/libkshark.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/libkshark.c b/src/libkshark.c index a54fdd5..c57ca01 100644 --- a/src/libkshark.c +++ b/src/libkshark.c @@ -361,6 +361,17 @@ kshark_get_data_stream(struct kshark_context *kshark_ctx, int sd) return NULL; } +static struct kshark_data_stream * +get_stream_object(struct kshark_context *kshark_ctx, int sd) +{ + if (sd >= 0 && sd <= kshark_ctx->stream_info.max_stream_id) + if (kshark_ctx->stream[sd] && + kshark_is_valid_stream(kshark_ctx->stream[sd])) + return kshark_ctx->stream[sd]; + + return NULL; +} + /** * @brief Get the Data stream object corresponding to a given entry * @@ -443,7 +454,7 @@ int kshark_close(struct kshark_context *kshark_ctx, int sd) struct kshark_data_stream *stream; int ret; - stream = kshark_get_data_stream(kshark_ctx, sd); + stream = get_stream_object(kshark_ctx, sd); if (!stream) return -EFAULT; @@ -1182,7 +1193,7 @@ bool kshark_filter_is_set(struct kshark_context *kshark_ctx, int sd) { struct kshark_data_stream *stream; - stream = kshark_get_data_stream(kshark_ctx, sd); + stream = get_stream_object(kshark_ctx, sd); if (!stream) return false; From patchwork Thu Feb 11 10: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: 12082707 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.7 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 8A068C433E6 for ; Thu, 11 Feb 2021 10:35:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 44CB164E6F for ; Thu, 11 Feb 2021 10:35:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229882AbhBKKfU (ORCPT ); Thu, 11 Feb 2021 05:35:20 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45820 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229867AbhBKKdE (ORCPT ); Thu, 11 Feb 2021 05:33:04 -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 EA759C061786 for ; Thu, 11 Feb 2021 02:32:23 -0800 (PST) Received: by mail-ej1-x62d.google.com with SMTP id b9so9213451ejy.12 for ; Thu, 11 Feb 2021 02:32:23 -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=G4XnnSPEFwz6ybwMmQh5Ff1BkSFr87krInZBmQ1upb8=; b=dzjpCg71GBB2Ft83lijuR0NlSix2kzc4Q5ffATxDIwqL42bjEhRAeRGhLJ4WiCPAb8 BnWGiZDVoBQwZrK/yJ/r08SX3OXQWDL3rg+RoBT4EUDU7VJa9waAzvObrvjGfnJI02D3 vgGoO7FXvtvxgNXswQ7+sLkqV8/tnveHL20xhS9fIbohPtzQXouZUciV1vXqnQisMsmt 9NoFrZ3yfKRRJa0BwlVkL99rNog+xPg77Fg/qwo5dvWUWHA0WQwok0O2kb6nGtsyKPPA eHtk2QMyW55csal0ZQr+JX7+7xkOlkp2I6LA/BeUb/wSC3YYgqu2Id1OjhsXIXGjzmfI XhPg== 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=G4XnnSPEFwz6ybwMmQh5Ff1BkSFr87krInZBmQ1upb8=; b=A3a5y4NsJ//YnvyhDuR81ETAx3f6CHOZQ2TYGEBTma8Hk4msmZHwvk1Dfiq/0QTdw+ g6VgcXx2pUy0/2nDvRB6bypsYWOjpRLF02UG3mGcw7/ogjVawSlDlzd+UpG2wqc53E+i bNtgeS/yej/zJBT9BtPs0av/dftWMjcZ0lckIENOhSWsMGmYYoQy0rjScM+boGVhaEeH ZXXYVY0q6fNKn+VAjCGZKRAkoIUSBAue2MskWNV3GhveVpjyM8TRf8fl30RtliYDp/z5 BLYBDaTtdXaFdvqVSFezYWg5m+QhZScAUegAKf96FJj3C2gIMZDrE7iLfRp9yimOnmB+ cIYw== X-Gm-Message-State: AOAM533pSoi5wHiiCqfz+Cw18RL5juZWiFfZl6rQpkuwzoof2OpArzTt bi2/X8zSsth7HFbqd6pNmX8= X-Google-Smtp-Source: ABdhPJxm2/pS/r6NW/gXwLfFaCA0aGYiY3YTb1a2R2159D/6pQZDzOfRjinN5FmBrgG/J8Hs8iy+Cg== X-Received: by 2002:a17:906:f259:: with SMTP id gy25mr2351684ejb.330.1613039542711; Thu, 11 Feb 2021 02:32:22 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:22 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 02/27] kernel-shark: Do proper reset in kshark_close_all() Date: Thu, 11 Feb 2021 12:31:40 +0200 Message-Id: <20210211103205.418588-3-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The function is supposed to close all Data streams and reset the session context object (kshark_ctx). However, this is not happening completely, because after closing the individual streams, the context still contains the history of all closed stream Ids, recorded inside the array of data stream descriptors. In this patch we add a proper resetting of this array and its info descriptor. Signed-off-by: Yordan Karadzhov (VMware) --- src/libkshark.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libkshark.c b/src/libkshark.c index c57ca01..dc58dcf 100644 --- a/src/libkshark.c +++ b/src/libkshark.c @@ -37,6 +37,7 @@ static bool kshark_default_context(struct kshark_context **context) kshark_ctx->stream = calloc(KS_DEFAULT_NUM_STREAMS, sizeof(*kshark_ctx->stream)); kshark_ctx->stream_info.array_size = KS_DEFAULT_NUM_STREAMS; + kshark_ctx->stream_info.next_free_stream_id = 0; kshark_ctx->stream_info.max_stream_id = -1; /* Will free kshark_context_handler. */ @@ -484,10 +485,22 @@ int kshark_close(struct kshark_context *kshark_ctx, int sd) */ void kshark_close_all(struct kshark_context *kshark_ctx) { + size_t mem_reset_size; int i; + if (kshark_ctx->stream_info.max_stream_id < 0) + return; + for (i = 0; i <= kshark_ctx->stream_info.max_stream_id; ++i) kshark_close(kshark_ctx, i); + + /* Reset the array of data stream descriptors. */ + mem_reset_size = (kshark_ctx->stream_info.max_stream_id + 1 ) * + sizeof(*kshark_ctx->stream); + memset(kshark_ctx->stream, 0, mem_reset_size); + + kshark_ctx->stream_info.next_free_stream_id = 0; + kshark_ctx->stream_info.max_stream_id = -1; } /** From patchwork Thu Feb 11 10:31:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082713 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.7 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 7B96AC433E0 for ; Thu, 11 Feb 2021 10:36:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 507E464E6F for ; Thu, 11 Feb 2021 10:36:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229943AbhBKKfb (ORCPT ); Thu, 11 Feb 2021 05:35:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45826 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229946AbhBKKdF (ORCPT ); Thu, 11 Feb 2021 05:33:05 -0500 Received: from mail-ej1-x631.google.com (mail-ej1-x631.google.com [IPv6:2a00:1450:4864:20::631]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E8791C061788 for ; Thu, 11 Feb 2021 02:32:24 -0800 (PST) Received: by mail-ej1-x631.google.com with SMTP id lg21so9280310ejb.3 for ; Thu, 11 Feb 2021 02:32:24 -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=ab+XjHrH4Ui6GgJS/A079C+sGotYarCnpXyXG3/dzSw=; b=Yw5LqZBo4WSvEnF/UEAiX8cGwfWPw285FuGewMhTGQUvfAUJpHjI3ZQw2JKe/ZyLuy a8ARGqUE09Pwtgt12x8PU1QnSigurfZT+vz8EmJ5jqxUmvmoxm06EbE9IN3HIF7Gi3nJ qCiTVde5AQCu1Yhq42ZjlpFKflHfmWFFmGdIi5HnlUOfvJJ0fo6yhz9PH9Ef6OQ7J0bi oIkXRVQAqD8Kj/HvS+18AiVsd68Sa/myfG5QGSMdelsn/4RjbekOPr54avjuXXwgxbHK 0sZYZPSnh64Wf7CmzEnMbuTsJhf5swWAs19AS4y+xMxuwPGVWkJc7L4dP0XBrSKw5Z6H /77g== 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=ab+XjHrH4Ui6GgJS/A079C+sGotYarCnpXyXG3/dzSw=; b=Cm56FXr+ieU22peuocPnW9kYrUUlt4oOGjXD9mudGIEM1Lzde2L2AmziR1WHrO4RZL gunEz+BEnj6DRMWZNceAArSnGUVQ/UZ5Pi4SRVXJ2vK2Dg2/GOb++7uL2YLry1+7m+7S KR1vW3jkhXVYdYOBvF+41OXx6vZiIArtNkVAPYahPVcS64eMyvRQfzZvbsDPN02lX40Q 44oorp2SSSATs3vOeazdK8ZeIo4BlIuv21tnr/XKFjwy6OA2xWCnBhqpVbeex2RSJ9lX jz4aTbtpQbe2Cm/B0n/ygTyiuFeQKJ7nuLWmUjreqX+xcchbKXx3vVnNcWrQPzGlduFO DFyg== X-Gm-Message-State: AOAM533cB3SlMVUsDS3JkNzU3PomAwpa/H4A6LAWAtbQRv5WRsqbqQ7s yAlkrg1dKbXi386/fCNhq9bN4RSIQV4= X-Google-Smtp-Source: ABdhPJw4CulKiUgj0oI/3hmMRRoVA/X9tFZZiac2TCN4Y+bn0Bzt2xYAtX/1GnAXLw6mWc7U6YOWrw== X-Received: by 2002:a17:906:73c2:: with SMTP id n2mr7933772ejl.224.1613039543683; Thu, 11 Feb 2021 02:32:23 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:23 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 03/27] kernel-shark: Restore the counting of event handlers Date: Thu, 11 Feb 2021 12:31:41 +0200 Message-Id: <20210211103205.418588-4-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The number of the event handlers, successfully registered by the plugins is supposed to be counted and returned by the functions kshark_handle_dpi() and kshark_handle_all_dpis(). Although this is not used by the GUI, we want the API to support this feature. In this patch we fix a regression that was introduced during the transformation of the API for KernelShark v2.0. Signed-off-by: Yordan Karadzhov (VMware) --- src/libkshark-plugin.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/libkshark-plugin.c b/src/libkshark-plugin.c index 74a5862..b85d0e9 100644 --- a/src/libkshark-plugin.c +++ b/src/libkshark-plugin.c @@ -457,7 +457,6 @@ kshark_register_input(struct kshark_context *kshark_ctx, input->interface = plugin; input->next = kshark_ctx->inputs; kshark_ctx->inputs = input; - return input; conflict: @@ -635,7 +634,7 @@ void kshark_unregister_plugin_from_stream(struct kshark_data_stream *stream, } } -static void plugin_init(struct kshark_data_stream *stream, +static int plugin_init(struct kshark_data_stream *stream, struct kshark_dpi_list *plugin) { int handler_count = plugin->interface->init(stream); @@ -660,13 +659,18 @@ static void plugin_init(struct kshark_data_stream *stream, plugin->status |= KSHARK_PLUGIN_FAILED; plugin->status &= ~KSHARK_PLUGIN_LOADED; } + + return handler_count; } -static void plugin_close(struct kshark_data_stream *stream, +static int plugin_close(struct kshark_data_stream *stream, struct kshark_dpi_list *plugin) { - plugin->interface->close(stream); + int handler_count = plugin->interface->close(stream); + plugin->status &= ~KSHARK_PLUGIN_LOADED; + + return handler_count; } /** @@ -689,24 +693,24 @@ int kshark_handle_dpi(struct kshark_data_stream *stream, switch (task_id) { case KSHARK_PLUGIN_INIT: if (plugin->status & KSHARK_PLUGIN_ENABLED) - plugin_init(stream, plugin); + handler_count += plugin_init(stream, plugin); break; case KSHARK_PLUGIN_UPDATE: if (plugin->status & KSHARK_PLUGIN_LOADED) - plugin_close(stream, plugin); + handler_count -= plugin_close(stream, plugin); plugin->status &= ~KSHARK_PLUGIN_FAILED; if (plugin->status & KSHARK_PLUGIN_ENABLED) - plugin_init(stream, plugin); + handler_count += plugin_init(stream, plugin); break; case KSHARK_PLUGIN_CLOSE: if (plugin->status & KSHARK_PLUGIN_LOADED) - plugin_close(stream, plugin); + handler_count -= plugin_close(stream, plugin); plugin->status &= ~KSHARK_PLUGIN_FAILED; break; From patchwork Thu Feb 11 10:31:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082715 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.7 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 1FFB5C433E0 for ; Thu, 11 Feb 2021 10:36:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DA5F164E6F for ; Thu, 11 Feb 2021 10:36:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229946AbhBKKfe (ORCPT ); Thu, 11 Feb 2021 05:35:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45832 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230011AbhBKKdI (ORCPT ); Thu, 11 Feb 2021 05:33:08 -0500 Received: from mail-ed1-x52d.google.com (mail-ed1-x52d.google.com [IPv6:2a00:1450:4864:20::52d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DF759C06178A for ; Thu, 11 Feb 2021 02:32:25 -0800 (PST) Received: by mail-ed1-x52d.google.com with SMTP id s5so6379452edw.8 for ; Thu, 11 Feb 2021 02:32:25 -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=XmVcXJgUz0miHehNivT+tRvOfOrwtVKDeNmjrBnSb5g=; b=n33J0nfmLFozr/ic4L3eXn5y2pVx8QSzNJe0ZNkGMdk4aaRRkWg7YncC3+EU3+2A5A /QyN6NSvYg5Tz9qiRnbso6tloMaj5a12PgeXuuINrhiksUI1LZgI/UiVqzKR0eItGYBZ z2/selfybcQRfC5druuDBRENNXMtsvEpM0eCIYFxkpqLmNqpRkjluaOhiD5Bm/fGMhgk Y0Cotu8qmlBM/KKDGzKHxkac+bxKsAw0Y15BQ7OduUuNGqHq7+9WXAkxAqPo62PoehNq wcgZQwucV2QP0HNcjW7Cm/kJEbKqFxawejNXmu6kojxxs49HQVkCNU3dOzERNAWEmxSh vfTw== 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=XmVcXJgUz0miHehNivT+tRvOfOrwtVKDeNmjrBnSb5g=; b=KljtA0TZ4fPAIZkF/HMW6PsX5JbK7COyoioCsPrIgM5BKVR1fA4H6yz9qKidceGbFu eYtKqKbe8DnLS9XIJZs7CnQUl0T+jdNOFu+xvcH5y7En8VHNq1W4oPixUaFuHICc3Ng1 DBoe3DFzhvf0BMfQHu9AcNK/6Iqrv1bAo08kekXCKTD2inru1yRE0NZ5oSwlzJkicsfm SQhfiO3DGhPSPnz6AUenDOlOiMTWcsgLTI1Bxq8l0n+Y7iXEwnAjg9W3o1jrnZOYqy/0 VwxOXVQzk15i52ucRrVYeBeQS0lJP6+3UmQJCqlbrl7t2/S0VLLcseFN8qOd6b2I/kuv wYmA== X-Gm-Message-State: AOAM5319f8UiANpKheSdJjXkVDxsLhkRBN5iZJtMSfK7RLyriVXboPMv 5zUK1zQoBo836snHK+7PY8457VN6FtA= X-Google-Smtp-Source: ABdhPJzNfqRdxE59jMXMILyfvr8e+kH69piYuUwtJe+faN3S+PgPiQdoNX+hitFkJnUlin3RtjdThA== X-Received: by 2002:a05:6402:1484:: with SMTP id e4mr7924400edv.104.1613039544677; Thu, 11 Feb 2021 02:32:24 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:24 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 04/27] kernel-shark: Fix a misleading comment Date: Thu, 11 Feb 2021 12:31:42 +0200 Message-Id: <20210211103205.418588-5-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Signed-off-by: Yordan Karadzhov (VMware) --- src/libkshark-plugin.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libkshark-plugin.c b/src/libkshark-plugin.c index b85d0e9..bc68186 100644 --- a/src/libkshark-plugin.c +++ b/src/libkshark-plugin.c @@ -577,7 +577,8 @@ kshark_register_plugin_to_stream(struct kshark_data_stream *stream, * The plugin has been registered already. Check if it * is initialized and if this is the case, close the * existing initialization. This way we guarantee a - * clean new initialization from. + * clean new initialization from kshark_handle_dpi() + * or kshark_handle_all_dpis(). */ if (plugin_list->status & KSHARK_PLUGIN_LOADED) kshark_handle_dpi(stream, plugin_list, From patchwork Thu Feb 11 10:31:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082717 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.7 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 3DA65C433DB for ; Thu, 11 Feb 2021 10:36:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 03F0E64E9A for ; Thu, 11 Feb 2021 10:36:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230011AbhBKKfl (ORCPT ); Thu, 11 Feb 2021 05:35:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45838 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230026AbhBKKdI (ORCPT ); Thu, 11 Feb 2021 05:33:08 -0500 Received: from mail-ej1-x631.google.com (mail-ej1-x631.google.com [IPv6:2a00:1450:4864:20::631]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E4BC3C06178B for ; Thu, 11 Feb 2021 02:32:26 -0800 (PST) Received: by mail-ej1-x631.google.com with SMTP id w1so9219684ejf.11 for ; Thu, 11 Feb 2021 02:32:26 -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=tge4VpWhNZLplgeS0avc+7KTpwHzqvBlhwQ81Ehq4Uk=; b=Hb2HIhmgCjcpzPr+AczL+hDTWorKD0IwDuh3/L7vHcgbKH/K632QxhbYQgQ5GjNDwf cVvTrfIK/N0zas/6UdczsmmpvDmMOk5DTmGAT3jDTqo6uwB0q4DWHdpzLNEIk1b+nO0x hVqoXKJwnyTCsK7Xf96eHkOJywlsRte28LFYsCFr4PtKTsOU0N0jOwoK28hEOlvtVaA6 YEV/9DBRFM2RXMa5GImmdHwqfZNpQbASBJVRB3IKdKNDEJi+ryt+rR2QRDOS9rN54wnA 0nCMhwfJoINf5yI2OgJU7qEaDjfsY8HmF+Zdfybl/B4XnpWUEQyEUL+7BlLk8f4HlBJD +Axg== 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=tge4VpWhNZLplgeS0avc+7KTpwHzqvBlhwQ81Ehq4Uk=; b=XU1OaoHqNQw6VKlRph6T9sOmA8nG4ruxulT5zTaYWDNkM75gbmlRrIr8MRCTqVz4PM O/rC2eR3heLOfphZwHP+0kzuBT+vHZuUrOVR73NgjqmTl7H21ccHOa+G5rHy0uJMghuz ThyHpXFEQDHA59u7Fstk1LNxTN+Ea7hUnWRomI2Q/d/NRK+wGAb2n63pKr0ps0BLZ2wE A/dt8gsUd4JyXm22D8FABB4d2a5rmquOlgukwsNlzUdCu0PRvnjY6r4v/cLCFJyL8GHw +dGtFaEwe1nT+nwl9IKWfQplF/XhOUhbJ+lO8iWe9ofdLft1qLS8CsTlOOK+Qb3+rl8e lUIg== X-Gm-Message-State: AOAM531j/2BtYBluMiyBmL4qghjSqUWH9BHfQqa3exhU0PUtlP+nQfXN 2QcbjLuNtfBHKKnTrLJJe6E= X-Google-Smtp-Source: ABdhPJy/WfWrLZ4ZdhE+qaSgN6bExGGhO9oAMD2z+ke57meKHOF7sRx8d2SnBAKgat2P5Fpqw8S1BA== X-Received: by 2002:a17:906:17c3:: with SMTP id u3mr7714587eje.304.1613039545585; Thu, 11 Feb 2021 02:32:25 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:25 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 05/27] kernel-shark: Count the number of readout interfaces Date: Thu, 11 Feb 2021 12:31:43 +0200 Message-Id: <20210211103205.418588-6-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The number of readout interfaces, successfully registered by the plugins is supposed to be counted and stored in the session context object. Although this is not used by the GUI, we want the API to support this feature. Sgned-off-by: Yordan Karadzhov (VMware) --- src/libkshark-plugin.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libkshark-plugin.c b/src/libkshark-plugin.c index bc68186..ebd2579 100644 --- a/src/libkshark-plugin.c +++ b/src/libkshark-plugin.c @@ -457,6 +457,7 @@ kshark_register_input(struct kshark_context *kshark_ctx, input->interface = plugin; input->next = kshark_ctx->inputs; kshark_ctx->inputs = input; + kshark_ctx->n_inputs++; return input; conflict: @@ -489,6 +490,7 @@ void kshark_unregister_input(struct kshark_context *kshark_ctx, *last = this_input->next; free(this_input); + kshark_ctx->n_inputs--; return; } From patchwork Thu Feb 11 10:31:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082711 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.7 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,URIBL_BLOCKED,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 EDC61C43381 for ; Thu, 11 Feb 2021 10:35:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9BD3E64E6F for ; Thu, 11 Feb 2021 10:35:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230094AbhBKKf0 (ORCPT ); Thu, 11 Feb 2021 05:35:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45846 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230127AbhBKKdL (ORCPT ); Thu, 11 Feb 2021 05:33:11 -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 E66BEC06178C for ; Thu, 11 Feb 2021 02:32:28 -0800 (PST) Received: by mail-ej1-x634.google.com with SMTP id lg21so9280582ejb.3 for ; Thu, 11 Feb 2021 02:32:28 -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=EUr80i8fJRsLU5UiLxhjh0gWzUYe9AbGMXYaMKCsSCg=; b=QXYNuoMze+J//Zhde4aA6zWstjQ5ZWnEWBxBwnVCWjOU2OIk9pl3cxcAGvnh/jQFHi LV0771NHZyke7o8O3/dwef0lQ8XUQ2OgDjRwmpYyR1pvoPNBRbzglz6TOmnKJVIrejxB PDeU/emE7YHXDWthGEobXWDBm6fBGC0AjCWAj75chpr7D/2OSYfWjfEhdt82WnZ0fZNd rVWaXIHTaNwcm6AW40TM7cqTni+jgVfATgKmn6YsV2uIEg0RLZOXBKmdhSCCWMM1fGyQ RKInu7fuLzfnDSnx7SiWbN/7G8YbJlxn/V/qfKqTfxSuyjBeRHuzfkyGJzn4t2IUmKnS 20mw== 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=EUr80i8fJRsLU5UiLxhjh0gWzUYe9AbGMXYaMKCsSCg=; b=OeSuJdIQvasfnZblin+5tpkFns1YURmIeF8zfXhIRkk8RcdwDzMEVbWcxst69fqtRn OzmxZE1kiKSqGRYwaVRTbhzisJZLWlgKiBCVs5FPXueYttcJzqo9W40rR/9iu5fGVVE6 cYPX5ga2iDJ3Fluy+scUcjM7HSinwDov3J/pF6ezO1ZZfpTObTvzLUHqrkivNTZERlM3 a/Esri4Y+uViCM7Tp87fIZUxBHUeEq9InQ8rnNKw3j7e037SV31NhQ9jZucbt4h1LyM0 pDtQv9MdZrGc0wtdRnKjssKuktIQwVtC7+bMWXTnl40IfmWpnCjVk6qrVk5RcjLVyyra /EsA== X-Gm-Message-State: AOAM530+p73i5q4XwXF05jZ4FTNsuw3FscnrCktABcLMfhiO6khOMRzt 3s1c/ww7sMhZ+3XeH25iDCM= X-Google-Smtp-Source: ABdhPJwDkDP0fwWafF0wJ4z1chE/kin7UqnGUL4O5QPfxn0oGR21KYW6k+Hi94TNT04pTe8sXfs+9g== X-Received: by 2002:a17:906:b50:: with SMTP id v16mr7536717ejg.298.1613039547015; Thu, 11 Feb 2021 02:32:27 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:26 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 06/27] kernel-shark: Update KsUtils Date: Thu, 11 Feb 2021 12:31:44 +0200 Message-Id: <20210211103205.418588-7-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The compilation of KsUtils is re-enabled and all functionalities provided in it are made compatible with the new version of the C API of libkshark (KernelShark 2.0). Signed-off-by: Yordan Karadzhov (VMware) --- CMakeLists.txt | 10 +- build/deff.h.cmake | 3 + src/CMakeLists.txt | 73 +-- src/KsUtils.cpp | 1154 +++++++++++++++++++++++++------------ src/KsUtils.hpp | 181 ++++-- tests/CMakeLists.txt | 2 +- tests/libkshark-tests.cpp | 1 + 7 files changed, 969 insertions(+), 455 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dd62091..e013916 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,12 +49,18 @@ set(OpenGL_GL_PREFERENCE LEGACY) find_package(OpenGL) find_package(GLUT) -# find_package(Qt5Widgets 5.7.1) -# find_package(Qt5Network) +find_package(Qt5Widgets 5.7.1) +find_package(Qt5Network) if (Qt5Widgets_FOUND) message(STATUS "Found Qt5Widgets: (version ${Qt5Widgets_VERSION})") + if(Qt5Widgets_VERSION VERSION_LESS "5.11") + + set(QT_VERSION_LESS_5_11 TRUE) + + endif() + endif (Qt5Widgets_FOUND) find_package (Boost COMPONENTS unit_test_framework) diff --git a/build/deff.h.cmake b/build/deff.h.cmake index 868ffec..5584574 100644 --- a/build/deff.h.cmake +++ b/build/deff.h.cmake @@ -26,6 +26,9 @@ /** GLUT has been found. */ #cmakedefine GLUT_FOUND +/** Qt - old version detected. */ +#cmakedefine QT_VERSION_LESS_5_11 + /** Semicolon-separated list of plugin names. */ #define KS_BUILTIN_PLUGINS "@PLUGINS@" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 980e802..5c9fe17 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -66,34 +66,34 @@ endif (OPENGL_FOUND) if (Qt5Widgets_FOUND AND Qt5Network_FOUND) message(STATUS "libkshark-gui") - set (ks-guiLib_hdr KsUtils.hpp - KsModels.hpp - KsGLWidget.hpp - KsSearchFSM.hpp - KsDualMarker.hpp - KsWidgetsLib.hpp - KsTraceGraph.hpp - KsTraceViewer.hpp - KsMainWindow.hpp - KsCaptureDialog.hpp - KsQuickContextMenu.hpp - KsAdvFilteringDialog.hpp) + set (ks-guiLib_hdr KsUtils.hpp) +# KsModels.hpp +# KsGLWidget.hpp +# KsSearchFSM.hpp +# KsDualMarker.hpp +# KsWidgetsLib.hpp +# KsTraceGraph.hpp +# KsTraceViewer.hpp +# KsMainWindow.hpp +# KsCaptureDialog.hpp +# KsQuickContextMenu.hpp +# KsAdvFilteringDialog.hpp) QT5_WRAP_CPP(ks-guiLib_hdr_moc ${ks-guiLib_hdr}) - add_library(kshark-gui SHARED ${ks-guiLib_hdr_moc} KsUtils.cpp - KsModels.cpp - KsSession.cpp - KsGLWidget.cpp - KsSearchFSM.cpp - KsDualMarker.cpp - KsWidgetsLib.cpp - KsTraceGraph.cpp - KsTraceViewer.cpp - KsMainWindow.cpp - KsCaptureDialog.cpp - KsQuickContextMenu.cpp - KsAdvFilteringDialog.cpp) + add_library(kshark-gui SHARED ${ks-guiLib_hdr_moc} KsUtils.cpp) +# KsModels.cpp +# KsSession.cpp +# KsGLWidget.cpp +# KsSearchFSM.cpp +# KsDualMarker.cpp +# KsWidgetsLib.cpp +# KsTraceGraph.cpp +# KsTraceViewer.cpp +# KsMainWindow.cpp +# KsCaptureDialog.cpp +# KsQuickContextMenu.cpp +# KsAdvFilteringDialog.cpp) target_link_libraries(kshark-gui kshark-plot Qt5::Widgets @@ -102,19 +102,20 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) set_target_properties(kshark-gui PROPERTIES SUFFIX ".so.${KS_VERSION_STRING}") - message(STATUS ${KS_APP_NAME}) - add_executable(${KS_APP_NAME} kernelshark.cpp) - target_link_libraries(${KS_APP_NAME} kshark-gui) +# message(STATUS ${KS_APP_NAME}) +# add_executable(${KS_APP_NAME} kernelshark.cpp) +# target_link_libraries(${KS_APP_NAME} kshark-gui) - message(STATUS "kshark-record") - add_executable(kshark-record kshark-record.cpp) - target_link_libraries(kshark-record kshark-gui) +# message(STATUS "kshark-record") +# add_executable(kshark-record kshark-record.cpp) +# target_link_libraries(kshark-record kshark-gui) + +# install(TARGETS ${KS_APP_NAME} kshark-record kshark-gui +# RUNTIME DESTINATION ${_INSTALL_PREFIX}/bin/ +# COMPONENT kernelshark +# LIBRARY DESTINATION ${_LIBDIR} +# COMPONENT kernelshark) - install(TARGETS ${KS_APP_NAME} kshark-record kshark-gui - RUNTIME DESTINATION ${_INSTALL_PREFIX}/bin/ - COMPONENT kernelshark - LIBRARY DESTINATION ${_LIBDIR} - COMPONENT kernelshark) install(FILES "${KS_DIR}/${KS_APP_NAME}.desktop" DESTINATION ${_INSTALL_PREFIX}/share/applications/ diff --git a/src/KsUtils.cpp b/src/KsUtils.cpp index 24f7178..36f9b25 100644 --- a/src/KsUtils.cpp +++ b/src/KsUtils.cpp @@ -10,90 +10,244 @@ */ // KernelShark +#include "libkshark-plugin.h" +#include "libkshark-tepdata.h" #include "KsUtils.hpp" -#include "KsWidgetsLib.hpp" namespace KsUtils { -/** @brief Get a sorted vector of CPU Ids. */ -QVector getCPUList() +/** + * @brief Get a sorted vector of CPU Ids associated with a given Data stream. + * + * @param sd: Data stream identifier. + * + * @returns Vector of CPU Ids on success or an empty vector on failure. + */ +QVector getCPUList(int sd) { kshark_context *kshark_ctx(nullptr); - int nCPUs; + kshark_data_stream *stream; if (!kshark_instance(&kshark_ctx)) return {}; - nCPUs = tep_get_cpus(kshark_ctx->pevent); - QVector allCPUs = QVector(nCPUs); + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return {}; + + QVector allCPUs = QVector(stream->n_cpus); std::iota(allCPUs.begin(), allCPUs.end(), 0); return allCPUs; } -/** @brief Get a sorted vector of Task's Pids. */ -QVector getPidList() +/** + * @brief Get a sorteg vector of Task's PIDs associated with a given Data + * stream. + * + * @param sd: Data stream identifier. + * + * @returns Vector of PIDs on success or an empty vector on failure. + */ +QVector getPidList(int sd) { kshark_context *kshark_ctx(nullptr); - int nTasks, *tempPids; - QVector pids; + int nTasks, *ids; if (!kshark_instance(&kshark_ctx)) - return pids; + return {}; - nTasks = kshark_get_task_pids(kshark_ctx, &tempPids); - for (int r = 0; r < nTasks; ++r) { - pids.append(tempPids[r]); - } + nTasks = kshark_get_task_pids(kshark_ctx, sd, &ids); - free(tempPids); + QVector pids(nTasks); + for (int i = 0; i < nTasks; ++i) + pids[i] = ids[i]; - std::sort(pids.begin(), pids.end()); + free(ids); return pids; } /** - * @brief Get a sorted vector of Event Ids. + * @brief Get a vector of all Event Ids associated with a given Data stream. + * + * @param sd: Data stream identifier. + * + * @returns Vector of Event Ids on success or an empty vector on failure. */ -QVector getEventIdList(tep_event_sort_type sortType) +QVector getEventIdList(int sd) { kshark_context *kshark_ctx(nullptr); - tep_event **events; - int nEvts; + kshark_data_stream *stream; + int *ids; if (!kshark_instance(&kshark_ctx)) return {}; - nEvts = tep_get_events_count(kshark_ctx->pevent); - events = tep_list_events(kshark_ctx->pevent, sortType); + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return {}; + + ids = kshark_get_all_event_ids(stream); + if (!ids) + return {}; - QVector allEvts(nEvts); - for (int i = 0; i < nEvts; ++i) - allEvts[i] = events[i]->id; + QVector evts(stream->n_events); + for (int i = 0; i < stream->n_events; ++i) + evts[i] = ids[i]; - return allEvts; + free(ids); + + return evts; } -/** @brief Get a sorted vector of Id values of a filter. */ -QVector getFilterIds(tracecmd_filter_id *filter) +/** + * @brief Retrieve the unique Id of the event. + * + * @param sd: Data stream identifier. + * @param eventName: The name of the event. + * + * @returns Event Id on success or a negative errno code on failure. + */ +int getEventId(int sd, const QString &eventName) { + const std::string buff = eventName.toStdString(); kshark_context *kshark_ctx(nullptr); - int *cpuFilter, n; - QVector v; + kshark_data_stream *stream; if (!kshark_instance(&kshark_ctx)) - return v; + return -EFAULT; + + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return -ENODEV; + + return kshark_find_event_id(stream, buff.c_str()); +} + +static kshark_entry probeEntry(int sd, int eventId) +{ + kshark_entry e; - cpuFilter = tracecmd_filter_ids(filter); - n = filter->count; + e.stream_id = sd; + e.event_id = eventId; + e.visible = 0xff; + + return e; +} + +/** + * @brief Retrieve the name of the event. + * + * @param sd: Data stream identifier. + * @param eventId: The unique Id of the event. + * + * @returns Event name on success or "Unknown" on failure. + */ +QString getEventName(int sd, int eventId) +{ + kshark_entry entry = probeEntry(sd, eventId); + QString ret("Unknown"); + char *event; + + event = kshark_get_event_name(&entry); + if (event) { + ret = QString(event); + free(event); + } + + return QString(ret); +} + +/** + * @brief Get the namse of all data fields associated with a given trace event. + * + * @param sd: Data stream identifier. + * @param eventId: The unique Id of the event. + * + * @returns List of fieldsnames on success or an empty list on failure. + */ +QStringList getEventFieldsList(int sd, int eventId) +{ + kshark_entry entry = probeEntry(sd, eventId); + QStringList fieldList; + char **eventFields; + int nFields; + + nFields = kshark_get_all_event_field_names(&entry, &eventFields); + if (nFields <= 0) + return {}; + + for (int i = 0; i < nFields; ++i) { + fieldList << eventFields[i]; + free(eventFields[i]); + } + + free(eventFields); + + return fieldList; +} + +/** + * @brief Retrieve the type of a given data field associatedwith a given trace + * event. + * + * @param sd: Data stream identifier. + * @param eventId: The unique Id of the event. + * @param fieldName: The name of the data field. + * + * @returns Field format identifier. + */ +kshark_event_field_format getEventFieldType(int sd, int eventId, + const QString &fieldName) +{ + const std::string buff = fieldName.toStdString(); + kshark_entry entry = probeEntry(sd, eventId); + + return kshark_get_event_field_type(&entry, buff.c_str()); +} + +/** + * @brief Get all Data stream Ids. + * + * @param kshark_ctx: Input location for context pointer. + * + * @returns Vector of Data stream Ids. + */ +QVector getStreamIdList(kshark_context *kshark_ctx) +{ + int *ids = kshark_all_streams(kshark_ctx); + QVector streamIds(kshark_ctx->n_streams); + + for (int i = 0; i < kshark_ctx->n_streams; ++i) + streamIds[i] = ids[i]; + + free(ids); + + return streamIds; +} + +/** + * @brief Get a sorted vector of Id values of a filter. + * + * @param filter: Input location for the filter object. + */ +QVector getFilterIds(kshark_hash_id *filter) +{ + kshark_context *kshark_ctx(nullptr); + int *ids, n = filter->count; + + if (!kshark_instance(&kshark_ctx)) + return {}; + + ids = kshark_hash_ids(filter); + QVector filterIds(n); for (int i = 0; i < n; ++i) - v.append(cpuFilter[i]); + filterIds[i] = ids[i]; - std::sort(v.begin(), v.end()); + free(ids); - free(cpuFilter); - return v; + return filterIds; } /** @@ -134,7 +288,6 @@ void graphFilterSync(bool state) } } - /** * @brief Add a checkbox to a menu. * @@ -164,15 +317,46 @@ QCheckBox *addCheckBoxToMenu(QMenu *menu, QString name) * * @param kshark_ctx: Input location for the session context pointer. * @param e: kshark_entry to be checked. + * @param sd: Data stream identifier. * @param cpu: Matching condition value. * * @returns True if the CPU of the entry matches the value of "cpu" and * the entry is visibility in Graph. Otherwise false. */ bool matchCPUVisible(struct kshark_context *kshark_ctx, - struct kshark_entry *e, int cpu) + struct kshark_entry *e, int sd, int *cpu) { - return (e->cpu == cpu && (e->visible & KS_GRAPH_VIEW_FILTER_MASK)); + return (e->cpu == *cpu && + e->stream_id == sd && + (e->visible & KS_GRAPH_VIEW_FILTER_MASK)); +} + +/** + * @brief Get an elided version of the string that will fit within a label. + * + * @param label: Pointer to the label object. + * @param text: The text to be elided. + * @param mode: Parameter specifies whether the text is elided on the left, + * in the middle, or on the right. + * @param labelWidth: The desired width of the label. + */ +void setElidedText(QLabel* label, QString text, + enum Qt::TextElideMode mode, + int labelWidth) +{ + QFontMetrics metrix(label->font()); + QString elidedText; + int textWidth; + + textWidth = labelWidth - FONT_WIDTH * 3; + elidedText = metrix.elidedText(text, Qt::ElideRight, textWidth); + + while(labelWidth < STRING_WIDTH(elidedText) + FONT_WIDTH * 5) { + textWidth -= FONT_WIDTH * 3; + elidedText = metrix.elidedText(text, mode, textWidth); + } + + label->setText(elidedText); } /** @@ -268,36 +452,8 @@ QStringList getFiles(QWidget *parent, } /** - * @brief Open a standard Qt getFileName dialog and return the name of the - * selected file. Only one file can be selected. - */ -QString getSaveFile(QWidget *parent, - const QString &windowName, - const QString &filter, - const QString &extension, - QString &lastFilePath) -{ - QString fileName = getFileDialog(parent, - windowName, - filter, - lastFilePath, - true); - - if (!fileName.isEmpty() && !fileName.endsWith(extension)) { - fileName += extension; - - if (QFileInfo(fileName).exists()) { - if (!KsWidgetsLib::fileExistsDialog(fileName)) - fileName.clear(); - } - } - - return fileName; -} - -/** - * Separate the command line arguments inside the string taking into account - * possible shell quoting and new lines. + * @brief Separate the command line arguments inside the string taking into + * account possible shell quoting and new lines. */ QStringList splitArguments(QString cmd) { @@ -336,7 +492,10 @@ QStringList splitArguments(QString cmd) return argv; } -/** Parse a string containing Ids. The string can be of the form "1 4-7 9". */ +/** + * @brief Parse a string containing Ids. The string can be of the form + * "1,4-7,9". + */ QVector parseIdList(QString v_str) { QStringList list = v_str.split(",", QString::SkipEmptyParts); @@ -360,6 +519,63 @@ QVector parseIdList(QString v_str) return v; } +/** + * @brief Split the ststem name from the actual name of the event itself. + * + * @param sd: Data stream identifier. + * @param eventId: Identifier of the Event. + */ +QStringList getTepEvtName(int sd, int eventId) +{ + QString name(kshark_event_from_id(sd, eventId)); + + return name.split('/'); +} + +/** + * @brief Get a string to be used as a standard name of a task graph. + * + * @param sd: Graph's Data stream identifier. + * @param pid: Graph's progress Id. + */ +QString taskPlotName(int sd, int pid) +{ + kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; + QString name; + + if (!kshark_instance(&kshark_ctx)) + return {}; + + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return {}; + + name = kshark_comm_from_pid(sd, pid); + name += "-"; + name += QString("%1").arg(pid); + + return name; +} + +/** + * @brief Get a description of the stream showing its data file and buffer + * name. + * + * @param stream: Input location for a Trace data stream pointer. + */ +QString streamDescription(kshark_data_stream *stream) +{ + QString descr(stream->file); + QString buffName(stream->name); + if (!buffName.isEmpty() && !kshark_tep_is_top_stream(stream)) { + descr += ":"; + descr += stream->name; + } + + return descr; +} + }; // KsUtils /** A stream operator for converting QColor into KsPlot::Color. */ @@ -370,10 +586,17 @@ KsPlot::Color& operator <<(KsPlot::Color &thisColor, const QColor &c) return thisColor; } +/** A stream operator for converting KsPlot::Color into QColor. */ +QColor& operator <<(QColor &thisColor, const KsPlot::Color &c) +{ + thisColor.setRgb(c.r(), c.g(), c.b()); + + return thisColor; +} + /** Create a default (empty) KsDataStore. */ KsDataStore::KsDataStore(QWidget *parent) : QObject(parent), - _tep(nullptr), _rows(nullptr), _dataSize(0) {} @@ -382,29 +605,127 @@ KsDataStore::KsDataStore(QWidget *parent) KsDataStore::~KsDataStore() {} +int KsDataStore::_openDataFile(kshark_context *kshark_ctx, + const QString &file) +{ + int sd = kshark_open(kshark_ctx, file.toStdString().c_str()); + if (sd < 0) { + qCritical() << "ERROR:" << sd << "while opening file " << file; + return sd; + } + + if (kshark_is_tep(kshark_ctx->stream[sd])) { + kshark_tep_init_all_buffers(kshark_ctx, sd); + for (int i = 0; i < kshark_ctx->n_streams; ++i) + kshark_tep_handle_plugins(kshark_ctx, i); + } + + return sd; +} + +void KsDataStore::_addPluginsToStream(kshark_context *kshark_ctx, int sd, + QVector plugins) +{ + kshark_data_stream *stream; + + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return; + + for (auto const &p: plugins) { + struct kshark_dpi_list *plugin; + + plugin = kshark_register_plugin_to_stream(stream, p, true); + kshark_handle_dpi(stream, plugin, KSHARK_PLUGIN_INIT); + } +} + /** Load trace data for file. */ -void KsDataStore::loadDataFile(const QString &file) +int KsDataStore::loadDataFile(const QString &file, + QVector plugins) { kshark_context *kshark_ctx(nullptr); + int i, sd, n_streams; if (!kshark_instance(&kshark_ctx)) - return; + return -EFAULT; clear(); - if (!kshark_open(kshark_ctx, file.toStdString().c_str())) { - qCritical() << "ERROR Loading file " << file; - return; + sd = _openDataFile(kshark_ctx, file); + if (sd != 0) + return sd; + + /* + * The file may contain multiple buffers so we can have multiple + * streams loaded. + */ + n_streams = kshark_ctx->n_streams; + for (i = 0; i < n_streams; ++i) + _addPluginsToStream(kshark_ctx, i, plugins); + + _dataSize = kshark_load_all_entries(kshark_ctx, &_rows); + if (_dataSize <= 0) { + kshark_close_all(kshark_ctx); + return _dataSize; } - _tep = kshark_ctx->pevent; + registerCPUCollections(); - if (kshark_ctx->event_handlers == nullptr) - kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_INIT); - else - kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_UPDATE); + return sd; +} + +/** + * @brief Append a trace data file to the data-set that is already loaded. + * The clock of the new data will be calibrated in order to be + * compatible with the clock of the prior data. + * + * @param file: Trace data file, to be append to the already loaded data. + * @param offset: The offset in time of the Data stream to be appended. + */ +int KsDataStore::appendDataFile(const QString &file, int64_t offset) +{ + kshark_context *kshark_ctx(nullptr); + struct kshark_entry **mergedRows; + ssize_t nLoaded = _dataSize; + int i, sd; + + if (!kshark_instance(&kshark_ctx)) + return -EFAULT; + + unregisterCPUCollections(); + + sd = _openDataFile(kshark_ctx, file); + if (sd < 0) + return sd; + + for (i = sd; i < kshark_ctx->n_streams; ++i) { + kshark_ctx->stream[sd]->calib = kshark_offset_calib; + kshark_ctx->stream[sd]->calib_array = + (int64_t *) calloc(1, sizeof(int64_t)); + kshark_ctx->stream[sd]->calib_array[0] = offset; + kshark_ctx->stream[sd]->calib_array_size = 1; + } + + _dataSize = kshark_append_all_entries(kshark_ctx, _rows, nLoaded, sd, + &mergedRows); + + if (_dataSize <= 0 || _dataSize == nLoaded) { + QErrorMessage *em = new QErrorMessage(); + em->showMessage(QString("File %1 contains no data.").arg(file)); + em->exec(); + + for (i = sd; i < kshark_ctx->n_streams; ++i) + kshark_close(kshark_ctx, i); + + return _dataSize; + } + + _rows = mergedRows; + + registerCPUCollections(); - _dataSize = kshark_load_data_entries(kshark_ctx, &_rows); + return sd; } void KsDataStore::_freeData() @@ -430,8 +751,14 @@ void KsDataStore::reload() _freeData(); - _dataSize = kshark_load_data_entries(kshark_ctx, &_rows); - _tep = kshark_ctx->pevent; + if (kshark_ctx->n_streams == 0) + return; + + unregisterCPUCollections(); + + _dataSize = kshark_load_all_entries(kshark_ctx, &_rows); + + registerCPUCollections(); emit updateWidgets(this); } @@ -441,11 +768,12 @@ void KsDataStore::clear() { kshark_context *kshark_ctx(nullptr); - _freeData(); - _tep = nullptr; + if (!kshark_instance(&kshark_ctx)) + return; - if (kshark_instance(&kshark_ctx) && kshark_ctx->handle) - kshark_close(kshark_ctx); + _freeData(); + unregisterCPUCollections(); + kshark_close_all(kshark_ctx); } /** Update the visibility of the entries (filter). */ @@ -456,93 +784,113 @@ void KsDataStore::update() if (!kshark_instance(&kshark_ctx)) return; - _unregisterCPUCollections(); + unregisterCPUCollections(); - if (kshark_filter_is_set(kshark_ctx)) { - kshark_filter_entries(kshark_ctx, _rows, _dataSize); - emit updateWidgets(this); - } + kshark_filter_all_entries(kshark_ctx, _rows, _dataSize); registerCPUCollections(); + + emit updateWidgets(this); } /** Register a collection of visible entries for each CPU. */ void KsDataStore::registerCPUCollections() { kshark_context *kshark_ctx(nullptr); + int *streamIds, nCPUs, sd; - if (!kshark_instance(&kshark_ctx) || - !kshark_filter_is_set(kshark_ctx)) + if (!kshark_instance(&kshark_ctx)) return; - int nCPUs = tep_get_cpus(_tep); - for (int cpu = 0; cpu < nCPUs; ++cpu) { - kshark_register_data_collection(kshark_ctx, - _rows, _dataSize, - KsUtils::matchCPUVisible, - cpu, - 0); + streamIds = kshark_all_streams(kshark_ctx); + for (int i = 0; i < kshark_ctx->n_streams; ++i) { + sd = streamIds[i]; + + nCPUs = kshark_ctx->stream[sd]->n_cpus; + for (int cpu = 0; cpu < nCPUs; ++cpu) { + kshark_register_data_collection(kshark_ctx, + _rows, _dataSize, + KsUtils::matchCPUVisible, + sd, &cpu, 1, + 0); + } } + + free(streamIds); } -void KsDataStore::_unregisterCPUCollections() +/** Unregister all CPU collections. */ +void KsDataStore::unregisterCPUCollections() { kshark_context *kshark_ctx(nullptr); + int *streamIds, nCPUs, sd; if (!kshark_instance(&kshark_ctx)) return; - int nCPUs = tep_get_cpus(_tep); - for (int cpu = 0; cpu < nCPUs; ++cpu) { - kshark_unregister_data_collection(&kshark_ctx->collections, - KsUtils::matchCPUVisible, - cpu); + streamIds = kshark_all_streams(kshark_ctx); + for (int i = 0; i < kshark_ctx->n_streams; ++i) { + sd = streamIds[i]; + + nCPUs = kshark_ctx->stream[sd]->n_cpus; + for (int cpu = 0; cpu < nCPUs; ++cpu) { + kshark_unregister_data_collection(&kshark_ctx->collections, + KsUtils::matchCPUVisible, + sd, &cpu, 1); + } } + + free(streamIds); } -void KsDataStore::_applyIdFilter(int filterId, QVector vec) +void KsDataStore::_applyIdFilter(int filterId, QVector vec, int sd) { kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; if (!kshark_instance(&kshark_ctx)) return; + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return; + switch (filterId) { case KS_SHOW_EVENT_FILTER: case KS_HIDE_EVENT_FILTER: - kshark_filter_clear(kshark_ctx, KS_SHOW_EVENT_FILTER); - kshark_filter_clear(kshark_ctx, KS_HIDE_EVENT_FILTER); + kshark_filter_clear(kshark_ctx, sd, KS_SHOW_EVENT_FILTER); + kshark_filter_clear(kshark_ctx, sd, KS_HIDE_EVENT_FILTER); break; case KS_SHOW_TASK_FILTER: case KS_HIDE_TASK_FILTER: - kshark_filter_clear(kshark_ctx, KS_SHOW_TASK_FILTER); - kshark_filter_clear(kshark_ctx, KS_HIDE_TASK_FILTER); + kshark_filter_clear(kshark_ctx, sd, KS_SHOW_TASK_FILTER); + kshark_filter_clear(kshark_ctx, sd, KS_HIDE_TASK_FILTER); break; case KS_SHOW_CPU_FILTER: case KS_HIDE_CPU_FILTER: - kshark_filter_clear(kshark_ctx, KS_SHOW_CPU_FILTER); - kshark_filter_clear(kshark_ctx, KS_HIDE_CPU_FILTER); + kshark_filter_clear(kshark_ctx, sd, KS_SHOW_CPU_FILTER); + kshark_filter_clear(kshark_ctx, sd, KS_HIDE_CPU_FILTER); break; default: return; } for (auto &&val: vec) - kshark_filter_add_id(kshark_ctx, filterId, val); + kshark_filter_add_id(kshark_ctx, sd, filterId, val); - if (!_tep) + if (!kshark_ctx->n_streams) return; - _unregisterCPUCollections(); + unregisterCPUCollections(); /* - * If the advanced event filter is set, the data has to be reloaded, + * If the advanced event filter is set the data has to be reloaded, * because the advanced filter uses tep_records. */ - if (kshark_ctx->advanced_event_filter->filters) + if (kshark_is_tep(stream) && kshark_tep_filter_is_set(stream)) reload(); else - kshark_filter_entries(kshark_ctx, _rows, _dataSize); + kshark_filter_stream_entries(kshark_ctx, sd, _rows, _dataSize); registerCPUCollections(); @@ -550,381 +898,475 @@ void KsDataStore::_applyIdFilter(int filterId, QVector vec) } /** Apply Show Task filter. */ -void KsDataStore::applyPosTaskFilter(QVector vec) +void KsDataStore::applyPosTaskFilter(int sd, QVector vec) { - _applyIdFilter(KS_SHOW_TASK_FILTER, vec); + _applyIdFilter(KS_SHOW_TASK_FILTER, vec, sd); } /** Apply Hide Task filter. */ -void KsDataStore::applyNegTaskFilter(QVector vec) +void KsDataStore::applyNegTaskFilter(int sd, QVector vec) { - _applyIdFilter(KS_HIDE_TASK_FILTER, vec); + _applyIdFilter(KS_HIDE_TASK_FILTER, vec, sd); } /** Apply Show Event filter. */ -void KsDataStore::applyPosEventFilter(QVector vec) +void KsDataStore::applyPosEventFilter(int sd, QVector vec) { - _applyIdFilter(KS_SHOW_EVENT_FILTER, vec); + _applyIdFilter(KS_SHOW_EVENT_FILTER, vec, sd); } /** Apply Hide Event filter. */ -void KsDataStore::applyNegEventFilter(QVector vec) +void KsDataStore::applyNegEventFilter(int sd, QVector vec) { - _applyIdFilter(KS_HIDE_EVENT_FILTER, vec); + _applyIdFilter(KS_HIDE_EVENT_FILTER, vec, sd); } /** Apply Show CPU filter. */ -void KsDataStore::applyPosCPUFilter(QVector vec) +void KsDataStore::applyPosCPUFilter(int sd, QVector vec) { - _applyIdFilter(KS_SHOW_CPU_FILTER, vec); + _applyIdFilter(KS_SHOW_CPU_FILTER, vec, sd); } /** Apply Hide CPU filter. */ -void KsDataStore::applyNegCPUFilter(QVector vec) +void KsDataStore::applyNegCPUFilter(int sd, QVector vec) { - _applyIdFilter(KS_HIDE_CPU_FILTER, vec); + _applyIdFilter(KS_HIDE_CPU_FILTER, vec, sd); } /** Disable all filters. */ void KsDataStore::clearAllFilters() { kshark_context *kshark_ctx(nullptr); + int *streamIds, sd; - if (!kshark_instance(&kshark_ctx) || !_tep) + if (!kshark_instance(&kshark_ctx) || !kshark_ctx->n_streams) return; - _unregisterCPUCollections(); + unregisterCPUCollections(); + + streamIds = kshark_all_streams(kshark_ctx); + for (int i = 0; i < kshark_ctx->n_streams; ++i) { + sd = streamIds[i]; + + kshark_filter_clear(kshark_ctx, sd, KS_SHOW_TASK_FILTER); + kshark_filter_clear(kshark_ctx, sd, KS_HIDE_TASK_FILTER); + kshark_filter_clear(kshark_ctx, sd, KS_SHOW_EVENT_FILTER); + kshark_filter_clear(kshark_ctx, sd, KS_HIDE_EVENT_FILTER); + kshark_filter_clear(kshark_ctx, sd, KS_SHOW_CPU_FILTER); + kshark_filter_clear(kshark_ctx, sd, KS_HIDE_CPU_FILTER); + + if (kshark_is_tep(kshark_ctx->stream[sd])) + kshark_tep_filter_reset(kshark_ctx->stream[sd]); + } - kshark_filter_clear(kshark_ctx, KS_SHOW_TASK_FILTER); - kshark_filter_clear(kshark_ctx, KS_HIDE_TASK_FILTER); - kshark_filter_clear(kshark_ctx, KS_SHOW_EVENT_FILTER); - kshark_filter_clear(kshark_ctx, KS_HIDE_EVENT_FILTER); - kshark_filter_clear(kshark_ctx, KS_SHOW_CPU_FILTER); - kshark_filter_clear(kshark_ctx, KS_HIDE_CPU_FILTER); + free(streamIds); - tep_filter_reset(kshark_ctx->advanced_event_filter); kshark_clear_all_filters(kshark_ctx, _rows, _dataSize); + registerCPUCollections(); emit updateWidgets(this); } /** - * @brief Create Plugin Manager. Use list of plugins declared in the - * CMake-generated header file. + * @brief Apply constant offset to the timestamps of all entries from a given + * Data stream. + * + * @param sd: Data stream identifier. + * @param offset: The constant offset to be added (in nanosecond). */ -KsPluginManager::KsPluginManager(QWidget *parent) -: QObject(parent) +void KsDataStore::setClockOffset(int sd, int64_t offset) { kshark_context *kshark_ctx(nullptr); - _parsePluginList(); if (!kshark_instance(&kshark_ctx)) return; - registerFromList(kshark_ctx); + if (!kshark_get_data_stream(kshark_ctx, sd)) + return; + + unregisterCPUCollections(); + kshark_set_clock_offset(kshark_ctx, _rows, _dataSize, sd, offset); + registerCPUCollections(); } -/** Parse the plugin list declared in the CMake-generated header file. */ -void KsPluginManager::_parsePluginList() +/** + * @brief Create Plugin Manager. Use the list of plugins declared in the + * CMake-generated header file. + */ +KsPluginManager::KsPluginManager(QWidget *parent) +: QObject(parent) { - _ksPluginList = KsUtils::getPluginList(); - int nPlugins = _ksPluginList.count(); + _loadPluginList(KsUtils::getPluginList()); +} - _registeredKsPlugins.resize(nPlugins); +QVector +KsPluginManager::_loadPluginList(const QStringList &plugins) +{ + kshark_context *kshark_ctx(nullptr); + QVector vec; + kshark_plugin_list *plugin; + std::string name, lib; + int nPlugins; + + if (!kshark_instance(&kshark_ctx)) + return vec; + + nPlugins = plugins.count(); for (int i = 0; i < nPlugins; ++i) { - if (_ksPluginList[i].contains(" default", Qt::CaseInsensitive)) { - _ksPluginList[i].remove(" default", Qt::CaseInsensitive); - _registeredKsPlugins[i] = true; + if (plugins[i].endsWith(".so")) { + lib = plugins[i].toStdString(); + name = _pluginNameFromLib(plugins[i]); } else { - _registeredKsPlugins[i] = false; + lib = _pluginLibFromName(plugins[i]); + name = plugins[i].toStdString(); + } + + plugin = kshark_find_plugin(kshark_ctx->plugins, + lib.c_str()); + + if (!plugin) { + plugin = kshark_register_plugin(kshark_ctx, + name.c_str(), + lib.c_str()); + + if (plugin) + vec.append(plugin); } } + + return vec; } /** - * Register the plugins by using the information in "_ksPluginList" and - * "_registeredKsPlugins". + * @brief Get a list of all plugins registered to a given Data stream. + * + * @param sd: Data stream identifier. + * @return List of plugin names. */ -void KsPluginManager::registerFromList(kshark_context *kshark_ctx) +QStringList KsPluginManager::getStreamPluginList(int sd) const { - auto lamRegBuiltIn = [&kshark_ctx, this](const QString &plugin) - { - char *lib; - int n; - - lib = _pluginLibFromName(plugin, n); - if (n <= 0) - return; + kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; + kshark_dpi_list *plugin; + QStringList list; - kshark_register_plugin(kshark_ctx, lib); - free(lib); - }; + if (!kshark_instance(&kshark_ctx)) + return {}; - auto lamRegUser = [&kshark_ctx](const QString &plugin) - { - std::string lib = plugin.toStdString(); - kshark_register_plugin(kshark_ctx, lib.c_str()); - }; + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return {}; - _forEachInList(_ksPluginList, - _registeredKsPlugins, - lamRegBuiltIn); + plugin = stream->plugins; + while (plugin) { + list.append(plugin->interface->name); + plugin = plugin->next; + } - _forEachInList(_userPluginList, - _registeredUserPlugins, - lamRegUser); + return list; } /** - * Unegister the plugins by using the information in "_ksPluginList" and - * "_registeredKsPlugins". + * @brief Get a list of all plugins registered to a given Data stream. + * + * @param sd: Data stream identifier. */ -void KsPluginManager::unregisterFromList(kshark_context *kshark_ctx) +QVector KsPluginManager::getActivePlugins(int sd) const { - auto lamUregBuiltIn = [&kshark_ctx, this](const QString &plugin) - { - char *lib; - int n; + kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; + kshark_dpi_list *plugin; + QVector vec; + int i(0); - lib = _pluginLibFromName(plugin, n); - if (n <= 0) - return; + if (!kshark_instance(&kshark_ctx)) + return {}; - kshark_unregister_plugin(kshark_ctx, lib); - free(lib); - }; + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return {}; - auto lamUregUser = [&kshark_ctx](const QString &plugin) - { - std::string lib = plugin.toStdString(); - kshark_unregister_plugin(kshark_ctx, lib.c_str()); - }; + plugin = stream->plugins; - _forEachInList(_ksPluginList, - _registeredKsPlugins, - lamUregBuiltIn); + while (plugin) { + vec.append(plugin->status & KSHARK_PLUGIN_ENABLED); + plugin = plugin->next; + i++; + } - _forEachInList(_userPluginList, - _registeredUserPlugins, - lamUregUser); + return vec; } -char *KsPluginManager::_pluginLibFromName(const QString &plugin, int &n) +/** + * @brief Get the indexes of all plugins registered to a given stream and + * having given status. + */ +QVector KsPluginManager::getPluginsByStatus(int sd, int status) const { - QString appPath = QCoreApplication::applicationDirPath(); - QString libPath = appPath + "/../../kernel-shark/lib"; - std::string pluginStr = plugin.toStdString(); - char *lib; + kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; + kshark_dpi_list *plugin; + QVector vec; + int i(0); - libPath = QDir::cleanPath(libPath); - if (!KsUtils::isInstalled() && QDir(libPath).exists()) { - std::string pathStr = libPath.toStdString(); - n = asprintf(&lib, "%s/plugin-%s.so", - pathStr.c_str(), pluginStr.c_str()); - } else { - n = asprintf(&lib, "%s/plugin-%s.so", - KS_PLUGIN_INSTALL_PREFIX, pluginStr.c_str()); + if (!kshark_instance(&kshark_ctx)) + return {}; + + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return {}; + + plugin = stream->plugins; + + while (plugin) { + if (plugin->status & status) + vec.append(i); + + plugin = plugin->next; + i++; } - return lib; + return vec; } /** - * @brief Register a Plugin. - * - * @param plugin: provide here the name of the plugin (as in the CMake-generated - * header file) of a name of the plugin's library file (.so). + * @brief Loop over the registered plugins and register all plugin-defined + * menus (if any). */ -void KsPluginManager::registerPlugin(const QString &plugin) +void KsPluginManager::registerPluginMenues() { kshark_context *kshark_ctx(nullptr); - char *lib; - int n; + kshark_plugin_list *plugin; if (!kshark_instance(&kshark_ctx)) return; - for (int i = 0; i < _ksPluginList.count(); ++i) { - if (_ksPluginList[i] == plugin) { - /* - * The argument is the name of the plugin. From the - * name get the library .so file. - */ - lib = _pluginLibFromName(plugin, n); - if (n > 0) { - kshark_register_plugin(kshark_ctx, lib); - _registeredKsPlugins[i] = true; - free(lib); + for (plugin = kshark_ctx->plugins; plugin; plugin = plugin->next) + if (plugin->handle && plugin->ctrl_interface) { + void *dialogPtr = plugin->ctrl_interface(parent()); + if (dialogPtr) { + QWidget *dialog = + static_cast(dialogPtr); + _pluginDialogs.append(dialog); } + } +} - return; +std::string KsPluginManager::_pluginLibFromName(const QString &plugin) +{ + QString appPath = QCoreApplication::applicationDirPath(); + QString libPath = appPath + "/../lib"; + std::string lib; - } else if (plugin.contains("/lib/plugin-" + _ksPluginList[i], - Qt::CaseInsensitive)) { - /* - * The argument is the name of the library .so file. - */ - n = asprintf(&lib, "%s", plugin.toStdString().c_str()); - if (n > 0) { - kshark_register_plugin(kshark_ctx, lib); - _registeredKsPlugins[i] = true; - free(lib); - } + auto lamFileName = [&] () { + return std::string("/plugin-" + plugin.toStdString() + ".so"); + }; - return; - } - } + libPath = QDir::cleanPath(libPath); + if (!KsUtils::isInstalled() && QDir(libPath).exists()) + lib = libPath.toStdString() + lamFileName(); + else + lib = std::string(KS_PLUGIN_INSTALL_PREFIX) + lamFileName(); - /* No plugin with this name in the list. Try to add it anyway. */ - if (plugin.endsWith(".so") && QFileInfo::exists(plugin)) { - kshark_register_plugin(kshark_ctx, - plugin.toStdString().c_str()); + return lib; +} - _userPluginList.append(plugin); - _registeredUserPlugins.append(true); - } else { - qCritical() << "ERROR: " << plugin << "cannot be registered!"; - } +std::string KsPluginManager::_pluginNameFromLib(const QString &plugin) +{ + QString name = plugin.section('/', -1); + name.remove("plugin-"); + name.remove(".so"); + + return name.toStdString(); } -/** @brief Unregister a Built in KernelShark plugin. - *
- * WARNING: Do not use this function to unregister User plugins. - * Instead use directly kshark_unregister_plugin(). +/** + * @brief Register a list pf plugins * - * @param plugin: provide here the name of the plugin (as in the CMake-generated - * header file) or a name of the plugin's library file (.so). + * @param pluginNames: Provide here the names of the plugin (as in the + * CMake-generated header file) or the names of the + * plugin's library files (.so including path). + * The names must be comma separated. + */ +void KsPluginManager::registerPlugins(const QString &pluginNames) +{ + _userPlugins.append(_loadPluginList(pluginNames.split(','))); +} + +/** + * @brief Unregister a list pf plugins. * + * @param pluginNames: Provide here a comma separated list of plugin names (as + * in the CMake-generated header file). */ -void KsPluginManager::unregisterPlugin(const QString &plugin) +void KsPluginManager::unregisterPlugins(const QString &pluginNames) { kshark_context *kshark_ctx(nullptr); - char *lib; - int n; + kshark_plugin_list *plugin; + kshark_data_stream *stream; + int *streamArray; if (!kshark_instance(&kshark_ctx)) return; - for (int i = 0; i < _ksPluginList.count(); ++i) { - if (_ksPluginList[i] == plugin) { - /* - * The argument is the name of the plugin. From the - * name get the library .so file. - */ - lib = _pluginLibFromName(plugin, n); - if (n > 0) { - kshark_unregister_plugin(kshark_ctx, lib); - _registeredKsPlugins[i] = false; - free(lib); - } - - return; - } else if (plugin.contains("/lib/plugin-" + - _ksPluginList[i], Qt::CaseInsensitive)) { - /* - * The argument is the name of the library .so file. - */ - n = asprintf(&lib, "%s", plugin.toStdString().c_str()); - if (n > 0) { - kshark_unregister_plugin(kshark_ctx, lib); - _registeredKsPlugins[i] = false; - free(lib); - } + for (auto const &name: pluginNames.split(',')) { + plugin = kshark_find_plugin_by_name(kshark_ctx->plugins, + name.toStdString().c_str()); - return; + streamArray = kshark_all_streams(kshark_ctx); + for (int i = 0; i < kshark_ctx->n_streams; ++i) { + stream = kshark_get_data_stream(kshark_ctx, + streamArray[i]); + kshark_unregister_plugin_from_stream(stream, + plugin->process_interface); } + + kshark_unregister_plugin(kshark_ctx, + name.toStdString().c_str(), + plugin->file); } } -/** @brief Add to the list and initialize user-provided plugins. All other - * previously loaded plugins will be reinitialized and the data will be - * reloaded. - * - * @param fileNames: the library files (.so) of the plugins. -*/ -void KsPluginManager::addPlugins(const QStringList &fileNames) +void KsPluginManager::_pluginToStream(const QString &pluginName, + QVector streamIds, + bool reg) { kshark_context *kshark_ctx(nullptr); + kshark_plugin_list *plugin; + kshark_data_stream *stream; if (!kshark_instance(&kshark_ctx)) return; - kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_CLOSE); + plugin = kshark_find_plugin_by_name(kshark_ctx->plugins, + pluginName.toStdString().c_str()); - for (auto const &p: fileNames) - registerPlugin(p); + if (!plugin || !plugin->process_interface) + return; - kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_INIT); + for (auto const &sd: streamIds) { + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + continue; + + if (reg) + kshark_register_plugin_to_stream(stream, + plugin->process_interface, + true); + else + kshark_unregister_plugin_from_stream(stream, + plugin->process_interface); + + kshark_handle_all_dpis(stream, KSHARK_PLUGIN_UPDATE); + } emit dataReload(); } -/** Unload all plugins. */ -void KsPluginManager::unloadAll() +/** + * @brief Register a given plugin to given Data streams. + * + * @param pluginName: The name of the plugin to register. + * @param streamIds: Vector of Data stream identifiers. + */ +void KsPluginManager::registerPluginToStream(const QString &pluginName, + QVector streamIds) +{ + _pluginToStream(pluginName, streamIds, true); +} + +/** + * @brief Unregister a given plugin from given Data streams. + * + * @param pluginName: The name of the plugin to unregister. + * @param streamIds: Vector of Data stream identifiers. + */ +void KsPluginManager::unregisterPluginFromStream(const QString &pluginName, + QVector streamIds) +{ + _pluginToStream(pluginName, streamIds, false); +} + +/** @brief Add to the list and initialize user-provided plugins. All other + * previously loaded plugins will be reinitialized and the data will be + * reloaded. + * + * @param fileNames: The library files (.so) of the plugins. + * @param streamIds: Vector of Data stream identifiers. If the vector is empty + * the plugins will be registered to all Data streams. + * Otherwise the plugins will be registered to the listed + * streams. +*/ +void KsPluginManager::addPlugins(const QStringList &fileNames, + QVector streamIds) { + QVector plugins; kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; if (!kshark_instance(&kshark_ctx)) return; - kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_CLOSE); - kshark_free_plugin_list(kshark_ctx->plugins); - kshark_ctx->plugins = nullptr; - kshark_free_event_handler_list(kshark_ctx->event_handlers); + plugins = _loadPluginList(fileNames); + _userPlugins.append(plugins); - unregisterFromList(kshark_ctx); + if (streamIds.isEmpty()) + streamIds = KsUtils::getStreamIdList(kshark_ctx); + + for (auto const &sd: streamIds) { + stream = kshark_get_data_stream(kshark_ctx, sd); + + for (auto const &p: plugins) { + if (p->process_interface) + kshark_register_plugin_to_stream(stream, + p->process_interface, + true); + } + + kshark_handle_all_dpis(stream, KSHARK_PLUGIN_UPDATE); + } } -/** @brief Update (change) the Plugins. +/** @brief Update (change) the plugins for a given Data stream. * - * @param pluginIds: The indexes of the plugins to be loaded. + * @param sd: Data stream identifier. + * @param pluginStates: A vector of plugin's states (0 or 1) telling which + * plugins to be loaded. */ -void KsPluginManager::updatePlugins(QVector pluginIds) +void KsPluginManager::updatePlugins(int sd, QVector pluginStates) { kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; + kshark_dpi_list *plugin; + QVector vec; + int i(0); if (!kshark_instance(&kshark_ctx)) return; - auto register_plugins = [&] (QVector ids) - { - int nKsPlugins = _registeredKsPlugins.count(); - - /* First clear all registered plugins. */ - for (auto &p: _registeredKsPlugins) - p = false; - for (auto &p: _registeredUserPlugins) - p = false; - - /* The vector contains the indexes of those to register. */ - for (auto const &p: ids) { - if (p < nKsPlugins) - _registeredKsPlugins[p] = true; - else - _registeredUserPlugins[p - nKsPlugins] = true; - } - registerFromList(kshark_ctx); - }; + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return; - if (!kshark_ctx->pevent) { - kshark_free_plugin_list(kshark_ctx->plugins); - kshark_ctx->plugins = nullptr; + plugin = stream->plugins; + while (plugin) { + if (pluginStates[i++]) + plugin->status |= KSHARK_PLUGIN_ENABLED; + else + plugin->status &= ~KSHARK_PLUGIN_ENABLED; - /* - * No data is loaded. For the moment, just register the - * plugins. Handling of the plugins will be done after - * we load a data file. - */ - register_plugins(pluginIds); - return; + plugin = plugin->next; } - /* Clean up all old plugins first. */ - unloadAll(); - - /* Now load. */ - register_plugins(pluginIds); - kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_INIT); + kshark_handle_all_dpis(stream, KSHARK_PLUGIN_UPDATE); +} - emit dataReload(); +/** + * @brief Destroy all Plugin dialogs. + */ +void KsPluginManager::deletePluginDialogs() +{ + /** Delete all register plugin dialogs. */ + for (auto &pd: _pluginDialogs) + delete pd; } diff --git a/src/KsUtils.hpp b/src/KsUtils.hpp index 2772b84..0d2c9c3 100644 --- a/src/KsUtils.hpp +++ b/src/KsUtils.hpp @@ -45,7 +45,15 @@ static auto stringWidth = [](QString s) QFont font; QFontMetrics fm(font); +#ifdef QT_VERSION_LESS_5_11 + + return fm.width(s); + +#else + return fm.horizontalAdvance(s); + +#endif // QT_VERSION_LESS_5_11 }; //! @endcond @@ -54,13 +62,13 @@ static auto stringWidth = [](QString s) #define FONT_HEIGHT fontHeight() /** Macro providing the width of the font in pixels. */ -#define FONT_WIDTH stringWidth("4") +#define FONT_WIDTH (stringWidth("KernelShark") / 11) /** Macro providing the width of a string in pixels. */ #define STRING_WIDTH(s) stringWidth(s) /** Macro providing the height of the KernelShark graphs in pixels. */ -#define KS_GRAPH_HEIGHT (FONT_HEIGHT*2) +#define KS_GRAPH_HEIGHT (FONT_HEIGHT * 2) //! @cond Doxygen_Suppress @@ -82,16 +90,27 @@ std::chrono::high_resolution_clock::now() - t0).count() namespace KsUtils { -QVector getCPUList(); +QVector getCPUList(int sd); + +QVector getPidList(int sd); + +QVector getEventIdList(int sd); + +int getEventId(int sd, const QString &eventName); + +QString getEventName(int sd, int eventId); + +QStringList getEventFieldsList(int sd, int eventId); -QVector getPidList(); +kshark_event_field_format getEventFieldType(int sd, int eventId, + const QString &fieldName); -QVector getEventIdList(tep_event_sort_type sortType=TEP_EVENT_SORT_ID); +QVector getStreamIdList(kshark_context *kshark_ctx); -QVector getFilterIds(tracecmd_filter_id *filter); +QVector getFilterIds(kshark_hash_id *filter); -/** @brief Geat the list of plugins. */ -inline QStringList getPluginList() {return plugins.split(";");} +/** @brief Geat the list of plugins provided by the package. */ +inline QStringList getPluginList() {return QString(KS_BUILTIN_PLUGINS).split(";");} void listFilterSync(bool state); @@ -113,8 +132,8 @@ inline QString Ts2String(int64_t ts, int prec) return QString::number(ts * 1e-9, 'f', prec); } -bool matchCPUVisible(struct kshark_context *kshark_ctx, - struct kshark_entry *e, int cpu); +bool matchCPUVisible(kshark_context *kshark_ctx, + kshark_entry *e, int sd, int *cpu); bool isInstalled(); @@ -134,10 +153,33 @@ QString getSaveFile(QWidget *parent, const QString &extension, QString &lastFilePath); +void setElidedText(QLabel* label, QString text, + enum Qt::TextElideMode mode, + int labelWidth); + QStringList splitArguments(QString cmd); QVector parseIdList(QString v_str); +QStringList getTepEvtName(int sd, int eventId); + +/** Get a string to be used as a standard name of a CPU graph. */ +inline QString cpuPlotName(int cpu) {return QString("CPU %1").arg(cpu);} + +QString taskPlotName(int sd, int pid); + +/** Get the total number of Data streams. */ +inline int getNStreams() +{ + kshark_context *kshark_ctx(nullptr); + + if (!kshark_instance(&kshark_ctx)) + return -1; + return kshark_ctx->n_streams; +} + +QString streamDescription(kshark_data_stream *stream); + }; // KsUtils /** Identifier of the Dual Marker active state. */ @@ -158,39 +200,49 @@ public: ~KsDataStore(); - void loadDataFile(const QString &file); + int loadDataFile(const QString &file, + QVector plugins); + + int appendDataFile(const QString &file, int64_t shift); void clear(); - /** Get the trace event parser. */ - tep_handle *tep() const {return _tep;} + /** Get the trace data array. */ + kshark_entry **rows() const {return _rows;} - /** Get the trace data array.. */ - struct kshark_entry **rows() const {return _rows;} + /** Get a reference of the trace data array. */ + kshark_entry ***rows_r() {return &_rows;} /** Get the size of the data array. */ ssize_t size() const {return _dataSize;} + /** Set the size of the data (number of entries). */ + void setSize(ssize_t s) {_dataSize = s;} + void reload(); void update(); void registerCPUCollections(); - void applyPosTaskFilter(QVector); + void unregisterCPUCollections(); + + void applyPosTaskFilter(int sd, QVector vec); - void applyNegTaskFilter(QVector); + void applyNegTaskFilter(int sd, QVector vec); - void applyPosEventFilter(QVector); + void applyPosEventFilter(int sd, QVector vec); - void applyNegEventFilter(QVector); + void applyNegEventFilter(int sd, QVector vec); - void applyPosCPUFilter(QVector); + void applyPosCPUFilter(int sd, QVector vec); - void applyNegCPUFilter(QVector); + void applyNegCPUFilter(int sd, QVector vec); void clearAllFilters(); + void setClockOffset(int sd, int64_t offset); + signals: /** * This signal is emitted when the data has changed and the View @@ -199,75 +251,84 @@ signals: void updateWidgets(KsDataStore *); private: - /** Page event used to parse the page. */ - tep_handle *_tep; - /** Trace data array. */ - struct kshark_entry **_rows; + kshark_entry **_rows; /** The size of the data array. */ ssize_t _dataSize; + int _openDataFile(kshark_context *kshark_ctx, const QString &file); + void _freeData(); - void _unregisterCPUCollections(); - void _applyIdFilter(int filterId, QVector vec); + + void _applyIdFilter(int filterId, QVector vec, int sd); + + void _addPluginsToStream(kshark_context *kshark_ctx, int sd, + QVector plugins); }; -/** A Plugin Manage class. */ +/** A Plugin Manager class. */ class KsPluginManager : public QObject { Q_OBJECT public: explicit KsPluginManager(QWidget *parent = nullptr); - /** A list of available built-in plugins. */ - QStringList _ksPluginList; + QStringList getStreamPluginList(int sd) const; + + QVector getActivePlugins(int sd) const; - /** A list of registered built-in plugins. */ - QVector _registeredKsPlugins; + QVector getPluginsByStatus(int sd, int status) const; - /** A list of available user plugins. */ - QStringList _userPluginList; + /** Get a list of all plugins added by the user. */ + const QVector + getUserPlugins() const {return _userPlugins;} - /** A list of registered user plugins. */ - QVector _registeredUserPlugins; + void registerPluginMenues(); - void registerFromList(kshark_context *kshark_ctx); - void unregisterFromList(kshark_context *kshark_ctx); + void updatePlugins(int sd, QVector pluginStates); - void registerPlugin(const QString &plugin); - void unregisterPlugin(const QString &plugin); + void addPlugins(const QStringList &fileNames, QVector streams); - void addPlugins(const QStringList &fileNames); + void registerPlugins(const QString &pluginNames); - void unloadAll(); + void unregisterPlugins(const QString &pluginNames); - void updatePlugins(QVector pluginId); + void registerPluginToStream(const QString &pluginName, + QVector streamId); + + void unregisterPluginFromStream(const QString &pluginName, + QVector streamId); + + void deletePluginDialogs(); + + /** Append to the list of User plugin. */ + void addUserPluginToList(kshark_plugin_list *p) {_userPlugins.append(p);} signals: /** This signal is emitted when a plugin is loaded or unloaded. */ void dataReload(); private: - void _parsePluginList(); - - char *_pluginLibFromName(const QString &plugin, int &n); - - template - void _forEachInList(const QStringList &pl, - const QVector ®, - T action) - { - int nPlugins; - nPlugins = pl.count(); - for (int i = 0; i < nPlugins; ++i) { - if (reg[i]) { - action(pl[i]); - } - } - } + QVector _userPlugins; + + /** Plugin dialogs. */ + QVector _pluginDialogs; + + QVector + _loadPluginList(const QStringList &plugins); + + std::string _pluginLibFromName(const QString &plugin); + + std::string _pluginNameFromLib(const QString &plugin); + + void _pluginToStream(const QString &pluginName, + QVector streamId, + bool reg); }; KsPlot::Color& operator <<(KsPlot::Color &thisColor, const QColor &c); +QColor& operator <<(QColor &thisColor, const KsPlot::Color &c); + #endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a1e3085..17b586e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,7 +6,7 @@ set(EXECUTABLE_OUTPUT_PATH ${KS_TEST_DIR}) add_executable(kshark-tests libkshark-tests.cpp) target_include_directories(kshark-tests PRIVATE ${Boost_INCLUDE_DIRS}) target_compile_definitions(kshark-tests PRIVATE "BOOST_TEST_DYN_LINK=1") -target_link_libraries(kshark-tests kshark +target_link_libraries(kshark-tests kshark-gui ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) add_test(NAME "libkshark_tests" diff --git a/tests/libkshark-tests.cpp b/tests/libkshark-tests.cpp index 780a3fa..eb5cb1f 100644 --- a/tests/libkshark-tests.cpp +++ b/tests/libkshark-tests.cpp @@ -46,6 +46,7 @@ BOOST_AUTO_TEST_CASE(add_remove_streams) BOOST_CHECK_EQUAL(sd, -ENODEV); kshark_close_all(kshark_ctx); + kshark_free(kshark_ctx); } #define ARRAY_DEFAULT_SIZE 1000 From patchwork Thu Feb 11 10:31:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082709 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.7 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 BD1A5C433DB for ; Thu, 11 Feb 2021 10:35:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6CDC664E92 for ; Thu, 11 Feb 2021 10:35:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229867AbhBKKfW (ORCPT ); Thu, 11 Feb 2021 05:35:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45848 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230116AbhBKKdL (ORCPT ); Thu, 11 Feb 2021 05:33:11 -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 2D57AC061793 for ; Thu, 11 Feb 2021 02:32:29 -0800 (PST) Received: by mail-ej1-x633.google.com with SMTP id hs11so9311754ejc.1 for ; Thu, 11 Feb 2021 02:32:29 -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=YHv9DqnPb/dDXcIDEU5MHloGNIV4C62FNB+9Lmijnwc=; b=HDeHK5CQmN25uSx2AJ6hnzVBi3h0rW4HiNDIH815ZOML/k/aJ7fd07xmHop8GImWX8 VWqXMkbLWoQdVbYUcq0AOyJ3/dKtTH8ERyLUZsSePqPRz655q5P6qqpEs19c8Xe5JwsK o4tkQvnrqUdHLYF9PxCsTYrAbUZRfMq5nrjfh3fYXcPQNTc+1Yi9iF40HRUrqjruB7sp CMKnoluEwtvqC7kL9XQgSXZdA5NM997uWusOpUjktVSbrmd5ROzNlKp+DtGmjS2WnV6g sDFYktz1Rr1mu71v9/tRX/eLzK2qfkC21EaJYEZ6CZQTJjxgQsDhLidMesgRff+xGTgl ZB3A== 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=YHv9DqnPb/dDXcIDEU5MHloGNIV4C62FNB+9Lmijnwc=; b=kjzz77ANu0UynJ5c6D2KjyKdr0jwgeUrLK5z3lmcrxS2mDZeJt5j2dSfbaJM42l504 0fwvPyY6WLBpOqRga2FX4ZhS85BpRVdv6oPzt6L7wBfSnBOdRkG8a557mQHwEUuRrd+o yjc+IKSWveYnmWoksBKODGcYMaaqTLluAfcNTRnXwn2p7icB1n+nnVRNYDlc2clQAqTy SFt2mHg/beksuOzBFy3VM80ctN3XuE/+/fqsltxL7EUl1LhX3EVeRCP0opCBheCF0zAE 9upU8Z90yU0121JgW7RiBxmai3HCf2U24Ix0VgjsNLI+GOvLaU1LAYb2vJrVohgQqvSZ u3zA== X-Gm-Message-State: AOAM532R53TNx3EBIeKnf1jRqZZKers4spc2bnzkTFQ2Nm3zlgRgD5uq fsCEK2B8mwajs0ZJHFA59X5m4XUQOR4= X-Google-Smtp-Source: ABdhPJznvUN27Pa41zRKtL38iNKfOAW5FKN6U8EFVQ/kxFWA0q0YrVaWcMDcBGuvaT8ZEqS2WemCag== X-Received: by 2002:a17:906:ada:: with SMTP id z26mr7741065ejf.218.1613039547864; Thu, 11 Feb 2021 02:32:27 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:27 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 07/27] kernel-shark: Update KsModels and KsSearchFSM Date: Thu, 11 Feb 2021 12:31:45 +0200 Message-Id: <20210211103205.418588-8-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The compilation of KsModels.cpp and KsSearchFSM.cpp is re-enabled and all functionalities are made compatible with the new version of the C API of libkshark (KernelShark 2.0). The two source files are updated in a single patch because of their interdependence. Signed-off-by: Yordan Karadzhov (VMware) --- src/CMakeLists.txt | 12 ++--- src/KsModels.cpp | 112 +++++++++++++++++++++++++++++++++++++------- src/KsModels.hpp | 28 +++++++---- src/KsSearchFSM.cpp | 12 ++++- 4 files changed, 132 insertions(+), 32 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5c9fe17..21d5b85 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -66,10 +66,10 @@ endif (OPENGL_FOUND) if (Qt5Widgets_FOUND AND Qt5Network_FOUND) message(STATUS "libkshark-gui") - set (ks-guiLib_hdr KsUtils.hpp) -# KsModels.hpp + set (ks-guiLib_hdr KsUtils.hpp + KsModels.hpp # KsGLWidget.hpp -# KsSearchFSM.hpp + KsSearchFSM.hpp) # KsDualMarker.hpp # KsWidgetsLib.hpp # KsTraceGraph.hpp @@ -81,11 +81,11 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) QT5_WRAP_CPP(ks-guiLib_hdr_moc ${ks-guiLib_hdr}) - add_library(kshark-gui SHARED ${ks-guiLib_hdr_moc} KsUtils.cpp) -# KsModels.cpp + add_library(kshark-gui SHARED ${ks-guiLib_hdr_moc} KsUtils.cpp + KsModels.cpp # KsSession.cpp # KsGLWidget.cpp -# KsSearchFSM.cpp + KsSearchFSM.cpp) # KsDualMarker.cpp # KsWidgetsLib.cpp # KsTraceGraph.cpp diff --git a/src/KsModels.cpp b/src/KsModels.cpp index 51a7b79..df8373e 100644 --- a/src/KsModels.cpp +++ b/src/KsModels.cpp @@ -227,16 +227,54 @@ QList KsFilterProxyModel::searchThread(int column, return matchList; } +int KsFilterProxyModel::mapRowFromSource(int r) const +{ + /* + * This works because the row number is shown in column + * TRACE_VIEW_COL_INDEX (or TRACE_VIEW_COL_INDEX - 1 in the case when + * the Stream Id column is hidden). + */ + int column = KsViewModel::TRACE_VIEW_COL_INDEX; + + if(_source->singleStream()) + column--; + + return this->data(this->index(r, column)).toInt(); +} + /** Create default (empty) KsViewModel object. */ KsViewModel::KsViewModel(QObject *parent) : QAbstractTableModel(parent), _data(nullptr), _nRows(0), - _header({"#", "CPU", "Time Stamp", "Task", "PID", - "Latency", "Event", "Info"}), _markA(KS_NO_ROW_SELECTED), - _markB(KS_NO_ROW_SELECTED) -{} + _markB(KS_NO_ROW_SELECTED), + _singleStream(true) +{ + _updateHeader(); +} + +/** Update the list of table headers. */ +void KsViewModel::_updateHeader() +{ + beginRemoveColumns(QModelIndex(), 0, _header.count()); + endRemoveColumns(); + + _header.clear(); + + if (KsUtils::getNStreams() > 1) { + _header << " >> "; + _singleStream = false; + } else { + _singleStream = true; + } + + _header << "#" << "CPU" << "Time Stamp" << "Task" << "PID" + << "Latency" << "Event" << "Info"; + + beginInsertColumns(QModelIndex(), 0, _header.count() - 1); + endInsertColumns(); +} /** * Get the data stored under the given role for the item referred to by @@ -246,10 +284,10 @@ KsViewModel::KsViewModel(QObject *parent) QVariant KsViewModel::data(const QModelIndex &index, int role) const { if (role == Qt::ForegroundRole) { - if (index.row() == _markA) + if (index.row() == _markA && index.column() != 0) return QVariant::fromValue(QColor(Qt::white)); - if (index.row() == _markB) + if (index.row() == _markB && index.column() != 0) return QVariant::fromValue(QColor(Qt::white)); } @@ -259,6 +297,15 @@ QVariant KsViewModel::data(const QModelIndex &index, int role) const if (index.row() == _markB) return QVariant::fromValue(QColor(_colorMarkB)); + + if (index.column() == TRACE_VIEW_COL_STREAM && + !_singleStream) { + int sd = _data[index.row()]->stream_id; + QColor col; + col << KsPlot::getColor(&_streamColors, sd); + + return QVariant::fromValue(col); + } } if (role == Qt::DisplayRole) @@ -270,9 +317,26 @@ QVariant KsViewModel::data(const QModelIndex &index, int role) const /** Get the string data stored in a given cell of the table. */ QString KsViewModel::getValueStr(int column, int row) const { + char *buffer; int pid; + /* + * If only one Data stream (file) is loaded, the first column + * (TRACE_VIEW_COL_STREAM) is not shown. + */ + if(_singleStream) + column++; + + auto lanMakeString = [&buffer] () { + QString str(buffer); + free(buffer); + return str; + }; + switch (column) { + case TRACE_VIEW_COL_STREAM : + return QString("%1").arg(_data[row]->stream_id); + case TRACE_VIEW_COL_INDEX : return QString("%1").arg(row); @@ -283,20 +347,24 @@ QString KsViewModel::getValueStr(int column, int row) const return KsUtils::Ts2String(_data[row]->ts, 6); case TRACE_VIEW_COL_COMM: - return kshark_get_task_easy(_data[row]); + buffer = kshark_get_task(_data[row]); + return lanMakeString(); case TRACE_VIEW_COL_PID: - pid = kshark_get_pid_easy(_data[row]); + pid = kshark_get_pid(_data[row]); return QString("%1").arg(pid); - case TRACE_VIEW_COL_LAT: - return kshark_get_latency_easy(_data[row]); + case TRACE_VIEW_COL_AUX: + buffer = kshark_get_aux_info(_data[row]); + return lanMakeString(); case TRACE_VIEW_COL_EVENT: - return kshark_get_event_name_easy(_data[row]); + buffer = kshark_get_event_name(_data[row]); + return lanMakeString(); case TRACE_VIEW_COL_INFO : - return kshark_get_info_easy(_data[row]); + buffer = kshark_get_info(_data[row]); + return lanMakeString(); default: return {}; @@ -333,8 +401,10 @@ void KsViewModel::fill(KsDataStore *data) _data = data->rows(); _nRows = data->size(); + _streamColors = KsPlot::streamColorTable(); endInsertRows(); + _updateHeader(); } /** @brief Select a row in the table. @@ -375,6 +445,14 @@ void KsViewModel::update(KsDataStore *data) fill(data); } +/** Update the color scheme used by the model. */ +void KsViewModel::loadColors() +{ + beginResetModel(); + _streamColors = KsPlot::streamColorTable(); + endResetModel(); +} + /** @brief Search the content of the table for a data satisfying an abstract * condition. * @@ -420,12 +498,12 @@ KsGraphModel::~KsGraphModel() /** * @brief Provide the Visualization model with data. Calculate the current * state of the model. - * - * @param entries: Input location for the trace data. - * @param n: Number of bins. */ -void KsGraphModel::fill(kshark_entry **entries, size_t n) +void KsGraphModel::fill(KsDataStore *data) { + kshark_entry **entries = data->rows(); + size_t n = data->size(); + if (n == 0) return; @@ -435,7 +513,7 @@ void KsGraphModel::fill(kshark_entry **entries, size_t n) ksmodel_set_bining(&_histo, KS_DEFAULT_NBUNS, entries[0]->ts, - entries[n-1]->ts); + entries[n - 1]->ts); ksmodel_fill(&_histo, entries, n); diff --git a/src/KsModels.hpp b/src/KsModels.hpp index d360ad6..3a6d3f1 100644 --- a/src/KsModels.hpp +++ b/src/KsModels.hpp @@ -26,6 +26,7 @@ // KernelShark #include "libkshark.h" #include "libkshark-model.h" +#include "KsPlotTools.hpp" #include "KsSearchFSM.hpp" /** A negative row index, to be used for deselecting the Passive Marker. */ @@ -45,7 +46,7 @@ public: explicit KsViewModel(QObject *parent = nullptr); /** Set the colors of the two markers. */ - void setColors(const QColor &colA, const QColor &colB) { + void setMarkerColors(const QColor &colA, const QColor &colB) { _colorMarkA = colA; _colorMarkB = colB; }; @@ -91,8 +92,16 @@ public: search_condition_func cond, QList *matchList); + void loadColors(); + + /** Returns True is only one Data stream is open. */ + bool singleStream() const {return _singleStream;} + /** Table columns Identifiers. */ enum { + /** Identifier of the Data stream. */ + TRACE_VIEW_COL_STREAM, + /** Identifier of the Index column. */ TRACE_VIEW_COL_INDEX, @@ -109,7 +118,7 @@ public: TRACE_VIEW_COL_PID, /** Identifier of the Latency Id column. */ - TRACE_VIEW_COL_LAT, + TRACE_VIEW_COL_AUX, /** Identifier of the Event name Id column. */ TRACE_VIEW_COL_EVENT, @@ -122,6 +131,8 @@ public: }; private: + void _updateHeader(); + /** Trace data array. */ kshark_entry **_data; @@ -142,6 +153,11 @@ private: /** The color of the row selected by marker B. */ QColor _colorMarkB; + + /** True if only one Data stream is open. */ + bool _singleStream; + + KsPlot::ColorTable _streamColors; }; /** @@ -192,11 +208,7 @@ public: * Use the "row" index in the Proxy model to retrieve the "row" index * in the source model. */ - int mapRowFromSource(int r) const - { - /*This works because the row number is shown in column "0". */ - return this->data(this->index(r, 0)).toInt(); - } + int mapRowFromSource(int r) const; /** Get the source model. */ KsViewModel *source() {return _source;} @@ -272,7 +284,7 @@ public: /** Get the kshark_trace_histo object. */ kshark_trace_histo *histo() {return &_histo;} - void fill(kshark_entry **entries, size_t n); + void fill(KsDataStore *data); void shiftForward(size_t n); diff --git a/src/KsSearchFSM.cpp b/src/KsSearchFSM.cpp index 6a93ca7..a5f3682 100644 --- a/src/KsSearchFSM.cpp +++ b/src/KsSearchFSM.cpp @@ -136,6 +136,16 @@ void KsSearchFSM ::_lockSearchPanel(bool lock) /** Act according to the provided input. */ void NotDone::handleInput(KsSearchFSM* sm, sm_input_t input) { + int column = sm->column(); + if (sm->_columnComboBox.findText(">>", Qt::MatchContains) < 0) { + /* + * If only one Data stream (file) is loaded, the ">>" column + * (TRACE_VIEW_COL_STREAM) is not shown. The column index has + * to be corrected. + */ + ++column; + } + switch(input) { case sm_input_t::Start: sm->_lastRowSearched = -1; @@ -166,7 +176,7 @@ void Paused::handleInput(KsSearchFSM* sm, sm_input_t input) sm->searchRestartVisible(false); if (sm->column() != KsViewModel::TRACE_VIEW_COL_INFO && - sm->column() != KsViewModel::TRACE_VIEW_COL_LAT) + sm->column() != KsViewModel::TRACE_VIEW_COL_AUX) sm->_searchCountLabel.setText(""); sm->changeState(std::shared_ptr(new InProgress)); From patchwork Thu Feb 11 10:31:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082729 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=-20.7 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,MENTIONS_GIT_HOSTING,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, 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 8186BC433E6 for ; Thu, 11 Feb 2021 10:37:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3E22E64E9A for ; Thu, 11 Feb 2021 10:37:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230029AbhBKKgh (ORCPT ); Thu, 11 Feb 2021 05:36:37 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46042 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229919AbhBKKeE (ORCPT ); Thu, 11 Feb 2021 05:34:04 -0500 Received: from mail-ed1-x534.google.com (mail-ed1-x534.google.com [IPv6:2a00:1450:4864:20::534]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7AFF4C061794 for ; Thu, 11 Feb 2021 02:32:30 -0800 (PST) Received: by mail-ed1-x534.google.com with SMTP id y18so6359053edw.13 for ; Thu, 11 Feb 2021 02:32:30 -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=3o4JFJE4ZIhEaleh7g9dxBiNEMdj76Ko5GwKXdRPcms=; b=FHW9wzSMpCeCuWzk0c9BFPxbVpJSliGhICPOi4BRY0p7liSs5fAc29CPtD/78cPe73 98an3tvH7lUBYmUTlgp3O71XClb+CawfBmlJ9T/Ugg7BOHukp4aeWn5zyyMPYBvdflat 31BKf0AiOejQNJ/I8jVWirLGkDmj3z2WJmVLXzpGz3N2MDcpe9E5ObhSS88UJbkajRg8 /m90izL6Q2ZTd2RtbAFfcDZoJhXMRAY32BvhLU02b3z3TP9bnrfgQ9JhPtGsA5jXb09j 39cR3nFq66y8EG4W3BN8u4Q5JUNp2Pd+2+sqG+RJHXVnFw8zoRF/WWHUOMuKwQzubQCY 1kTQ== 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=3o4JFJE4ZIhEaleh7g9dxBiNEMdj76Ko5GwKXdRPcms=; b=Vb43SVrjhW9ltzTCY+h2QSiwzFyZ4N2ZAFLZg05ysbOJ4QFLnL08O73kbc6LPHm0V9 DNrWdmU89ZPK9nk3Xe/cbEZZkS9isoduju5azHEDjl894b51hS88Q+z92GER0AuaijG5 G6ihzCsYIV00t31rprRwwHLChj8FcDkgVqiXwUU0RusEG1yllFMHhZSCmOe+oRuaWuyo ZzGt9SUrs2xU8NMJGOPQOhkPZtYANtAn+Lrp0Q8SMXyYcTlT+O/TzVS5Tl0S5RNwUwdC V8OiTUqFq2LvNVv62GbhyMpDHvnEBYHRErwTrPPt9IAAgPCtkHhtVeAETLFI1IH+GkKr Rt0Q== X-Gm-Message-State: AOAM531qEVKhllxSRLnKC3/EP3k60dt+7rkuz748U681B82kFTLxSn0m zukZ281YDnIcx2OZfjTbyoc= X-Google-Smtp-Source: ABdhPJxQZq3zhQyLVU1vNzyL4NhmnvgRM5CZPY+HgFHEvnYjDbt+SkzBZ2U7EraqYiXiaXDaPl58FQ== X-Received: by 2002:a50:fe11:: with SMTP id f17mr7698951edt.88.1613039549178; Thu, 11 Feb 2021 02:32:29 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:28 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 08/27] kernel-shark: Add trace data files for CI testing Date: Thu, 11 Feb 2021 12:31:46 +0200 Message-Id: <20210211103205.418588-9-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The patch adds a procedure to download two trace data files that will be used by the CI tests. The files are obtained from a dedicated github repository. The tests cases using the trace data files will be added in following patches. Signed-off-by: Yordan Karadzhov (VMware) --- .github/workflows/main.yml | 8 ++++++++ CMakeLists.txt | 3 ++- build/cmake_clean.sh | 1 + tests/CMakeLists.txt | 6 +++++- tests/get_test_data.sh | 21 +++++++++++++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) create mode 100755 tests/get_test_data.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a35f003..2cce624 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,6 +35,7 @@ jobs: make sudo make install sudo make install_libs + - name: Create Build Environment # Some projects don't allow in-source building, so create a separate build directory # We'll use this as our working directory for all subsequent commands @@ -61,3 +62,10 @@ jobs: shell: bash # Execute tests defined by the CMake configuration. run: ctest -C $BUILD_TYPE + + - name: Upload Artifacts + if: ${{ always() }} + uses: actions/upload-artifact@v2 + with: + name: artifacts-download + path: ${{runner.workspace}}/build/Testing/ diff --git a/CMakeLists.txt b/CMakeLists.txt index e013916..26fb7ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,8 +123,9 @@ add_subdirectory(${KS_DIR}/examples) if (Boost_FOUND) + set(KS_TEST_DIR "${KS_DIR}/tests") enable_testing() - add_subdirectory(${KS_DIR}/tests) + add_subdirectory(${KS_TEST_DIR}) endif() diff --git a/build/cmake_clean.sh b/build/cmake_clean.sh index f70b545..b534014 100755 --- a/build/cmake_clean.sh +++ b/build/cmake_clean.sh @@ -9,6 +9,7 @@ rm -rf src/ rm -rf examples/ rm -rf tests/ rm -rf Testing/ +rm -f ../tests/*.dat rm -f ../lib/* rm ../kernelshark.desktop rm ../org.freedesktop.kshark-record.policy diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 17b586e..0847414 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,5 @@ message("\n tests ...") -set(KS_TEST_DIR "${KS_DIR}/tests") set(EXECUTABLE_OUTPUT_PATH ${KS_TEST_DIR}) add_executable(kshark-tests libkshark-tests.cpp) @@ -9,6 +8,11 @@ target_compile_definitions(kshark-tests PRIVATE "BOOST_TEST_DYN_LINK=1") target_link_libraries(kshark-tests kshark-gui ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) +add_test(NAME "get_test_data" + COMMAND ${KS_TEST_DIR}/get_test_data.sh + WORKING_DIRECTORY ${KS_TEST_DIR}) + +message(STATUS "libkshark-tests") add_test(NAME "libkshark_tests" COMMAND ${KS_TEST_DIR}/kshark-tests --log_format=HRF WORKING_DIRECTORY ${KS_TEST_DIR}) diff --git a/tests/get_test_data.sh b/tests/get_test_data.sh new file mode 100755 index 0000000..b935d11 --- /dev/null +++ b/tests/get_test_data.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +TEST_DIR=`dirname $0` +TEST_DATA_DIR=kernel-shark_testdata +TEST_DATA_REPO=https://github.com/yordan-karadzhov/${TEST_DATA_DIR}.git + +rm -fv ${TEST_DIR}/*.dat + +if [ -d "${TEST_DATA_DIR}" ]; then + rm -rf ${TEST_DATA_DIR} +fi + +git clone ${TEST_DATA_REPO} + +if [ ! -d "${TEST_DATA_DIR}" ]; then + exit false +fi + +rm -f ${TEST_DATA_DIR}/LICENSE +cp -v ${TEST_DATA_DIR}/* ${TEST_DIR}/ +rm -rf ${TEST_DATA_DIR} From patchwork Thu Feb 11 10:31:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082721 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.7 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,URIBL_BLOCKED,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 93AD9C43381 for ; Thu, 11 Feb 2021 10:36:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5316B64E9A for ; Thu, 11 Feb 2021 10:36:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229928AbhBKKgK (ORCPT ); Thu, 11 Feb 2021 05:36:10 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46044 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229971AbhBKKeE (ORCPT ); Thu, 11 Feb 2021 05:34:04 -0500 Received: from mail-ed1-x531.google.com (mail-ed1-x531.google.com [IPv6:2a00:1450:4864:20::531]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B4964C061797 for ; Thu, 11 Feb 2021 02:32:31 -0800 (PST) Received: by mail-ed1-x531.google.com with SMTP id l12so6430168edt.3 for ; Thu, 11 Feb 2021 02:32:31 -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=r2Eg+rhQmizGC96oY5Jr30a7ek1kvD8HlbsfC/4YcRI=; b=vesyty2hbhk28L5zexfyk9Mca+87mBiLPxzawVOx5nI9bHle+MfyRwyYS+M7ngSotd egwZfXESZsB5qvsiUFrzuMtnXEAu9sof1GIR/zLqLnVBLaLx8IQYD8RauRe7pmsbwm06 AVE5UVsKWQAla4+dLMApAbq+XgsvXZ+IThslMa1yePNk3zKKZcNyYWN64HGRC7ftClzk 0Mf6XD3xG9tqZEZs7BWcnP6W508UwK1R3PIyi49JRg7oxsiWhoDbLYebUuFiH28GKlId R7GtCpOUbjUNC93eIG4Qqb1Ixnb4ge45NqdltoBWLig69QyLGHHfkh2GnztV3uppb76Z l58w== 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=r2Eg+rhQmizGC96oY5Jr30a7ek1kvD8HlbsfC/4YcRI=; b=PKdIZMnpJfm3G32x8n0A9PyPgmcmsf3/Nad016LZdePPVjJNZwGLVLqO2i1ifjIwNq D3Usv1ggyEfAbiJw3tm23LK5b7KLA3EJq6h5Okb9U2kur/V/ieCTFfJjJPVpQwsh1pTx 7LrNlIyR9Bp1IlNRfeOuh8a/TF8TBghF0L7u6NjB2fypzw5FrFwWLZiw38Rrb2UcbZlx Ahjpfp8pe0RbGIfX+Zt2FFiNtVcYoVF/Ol5hL+Jol/f8RUTGJBNFyQhVFXXEnj7QMOFv C/m9DE5x71nxzYH5L7n2f4pfLqho9ixxhq1HNNE8Ibn8SIUtGvNwDlCbIq77e7jKCACx j7Sg== X-Gm-Message-State: AOAM530313qyqY9O2ZSxpxWudf+TIvzFlj2Tnzrij4SOqL4N4Cl8I5ya SIn2Agno3ymHAZP18X40oEQ= X-Google-Smtp-Source: ABdhPJyLvY/dqaSPa3oI9GGlVXpS8mJhLLZxbl4+ElBRxGSndhOPsQzLUsJod8LO/ioYYDr9tyZXVA== X-Received: by 2002:a50:9dcd:: with SMTP id l13mr7766475edk.220.1613039550229; Thu, 11 Feb 2021 02:32:30 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:29 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 09/27] kernel-shark: Add plugin tests Date: Thu, 11 Feb 2021 12:31:47 +0200 Message-Id: <20210211103205.418588-10-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org We add a number of dummy plugins and we test the plugin-related part of the C API. We also add few simple test cases of the functionalities provided in KSUtils. Signed-off-by: Yordan Karadzhov (VMware) --- CMakeLists.txt | 11 +- build/cmake_clean.sh | 2 +- build/deff.h.cmake | 3 + src/CMakeLists.txt | 4 +- tests/CMakeLists.txt | 34 +++- tests/libkshark-gui-tests.cpp | 227 +++++++++++++++++++++++++ tests/libkshark-tests.cpp | 309 +++++++++++++++++++++++++++++++++- tests/test-input.c | 134 +++++++++++++++ tests/test-input_ctrl.c | 140 +++++++++++++++ tests/test-plugin_dpi.c | 26 +++ tests/test-plugin_dpi_ctrl.c | 32 ++++ tests/test-plugin_dpi_err.c | 26 +++ 12 files changed, 934 insertions(+), 14 deletions(-) create mode 100644 tests/libkshark-gui-tests.cpp create mode 100644 tests/test-input.c create mode 100644 tests/test-input_ctrl.c create mode 100644 tests/test-plugin_dpi.c create mode 100644 tests/test-plugin_dpi_ctrl.c create mode 100644 tests/test-plugin_dpi_err.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 26fb7ae..b9b947e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,10 +144,13 @@ if (_DOXYGEN_DOC AND DOXYGEN_FOUND) endif () -configure_file( ${KS_DIR}/build/ks.desktop.cmake - ${KS_DIR}/${KS_APP_NAME}.desktop) +configure_file(${KS_DIR}/build/deff.h.cmake + ${KS_DIR}/src/KsCmakeDef.hpp) -configure_file( ${KS_DIR}/build/org.freedesktop.kshark-record.policy.cmake - ${KS_DIR}/org.freedesktop.kshark-record.policy) +configure_file(${KS_DIR}/build/ks.desktop.cmake + ${KS_DIR}/${KS_APP_NAME}.desktop) + +configure_file(${KS_DIR}/build/org.freedesktop.kshark-record.policy.cmake + ${KS_DIR}/org.freedesktop.kshark-record.policy) message("") diff --git a/build/cmake_clean.sh b/build/cmake_clean.sh index b534014..2ca1136 100755 --- a/build/cmake_clean.sh +++ b/build/cmake_clean.sh @@ -3,7 +3,7 @@ rm CMakeCache.txt rm cmake_install.cmake rm Makefile rm CTestTestfile.cmake -rm DartConfiguration.tcl +rm -f DartConfiguration.tcl rm -rf CMakeFiles/ rm -rf src/ rm -rf examples/ diff --git a/build/deff.h.cmake b/build/deff.h.cmake index 5584574..423a2fd 100644 --- a/build/deff.h.cmake +++ b/build/deff.h.cmake @@ -29,6 +29,9 @@ /** Qt - old version detected. */ #cmakedefine QT_VERSION_LESS_5_11 +/** Location of the KernelShark tests. */ +#cmakedefine KS_TEST_DIR "@KS_TEST_DIR@" + /** Semicolon-separated list of plugin names. */ #define KS_BUILTIN_PLUGINS "@PLUGINS@" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 21d5b85..b308403 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -137,8 +137,6 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) endif (Qt5Widgets_FOUND AND Qt5Network_FOUND) add_subdirectory(plugins) +set(PLUGINS ${PLUGINS} PARENT_SCOPE) find_program(DO_AS_ROOT pkexec) - -configure_file( ${KS_DIR}/build/deff.h.cmake - ${KS_DIR}/src/KsCmakeDef.hpp) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0847414..28f711b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,18 +1,50 @@ message("\n tests ...") set(EXECUTABLE_OUTPUT_PATH ${KS_TEST_DIR}) +set(LIBRARY_OUTPUT_PATH ${KS_TEST_DIR}) add_executable(kshark-tests libkshark-tests.cpp) target_include_directories(kshark-tests PRIVATE ${Boost_INCLUDE_DIRS}) target_compile_definitions(kshark-tests PRIVATE "BOOST_TEST_DYN_LINK=1") -target_link_libraries(kshark-tests kshark-gui +target_link_libraries(kshark-tests kshark ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) add_test(NAME "get_test_data" COMMAND ${KS_TEST_DIR}/get_test_data.sh WORKING_DIRECTORY ${KS_TEST_DIR}) +add_library(dummy_dpi SHARED test-plugin_dpi.c) +set_target_properties(dummy_dpi PROPERTIES PREFIX "plugin-") +target_link_libraries(dummy_dpi kshark) + +add_library(dummy_dpi_ctrl SHARED test-plugin_dpi_ctrl.c) +set_target_properties(dummy_dpi_ctrl PROPERTIES PREFIX "plugin-") +target_link_libraries(dummy_dpi_ctrl kshark) + +add_library(dummy_dpi_err SHARED test-plugin_dpi_err.c) +set_target_properties(dummy_dpi_err PROPERTIES PREFIX "plugin-") +target_link_libraries(dummy_dpi_err kshark) + +add_library(dummy_input SHARED test-input.c) +set_target_properties(dummy_input PROPERTIES PREFIX "input-") +target_link_libraries(dummy_input kshark) + +add_library(dummy_input_ctrl SHARED test-input_ctrl.c) +set_target_properties(dummy_input_ctrl PROPERTIES PREFIX "input-") +target_link_libraries(dummy_input_ctrl kshark) + message(STATUS "libkshark-tests") add_test(NAME "libkshark_tests" COMMAND ${KS_TEST_DIR}/kshark-tests --log_format=HRF WORKING_DIRECTORY ${KS_TEST_DIR}) + +add_executable(kshark-gui-tests libkshark-gui-tests.cpp) +target_include_directories(kshark-gui-tests PRIVATE ${Boost_INCLUDE_DIRS}) +target_compile_definitions(kshark-gui-tests PRIVATE "BOOST_TEST_DYN_LINK=1") +target_link_libraries(kshark-gui-tests kshark-gui + ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) + +message(STATUS "libkshark-gui_tests") +add_test(NAME "libkshark-gui_tests" + COMMAND ${KS_TEST_DIR}/kshark-gui-tests --log_format=HRF + WORKING_DIRECTORY ${KS_TEST_DIR}) diff --git a/tests/libkshark-gui-tests.cpp b/tests/libkshark-gui-tests.cpp new file mode 100644 index 0000000..de6eb30 --- /dev/null +++ b/tests/libkshark-gui-tests.cpp @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: LGPL-2.1 + +/* + * Copyright (C) 2020 VMware Inc, Yordan Karadzhov (VMware) + */ + +// Boost +#define BOOST_TEST_MODULE KernelSharkTests +#include + +// KernelShark +#include "libkshark.h" +#include "libkshark-plugin.h" +#include "KsUtils.hpp" + +using namespace KsUtils; + +#define N_RECORDS_TEST1 1530 + +BOOST_AUTO_TEST_CASE(KsUtils_datatest) +{ + kshark_context *kshark_ctx{nullptr}; + kshark_entry **data{nullptr}; + std::string file(KS_TEST_DIR); + ssize_t n_rows; + int sd, ss_id; + + BOOST_REQUIRE(kshark_instance(&kshark_ctx)); + file += "/trace_test1.dat"; + sd = kshark_open(kshark_ctx, file.c_str()); + BOOST_CHECK_EQUAL(sd, 0); + + n_rows = kshark_load_entries(kshark_ctx, sd, &data); + BOOST_CHECK_EQUAL(n_rows, N_RECORDS_TEST1); + + auto cpus = getCPUList(sd); + BOOST_CHECK_EQUAL(cpus.size(), 8); + for (int i = 0; i < cpus.size(); ++i) + BOOST_CHECK_EQUAL(cpus[i], i); + + auto pids = getPidList(sd); + BOOST_CHECK_EQUAL(pids.size(), 46); + BOOST_CHECK_EQUAL(pids[0], 0); + for (int i = 1; i < pids.size(); ++i) + BOOST_CHECK(pids[i] > pids[i - 1]); + + auto evts = getEventIdList(sd); + BOOST_CHECK_EQUAL(evts.size(), 40); + BOOST_CHECK_EQUAL(evts[34], 323); + + ss_id = getEventId(sd, "sched/sched_switch"); + BOOST_CHECK_EQUAL(ss_id, 323); + + QString name = getEventName(sd, 323); + BOOST_CHECK(name == QString("sched/sched_switch")); + name = getEventName(sd, 999); + BOOST_CHECK(name == QString("Unknown")); + + auto fields = getEventFieldsList(sd, ss_id); + BOOST_CHECK_EQUAL(fields.size(), 11); + BOOST_CHECK(fields[10] == QString("next_prio")); + + BOOST_CHECK_EQUAL(getEventFieldType(sd, ss_id, "next_prio"), + KS_INTEGER_FIELD); + + BOOST_CHECK_EQUAL(getEventFieldType(sd, ss_id, "next_comm"), + KS_INVALID_FIELD); + + for (ssize_t r = 0; r < n_rows; ++r) + free(data[r]); + free(data); + + kshark_close(kshark_ctx, sd); + kshark_free(kshark_ctx); +} + +BOOST_AUTO_TEST_CASE(KsUtils_setFilterSync) +{ + struct kshark_context *kshark_ctx{nullptr}; + + BOOST_REQUIRE(kshark_instance(&kshark_ctx)); + kshark_ctx->filter_mask = KS_TEXT_VIEW_FILTER_MASK | + KS_GRAPH_VIEW_FILTER_MASK | + KS_EVENT_VIEW_FILTER_MASK; + + BOOST_CHECK_EQUAL(kshark_ctx->filter_mask, 0x7); + + listFilterSync(false); + BOOST_CHECK_EQUAL(kshark_ctx->filter_mask & KS_TEXT_VIEW_FILTER_MASK, 0); + BOOST_CHECK_EQUAL(kshark_ctx->filter_mask & KS_GRAPH_VIEW_FILTER_MASK, + KS_GRAPH_VIEW_FILTER_MASK); + BOOST_CHECK_EQUAL(kshark_ctx->filter_mask & KS_EVENT_VIEW_FILTER_MASK, + KS_EVENT_VIEW_FILTER_MASK); + listFilterSync(true); + BOOST_CHECK_EQUAL(kshark_ctx->filter_mask, 0x7); + + graphFilterSync(false); + BOOST_CHECK_EQUAL(kshark_ctx->filter_mask & KS_TEXT_VIEW_FILTER_MASK, + KS_TEXT_VIEW_FILTER_MASK); + BOOST_CHECK_EQUAL(kshark_ctx->filter_mask & KS_GRAPH_VIEW_FILTER_MASK, 0); + BOOST_CHECK_EQUAL(kshark_ctx->filter_mask & KS_EVENT_VIEW_FILTER_MASK, 0); + graphFilterSync(true); + BOOST_CHECK_EQUAL(kshark_ctx->filter_mask, 0x7); + + kshark_free(kshark_ctx); +} + +BOOST_AUTO_TEST_CASE(KsUtils_parseIds) +{ + QVector ids_test = parseIdList("1,33,4-6,3,55-57"); + QVector ids = {1, 33, 4, 5, 6, 3, 55, 56, 57}; + BOOST_CHECK(ids == ids_test); +} + +#define N_RECORDS_TEST2 73945 +BOOST_AUTO_TEST_CASE(KsUtils_KsDataStore) +{ + int64_t ts_last(0); + KsDataStore data; + int sd; + + BOOST_CHECK_EQUAL(data.size(), 0); + BOOST_CHECK_EQUAL(data.rows(), nullptr); + + sd = data.loadDataFile(QString(KS_TEST_DIR) + "/trace_test1.dat", {}); + BOOST_CHECK_EQUAL(sd, 0); + BOOST_CHECK_EQUAL(data.size(), N_RECORDS_TEST1); + BOOST_CHECK(data.rows() != nullptr); + + sd = data.appendDataFile(QString(KS_TEST_DIR) + "/trace_test2.dat", {}); + BOOST_CHECK_EQUAL(sd, 1); + BOOST_CHECK_EQUAL(data.size(), N_RECORDS_TEST1 + N_RECORDS_TEST2); + + kshark_entry **rows = data.rows(); + for (ssize_t i = 0; i < data.size(); ++i) { + BOOST_CHECK(rows[i]->ts >= ts_last); + ts_last = rows[i]->ts; + } + + data.clear(); + BOOST_CHECK_EQUAL(data.size(), 0); + BOOST_CHECK_EQUAL(data.rows(), nullptr); +} + +BOOST_AUTO_TEST_CASE(KsUtils_getPluginList) +{ + QStringList plugins{"sched_events"}; + + BOOST_CHECK(getPluginList() == plugins); +} + +#define PLUGIN_1_LIB "/plugin-dummy_dpi.so" +#define PLUGIN_2_LIB "/plugin-dummy_dpi_ctrl.so" +#define INPUT_A_LIB "/input-dummy_input.so" + +QString path(KS_TEST_DIR); + +BOOST_AUTO_TEST_CASE(KsUtils_KsPluginManager) +{ + struct kshark_context *kshark_ctx = NULL; + int sd, argc{0}; + QCoreApplication a(argc, nullptr); + + KsPluginManager pm; + pm.registerPlugins(path + INPUT_A_LIB); + + kshark_instance(&kshark_ctx); + BOOST_CHECK_EQUAL(kshark_ctx->n_inputs, 1); + BOOST_CHECK(kshark_ctx->inputs != nullptr); + + sd = kshark_add_stream(kshark_ctx); + BOOST_CHECK_EQUAL(sd, 0); + kshark_ctx->stream[sd]->interface = + malloc(1); + + sd = kshark_add_stream(kshark_ctx); + BOOST_CHECK_EQUAL(sd, 1); + kshark_ctx->stream[sd]->interface = malloc(1); + + pm.registerPluginToStream("sched_events", + getStreamIdList(kshark_ctx)); + + QStringList list = pm.getStreamPluginList(sd); + BOOST_CHECK_EQUAL(list.count(), 1); + BOOST_CHECK(list[0] == "sched_events"); + + QString testPlugins = path + PLUGIN_1_LIB + ","; + testPlugins += path + PLUGIN_2_LIB; + pm.registerPlugins(testPlugins); + auto listTest = pm.getUserPlugins(); + BOOST_CHECK_EQUAL(listTest.count(), 3); + list = pm.getStreamPluginList(sd); + + for (auto const &p: listTest) + pm.registerPluginToStream(p->name, {sd}); + + list = pm.getStreamPluginList(sd); + BOOST_CHECK_EQUAL(list.count(), 3); + + BOOST_CHECK(list == QStringList({"dummy_dpi_ctrl", + "dummy_dpi", + "sched_events"})); + + auto active = pm.getActivePlugins(sd); + BOOST_CHECK(pm.getActivePlugins(sd) == QVector({1, 1, 1})); + + auto enabled = pm.getPluginsByStatus(sd, KSHARK_PLUGIN_ENABLED); + BOOST_CHECK(enabled == QVector({0, 1, 2})); + auto loaded = pm.getPluginsByStatus(sd, KSHARK_PLUGIN_LOADED); + BOOST_CHECK(loaded == QVector({0, 1})); + auto failed = pm.getPluginsByStatus(sd, KSHARK_PLUGIN_FAILED); + BOOST_CHECK(failed == QVector({2})); + + active[1] = 0; + pm.updatePlugins(sd, active); + BOOST_CHECK(active == pm.getActivePlugins(sd)); + + enabled = pm.getPluginsByStatus(sd, KSHARK_PLUGIN_ENABLED); + BOOST_CHECK(enabled == QVector({0, 2})); + loaded = pm.getPluginsByStatus(sd, KSHARK_PLUGIN_LOADED); + BOOST_CHECK(loaded == QVector({0})); + failed = pm.getPluginsByStatus(sd, KSHARK_PLUGIN_FAILED); + BOOST_CHECK(failed == QVector({2})); + + kshark_free(kshark_ctx); + a.exit(); +} diff --git a/tests/libkshark-tests.cpp b/tests/libkshark-tests.cpp index eb5cb1f..a22c1e5 100644 --- a/tests/libkshark-tests.cpp +++ b/tests/libkshark-tests.cpp @@ -11,6 +11,7 @@ // KernelShark #include "libkshark.h" #include "libkshark-plugin.h" +#include "KsCmakeDef.hpp" #define N_TEST_STREAMS 1000 @@ -19,7 +20,7 @@ BOOST_AUTO_TEST_CASE(add_remove_streams) struct kshark_context *kshark_ctx = NULL; int sd, free = 0, i; - kshark_instance(&kshark_ctx); + BOOST_REQUIRE(kshark_instance(&kshark_ctx)); for (i = 0; i < N_TEST_STREAMS; ++i) { sd = kshark_add_stream(kshark_ctx); @@ -45,10 +46,46 @@ BOOST_AUTO_TEST_CASE(add_remove_streams) BOOST_CHECK_EQUAL(kshark_ctx->stream_info.array_size, INT16_MAX + 1); BOOST_CHECK_EQUAL(sd, -ENODEV); - kshark_close_all(kshark_ctx); kshark_free(kshark_ctx); } +BOOST_AUTO_TEST_CASE(get_stream) +{ + kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; + int sd; + + BOOST_REQUIRE(kshark_instance(&kshark_ctx)); + sd = kshark_add_stream(kshark_ctx); + stream = kshark_get_data_stream(kshark_ctx, sd); + BOOST_CHECK_EQUAL(stream, nullptr); + + kshark_ctx->stream[sd]->interface = malloc(1); + stream = kshark_get_data_stream(kshark_ctx, sd); + BOOST_CHECK(stream != nullptr); + + kshark_free(kshark_ctx); +} + +BOOST_AUTO_TEST_CASE(close_all) +{ + struct kshark_context *kshark_ctx(nullptr); + int sd, i; + + BOOST_REQUIRE(kshark_instance(&kshark_ctx)); + for (i = 0; i < N_TEST_STREAMS; ++i) { + sd = kshark_add_stream(kshark_ctx); + BOOST_CHECK_EQUAL(sd, i); + } + + kshark_close_all(kshark_ctx); + BOOST_CHECK_EQUAL(kshark_ctx->n_streams, 0); + BOOST_CHECK_EQUAL(kshark_ctx->stream_info.next_free_stream_id, 0); + BOOST_CHECK_EQUAL(kshark_ctx->stream_info.max_stream_id, -1); + for (i = 0; i < kshark_ctx->stream_info.array_size; ++i) + BOOST_CHECK_EQUAL(kshark_ctx->stream[i], nullptr); +} + #define ARRAY_DEFAULT_SIZE 1000 BOOST_AUTO_TEST_CASE(doule_size_macro) { @@ -90,7 +127,7 @@ BOOST_AUTO_TEST_CASE(fill_data_container) 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(data->data[i]->entry->ts >= ts_last); BOOST_CHECK_EQUAL(data->data[i]->entry->ts, 10 - data->data[i]->field); @@ -100,8 +137,8 @@ BOOST_AUTO_TEST_CASE(fill_data_container) 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); + BOOST_CHECK(data->data[i - 1]->entry->ts < MAX_TS / 2); + BOOST_CHECK(data->data[i]->entry->ts >= MAX_TS / 2); kshark_free_data_container(data); } @@ -136,3 +173,265 @@ BOOST_AUTO_TEST_CASE(init_close_plugin) __close(-1); } + +#define PLUGIN_1_LIB "/plugin-dummy_dpi.so" +#define PLUGIN_1_NAME "dummy_dpi" + +#define PLUGIN_2_LIB "/plugin-dummy_dpi_ctrl.so" +#define PLUGIN_2_NAME "dummy_dpi_ctrl" + +#define INPUT_A_LIB "/input-dummy_input.so" +#define INPUT_A_NAME "dummy_input" + +#define INPUT_B_LIB "/input-dummy_input_ctrl.so" +#define INPUT_B_NAME "dummy_input_ctrl" + +std::string path(KS_TEST_DIR); + +BOOST_AUTO_TEST_CASE(register_plugin) +{ + kshark_plugin_list *p1, *p2, *i1, *i2, *x1, *x2; + kshark_generic_stream_interface *interface; + kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; + std::string plugin; + int sd; + + BOOST_REQUIRE(kshark_instance(&kshark_ctx)); + BOOST_REQUIRE(kshark_ctx->plugins == nullptr); + BOOST_REQUIRE(kshark_ctx->inputs == nullptr); + BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 0); + + plugin = path + PLUGIN_1_LIB; + p1 = kshark_register_plugin(kshark_ctx, PLUGIN_1_NAME, plugin.c_str()); + BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 1); + BOOST_CHECK(kshark_ctx->plugins != nullptr); + BOOST_CHECK_EQUAL(kshark_ctx->plugins->next, nullptr); + BOOST_CHECK_EQUAL(kshark_ctx->plugins, p1); + BOOST_CHECK(p1 != nullptr); + BOOST_CHECK(p1->process_interface != nullptr); + BOOST_CHECK(p1->handle != nullptr); + BOOST_CHECK_EQUAL(strcmp(p1->file, plugin.c_str()), 0); + BOOST_CHECK_EQUAL(strcmp(p1->name, PLUGIN_1_NAME), 0); + + BOOST_CHECK_EQUAL(p1->ctrl_interface, nullptr); + BOOST_CHECK_EQUAL(p1->readout_interface, nullptr); + + plugin = path + PLUGIN_2_LIB; + p2 = kshark_register_plugin(kshark_ctx, PLUGIN_2_NAME, plugin.c_str()); + BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 2); + BOOST_CHECK_EQUAL(kshark_ctx->plugins, p2); + BOOST_CHECK_EQUAL(kshark_ctx->plugins->next, p1); + BOOST_CHECK(p2 != nullptr); + BOOST_CHECK(p2->process_interface != nullptr); + BOOST_CHECK(p2->handle != nullptr); + BOOST_CHECK_EQUAL(strcmp(p2->file, plugin.c_str()), 0); + BOOST_CHECK_EQUAL(strcmp(p2->name, PLUGIN_2_NAME), 0); + BOOST_CHECK(p2->ctrl_interface != nullptr); + + BOOST_CHECK_EQUAL(p2->readout_interface, nullptr); + + plugin = path + INPUT_A_LIB; + i1 = kshark_register_plugin(kshark_ctx, INPUT_A_NAME, plugin.c_str()); + BOOST_CHECK(i1 != nullptr); + BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 3); + BOOST_CHECK_EQUAL(kshark_ctx->n_inputs, 1); + BOOST_CHECK(kshark_ctx->inputs != nullptr); + BOOST_CHECK(i1->readout_interface != nullptr); + BOOST_CHECK(i1->handle != nullptr); + BOOST_CHECK_EQUAL(strcmp(i1->file, plugin.c_str()), 0); + BOOST_CHECK_EQUAL(strcmp(i1->name, INPUT_A_NAME), 0); + + BOOST_CHECK_EQUAL(i1->ctrl_interface, nullptr); + BOOST_CHECK_EQUAL(i1->process_interface, nullptr); + + plugin = path + INPUT_B_LIB; + i2 = kshark_register_plugin(kshark_ctx, INPUT_B_NAME, plugin.c_str()); + BOOST_CHECK(i2 != nullptr); + BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 4); + BOOST_CHECK_EQUAL(kshark_ctx->n_inputs, 2); + BOOST_CHECK(i2->readout_interface != nullptr); + BOOST_CHECK(i2->handle != nullptr); + BOOST_CHECK(strcmp(i2->file, plugin.c_str()) == 0); + BOOST_CHECK(strcmp(i2->name, INPUT_B_NAME) == 0); + BOOST_CHECK(i2->ctrl_interface != nullptr); + + BOOST_CHECK_EQUAL(i2->process_interface, nullptr); + + x1 = kshark_find_plugin_by_name(kshark_ctx->plugins, PLUGIN_2_NAME); + BOOST_CHECK_EQUAL(x1, p2); + + plugin = path + PLUGIN_2_LIB; + x2 = kshark_find_plugin(kshark_ctx->plugins, plugin.c_str()); + + BOOST_CHECK_EQUAL(x2, p2); + + sd = kshark_add_stream(kshark_ctx); + interface = + (kshark_generic_stream_interface *) malloc(sizeof(*interface)); + kshark_ctx->stream[sd]->interface = interface; + BOOST_CHECK_EQUAL(sd, 0); + + stream = kshark_get_data_stream(kshark_ctx, sd); + BOOST_CHECK(stream != nullptr); + + BOOST_CHECK_EQUAL(stream->plugins, nullptr); + kshark_register_plugin_to_stream(stream, + p1->process_interface, + true); + BOOST_CHECK_EQUAL(stream->n_plugins, 1); + BOOST_CHECK_EQUAL(stream->plugins->interface, p1->process_interface); + BOOST_CHECK_EQUAL(stream->plugins->next, nullptr); + + kshark_register_plugin_to_stream(stream, + p2->process_interface, + true); + BOOST_CHECK_EQUAL(stream->n_plugins, 2); + BOOST_CHECK_EQUAL(stream->plugins->interface, p2->process_interface); + BOOST_CHECK_EQUAL(stream->plugins->next->interface, p1->process_interface); + + kshark_unregister_plugin_from_stream(stream, p1->process_interface); + BOOST_CHECK_EQUAL(stream->n_plugins, 1); + BOOST_CHECK_EQUAL(stream->plugins->interface, p2->process_interface); + BOOST_CHECK_EQUAL(stream->plugins->next, nullptr); + + kshark_free(kshark_ctx); +} + +#define PLUGIN_ERR_LIB "/plugin-dummy_dpi_err.so" +#define PLUGIN_ERR_NAME "dummy_dpi_err" + +BOOST_AUTO_TEST_CASE(handle_plugin) +{ + kshark_dpi_list *dpi1, *dpi2, *dpi_err; + kshark_plugin_list *p1, *p2, *p_err; + kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; + std::string plugin; + int sd, ret; + + BOOST_REQUIRE(kshark_instance(&kshark_ctx)); + BOOST_CHECK_EQUAL(kshark_ctx->plugins, nullptr); + BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 0); + + plugin = path + PLUGIN_1_LIB; + p1 = kshark_register_plugin(kshark_ctx, PLUGIN_1_NAME, plugin.c_str()); + + plugin = path + PLUGIN_2_LIB; + p2 = kshark_register_plugin(kshark_ctx, PLUGIN_2_NAME, plugin.c_str()); + BOOST_CHECK(kshark_ctx->plugins != nullptr); + BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 2); + + sd = kshark_add_stream(kshark_ctx); + kshark_ctx->stream[sd]->interface = malloc(1); + stream = kshark_get_data_stream(kshark_ctx, sd); + BOOST_CHECK(stream != nullptr); + + dpi1 = kshark_register_plugin_to_stream(stream, + p1->process_interface, + true); + BOOST_CHECK_EQUAL(dpi1->status, KSHARK_PLUGIN_ENABLED); + + dpi2 = kshark_register_plugin_to_stream(stream, + p2->process_interface, + false); + BOOST_CHECK_EQUAL(dpi2->status, 0); + + ret = kshark_handle_dpi(stream, dpi1, KSHARK_PLUGIN_INIT); + BOOST_CHECK_EQUAL(ret, 1); + BOOST_CHECK_EQUAL(dpi1->status, + KSHARK_PLUGIN_LOADED | KSHARK_PLUGIN_ENABLED); + + ret = kshark_handle_dpi(stream, dpi2, KSHARK_PLUGIN_INIT); + BOOST_CHECK_EQUAL(ret, 0); + BOOST_CHECK_EQUAL(dpi2->status, 0); + + dpi2->status |= KSHARK_PLUGIN_ENABLED; + ret = kshark_handle_dpi(stream, dpi2, KSHARK_PLUGIN_INIT); + BOOST_CHECK_EQUAL(ret, 2); + BOOST_CHECK_EQUAL(dpi1->status, + KSHARK_PLUGIN_LOADED | KSHARK_PLUGIN_ENABLED); + + ret = kshark_handle_all_dpis(stream, KSHARK_PLUGIN_UPDATE); + BOOST_CHECK_EQUAL(ret, 0); + BOOST_CHECK_EQUAL(dpi1->status, + KSHARK_PLUGIN_LOADED | KSHARK_PLUGIN_ENABLED); + BOOST_CHECK_EQUAL(dpi2->status, + KSHARK_PLUGIN_LOADED | KSHARK_PLUGIN_ENABLED); + + plugin = path + PLUGIN_ERR_LIB; + p_err = kshark_register_plugin(kshark_ctx, PLUGIN_ERR_NAME, + plugin.c_str()); + BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 3); + dpi_err = kshark_register_plugin_to_stream(stream, + p_err->process_interface, + true); + BOOST_CHECK_EQUAL(ret, 0); + ret = kshark_handle_dpi(stream, dpi_err, KSHARK_PLUGIN_INIT); + BOOST_CHECK_EQUAL(dpi_err->status, + KSHARK_PLUGIN_FAILED | KSHARK_PLUGIN_ENABLED); + BOOST_CHECK_EQUAL(ret, 0); + ret = kshark_handle_dpi(stream, dpi_err, KSHARK_PLUGIN_CLOSE); + BOOST_CHECK_EQUAL(ret, 0); + BOOST_CHECK_EQUAL(dpi_err->status, KSHARK_PLUGIN_ENABLED); + + ret = kshark_handle_all_dpis(stream, KSHARK_PLUGIN_CLOSE); + BOOST_CHECK_EQUAL(ret, -3); + + kshark_free(kshark_ctx); +} + +#define FAKE_DATA_FILE_A "test.ta" +#define FAKE_DATA_A_SIZE 200 + +#define FAKE_DATA_FILE_B "test.tb" +#define FAKE_DATA_B_SIZE 100 + +BOOST_AUTO_TEST_CASE(readout_plugins) +{ + kshark_context *kshark_ctx(nullptr); + kshark_entry **entries{nullptr}; + kshark_data_stream *stream; + std::string plugin, data; + int sd, i, n_entries; + int64_t ts_last(0); + + BOOST_REQUIRE(kshark_instance(&kshark_ctx)); + + plugin = path + INPUT_A_LIB; + kshark_register_plugin(kshark_ctx, INPUT_A_NAME, plugin.c_str()); + plugin = path + INPUT_B_LIB; + kshark_register_plugin(kshark_ctx, INPUT_B_NAME, plugin.c_str()); + + data = FAKE_DATA_FILE_A; + sd = kshark_open(kshark_ctx, data.c_str()); + BOOST_CHECK_EQUAL(sd, 0); + + stream = kshark_get_data_stream(kshark_ctx, sd); + BOOST_CHECK(stream != nullptr); + BOOST_CHECK(stream->interface != nullptr); + BOOST_CHECK_EQUAL(strcmp(stream->data_format, "format_a"), 0); + + data = FAKE_DATA_FILE_B; + sd = kshark_open(kshark_ctx, data.c_str()); + BOOST_CHECK_EQUAL(sd, 1); + + stream = kshark_get_data_stream(kshark_ctx, sd); + BOOST_CHECK(stream != nullptr); + BOOST_CHECK(stream->interface != nullptr); + BOOST_CHECK_EQUAL(strcmp(stream->data_format, "format_b"), 0); + + n_entries = kshark_load_all_entries(kshark_ctx, &entries); + BOOST_CHECK_EQUAL(n_entries, FAKE_DATA_A_SIZE + FAKE_DATA_B_SIZE); + + for (i = 0; i < n_entries; ++i) { + BOOST_CHECK(ts_last <= entries[i]->ts); + ts_last = entries[i]->ts; + } + + for (i = 0; i < n_entries; ++i) + free(entries[i]); + free(entries); + + kshark_free(kshark_ctx); +} diff --git a/tests/test-input.c b/tests/test-input.c new file mode 100644 index 0000000..31620b9 --- /dev/null +++ b/tests/test-input.c @@ -0,0 +1,134 @@ + +// C +#ifndef _GNU_SOURCE +/** Use GNU C Library. */ +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#include +#include +#include +#include + +// KernelShark +#include "libkshark.h" +#include "libkshark-plugin.h" + +static ssize_t load_entries(struct kshark_data_stream *stream, + struct kshark_context *kshark_ctx, + struct kshark_entry ***data_rows) +{ + struct kshark_entry **rows; + ssize_t total = 200, i; + + rows = calloc(total, sizeof(struct kshark_entry *)); + for (i = 0; i < total; ++i) { + rows[i] = calloc(1, sizeof(struct kshark_entry)); + rows[i]->ts = 1000000 + i * 10000; + rows[i]->stream_id = stream->stream_id; + rows[i]->event_id = i % 5; + rows[i]->pid = 10 + i % 2; + rows[i]->cpu = i % 2; + rows[i]->visible = 0xff; + } + + *data_rows = rows; + return total; +} + +static char *dump_entry(struct kshark_data_stream *stream, + const struct kshark_entry *entry) +{ + char *entry_str; + int ret; + + ret = asprintf(&entry_str, "e: time=%li evt=%i s_id=%i", entry->ts, + entry->event_id, + entry->stream_id); + + if (ret <= 0) + return NULL; + + return entry_str; +} + +static const char *format_name = "format_a"; + +const char *KSHARK_INPUT_FORMAT() +{ + return format_name; +} + +bool KSHARK_INPUT_CHECK(const char *file, char **format) +{ + char *ext = strrchr(file, '.'); + + if (ext && strcmp(ext, ".ta") == 0) + return true; + + return false; +} + +static const int get_pid(struct kshark_data_stream *stream, + const struct kshark_entry *entry) +{ + return entry->pid; +} + +static char *get_task(struct kshark_data_stream *stream, + const struct kshark_entry *entry) +{ + char *entry_str; + int ret; + + ret = asprintf(&entry_str, "test_a/test"); + + if (ret <= 0) + return NULL; + + return entry_str; +} + +static char *get_event_name(struct kshark_data_stream *stream, + const struct kshark_entry *entry) +{ + char *evt_str; + int ret; + + ret = asprintf(&evt_str, "test_a/event-%i", entry->event_id); + + if (ret <= 0) + return NULL; + + return evt_str; +} + +int KSHARK_INPUT_INITIALIZER(struct kshark_data_stream *stream) +{ + struct kshark_generic_stream_interface *interface; + + stream->interface = interface = calloc(1, sizeof(*interface)); + if (!interface) + return -ENOMEM; + + interface->type = KS_GENERIC_DATA_INTERFACE; + + stream->n_cpus = 2; + stream->n_events = 5; + stream->idle_pid = 0; + + kshark_hash_id_add(stream->tasks, 10); + kshark_hash_id_add(stream->tasks, 11); + + interface->get_pid = get_pid; + interface->get_task = get_task; + interface->get_event_name = get_event_name; + + interface->dump_entry = dump_entry; + interface->load_entries = load_entries; + + return 0; +} + +void KSHARK_INPUT_DEINITIALIZER(struct kshark_data_stream *stream) +{} diff --git a/tests/test-input_ctrl.c b/tests/test-input_ctrl.c new file mode 100644 index 0000000..3dcc92e --- /dev/null +++ b/tests/test-input_ctrl.c @@ -0,0 +1,140 @@ + +// C +#ifndef _GNU_SOURCE +/** Use GNU C Library. */ +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#include +#include +#include +#include + +// KernelShark +#include "libkshark.h" +#include "libkshark-plugin.h" + +static ssize_t load_entries(struct kshark_data_stream *stream, + struct kshark_context *kshark_ctx, + struct kshark_entry ***data_rows) +{ + struct kshark_entry **rows; + ssize_t total = 100, i; + + rows = calloc(total, sizeof(struct kshark_entry *)); + for (i = 0; i < total; ++i) { + rows[i] = calloc(1, sizeof(struct kshark_entry)); + rows[i]->ts = 1000 + i * 15000; + rows[i]->stream_id = stream->stream_id; + rows[i]->event_id = i % 3; + rows[i]->pid = 20; + rows[i]->visible = 0xff; + } + + rows[i-1]->pid = 0; + + *data_rows = rows; + return total; +} + +static char *dump_entry(struct kshark_data_stream *stream, + const struct kshark_entry *entry) +{ + char *entry_str; + int ret; + + ret = asprintf(&entry_str, "e: time=%li evt=%i s_id=%i", entry->ts, + entry->event_id, + entry->stream_id); + + if (ret <= 0) + return NULL; + + return entry_str; +} + +static const char *format_name = "format_b"; +// static const char *format_name = "tep data"; + +const char *KSHARK_INPUT_FORMAT() +{ + return format_name; +} + +bool KSHARK_INPUT_CHECK(const char *file, char **format) +{ + char *ext = strrchr(file, '.'); + + if (ext && strcmp(ext, ".tb") == 0) + return true; + + return false; +} + +static const int get_pid(struct kshark_data_stream *stream, + const struct kshark_entry *entry) +{ + return entry->pid; +} + +static char *get_task(struct kshark_data_stream *stream, + const struct kshark_entry *entry) +{ + char *entry_str; + int ret; + + ret = asprintf(&entry_str, "test_b/test"); + + if (ret <= 0) + return NULL; + + return entry_str; +} + +static char *get_event_name(struct kshark_data_stream *stream, + const struct kshark_entry *entry) +{ + char *evt_str; + int ret; + + ret = asprintf(&evt_str, "test_b/event-%i", entry->event_id); + + if (ret <= 0) + return NULL; + + return evt_str; +} + +int KSHARK_INPUT_INITIALIZER(struct kshark_data_stream *stream) +{ + struct kshark_generic_stream_interface *interface; + + stream->interface = interface = calloc(1, sizeof(*interface)); + if (!interface) + return -ENOMEM; + + interface->type = KS_GENERIC_DATA_INTERFACE; + + stream->n_cpus = 1; + stream->n_events = 3; + stream->idle_pid = 0; + + kshark_hash_id_add(stream->tasks, 20); + + interface->get_pid = get_pid; + interface->get_task = get_task; + interface->get_event_name = get_event_name; + interface->dump_entry = dump_entry; + interface->load_entries = load_entries; + + return 0; +} + +void KSHARK_INPUT_DEINITIALIZER(struct kshark_data_stream *stream) +{} + +/** Initialize the control interface of the plugin. */ +void *KSHARK_MENU_PLUGIN_INITIALIZER(void *ptr) +{ + return NULL; +} diff --git a/tests/test-plugin_dpi.c b/tests/test-plugin_dpi.c new file mode 100644 index 0000000..82f94f3 --- /dev/null +++ b/tests/test-plugin_dpi.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: LGPL-2.1 + +/* + * Copyright (C) 2021 VMware Inc, Yordan Karadzhov + */ + +// C +#include + +// KernelShark +#include "libkshark.h" +#include "libkshark-plugin.h" + +/** Load this plugin. */ +int KSHARK_PLOT_PLUGIN_INITIALIZER(struct kshark_data_stream *stream) +{ + printf("--> plugin1\n"); + return 1; +} + +/** Unload this plugin. */ +int KSHARK_PLOT_PLUGIN_DEINITIALIZER(struct kshark_data_stream *stream) +{ + printf("<-- plugin1\n"); + return 1; +} diff --git a/tests/test-plugin_dpi_ctrl.c b/tests/test-plugin_dpi_ctrl.c new file mode 100644 index 0000000..5fafd1d --- /dev/null +++ b/tests/test-plugin_dpi_ctrl.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: LGPL-2.1 + +/* + * Copyright (C) 2021 VMware Inc, Yordan Karadzhov + */ + +// C +#include + +// KernelShark +#include "libkshark.h" +#include "libkshark-plugin.h" + +/** Load this plugin. */ +int KSHARK_PLOT_PLUGIN_INITIALIZER(struct kshark_data_stream *stream) +{ + printf("--> plugin2\n"); + return 2; +} + +/** Unload this plugin. */ +int KSHARK_PLOT_PLUGIN_DEINITIALIZER(struct kshark_data_stream *stream) +{ + printf("<-- plugin2\n"); + return 2; +} + +/** Initialize the control interface of the plugin. */ +void *KSHARK_MENU_PLUGIN_INITIALIZER(void *ptr) +{ + return NULL; +} diff --git a/tests/test-plugin_dpi_err.c b/tests/test-plugin_dpi_err.c new file mode 100644 index 0000000..4148930 --- /dev/null +++ b/tests/test-plugin_dpi_err.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: LGPL-2.1 + +/* + * Copyright (C) 2021 VMware Inc, Yordan Karadzhov + */ + +// C +#include + +// KernelShark +#include "libkshark.h" +#include "libkshark-plugin.h" + +/** Load this plugin. */ +int KSHARK_PLOT_PLUGIN_INITIALIZER(struct kshark_data_stream *stream) +{ + printf("--> plugin_err\n"); + return 0; +} + +/** Unload this plugin. */ +int KSHARK_PLOT_PLUGIN_DEINITIALIZER(struct kshark_data_stream *stream) +{ + printf("<-- plugin_err\n"); + return 0; +} From patchwork Thu Feb 11 10:31:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082735 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.7 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 23F43C433DB for ; Thu, 11 Feb 2021 10:38:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E5EAE64E9C for ; Thu, 11 Feb 2021 10:38:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229763AbhBKKiK (ORCPT ); Thu, 11 Feb 2021 05:38:10 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46394 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230116AbhBKKfo (ORCPT ); Thu, 11 Feb 2021 05:35:44 -0500 Received: from mail-ed1-x52a.google.com (mail-ed1-x52a.google.com [IPv6:2a00:1450:4864:20::52a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 47132C0617A7 for ; Thu, 11 Feb 2021 02:32:32 -0800 (PST) Received: by mail-ed1-x52a.google.com with SMTP id y18so6359136edw.13 for ; Thu, 11 Feb 2021 02:32:32 -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=93Pyq9e2J5uu8aZ1e9+b7X1+knvIcOeiDFz4tedcvkY=; b=ZI7eWK6g9NzlZ2tNjfViXePtzeCGeTpLNCxMepVUCarYTItCypx/DPMHsKxHiXZnp2 47IpuhkI75n+mHXjkcCrrJSWD9Y3N5xDfjmOkXvIPfP/FIbJtRl27NlxFhpqd7a1CVfC z/4Q/LbSJqXgi/40TzMpXhcP49VcRnGB26x2BM/VIfDNwYgmahRNf5LIij3289QzwbRd 3n8eqIzRGo2cq04nI+xOsLVUUhoeLjJFlBk6S2oORB7UQAShx9r3ufzaNzSjaGC1gkK1 q5av9t0yvACf3fbQJArhK5OR11bIVQfk+7FQlt7sydCZVizYoRt2IR78om/yYvZ8iZTi q/Iw== 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=93Pyq9e2J5uu8aZ1e9+b7X1+knvIcOeiDFz4tedcvkY=; b=mpZ2HAMw2L7q/v2I7hccpxDyLIJF6/A/c6sNqJiDV8fepYc/ADcx8/QTPg7LAxfE9C oulCXptQBsaj1MqoM6jziM/u1ixr4J1CiCu1MbkXokx38/wi6ELcPcFOzNtMxElYhLZL q4ETId8nFf7mmUCDKJLedTUMjrza+eIOmosvv3upa7N1FL12PVzbxZXr30puKvkR8c83 URbqCg7I3PsLt5ynCs9myoyBe5hEawQCDKNh69a7WfbX1/s99/ZkhLkJq8AvO8a3eXyV TPhktwh2NhScvdc72p39pIieNIzW9CoqFS2+miE6ZL3j53e5D4RdKtHYOAlURLsVbcg0 V7JQ== X-Gm-Message-State: AOAM530eqXfI9I5XO5S+2fehdBUlhqodms4+mLnRpAtfGlsSVf12RumA Pcm3RLQEeTRhwjpHUb4Ak1ix5Q1MtNU= X-Google-Smtp-Source: ABdhPJxV/FnAZiYkJz+Nd/Iq+SNesvsQD36gVJRQNKYW5DuZvFsEsSPhxPDpNY0obtJd8WawWWioZw== X-Received: by 2002:a05:6402:6cc:: with SMTP id n12mr7869034edy.69.1613039551097; Thu, 11 Feb 2021 02:32:31 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:30 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 10/27] kernel-shark: Add model tests Date: Thu, 11 Feb 2021 12:31:48 +0200 Message-Id: <20210211103205.418588-11-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org We add few simple test cases of the KsModel functionalities. Signed-off-by: Yordan Karadzhov (VMware) --- tests/libkshark-gui-tests.cpp | 59 +++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tests/libkshark-gui-tests.cpp b/tests/libkshark-gui-tests.cpp index de6eb30..dedd69f 100644 --- a/tests/libkshark-gui-tests.cpp +++ b/tests/libkshark-gui-tests.cpp @@ -12,6 +12,8 @@ #include "libkshark.h" #include "libkshark-plugin.h" #include "KsUtils.hpp" +#include "KsModels.hpp" + using namespace KsUtils; @@ -225,3 +227,60 @@ BOOST_AUTO_TEST_CASE(KsUtils_KsPluginManager) kshark_free(kshark_ctx); a.exit(); } + +BOOST_AUTO_TEST_CASE(ViewModel) +{ + QStringList header{"#", "CPU", "Time Stamp", "Task", "PID", "Latency", "Event", "Info"}; + struct kshark_context *kshark_ctx(nullptr); + KsViewModel model; + KsDataStore data; + + data.loadDataFile(QString(KS_TEST_DIR) + "/trace_test1.dat", {}); + model.fill(&data); + BOOST_CHECK_EQUAL(model.rowCount({}), N_RECORDS_TEST1); + BOOST_CHECK_EQUAL(model.columnCount({}), 8); + BOOST_CHECK_EQUAL(model.singleStream(), true); + BOOST_CHECK(model.header() == header); + + data.appendDataFile(QString(KS_TEST_DIR) + "/trace_test2.dat", {}); + BOOST_REQUIRE(kshark_instance(&kshark_ctx)); + BOOST_CHECK(getStreamIdList(kshark_ctx) == QVector({0, 1})); + + model.update(&data); + header = QStringList{" >> "} + header; + + BOOST_CHECK_EQUAL(model.rowCount({}), N_RECORDS_TEST1 + N_RECORDS_TEST2); + BOOST_CHECK_EQUAL(model.columnCount({}), 9); + BOOST_CHECK_EQUAL(model.singleStream(), false); + BOOST_CHECK(model.header() == header); + + BOOST_CHECK(model.getValueStr(0, 0) == "1"); + BOOST_CHECK(model.getValueStr(4, 1) == "trace-cmd"); + BOOST_CHECK(model.getValueStr(5, 2) == "29474"); + BOOST_CHECK(model.getValueStr(7, 2) == "sched/sched_switch"); + + BOOST_CHECK(model.getValueStr(0, N_RECORDS_TEST1 + N_RECORDS_TEST2 - 1) == "0"); + BOOST_CHECK(model.getValueStr(4, N_RECORDS_TEST1 + N_RECORDS_TEST2 - 1) == ""); + + model.reset(); + BOOST_CHECK_EQUAL(model.rowCount({}), 0); +} + +BOOST_AUTO_TEST_CASE(GraphModel) +{ + struct kshark_context *kshark_ctx(nullptr); + KsGraphModel model; + KsDataStore data; + + data.loadDataFile(QString(KS_TEST_DIR) + "/trace_test1.dat", {}); + BOOST_REQUIRE(kshark_instance(&kshark_ctx)); + BOOST_CHECK(getStreamIdList(kshark_ctx) == QVector({0})); + + model.fill(&data); + BOOST_CHECK_EQUAL(model.rowCount({}), KS_DEFAULT_NBUNS); + BOOST_CHECK(abs(model.histo()->min - data.rows()[0]->ts) < model.histo()->bin_size); + BOOST_CHECK(abs(model.histo()->max - data.rows()[N_RECORDS_TEST1 - 1]->ts) < model.histo()->bin_size); + + model.reset(); + BOOST_CHECK_EQUAL(model.rowCount({}), 0); +} From patchwork Thu Feb 11 10:31:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082737 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.7 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 A98C2C433E0 for ; Thu, 11 Feb 2021 10:38:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 55C7864E95 for ; Thu, 11 Feb 2021 10:38:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230258AbhBKKiR (ORCPT ); Thu, 11 Feb 2021 05:38:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46396 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230127AbhBKKfo (ORCPT ); Thu, 11 Feb 2021 05:35:44 -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 DF8ECC0617A9 for ; Thu, 11 Feb 2021 02:32:33 -0800 (PST) Received: by mail-ej1-x634.google.com with SMTP id w2so9207902ejk.13 for ; Thu, 11 Feb 2021 02:32:33 -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=aRGPnmVJ3x74ujs38CBBI0OlHVGEWkX91q8T7fnnn+E=; b=G01/ygWrJ5/wcqZGwJNwPpAeg+lidVdttijQBZQ+hVTWUfGAr9kb+pkifpYLA/TG3d R2YaJvdh5BZFCrJT6An0iegfU88E6JgYpdwrMFS7jAZ4PzmMPPBsP4kEpcLdzsIDfycG 5o12YQrHm88OGWmv2OGYreIcg0qtPDpmlXlf/HjDo65JnaKQmX5O77ygv873NCkszpGO TwDemh8L5gUAdT6nsij05jf+mirHndpVs3Tkyv0ONSdanzw2Tmn13hjxwOof4GI0Yc94 w+YLhGlLaF1iVDDnqcFUEFQMGGw3WwZIQuOTNO7HojKtZTn4faDWGa4XaP/ilruuEnQK pCZw== 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=aRGPnmVJ3x74ujs38CBBI0OlHVGEWkX91q8T7fnnn+E=; b=q1Cxzjc9pEviXlzHRdBX0ucmNH4gOJZhmgID6SuBSrG14MfTvoswrMuVgoxKGlZSxu DKZCusQRhy1rnc3yaSsWyKyHLvfIWXzByfzPFYi3lg/n+xFcOsMvtYnbZdq3hWzt0+u4 NDQSQc4PfEcL2YfLV61rLxfdm16kOF6YH1K4HLyM6h0lNXlnxbLEBhhHbM3Dz34DctDb rF8q394QEIhYar8ZWsuE/7UQosuMtiTNvrBQASzGJHZyg0WTtCO0qvtnjdqhmXIEnQOO nd8eJZGP9ZxPnNJtN55bveHBb9cPc8GzOOJd4w/5KA54WWwTXvO5mq1ayOHuM6JZyxgk GEgg== X-Gm-Message-State: AOAM533sX3VfTkldDqBw2ZfWT2aabqt5mi3zMvkDT4WQXE+ekBZZvLCF Jr5TA8Ldccn6GWr/tigi0rw= X-Google-Smtp-Source: ABdhPJwpJb2nMsQ1kkrLY00KDTku8Z6ayYcxwaaKpXzFtOV5+qSpn422Szo3nknHft1k7bEJuFoAPA== X-Received: by 2002:a17:906:2293:: with SMTP id p19mr7748099eja.206.1613039552191; Thu, 11 Feb 2021 02:32:32 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:31 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 11/27] kernel-shark: Update KsWidgetsLib Date: Thu, 11 Feb 2021 12:31:49 +0200 Message-Id: <20210211103205.418588-12-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The compilation of KsWidgetsLib is re-enabled and all functionalities are made compatible with the new version of the C API of libkshark (KernelShark 2.0). We re-enable the widgetdemo example as well. Signed-off-by: Yordan Karadzhov (VMware) --- examples/CMakeLists.txt | 24 +- examples/widgetdemo.cpp | 65 ++-- src/CMakeLists.txt | 8 +- src/KsUtils.cpp | 29 ++ src/KsWidgetsLib.cpp | 695 +++++++++++++++++++++++++++++++++++----- src/KsWidgetsLib.hpp | 331 +++++++++++++++++-- 6 files changed, 996 insertions(+), 156 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b8bc79a..8360841 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -23,15 +23,15 @@ target_link_libraries(confio kshark) # message(STATUS "dataplot") # add_executable(dplot dataplot.cpp) # target_link_libraries(dplot kshark-plot) -# -# if (Qt5Widgets_FOUND) -# -# message(STATUS "widgetdemo") -# add_executable(widgetdemo widgetdemo.cpp) -# target_link_libraries(widgetdemo kshark-gui) -# -# message(STATUS "cmd_split") -# add_executable(cmd_split cmd_split.cpp) -# target_link_libraries(cmd_split kshark-gui) -# -# endif (Qt5Widgets_FOUND) + +if (Qt5Widgets_FOUND) + + message(STATUS "widgetdemo") + add_executable(widgetdemo widgetdemo.cpp) + target_link_libraries(widgetdemo kshark-gui) + + message(STATUS "cmd_split") + add_executable(cmd_split cmd_split.cpp) + target_link_libraries(cmd_split kshark-gui) + +endif (Qt5Widgets_FOUND) diff --git a/examples/widgetdemo.cpp b/examples/widgetdemo.cpp index 73049bf..0234d4b 100644 --- a/examples/widgetdemo.cpp +++ b/examples/widgetdemo.cpp @@ -24,6 +24,7 @@ static char *input_file = nullptr; using namespace std; +using namespace KsWidgetsLib; void usage(const char *prog) { @@ -37,13 +38,11 @@ void usage(const char *prog) struct TaskPrint : public QObject { - tep_handle *_pevent; - - void print(QVector pids) + void print(int sd, QVector pids) { for (auto const &pid: pids) cout << "task: " - << tep_data_comm_from_pid(_pevent, pid) + << kshark_comm_from_pid(sd, pid) << " pid: " << pid << endl; } }; @@ -51,11 +50,12 @@ struct TaskPrint : public QObject int main(int argc, char **argv) { kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; QApplication a(argc, argv); KsPluginManager plugins; + int c, i(0), sd(-1); KsDataStore data; size_t nRows(0); - int c; if (!kshark_instance(&kshark_ctx)) return 1; @@ -71,11 +71,11 @@ int main(int argc, char **argv) break; case 'p': - plugins.registerPlugin(QString(optarg)); + plugins.registerPlugins(QString(optarg)); break; case 'u': - plugins.unregisterPlugin(QString(optarg)); + plugins.unregisterPlugins(QString(optarg)); break; case 'h': @@ -91,7 +91,7 @@ int main(int argc, char **argv) } if (input_file) { - data.loadDataFile(input_file); + sd = data.loadDataFile(input_file, {}); nRows = data.size(); } else { cerr << "No input file is provided.\n"; @@ -99,54 +99,51 @@ int main(int argc, char **argv) cout << nRows << " entries loaded\n"; - auto lamPrintPl = [&]() - { - kshark_plugin_list *pl; - for (pl = kshark_ctx->plugins; pl; pl = pl->next) - cout << pl->file << endl; - }; + if (!nRows) + return 1; + + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return 1; cout << "\n\n"; - lamPrintPl(); + for (kshark_plugin_list *pl = kshark_ctx->plugins; pl; pl = pl->next) + cout << pl->file << endl; sleep(1); - QVector registeredPlugins; QStringList pluginsList; + QVector streamIds, enabledPlugins, failedPlugins; - pluginsList << plugins._ksPluginList - << plugins._userPluginList; - - registeredPlugins << plugins._registeredKsPlugins - << plugins._registeredUserPlugins; + pluginsList = plugins.getStreamPluginList(sd); + enabledPlugins = plugins.getActivePlugins(sd); + failedPlugins = plugins.getPluginsByStatus(sd, KSHARK_PLUGIN_FAILED); KsCheckBoxWidget *pluginCBD - = new KsPluginCheckBoxWidget(pluginsList); - - pluginCBD->set(registeredPlugins); + = new KsPluginCheckBoxWidget(sd, pluginsList); + pluginCBD->set(enabledPlugins); - KsCheckBoxDialog *dialog1 = new KsCheckBoxDialog(pluginCBD); + KsCheckBoxDialog *dialog1 = new KsCheckBoxDialog({pluginCBD}); + dialog1->applyStatus(); QObject::connect(dialog1, &KsCheckBoxDialog::apply, - &plugins, &KsPluginManager::updatePlugins); + &plugins, &KsPluginManager::updatePlugins); dialog1->show(); a.exec(); cout << "\n\nYou selected\n"; - lamPrintPl(); - sleep(1); + enabledPlugins = plugins.getActivePlugins(sd); + for (auto const &p: pluginsList) + qInfo() << p << (bool) enabledPlugins[i++]; - if (!nRows) - return 1; + sleep(1); KsCheckBoxWidget *tasks_cbd = - new KsTasksCheckBoxWidget(data.tep(), true); + new KsTasksCheckBoxWidget(stream, true); tasks_cbd->setDefault(false); TaskPrint p; - p._pevent = data.tep(); - - KsCheckBoxDialog *dialog2 = new KsCheckBoxDialog(tasks_cbd); + KsCheckBoxDialog *dialog2 = new KsCheckBoxDialog({tasks_cbd}); QObject::connect(dialog2, &KsCheckBoxDialog::apply, &p, &TaskPrint::print); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b308403..140fed8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -69,9 +69,9 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) set (ks-guiLib_hdr KsUtils.hpp KsModels.hpp # KsGLWidget.hpp - KsSearchFSM.hpp) + KsSearchFSM.hpp # KsDualMarker.hpp -# KsWidgetsLib.hpp + KsWidgetsLib.hpp) # KsTraceGraph.hpp # KsTraceViewer.hpp # KsMainWindow.hpp @@ -85,9 +85,9 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) KsModels.cpp # KsSession.cpp # KsGLWidget.cpp - KsSearchFSM.cpp) + KsSearchFSM.cpp # KsDualMarker.cpp -# KsWidgetsLib.cpp + KsWidgetsLib.cpp) # KsTraceGraph.cpp # KsTraceViewer.cpp # KsMainWindow.cpp diff --git a/src/KsUtils.cpp b/src/KsUtils.cpp index 36f9b25..27cda55 100644 --- a/src/KsUtils.cpp +++ b/src/KsUtils.cpp @@ -13,6 +13,7 @@ #include "libkshark-plugin.h" #include "libkshark-tepdata.h" #include "KsUtils.hpp" +#include "KsWidgetsLib.hpp" namespace KsUtils { @@ -451,6 +452,34 @@ QStringList getFiles(QWidget *parent, return getFilesDialog(parent, windowName, filter, lastFilePath); } +/** + * @brief Open a standard Qt getFileName dialog and return the name of the + * selected file. Only one file can be selected. + */ +QString getSaveFile(QWidget *parent, + const QString &windowName, + const QString &filter, + const QString &extension, + QString &lastFilePath) +{ + QString fileName = getFileDialog(parent, + windowName, + filter, + lastFilePath, + true); + + if (!fileName.isEmpty() && !fileName.endsWith(extension)) { + fileName += extension; + + if (QFileInfo(fileName).exists()) { + if (!KsWidgetsLib::fileExistsDialog(fileName)) + fileName.clear(); + } + } + + return fileName; +} + /** * @brief Separate the command line arguments inside the string taking into * account possible shell quoting and new lines. diff --git a/src/KsWidgetsLib.cpp b/src/KsWidgetsLib.cpp index a84aff3..4ec6033 100644 --- a/src/KsWidgetsLib.cpp +++ b/src/KsWidgetsLib.cpp @@ -9,13 +9,18 @@ * @brief Defines small widgets and dialogues used by the KernelShark GUI. */ +// C +#include + // KernelShark -#include "libkshark.h" -#include "KsUtils.hpp" +#include "libkshark-tepdata.h" #include "KsCmakeDef.hpp" #include "KsPlotTools.hpp" #include "KsWidgetsLib.hpp" +namespace KsWidgetsLib +{ + /** * @brief Create KsProgressBar. * @@ -25,11 +30,12 @@ KsProgressBar::KsProgressBar(QString message, QWidget *parent) : QWidget(parent), _sb(this), - _pb(&_sb) { - resize(KS_BROGBAR_WIDTH, KS_BROGBAR_HEIGHT); + _pb(&_sb), + _notDone(false) { setWindowTitle("KernelShark"); setLayout(new QVBoxLayout); - + setFixedHeight(KS_PROGBAR_HEIGHT); + setFixedWidth(KS_PROGBAR_WIDTH); _pb.setOrientation(Qt::Horizontal); _pb.setTextVisible(false); _pb.setRange(0, KS_PROGRESS_BAR_MAX); @@ -45,6 +51,13 @@ KsProgressBar::KsProgressBar(QString message, QWidget *parent) show(); } +/** Destroy the KsProgressBar object. */ +KsProgressBar::~KsProgressBar() +{ + _notDone = false; + usleep(10000); +} + /** @brief Set the state of the progressbar. * * @param i: A value ranging from 0 to KS_PROGRESS_BAR_MAX. @@ -54,6 +67,101 @@ void KsProgressBar::setValue(int i) { QApplication::processEvents(); } +/** Show continuous work. */ +void KsProgressBar::workInProgress() +{ + int progress, inc; + bool inv = false; + + progress = inc = 5; + _notDone = true; + while (_notDone) { + if (progress > KS_PROGRESS_BAR_MAX || + progress <= 0) { + inc = -inc; + inv = !inv; + _pb.setInvertedAppearance(inv); + } + + setValue(progress); + progress += inc; + usleep(30000); + } +} + +/** + * @brief Create KsWorkInProgress. + * + * @param parent: The parent of this widget. + */ +KsWorkInProgress::KsWorkInProgress(QWidget *parent) +: QWidget(parent), + _icon(this), + _message("work in progress", this) +{ + QIcon statusIcon = QIcon::fromTheme("dialog-warning"); + _icon.setPixmap(statusIcon.pixmap(.8 * FONT_HEIGHT)); +} + +/** + * @brief Show the "work in progress" notification. + * + * @param w: Data Work identifier. + */ +void KsWorkInProgress::show(KsDataWork w) +{ + _works.insert(w); + if (_works.size() == 1) { + _icon.show(); + _message.show(); + + if (w != KsDataWork::RenderGL && + w != KsDataWork::ResizeGL) + QApplication::processEvents(); + } +} + +/** + * @brief Hide the "work in progress" notification. + * + * @param w: Data Work identifier. + */ +void KsWorkInProgress::hide(KsDataWork w) +{ + _works.remove(w); + if (_works.isEmpty()) { + _icon.hide(); + _message.hide(); + + if (w != KsDataWork::RenderGL && + w != KsDataWork::ResizeGL) + QApplication::processEvents(); + } +} + +/** + * @brief Returns True the "work in progress" notification is active. + * Otherwise False. + * + * @param w: Data Work identifier. + */ +bool KsWorkInProgress::isBusy(KsDataWork w) const +{ + if (w == KsDataWork::AnyWork) + return _works.isEmpty()? false : true; + + return _works.contains(w)? true : false; +} + +/** Add the KsWorkInProgress widget to a given Status Bar. */ +void KsWorkInProgress::addToStatusBar(QStatusBar *sb) +{ + sb->addPermanentWidget(&_icon); + sb->addPermanentWidget(&_message); + _icon.hide(); + _message.hide(); +} + /** * @brief Create KsMessageDialog. * @@ -76,9 +184,6 @@ KsMessageDialog::KsMessageDialog(QString message, QWidget *parent) this->setLayout(&_layout); } -namespace KsWidgetsLib -{ - /** * @brief Launch a File exists dialog. Use this function to ask the user * before overwriting an existing file. @@ -103,38 +208,156 @@ bool fileExistsDialog(QString fileName) return (msgBox.exec() == QMessageBox::Save); } -}; // KsWidgetsLib +/** Create KsTimeOffsetDialog. */ +KsTimeOffsetDialog::KsTimeOffsetDialog(QWidget *parent) +{ + kshark_context *kshark_ctx(nullptr); + QVector streamIds; + QString streamName; + int64_t max_ofst; + + auto lamApply = [&] (double val) { + int sd = _streamCombo.currentData().toInt(); + emit apply(sd, val); + close(); + }; + + if (!kshark_instance(&kshark_ctx)) + return; + + this->setLayout(new QVBoxLayout); + + streamIds = KsUtils::getStreamIdList(kshark_ctx); + if (streamIds.size() > 1) { + for (auto const &sd: streamIds) + if (sd != 0) { + streamName = KsUtils::streamDescription(kshark_ctx->stream[sd]); + _streamCombo.addItem(streamName); + } + + layout()->addWidget(&_streamCombo); + } + + _input.setInputMode(QInputDialog::DoubleInput); + max_ofst = (int64_t) 1 << 60; + _input.setDoubleRange(-max_ofst, max_ofst); + _input.setDoubleDecimals(3); + _input.setLabelText("Offset [usec]:"); + _setDefault(_streamCombo.currentIndex()); + + layout()->addWidget(&_input); + + connect(&_input, &QInputDialog::doubleValueSelected, + lamApply); + + connect(&_input, &QDialog::rejected, + this, &QWidget::close); + + connect(&_streamCombo, SIGNAL(currentIndexChanged(int)), + SLOT(_setDefault(int))); + + show(); +} + +void KsTimeOffsetDialog::_setDefault(int index) { + int sd = _streamCombo.currentData().toInt(); + kshark_context *kshark_ctx(nullptr); + struct kshark_data_stream *stream; + double offset; + + if (!kshark_instance(&kshark_ctx)) + return; + + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return; + + if (!stream->calib_array) { + stream->calib = kshark_offset_calib; + stream->calib_array = + (int64_t *) calloc(1, sizeof(int64_t)); + stream->calib_array_size = 1; + } + + offset = stream->calib_array[0] * 1e-3; + _input.setDoubleValue(offset); +} + +/** + * @brief Static function that starts a KsTimeOffsetDialog and returns value + * selected by the user. + * + * @param dataFile: The name of the trace file to which the Time Offset will + * apply. To be shown by the dialog. + * @param ok: Output location to a success flag. True if the user has pressed + * "Apply". + */ +double KsTimeOffsetDialog::getValueNanoSec(QString dataFile, bool *ok) +{ + KsTimeOffsetDialog dialog; + int64_t ofst(0); + int sd(-1); + + *ok = false; + + auto lamGetOffset = [&] (int stream_id, double ms) { + ofst = ms * 1000; + sd = stream_id; + *ok = true; + }; + + connect(&dialog, &KsTimeOffsetDialog::apply, lamGetOffset); + dialog._streamCombo.hide(); + dialog._input.setLabelText(dataFile + "\nOffset [usec]:"); + dialog.exec(); + + return ofst; +} /** * @brief Create KsCheckBoxWidget. * + * @param sd: Data stream identifier. * @param name: The name of this widget. * @param parent: The parent of this widget. */ -KsCheckBoxWidget::KsCheckBoxWidget(const QString &name, QWidget *parent) +KsCheckBoxWidget::KsCheckBoxWidget(int sd, const QString &name, + QWidget *parent) : QWidget(parent), - _tb(this), - _allCb("all", &_tb), + _userInput(false), + _sd(sd), + _allCb("all"), _cbWidget(this), _cbLayout(&_cbWidget), _topLayout(this), + _allCbAction(nullptr), + _streamLabel("", this), _name(name), - _nameLabel(name + ": ",&_tb) + _nameLabel(name + ": ") { setWindowTitle(_name); setMinimumHeight(SCREEN_HEIGHT / 2); + setMinimumWidth(FONT_WIDTH * 20); + + auto lamCheckAll = [this] (bool s) { + _userInput = true; + _checkAll(s); + }; connect(&_allCb, &QCheckBox::clicked, - this, &KsCheckBoxWidget::_checkAll); + lamCheckAll); _cbWidget.setLayout(&_cbLayout); + _setStream(sd); + if (!_streamLabel.text().isEmpty()) + _topLayout.addWidget(&_streamLabel); + _tb.addWidget(&_nameLabel); - _tb.addWidget(&_allCb); - _topLayout.addWidget(&_tb); + _allCbAction = _tb.addWidget(&_allCb); + _topLayout.addWidget(&_tb); _topLayout.addWidget(&_cbWidget); - _topLayout.setContentsMargins(0, 0, 0, 0); setLayout(&_topLayout); _allCb.setCheckState(Qt::Checked); @@ -154,6 +377,27 @@ void KsCheckBoxWidget::setDefault(bool st) _checkAll(state); } +/** Set the stream Id of the widget. */ +void KsCheckBoxWidget::_setStream(int8_t sd) +{ + kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; + + if (!kshark_instance(&kshark_ctx)) + return; + + _sd = sd; + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return; + + _streamName = KsUtils::streamDescription(stream); + + KsUtils::setElidedText(&_streamLabel, _streamName, + Qt::ElideLeft, width()); + QApplication::processEvents(); +} + /** Get a vector containing the indexes of all checked boxes. */ QVector KsCheckBoxWidget::getCheckedIds() { @@ -167,12 +411,24 @@ QVector KsCheckBoxWidget::getCheckedIds() return vec; } +/** Get a vector containing the state of all checkboxes. */ +QVector KsCheckBoxWidget::getStates() +{ + int n = _id.size(); + QVector vec(n); + + for (int i = 0; i < n; ++i) + vec[i] = !!_checkState(i); + + return vec; +} + /** * @brief Set the state of the checkboxes. * - * @param v: Vector containing the bool values for all checkboxes. + * @param v: Vector containing the state values for all checkboxes. */ -void KsCheckBoxWidget::set(QVector v) +void KsCheckBoxWidget::set(QVector v) { Qt::CheckState state; int nChecks; @@ -215,18 +471,24 @@ void KsCheckBoxWidget::_checkAll(bool st) /** * @brief Create KsCheckBoxDialog. * - * @param cbw: A KsCheckBoxWidget to be nested in this dialog. + * @param cbws: A vector of KsCheckBoxWidgets to be nested in this dialog. * @param parent: The parent of this widget. */ -KsCheckBoxDialog::KsCheckBoxDialog(KsCheckBoxWidget *cbw, QWidget *parent) -: QDialog(parent), _checkBoxWidget(cbw), +KsCheckBoxDialog::KsCheckBoxDialog(QVector cbws, QWidget *parent) +: QDialog(parent), + _applyIds(true), + _checkBoxWidgets(cbws), _applyButton("Apply", this), _cancelButton("Cancel", this) { int buttonWidth; - setWindowTitle(cbw->name()); - _topLayout.addWidget(_checkBoxWidget); + if (!cbws.isEmpty()) + setWindowTitle(cbws[0]->name()); + + for (auto const &w: _checkBoxWidgets) + _cbLayout.addWidget(w); + _topLayout.addLayout(&_cbLayout); buttonWidth = STRING_WIDTH("--Cancel--"); _applyButton.setFixedWidth(buttonWidth); @@ -256,16 +518,29 @@ KsCheckBoxDialog::KsCheckBoxDialog(KsCheckBoxWidget *cbw, QWidget *parent) void KsCheckBoxDialog::_applyPress() { - QVector vec = _checkBoxWidget->getCheckedIds(); - emit apply(vec); + QVector vec; /* * Disconnect _applyButton. This is done in order to protect * against multiple clicks. */ disconnect(_applyButtonConnection); -} + _preApplyAction(); + + for (auto const &w: _checkBoxWidgets) { + if (!w->_userInput) + continue; + + if (_applyIds) + vec = w->getCheckedIds(); + else + vec = w->getStates(); + emit apply(w->sd(), vec); + } + + _postApplyAction(); +} /** * @brief Create KsCheckBoxTable. @@ -356,12 +631,13 @@ void KsCheckBoxTable::_doubleClicked(int row, int col) /** * @brief Create KsCheckBoxTableWidget. * + * @param sd: Data stream identifier. * @param name: The name of this widget. * @param parent: The parent of this widget. */ -KsCheckBoxTableWidget::KsCheckBoxTableWidget(const QString &name, +KsCheckBoxTableWidget::KsCheckBoxTableWidget(int sd, const QString &name, QWidget *parent) -: KsCheckBoxWidget(name, parent), +: KsCheckBoxWidget(sd, name, parent), _table(this) { connect(&_table, &KsCheckBoxTable::changeState, @@ -409,6 +685,8 @@ void KsCheckBoxTableWidget::_update(bool state) /* If a Checkbox is being unchecked. Unchecked "all" as well. */ if (!state) _allCb.setCheckState(Qt::Unchecked); + + _userInput = true; } void KsCheckBoxTableWidget::_changeState(int row) @@ -425,6 +703,8 @@ void KsCheckBoxTableWidget::_changeState(int row) break; } } + + _userInput = true; } static void update_r(QTreeWidgetItem *item, Qt::CheckState state) @@ -511,16 +791,24 @@ void KsCheckBoxTree::mousePressEvent(QMouseEvent *event) /** * @brief Create KsCheckBoxTreeWidget. * + * @param sd: Data stream identifier. * @param name: The name of this widget. * @param parent: The parent of this widget. */ -KsCheckBoxTreeWidget::KsCheckBoxTreeWidget(const QString &name, +KsCheckBoxTreeWidget::KsCheckBoxTreeWidget(int sd, const QString &name, QWidget *parent) -: KsCheckBoxWidget(name, parent), +: KsCheckBoxWidget(sd, name, parent), _tree(this) { - connect(&_tree, &KsCheckBoxTree::verify, - this, &KsCheckBoxTreeWidget::_verify); + connect(&_tree, &KsCheckBoxTree::verify, + this, &KsCheckBoxTreeWidget::_verify); + + auto lamSetUserInput = [this] (QTreeWidgetItem *, int) { + _userInput = true; + }; + + connect(&_tree, &QTreeWidget::itemClicked, + lamSetUserInput); } /** Initialize the KsCheckBoxTree and its layout. */ @@ -553,7 +841,7 @@ void KsCheckBoxTreeWidget::_adjustSize() width = _tree.visualItemRect(_tree.topLevelItem(0)).width(); } - width += FONT_WIDTH*3 + style()->pixelMetric(QStyle::PM_ScrollBarExtent); + width += FONT_WIDTH * 3 + style()->pixelMetric(QStyle::PM_ScrollBarExtent); _cbWidget.resize(width, _cbWidget.height()); for (int i = 0; i < n; ++i) @@ -614,14 +902,13 @@ void KsCheckBoxTreeWidget::_verify() /** * @brief Create KsCPUCheckBoxWidget. * - * @param tep: Trace event parseer. + * @param stream: Input location for a Data stream pointer. * @param parent: The parent of this widget. */ -KsCPUCheckBoxWidget::KsCPUCheckBoxWidget(struct tep_handle *tep, - QWidget *parent) -: KsCheckBoxTreeWidget("CPUs", parent) +KsCPUCheckBoxWidget::KsCPUCheckBoxWidget(kshark_data_stream *stream, QWidget *parent) +: KsCheckBoxTreeWidget(stream->stream_id, "CPUs", parent) { - int nCPUs(0), height(FONT_HEIGHT * 1.5); + int height(FONT_HEIGHT * 1.5); KsPlot::ColorTable colors; QString style; @@ -630,19 +917,16 @@ KsCPUCheckBoxWidget::KsCPUCheckBoxWidget(struct tep_handle *tep, _initTree(); - if (tep) - nCPUs = tep_get_cpus(tep); + _id.resize(stream->n_cpus); + _cb.resize(stream->n_cpus); + colors = KsPlot::CPUColorTable(); - _id.resize(nCPUs); - _cb.resize(nCPUs); - colors = KsPlot::getCPUColorTable(); - - for (int i = 0; i < nCPUs; ++i) { + for (int i = 0; i < stream->n_cpus; ++i) { QTreeWidgetItem *cpuItem = new QTreeWidgetItem; cpuItem->setText(0, " "); cpuItem->setText(1, QString("CPU %1").arg(i)); cpuItem->setCheckState(0, Qt::Checked); - cpuItem->setBackground(0, QColor(colors[i].r(), + cpuItem->setBackgroundColor(0, QColor(colors[i].r(), colors[i].g(), colors[i].b())); _tree.addTopLevelItem(cpuItem); @@ -656,36 +940,66 @@ KsCPUCheckBoxWidget::KsCPUCheckBoxWidget(struct tep_handle *tep, /** * @brief Create KsEventsCheckBoxWidget. * - * @param tep: Trace event parseer. + * @param stream: Input location for a Data stream pointer. * @param parent: The parent of this widget. */ -KsEventsCheckBoxWidget::KsEventsCheckBoxWidget(struct tep_handle *tep, +KsEventsCheckBoxWidget::KsEventsCheckBoxWidget(kshark_data_stream *stream, QWidget *parent) -: KsCheckBoxTreeWidget("Events", parent) +: KsCheckBoxTreeWidget(stream->stream_id, "Events", parent) { - QTreeWidgetItem *sysItem, *evtItem; - tep_event **events(nullptr); - QString sysName, evtName; - int nEvts(0), i(0); + QVector eventIds = KsUtils::getEventIdList(stream->stream_id); + + _initTree(); + if(!stream->n_events || eventIds.isEmpty()) + return; + + _id.resize(stream->n_events); + _cb.resize(stream->n_events); - if (tep) { - nEvts = tep_get_events_count(tep); - events = tep_list_events(tep, TEP_EVENT_SORT_SYSTEM); + if (kshark_is_tep(stream)) + _makeTepEventItems(stream, eventIds); + else + _makeItems(stream, eventIds); +} + +void KsEventsCheckBoxWidget::_makeItems(kshark_data_stream *stream, + QVector eventIds) +{ + QTreeWidgetItem *evtItem; + QString evtName; + + for (int i = 0; i < stream->n_events; ++i) { + evtName = KsUtils::getEventName(stream->stream_id, + eventIds[i]); + evtItem = new QTreeWidgetItem; + evtItem->setText(0, evtName); + evtItem->setCheckState(0, Qt::Checked); + evtItem->setFlags(evtItem->flags() | + Qt::ItemIsUserCheckable); + _tree.addTopLevelItem(evtItem); + _cb[i] = evtItem; } +} - _initTree(); - _id.resize(nEvts); - _cb.resize(nEvts); +void KsEventsCheckBoxWidget::_makeTepEventItems(kshark_data_stream *stream, + QVector eventIds) +{ + QTreeWidgetItem *sysItem, *evtItem; + QString sysName, evtName; + QStringList name; + int i(0); - while (i < nEvts) { - sysName = events[i]->system; + while (i < stream->n_events) { + name = KsUtils::getTepEvtName(stream->stream_id, + eventIds[i]); + sysName = name[0]; sysItem = new QTreeWidgetItem; sysItem->setText(0, sysName); sysItem->setCheckState(0, Qt::Checked); _tree.addTopLevelItem(sysItem); - while (sysName == events[i]->system) { - evtName = events[i]->name; + while (sysName == name[0]) { + evtName = name[1]; evtItem = new QTreeWidgetItem; evtItem->setText(0, evtName); evtItem->setCheckState(0, Qt::Checked); @@ -694,11 +1008,13 @@ KsEventsCheckBoxWidget::KsEventsCheckBoxWidget(struct tep_handle *tep, sysItem->addChild(evtItem); - _id[i] = events[i]->id; + _id[i] = eventIds[i]; _cb[i] = evtItem; - - if (++i == nEvts) + if (++i == stream->n_events) break; + + name = KsUtils::getTepEvtName(stream->stream_id, + eventIds[i]); } } @@ -726,7 +1042,7 @@ QStringList KsEventsCheckBoxWidget::getCheckedEvents(bool option) optStr = "-e"; nSys = _tree.topLevelItemCount(); - for (int t = 0; t < nSys; ++t) { + for(int t = 0; t < nSys; ++t) { sysItem = _tree.topLevelItem(t); if (sysItem->checkState(0) == Qt::Checked) { list << optStr + sysItem->text(0); @@ -763,48 +1079,48 @@ void KsEventsCheckBoxWidget::removeSystem(QString name) { /** * @brief Create KsTasksCheckBoxWidget. * - * @param pevent: Page event used to parse the page. + * @param stream: Input location for a Data stream pointer. * @param cond: If True make a "Show Task" widget. Otherwise make "Hide Task". * @param parent: The parent of this widget. */ -KsTasksCheckBoxWidget::KsTasksCheckBoxWidget(struct tep_handle *pevent, +KsTasksCheckBoxWidget::KsTasksCheckBoxWidget(kshark_data_stream *stream, bool cond, QWidget *parent) -: KsCheckBoxTableWidget("Tasks", parent) +: KsCheckBoxTableWidget(stream->stream_id, "Tasks", parent), + _cond(cond) { - kshark_context *kshark_ctx(nullptr); QTableWidgetItem *pidItem, *comItem; KsPlot::ColorTable colors; QStringList headers; + kshark_entry entry; const char *comm; int nTasks, pid; - if (!kshark_instance(&kshark_ctx)) - return; - if (_cond) headers << "Show" << "Pid" << "Task"; else headers << "Hide" << "Pid" << "Task"; - _id = KsUtils::getPidList(); + _id = KsUtils::getPidList(stream->stream_id); nTasks = _id.count(); _initTable(headers, nTasks); - colors = KsPlot::getTaskColorTable(); - + colors = KsPlot::taskColorTable(); + entry.stream_id = stream->stream_id; + entry.visible = 0xff; for (int i = 0; i < nTasks; ++i) { - pid = _id[i]; - pidItem = new QTableWidgetItem(tr("%1").arg(pid)); + entry.pid = pid = _id[i]; + pidItem = new QTableWidgetItem(tr("%1").arg(pid)); _table.setItem(i, 1, pidItem); - comm = tep_data_comm_from_pid(kshark_ctx->pevent, pid); + comm = kshark_get_task(&entry); + comItem = new QTableWidgetItem(tr(comm)); - pidItem->setBackground(QColor(colors[pid].r(), + pidItem->setBackgroundColor(QColor(colors[pid].r(), colors[pid].g(), colors[pid].b())); if (_id[i] == 0) - pidItem->setForeground(Qt::white); + pidItem->setTextColor(Qt::white); _table.setItem(i, 2, comItem); } @@ -815,12 +1131,13 @@ KsTasksCheckBoxWidget::KsTasksCheckBoxWidget(struct tep_handle *pevent, /** * @brief Create KsPluginCheckBoxWidget. * + * @param sd: Data stream identifier. * @param pluginList: A list of plugin names. * @param parent: The parent of this widget. */ -KsPluginCheckBoxWidget::KsPluginCheckBoxWidget(QStringList pluginList, +KsPluginCheckBoxWidget::KsPluginCheckBoxWidget(int sd, QStringList pluginList, QWidget *parent) -: KsCheckBoxTableWidget("Plugins", parent) +: KsCheckBoxTableWidget(sd, "Manage plugins", parent) { QTableWidgetItem *nameItem, *infoItem; QStringList headers; @@ -833,7 +1150,16 @@ KsPluginCheckBoxWidget::KsPluginCheckBoxWidget(QStringList pluginList, _id.resize(nPlgins); for (int i = 0; i < nPlgins; ++i) { - nameItem = new QTableWidgetItem(pluginList[i]); + if (pluginList[i] < 30) { + nameItem = new QTableWidgetItem(pluginList[i]); + } else { + QLabel l; + KsUtils::setElidedText(&l, pluginList[i], + Qt::ElideLeft, + FONT_WIDTH * 30); + nameItem = new QTableWidgetItem(l.text()); + } + _table.setItem(i, 1, nameItem); infoItem = new QTableWidgetItem(" -- "); _table.setItem(i, 2, infoItem); @@ -842,3 +1168,200 @@ KsPluginCheckBoxWidget::KsPluginCheckBoxWidget(QStringList pluginList, _adjustSize(); } + +/** + * @brief Set the "Info" field inside the table of the widget. + * + * @param row: The row number in the table. + * @param info: The "Info" string to be shown. + */ +void KsPluginCheckBoxWidget::setInfo(int row, QString info) +{ + QTableWidgetItem *infoItem = _table.item(row, 2); + infoItem->setText(info); +} + +/** + * @brief Set the "Active" field inside the table of the widget. + * + * @param rows: The row numbers in the table. + * @param a: Are those plugins active. + */ +void KsPluginCheckBoxWidget::setActive(QVector rows, bool a) +{ + for (auto const &r: rows) { + QTableWidgetItem *infoItem = _table.item(r, 2); + if (a) { + infoItem->setText("- Active"); + infoItem->setForeground(QBrush(QColor(0, 220, 80))); + } else { + infoItem->setText("- Not Active"); + infoItem->setForeground(QBrush(QColor(255, 50, 50))); + } + } +} + +void KsPluginsCheckBoxDialog::_postApplyAction() +{ + emit _data->updateWidgets(_data); +} + +/** + * @brief Create KsDStreamCheckBoxWidget. + * + * @param parent: The parent of this widget. + */ +KsDStreamCheckBoxWidget::KsDStreamCheckBoxWidget(QWidget *parent) +: KsCheckBoxTableWidget(-1, "Select Data stream", parent) +{ + kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; + QTableWidgetItem *nameItem; + QVector streamIds; + QStringList headers; + int nStreams; + + if (!kshark_instance(&kshark_ctx)) + return; + + headers << "Apply" << "To stream"; + streamIds = KsUtils::getStreamIdList(kshark_ctx); + nStreams = streamIds.size(); + _initTable(headers, nStreams); + _id.resize(nStreams); + + for (int i = 0; i < nStreams; ++i) { + stream = kshark_ctx->stream[streamIds[i]]; + QString name = KsUtils::streamDescription(stream); + if (name < 40) { + nameItem = new QTableWidgetItem(name); + } else { + QLabel l; + KsUtils::setElidedText(&l, name, + Qt::ElideLeft, + FONT_WIDTH * 40); + nameItem = new QTableWidgetItem(l.text()); + } + + _table.setItem(i, 1, nameItem); + _id[i] = stream->stream_id; + } + + _adjustSize(); +} + +/** + * @brief Create KsEventFieldSelectWidget. + * + * @param parent: The parent of this widget. + */ +KsEventFieldSelectWidget::KsEventFieldSelectWidget(QWidget *parent) +: QWidget(parent), + _streamLabel("Data stream", this), + _eventLabel("Event (type in for searching)", this), + _fieldLabel("Field", this) +{ + auto lamAddLine = [&] { + QFrame* line = new QFrame(); + QSpacerItem *spacer = new QSpacerItem(1, FONT_HEIGHT / 2, + QSizePolicy::Expanding, + QSizePolicy::Minimum); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + _topLayout.addSpacerItem(spacer); + _topLayout.addWidget(line); + }; + + _topLayout.addWidget(&_streamLabel); + _topLayout.addWidget(&_streamComboBox); + + /* + * Using the old Signal-Slot syntax because QComboBox::currentIndexChanged + * has overloads. + */ + connect(&_streamComboBox, SIGNAL(currentIndexChanged(const QString&)), + this, SLOT(_streamChanged(const QString&))); + + lamAddLine(); + + _topLayout.addWidget(&_eventLabel); + _topLayout.addWidget(&_eventComboBox); + _eventComboBox.setEditable(true); + _eventComboBox.view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + _eventComboBox.setMaxVisibleItems(25); + + /* + * Using the old Signal-Slot syntax because QComboBox::currentIndexChanged + * has overloads. + */ + connect(&_eventComboBox, SIGNAL(currentIndexChanged(const QString&)), + this, SLOT(_eventChanged(const QString&))); + + lamAddLine(); + + _topLayout.addWidget(&_fieldLabel); + _topLayout.addWidget(&_fieldComboBox); + + lamAddLine(); + + setLayout(&_topLayout); +} + +/** Populate the Data stream selection combo box. */ +void KsEventFieldSelectWidget::setStreamCombo() +{ + kshark_context *kshark_ctx(NULL); + kshark_data_stream *stream; + QVector streamIds; + + if (!kshark_instance(&kshark_ctx)) + return; + + streamIds = KsUtils::getStreamIdList(kshark_ctx); + for (auto const &sd: streamIds) { + stream = kshark_ctx->stream[sd]; + if (_streamComboBox.findData(sd) < 0) + _streamComboBox.addItem(KsUtils::streamDescription(stream), sd); + } +} + +void KsEventFieldSelectWidget::_streamChanged(const QString &streamFile) +{ + int sd = _streamComboBox.currentData().toInt(); + QVector eventIds = KsUtils::getEventIdList(sd); + QStringList evtsList; + + _eventComboBox.clear(); + + for (auto const &eid: eventIds) + evtsList << KsUtils::getEventName(sd, eid); + + std::sort(evtsList.begin(), evtsList.end()); + _eventComboBox.addItems(evtsList); +} + +void KsEventFieldSelectWidget::_eventChanged(const QString &eventName) +{ + int sd = _streamComboBox.currentData().toInt(); + int eventId = KsUtils::getEventId(sd, eventName); + QStringList fieldsList = KsUtils::getEventFieldsList(sd, eventId); + + auto lamIsValide = [&] (const QString &f) { + return KsUtils::getEventFieldType(sd, eventId, f) == + KS_INVALID_FIELD; + }; + + _fieldComboBox.clear(); + + fieldsList.erase(std::remove_if(fieldsList.begin(), fieldsList.end(), + lamIsValide), fieldsList.end()); + + if (fieldsList.isEmpty()) + return; + + std::sort(fieldsList.begin(), fieldsList.end()); + + _fieldComboBox.addItems(fieldsList); +} + +}; // KsWidgetsLib diff --git a/src/KsWidgetsLib.hpp b/src/KsWidgetsLib.hpp index 59e773d..428e8dd 100644 --- a/src/KsWidgetsLib.hpp +++ b/src/KsWidgetsLib.hpp @@ -15,6 +15,13 @@ // Qt #include +// KernelShark +#include "libkshark.h" +#include "KsUtils.hpp" + +namespace KsWidgetsLib +{ + /** * The KsProgressBar class provides a visualization of the progress of a * running job. @@ -30,17 +37,133 @@ class KsProgressBar : public QWidget public: KsProgressBar(QString message, QWidget *parent = nullptr); + virtual ~KsProgressBar(); + void setValue(int i); + + void workInProgress(); + +private: + bool _notDone; }; /** Defines the progress bar's maximum value. */ #define KS_PROGRESS_BAR_MAX 200 /** The height of the KsProgressBar widget. */ -#define KS_BROGBAR_HEIGHT (FONT_HEIGHT * 5) +#define KS_PROGBAR_HEIGHT (FONT_HEIGHT * 5) /** The width of the KsProgressBar widget. */ -#define KS_BROGBAR_WIDTH (FONT_WIDTH * 50) +#define KS_PROGBAR_WIDTH (FONT_WIDTH * 50) + +/** Data Work identifiers. */ +enum class KsDataWork +{ + AnyWork, + EditPlotList, + ZoomIn, + QuickZoomIn, + ZoomOut, + QuickZoomOut, + ScrollLeft, + ScrollRight, + JumpTo, + GraphUpdateGeom, + UpdatePlugins, + ResizeGL, + RenderGL, +}; + +/** Defines hash function needed by the QSet tempate container class. */ +inline uint qHash(KsDataWork key, uint seed) +{ + /* + * Cast the enum class to uint and use the definition of qHash outside + * the current scope. + */ + return ::qHash(static_cast(key), seed); +} + +/** + * The KsWorkInProgress class provides a widget showing the + * "work in progress" notification. + */ +class KsWorkInProgress : public QWidget +{ +public: + explicit KsWorkInProgress(QWidget *parent = nullptr); + + void show(KsDataWork w); + + void hide(KsDataWork w); + + bool isBusy(KsDataWork w = KsDataWork::AnyWork) const; + + void addToStatusBar(QStatusBar *sb); + +private: + QLabel _icon, _message; + + QSet _works; +}; + +/** + * The KsDataWidget class provides a base widget that provides the capability + * to show the "work in progress" notification. The class must be inherited by + * the widgets performing heavy data processing operations. + */ +class KsDataWidget : public QWidget +{ +public: + /** + * @brief Create KsDataWidget. + * + * @param parent: The parent of this widget. + */ + explicit KsDataWidget(QWidget *parent = nullptr) + : QWidget(parent), _workInProgress(nullptr) {} + + /** Set a pointer to the KsWorkInProgress widget. */ + const KsWorkInProgress *wipPtr(KsWorkInProgress *wip) const + { + return _workInProgress; + } + + /** Set the pointer to the KsWorkInProgress widget. */ + void setWipPtr(KsWorkInProgress *wip) + { + _workInProgress = wip; + } + + /** + * Call this function when a given work is about to start in order to + * show the "work in progress" notification. + */ + void startOfWork(KsDataWork w) + { + if (_workInProgress) + _workInProgress->show(w); + } + + /** + * Call this function when a given work is done in order to hide the + * "work in progress" notification. + */ + void endOfWork(KsDataWork w) + { + if (_workInProgress) + _workInProgress->hide(w); + } + + /** Check if the GUI is busy processing data. */ + bool isBusy(KsDataWork w = KsDataWork::AnyWork) const + { + return _workInProgress ? _workInProgress->isBusy(w) : false; + } + +private: + KsWorkInProgress *_workInProgress; +}; /** * The KsMessageDialog class provides a widget showing a message and having @@ -66,12 +189,32 @@ public: /** The width of the KsMessageDialog widget. */ #define KS_MSG_DIALOG_WIDTH (SCREEN_WIDTH / 10) -namespace KsWidgetsLib +bool fileExistsDialog(QString fileName); + +/** + * The KsTimeOffsetDialog class provides a dialog used to enter the value of + * the time offset between two Data streams. + */ +class KsTimeOffsetDialog : public QDialog { + Q_OBJECT +public: + explicit KsTimeOffsetDialog(QWidget *parent = nullptr); -bool fileExistsDialog(QString fileName); + static double getValueNanoSec(QString dataFile, bool *ok); -}; // KsWidgetsLib +signals: + /** Signal emitted when the "Apply" button is pressed. */ + void apply(int sd, double val); + +private: + QInputDialog _input; + + QComboBox _streamCombo; + +private slots: + void _setDefault(int index); +}; /** * The KsCheckBoxWidget class is the base class of all CheckBox widget used @@ -81,7 +224,7 @@ class KsCheckBoxWidget : public QWidget { Q_OBJECT public: - KsCheckBoxWidget(const QString &name = "", + KsCheckBoxWidget(int sd, const QString &name = "", QWidget *parent = nullptr); /** Get the name of the widget. */ @@ -95,9 +238,12 @@ public: return false; } + /** The "all" checkboxe to be visible or not. */ + void setVisibleCbAll(bool v) {_allCbAction->setVisible(v);} + void setDefault(bool); - void set(QVector v); + void set(QVector v); /** * Get a vector containing all Ids (can be PID CPU Ids etc.) managed @@ -107,10 +253,35 @@ public: QVector getCheckedIds(); + QVector getStates(); + + /** + * Get the identifier of the Data stream for which the selection + * applies. + */ + int sd() const {return _sd;} + + /** + * Reimplemented event handler used to update the geometry of the widget on + * resize events. + */ + void resizeEvent(QResizeEvent* event) + { + KsUtils::setElidedText(&_streamLabel, _streamName, + Qt::ElideLeft, width()); + QApplication::processEvents(); + } + + /** The user provided an input. The widget has been modified. */ + bool _userInput; + private: QToolBar _tb; protected: + /** Identifier of the Data stream for which the selection applies. */ + int _sd; + /** The "all" checkboxe. */ QCheckBox _allCb; @@ -126,13 +297,25 @@ protected: /** The top level layout of this widget. */ QVBoxLayout _topLayout; +private: + QAction *_allCbAction; + + /** + * The name of this Data stream. Typically this will be the name of + * the data file. + */ + QString _streamName; + /** + * A label to show the name of the Data stream for which the selection + * applies. */ + QLabel _streamLabel; + /** The name of this widget. */ QString _name; /** A label to show the name of the widget. */ QLabel _nameLabel; -private: virtual void _setCheckState(int i, Qt::CheckState st) = 0; virtual Qt::CheckState _checkState(int i) const = 0; @@ -140,6 +323,8 @@ private: virtual void _verify() {}; void _checkAll(bool); + + void _setStream(int8_t sd); }; /** @@ -152,26 +337,65 @@ class KsCheckBoxDialog : public QDialog public: KsCheckBoxDialog() = delete; - KsCheckBoxDialog(KsCheckBoxWidget *cbw, QWidget *parent = nullptr); + KsCheckBoxDialog(QVector cbws, + QWidget *parent = nullptr); + + /** + * The "apply" signal will emit a vector containing the Ids of all + * checked checkboxe. + */ + void applyIds(bool v = true) {_applyIds = v;} + + /** + * The "apply" signal will emit a vector containing the statuse of all + * checkboxe. + */ + void applyStatus(bool v = true) {_applyIds = !v;} signals: /** Signal emitted when the "Apply" button is pressed. */ - void apply(QVector); + void apply(int sd, QVector); private: void _applyPress(); - QVBoxLayout _topLayout; + virtual void _preApplyAction() {} + + virtual void _postApplyAction() {} + + bool _applyIds; + + QVBoxLayout _topLayout; - QHBoxLayout _buttonLayout; + QHBoxLayout _cbLayout, _buttonLayout; - KsCheckBoxWidget *_checkBoxWidget; + QVector _checkBoxWidgets; - QPushButton _applyButton, _cancelButton; + QPushButton _applyButton, _cancelButton; QMetaObject::Connection _applyButtonConnection; }; +/** + * The KsPluginsCheckBoxDialog provides dialog for selecting plugins. + * used by KernelShark. The class is used to override _postApplyAction(). + */ +class KsPluginsCheckBoxDialog : public KsCheckBoxDialog +{ +public: + KsPluginsCheckBoxDialog() = delete; + + /** Create KsPluginsCheckBoxDialog. */ + KsPluginsCheckBoxDialog(QVector cbws, + KsDataStore *d, QWidget *parent = nullptr) + : KsCheckBoxDialog(cbws, parent), _data(d) {} + +private: + virtual void _postApplyAction() override; + + KsDataStore *_data; +}; + /** The KsCheckBoxTable class provides a table of checkboxes. */ class KsCheckBoxTable : public QTableWidget { @@ -205,9 +429,16 @@ class KsCheckBoxTableWidget : public KsCheckBoxWidget { Q_OBJECT public: - KsCheckBoxTableWidget(const QString &name = "", + KsCheckBoxTableWidget(int sd, const QString &name = "", QWidget *parent = nullptr); + /** Only one checkboxe at the time can be checked. */ + void setSingleSelection() + { + _table.setSelectionMode(QAbstractItemView::SingleSelection); + setVisibleCbAll(false); + } + protected: void _adjustSize(); @@ -266,9 +497,16 @@ class KsCheckBoxTreeWidget : public KsCheckBoxWidget public: KsCheckBoxTreeWidget() = delete; - KsCheckBoxTreeWidget(const QString &name = "", + KsCheckBoxTreeWidget(int sd, const QString &name = "", QWidget *parent = nullptr); + /** Only one checkboxe at the time can be checked. */ + void setSingleSelection() + { + _tree.setSelectionMode(QAbstractItemView::SingleSelection); + setVisibleCbAll(false); + } + protected: void _adjustSize(); @@ -304,7 +542,7 @@ struct KsCPUCheckBoxWidget : public KsCheckBoxTreeWidget { KsCPUCheckBoxWidget() = delete; - KsCPUCheckBoxWidget(struct tep_handle *pe, + KsCPUCheckBoxWidget(kshark_data_stream *stream, QWidget *parent = nullptr); }; @@ -316,7 +554,7 @@ struct KsTasksCheckBoxWidget : public KsCheckBoxTableWidget { KsTasksCheckBoxWidget() = delete; - KsTasksCheckBoxWidget(struct tep_handle *pe, + KsTasksCheckBoxWidget(kshark_data_stream *stream, bool cond = true, QWidget *parent = nullptr); @@ -336,12 +574,17 @@ struct KsEventsCheckBoxWidget : public KsCheckBoxTreeWidget { KsEventsCheckBoxWidget() = delete; - KsEventsCheckBoxWidget(struct tep_handle *pe, + KsEventsCheckBoxWidget(kshark_data_stream *stream, QWidget *parent = nullptr); QStringList getCheckedEvents(bool option); void removeSystem(QString name); + +private: + void _makeItems(kshark_data_stream *stream, QVector eventIds); + + void _makeTepEventItems(kshark_data_stream *stream, QVector eventIds); }; /** @@ -351,8 +594,56 @@ struct KsPluginCheckBoxWidget : public KsCheckBoxTableWidget { KsPluginCheckBoxWidget() = delete; - KsPluginCheckBoxWidget(QStringList pluginList, + KsPluginCheckBoxWidget(int sd, QStringList pluginList, QWidget *parent = nullptr); + + void setInfo(int row, QString info); + + void setActive(QVector rows, bool a); }; +/** + * The KsDStreamCheckBoxWidget class provides a widget for selecting Data streams. + */ +struct KsDStreamCheckBoxWidget : public KsCheckBoxTableWidget +{ + explicit KsDStreamCheckBoxWidget(QWidget *parent = nullptr); +}; + +/** + * The KsEventFieldSelectWidget class provides a widget for selecting a data + * field of the trace event. + */ +class KsEventFieldSelectWidget : public QWidget +{ + Q_OBJECT +public: + explicit KsEventFieldSelectWidget(QWidget *parent = nullptr); + + /** Get the currently selected stream Id. */ + int streamId() const {return _streamComboBox.currentData().toInt();} + + /** Get the currently selected event name. */ + QString eventName() const {return _eventComboBox.currentText();} + + /** Get the currently selected field name. */ + QString fieldName() const {return _fieldComboBox.currentText();} + + void setStreamCombo(); + +private slots: + void _streamChanged(const QString &stream); + + void _eventChanged(const QString &event); + +private: + QVBoxLayout _topLayout; + + QComboBox _streamComboBox, _eventComboBox, _fieldComboBox; + + QLabel _streamLabel, _eventLabel, _fieldLabel; +}; + +}; // KsWidgetsLib + #endif From patchwork Thu Feb 11 10:31:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082731 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.7 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 C6BD1C433E0 for ; Thu, 11 Feb 2021 10:38:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9709964E95 for ; Thu, 11 Feb 2021 10:38:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229891AbhBKKhw (ORCPT ); Thu, 11 Feb 2021 05:37:52 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46400 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230144AbhBKKfo (ORCPT ); Thu, 11 Feb 2021 05:35:44 -0500 Received: from mail-ed1-x52c.google.com (mail-ed1-x52c.google.com [IPv6:2a00:1450:4864:20::52c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 70D34C0617AA for ; Thu, 11 Feb 2021 02:32:34 -0800 (PST) Received: by mail-ed1-x52c.google.com with SMTP id q2so6424158edi.4 for ; Thu, 11 Feb 2021 02:32:34 -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=m4+jUQ3tJ43/c+ftesBve5vHRlWZboe+bBaAh67cMdM=; b=nasoYyC47KNBNY9nWHPKvAQwq7iTmNKjDyDcf6HgeJa1mBXIxDCNFvg2OKpHMtSGdZ wGPdMCbxUI8By5WXU2z6GvGa6v5ypUUFyCiF7vH9lbRMvYBUMGblve9eRbRPYSELBeG6 7gxpVVM6slRCjhmP+d0ejC5F/rrbvEZDtfF4/xJx+WBD3kgAZkMpOoyFJsNRaVT3+61W TOPlowCIH8esoiViOHmjS//Szosnoh4J5LpI80ssn9eH3fb2oTjQ+DxazCmFU1nAA56X AZFxN2ZS1+YlJ39Uj47Gb9GLGzO6pFhgiTWrqpGuUsph8MGrA7b7dc+oLjbWx2ISw5oU J3dA== 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=m4+jUQ3tJ43/c+ftesBve5vHRlWZboe+bBaAh67cMdM=; b=cNpqDdvFbp/NKUiiuhmuvv4Ur+wQzC1RNpy8GTy26fxTMKlD1adxzlN7xAes/Y6f1O P5pyRXGs12x+FslHzu873Njp9vGB0Nd1lTNTldsQLqC6SamEkqSprcfANwnEINhWTQyt gTHv2M8HfSCXs0L+3jvkUb6u+ctH2FeguhddOUWJ9zoDg679u3yhfyPyhVbqxO2ZGlXc KIDExKEXbTMhuACFAyWeHbvwTeYI/9xx2yDItTLrJTRakme73TZs5QfIqQxT8XwQ8yJ/ Pak67VQkhbOZ8rLaoHQ5Uoe/Di1FajmCdnCV/rbCwBowkeSlfWLv6R615n5pkgGcvHLI FFLg== X-Gm-Message-State: AOAM530YOJ+LU2rkvqX/hLgRkZxUXQnKhOcYzxUuw33HNJUEPQYrcX6p 6khGR8h0U0BkkPFtHSALwGA= X-Google-Smtp-Source: ABdhPJzmTDa+JvKkV53NAw3Jlwkq/eXVy7bIq4PANIp+DxCqhAktGjkbZhWDOwa8i49ReNhBIA/byQ== X-Received: by 2002:a50:8a90:: with SMTP id j16mr7624796edj.334.1613039553173; Thu, 11 Feb 2021 02:32:33 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:32 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 12/27] kernel-shark: Add combo point to Mark Date: Thu, 11 Feb 2021 12:31:50 +0200 Message-Id: <20210211103205.418588-13-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org KsPlot::Mark uses colored point to highlight the selected trace event on CPU and Task plots. Here we add a combo point that will highlight the selected event in Combo plots, like "Virtual Combo" for example. Those Combo plots will be introduced at the level of the GUI code in successive patches. Signed-off-by: Yordan Karadzhov (VMware) --- src/KsPlotTools.cpp | 23 ++++++++++++++++++++++- src/KsPlotTools.hpp | 15 ++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/KsPlotTools.cpp b/src/KsPlotTools.cpp index ac9c5b2..225dc34 100644 --- a/src/KsPlotTools.cpp +++ b/src/KsPlotTools.cpp @@ -701,7 +701,7 @@ void Mark::_draw(const Color &col, float size) const void Mark::setDPR(int dpr) { _size = 1.5 * dpr; - _task._size = _cpu._size = 1.5 + 4.0 * dpr; + _task._size = _cpu._size = _combo._size = 1.5 + 4.0 * dpr; } /** @@ -715,6 +715,7 @@ void Mark::setX(int x) _b.setX(x); _cpu.setX(x); _task.setX(x); + _combo.setX(x); } /** @@ -769,6 +770,26 @@ void Mark::setTaskVisible(bool v) _task._visible = v; } +/** + * @brief Set the visiblity of the Mark's Combo point. + * + * @param v: If True, the Task point will be visible. + */ +void Mark::setComboVisible(bool v) +{ + _combo._visible = v; +} + +/** + * @brief Set the Y coordinates (vertical) of the Mark's Combo points. + * + * @param yCombo: Y coordinate of the Mark's Task point. + */ +void Mark::setComboY(int yCombo) +{ + _combo.setY(yCombo); +} + /** * @brief Create a default Bin. */ diff --git a/src/KsPlotTools.hpp b/src/KsPlotTools.hpp index c993181..a9a5ba8 100644 --- a/src/KsPlotTools.hpp +++ b/src/KsPlotTools.hpp @@ -406,6 +406,16 @@ public: /** If True, the Mark will be plotted as a dashed line. */ void setDashed(bool d) {_dashed = d;} + /** Get the Y coordinate of the Mark's Combo point. */ + int comboY() const {return _combo.y();} + + void setComboY(int yCombo); + + /** Is the Combo point visible. */ + bool comboIsVisible() const {return _combo._visible;} + + void setComboVisible(bool v); + private: void _draw(const Color &col, float size = 1.) const override; @@ -421,7 +431,10 @@ private: /** A point indicating the position of the Mark in a Task graph. */ Point _task; - /* If True, plot the Mark as a dashed line. */ + /** A point indicating the position of the Mark in a Combo graph. */ + Point _combo; + + /** If True, plot the Mark as a dashed line. */ bool _dashed; }; From patchwork Thu Feb 11 10:31:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082739 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.7 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 39907C433E0 for ; Thu, 11 Feb 2021 10:38:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0593864E95 for ; Thu, 11 Feb 2021 10:38:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230116AbhBKKiY (ORCPT ); Thu, 11 Feb 2021 05:38:24 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46402 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230147AbhBKKfo (ORCPT ); Thu, 11 Feb 2021 05:35:44 -0500 Received: from mail-ed1-x534.google.com (mail-ed1-x534.google.com [IPv6:2a00:1450:4864:20::534]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5CDE1C0617AB for ; Thu, 11 Feb 2021 02:32:35 -0800 (PST) Received: by mail-ed1-x534.google.com with SMTP id v7so6371109eds.10 for ; Thu, 11 Feb 2021 02:32:35 -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=77/C7IL9bwjDIfN6W1HD95rM7DeBqtf9m1fmX4fHhKw=; b=kUn8BrAQ0do04hXIawa2VF4gl/Ft/XL6ycMD/Uy30P5FLZg8GVkt3aTSc9tTDCAFim 4REymHDFhQKklc2s8Rr0oGf7kooxp/37R5COPZ42K5EKiP7qNfctyNPAgaOzGU8dyg54 JEZehIdHlmm5gD3y/Gl+kNEh+1XgHcTFXkpDz+uX6QUvbLlGo/DgUDPaym2Y9M4v6SO2 mne8JM6EBcQPvnQK+goGFBN2eo/11nobNcmvDjFq3XrsxmEcLMghOaZYDLTw/7JfINsC egqFwtPfAHjHI89TEMflqN6AguEIZoux1Rb6va7O2kiFc/Awt9nwRLfUg+xLr1pHHgNl dj4w== 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=77/C7IL9bwjDIfN6W1HD95rM7DeBqtf9m1fmX4fHhKw=; b=A8oND7WL/UwBLXYCJ78TZ3lDmjXHbD9nT4Iwg+tJNSnjjqfsvUQmZ7HHZAeSHahZ5M DhE1uHvbfF9NBs2yIJsLvOyGhzG6KoEULUCmyLrmHzEjXJErNhOD/Bsv5YNHxykrDeM7 ysdInqf1EVdRpqcu6rN3z753YQYi0WxODPJlzLCxf2aWMOwJGxwPNXw1b8EKStS602/M S4E6hwEU0s5uP9J3pWyY/YwK6iC2cj48i++GZ2G9Tzo0ZrzWuqxj1fQDkM6oU7Kp42/t LV3QqrKDbzjWu39BKwIOb6AcAmxkVeIKt6PnjKH4qK5OcNIEhz2ApQ346Ltp8VVbqBxY Zztg== X-Gm-Message-State: AOAM5336HYgIUTGo89er1yJz8WQ1HmvEMKDni6d6HfcqOHlQBU79N0pq Oqwyy/cZuzBNslkV9gDrFLo= X-Google-Smtp-Source: ABdhPJyVoJZ+oY+U0rF/PSszKJnbHiMqeR108mRcYDoP5Qqq1MdQa/trRGwHxGvWTFkXn8PK66ybIQ== X-Received: by 2002:a05:6402:1152:: with SMTP id g18mr7874839edw.18.1613039554193; Thu, 11 Feb 2021 02:32:34 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:33 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 13/27] kernel-shark: Add new methods to KsPlot::Mark Date: Thu, 11 Feb 2021 12:31:51 +0200 Message-Id: <20210211103205.418588-14-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The new "get" methods are needed by the logic of the GUI. Signed-off-by: Yordan Karadzhov (VMware) --- src/KsPlotTools.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/KsPlotTools.hpp b/src/KsPlotTools.hpp index a9a5ba8..1725926 100644 --- a/src/KsPlotTools.hpp +++ b/src/KsPlotTools.hpp @@ -395,12 +395,24 @@ public: void setY(int yA, int yB); + /** Get the Y coordinate of the Mark's CPU point. */ + int cpuY() const {return _cpu.y();} + void setCPUY(int yCPU); + /** Is the CPU point visible. */ + bool cpuIsVisible() const {return _cpu._visible;} + void setCPUVisible(bool v); + /** Get the Y coordinate of the Mark's Task point. */ + int taskY() const {return _task.y();} + void setTaskY(int yTask); + /** Is the Task point visible. */ + bool taskIsVisible() const {return _task._visible;} + void setTaskVisible(bool v); /** If True, the Mark will be plotted as a dashed line. */ From patchwork Thu Feb 11 10:31:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082733 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.7 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 0AA84C433E0 for ; Thu, 11 Feb 2021 10:38:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C928064E95 for ; Thu, 11 Feb 2021 10:38:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230365AbhBKKh4 (ORCPT ); Thu, 11 Feb 2021 05:37:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46408 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230155AbhBKKfp (ORCPT ); Thu, 11 Feb 2021 05:35:45 -0500 Received: from mail-ed1-x52d.google.com (mail-ed1-x52d.google.com [IPv6:2a00:1450:4864:20::52d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3C78FC061356 for ; Thu, 11 Feb 2021 02:32:36 -0800 (PST) Received: by mail-ed1-x52d.google.com with SMTP id y8so6400868ede.6 for ; Thu, 11 Feb 2021 02:32: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=mk7RKVqltUL8uHv6iXoM+w2VJPqVIq3/xp5TZZFUx4Y=; b=ZCV6gJVVhRR9iD4Bd5DEVOsvNOIB8pUPhlJJhy1Ie0KrE650lfICKNPzd6wzHHZWcL nUO6lFtQeB1qfizVyTMevLBG6/JwHC5TxwKtqpHszHEuInab/8ciAlpJS4SXhqWMX88+ 9NwjSr/RM0Oeb9BWb3Ce14b+zQxVSOeQ3ebNbavwEHCN+7ED8LKlPhNbHWnz9ND58b/+ ebnDIsM0JNgag3a7qu+nGvzefyXQ1glQd8snxOfKEXTyBDQsu0vJpMB7sqNhcElGugyQ O+QjMNhDpfUTEyRTZtJ7BEP1zxIAv2pDOpNGMI3VS1OimTWwpSEr5uu8tIjhGJnxBmNN P6+A== 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=mk7RKVqltUL8uHv6iXoM+w2VJPqVIq3/xp5TZZFUx4Y=; b=Xe8B1BbAlDxpVTKE8AXFLVQ+oaYxXB6OGnOrwh6BN0KWl6np8cxB996yPITTjBkIh5 s8Kr/MLo+BNN9vOhMphpG7tJuDu1oUQG0HTK3ClAw6Jo1FcYn9RQ5dlxTYJBJJr9XVWK c8FzO0rr0J8m/XiMzxJ6V+IDecdJ/MUUtqVaNbLYqB7aKMhXUCK23W1lcRr8mMWMocKG whcG99RYCO53NQGAyQ7IezoiI5BEAa1+aUxf/rznpuA4UanCNcHN4bhy/0nCHQjC7T+C jJxFkaqG223KdB+ozrjEhCNwmZOHbNp0XlMHyURmmM2H5QBJf7xXhI7BxykKZJv6EXI1 WiRg== X-Gm-Message-State: AOAM530sRqKGqi+NbN4UmBp1Q8aon61eafRWEBn8je0PMeAdgnPKmrvM ykz7jY3GeqZAv7G6DOO38sY= X-Google-Smtp-Source: ABdhPJyP7LYGgw1VRvtb853EVpSyc9O4wY8qTI9ofSTyLEjpFc60AeeI5U58WzDT1VJF5vESk6b18Q== X-Received: by 2002:aa7:d692:: with SMTP id d18mr7829208edr.327.1613039554963; Thu, 11 Feb 2021 02:32:34 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:34 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 14/27] kernel-shark: Update the plotting example Date: Thu, 11 Feb 2021 12:31:52 +0200 Message-Id: <20210211103205.418588-15-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The compilation of the plotting example is re-enabled and it is made compatible with the new version of the C API of libkshark (KernelShark 2.0). Signed-off-by: Yordan Karadzhov (VMware) --- examples/CMakeLists.txt | 6 +-- examples/dataplot.cpp | 88 ++++++++++++++++++++++++++++------------- 2 files changed, 63 insertions(+), 31 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 8360841..e6af5f2 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -20,9 +20,9 @@ message(STATUS "confogio") add_executable(confio configio.c) target_link_libraries(confio kshark) -# message(STATUS "dataplot") -# add_executable(dplot dataplot.cpp) -# target_link_libraries(dplot kshark-plot) +message(STATUS "dataplot") +add_executable(dplot dataplot.cpp) +target_link_libraries(dplot kshark-plot) if (Qt5Widgets_FOUND) diff --git a/examples/dataplot.cpp b/examples/dataplot.cpp index 94841e7..b3ff29f 100644 --- a/examples/dataplot.cpp +++ b/examples/dataplot.cpp @@ -10,6 +10,7 @@ // C++ #include #include +#include // OpenGL #include @@ -20,25 +21,29 @@ using namespace std; -#define GRAPH_HEIGHT 40 // width of the graph in pixels -#define GRAPH_H_MARGIN 50 // size of the white space surrounding the graph -#define WINDOW_WIDTH 800 // width of the screen window in pixels -#define WINDOW_HEIGHT 480 // height of the scrren window in pixels +#define GRAPH_HEIGHT 40 // width of the graph in pixels +#define GRAPH_H_MARGIN 15 // size of the white space surrounding + // the graph +#define GRAPH_LABEL_WIDTH 80 // width of the graph's label in pixels +#define WINDOW_WIDTH 800 // width of the screen window in pixels +#define WINDOW_HEIGHT 480 // height of the scrren window in pixels #define default_file (char*)"trace.dat" struct kshark_trace_histo histo; vector graphs; +struct ksplot_font font; +int stream_id; void usage(const char *prog) { cout << "Usage: " << prog << endl; - cout << " -h Display this help message\n"; + cout << " -h Display this help message.\n"; cout << " -s Draw shapes. This demonstrates how to draw simple " << "geom. shapes.\n"; cout << " -i Input file and draw animated graphs.\n"; cout << " No args. Import " << default_file - << "and draw animated graphs.\n"; + << " and draw animated graphs.\n"; } /* An example function drawing something. */ @@ -57,6 +62,11 @@ void drawShapes() t._color = {100, 200, 50}; t.draw(); + /* Print/draw "Hello Kernel!". */ + KsPlot::Color col = {50, 150, 255}; + KsPlot::TextBox tb(&font, "Hello Kernel!", col, {250, 70}, 250); + tb.draw(); + KsPlot::Rectangle r; KsPlot::Point d(400, 200), e(400, 300), f(500, 300), g(500, 200); r.setPoint(0, d); @@ -78,13 +88,14 @@ void drawShapes() /* An example function demonstrating Zoom In and Zoom Out. */ void play() { - KsPlot::ColorTable taskColors = KsPlot::getTaskColorTable(); - KsPlot::ColorTable cpuColors = KsPlot::getCPUColorTable(); + KsPlot::ColorTable taskColors = KsPlot::taskColorTable(); + KsPlot::ColorTable cpuColors = KsPlot::CPUColorTable(); vector::iterator it; + KsPlot::Graph *graph; vector CPUs, Tasks; bool zoomIn(true); int base; - size_t i; + size_t i(1); CPUs = {3, 4, 6}; Tasks = {}; // Add valid pids here, if you want task plots. @@ -92,35 +103,47 @@ void play() auto lamAddGraph = [&] (KsPlot::Graph *g) { /* Set the dimensions of the Graph. */ g->setHeight(GRAPH_HEIGHT); - g->setHMargin(GRAPH_H_MARGIN); /* * Set the Y coordinate of the Graph's base. * Remember that the "Y" coordinate is inverted. */ - base = 1.7 * GRAPH_HEIGHT * (i + 1); + base = 1.7 * GRAPH_HEIGHT * (i++); g->setBase(base); + g->setLabelAppearance(&font, {160, 255, 255}, GRAPH_LABEL_WIDTH, + GRAPH_H_MARGIN); + /* Add the Graph. */ graphs.push_back(g); }; - for (i = 0; i < CPUs.size(); ++i) - lamAddGraph(new KsPlot::Graph(&histo, &taskColors, - &taskColors)); + for (auto const &cpu: CPUs) { + std::stringstream ss; + ss << "CPU " << cpu; + + graph = new KsPlot::Graph(&histo, &taskColors, &taskColors); + graph->setLabelText(ss.str()); + lamAddGraph(graph); + } + + for (auto const &pid: Tasks) { + std::stringstream ss; + ss << "PID " << pid; - for (;i < CPUs.size() + Tasks.size(); ++i) - lamAddGraph(new KsPlot::Graph(&histo, &taskColors, - &cpuColors)); + graph = new KsPlot::Graph(&histo, &taskColors, &cpuColors); + graph->setLabelText(ss.str()); + lamAddGraph(graph); + } for (i = 1; i < 1000; ++i) { it = graphs.begin(); for (int const &cpu: CPUs) - (*it++)->fillCPUGraph(cpu); + (*it++)->fillCPUGraph(stream_id, cpu); for (int const &pid: Tasks) - (*it++)->fillTaskGraph(pid); + (*it++)->fillTaskGraph(stream_id, pid); /* Clear the screen. */ glClear(GL_COLOR_BUFFER_BIT); @@ -146,7 +169,8 @@ int main(int argc, char **argv) struct kshark_context *kshark_ctx(nullptr); struct kshark_entry **data(nullptr); static char *input_file(nullptr); - bool status, shapes(false); + bool shapes(false); + char *font_file; size_t r, nRows; int c, nBins; @@ -166,11 +190,20 @@ int main(int argc, char **argv) } } + font_file = ksplot_find_font_file("FreeMono", "FreeMonoBold"); + if (!font_file) + return 1; + auto lamDraw = [&] (void (*func)(void)) { - /* Initialize OpenGL/Glut. */ + /* Initialize Glut. */ glutInit(&argc, argv); ksplot_make_scene(WINDOW_WIDTH, WINDOW_HEIGHT); + + /* Initialize OpenGL. */ ksplot_init_opengl(1); + ksplot_resize_opengl(WINDOW_WIDTH, WINDOW_HEIGHT); + + ksplot_init_font(&font, 18, font_file); /* Display something. */ glutDisplayFunc(func); @@ -191,8 +224,8 @@ int main(int argc, char **argv) if (!input_file) input_file = default_file; - status = kshark_open(kshark_ctx, input_file); - if (!status) { + stream_id = kshark_open(kshark_ctx, input_file); + if (stream_id < 0) { kshark_free(kshark_ctx); usage(argv[0]); cerr << "\nFailed to open file " << input_file << endl; @@ -201,12 +234,12 @@ int main(int argc, char **argv) } /* Load the content of the file into an array of entries. */ - nRows = kshark_load_data_entries(kshark_ctx, &data); + nRows = kshark_load_entries(kshark_ctx, stream_id, &data); /* Initialize the Visualization Model. */ ksmodel_init(&histo); - nBins = WINDOW_WIDTH - 2 * GRAPH_HEIGHT; + nBins = WINDOW_WIDTH - GRAPH_LABEL_WIDTH - 3 * GRAPH_H_MARGIN; ksmodel_set_bining(&histo, nBins, data[0]->ts, data[nRows - 1]->ts); @@ -216,6 +249,8 @@ int main(int argc, char **argv) /* Play animated Graph. */ lamDraw(play); + free(font_file); + /* Free the memory. */ for (auto &g: graphs) delete g; @@ -227,9 +262,6 @@ int main(int argc, char **argv) /* Reset (clear) the model. */ ksmodel_clear(&histo); - /* Close the file. */ - kshark_close(kshark_ctx); - /* Close the session. */ kshark_free(kshark_ctx); From patchwork Thu Feb 11 10:31:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082745 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=-20.7 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,MENTIONS_GIT_HOSTING,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 6E49BC433DB for ; Thu, 11 Feb 2021 10:39:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 364FD64E9A for ; Thu, 11 Feb 2021 10:39:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230191AbhBKKih (ORCPT ); Thu, 11 Feb 2021 05:38:37 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46410 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230177AbhBKKfp (ORCPT ); Thu, 11 Feb 2021 05:35:45 -0500 Received: from mail-ej1-x631.google.com (mail-ej1-x631.google.com [IPv6:2a00:1450:4864:20::631]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 282BFC06121C for ; Thu, 11 Feb 2021 02:32:37 -0800 (PST) Received: by mail-ej1-x631.google.com with SMTP id f14so9257129ejc.8 for ; Thu, 11 Feb 2021 02:32: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=Q0x7OzHuHGLt4vm+vDXFtc2NcFBhXSQjvX9kEj5iZvE=; b=LS8ENm3nHcPJlWDndpWaVkCOaI/gCE1oMygjCMkPG05OPzgGReF/YwqB5q3ebprzX2 q1hqPpLQb5WuRn3VL1ktpMc3v42s4lSMB/OZP8SrNvSRi8v4AA5XFZNGoRA3HRqcrKTv r2J/HVuF6/gto2RayhBTQAGa+yOrz3wSWVjf92xgNIfgeQsBtZV4ffNPXXgTlU/kKDB8 8C2FNrFGBWlr9b359qduNlQcdv7GFCCTIpxHr8KFuPr4b8q9yTucxHGOi2oyYqqUajk+ hPh8u/47PV+IdMMwdSaZo3QfjSEeh3lxKHtSwvQFtKe+6U1OTgYhX0NsdeyA0QZNyGlL vVZQ== 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=Q0x7OzHuHGLt4vm+vDXFtc2NcFBhXSQjvX9kEj5iZvE=; b=XP+MfJc/PWaALBP+hwzVLmRpRtZdHvWkaRAX9rvzfqtHJMHtViKGluF+66nJYSzvMB rdpJTVSjbKc1GTk5YG+TonH2o5bphC/mSgrM9llGcd4bkKfDcN/4wUXa3G+OmwiIU5PB 6cD1rV9fiNr9CGy7tcZvIRYvu5Xmlp33IyTRPOICH4xcektNdZLEPnJ0ZZmEEDEqg92p Tx9hiDYoO43zW44N46cyohM78r/c2Uc8dgXtkLupdude8dTp7PxOLNz4lp1w6JXak4Ma WIgEYCr+Bjr99cd2gd84y39Qw1vRC+KvxsKX4Az3NfNaW7N7JCO8mKJXmyBPDMGAIpzH nY+g== X-Gm-Message-State: AOAM5327+TbEka+tJuPb1LIcSstY9KsOOzizjgK0X0cTR124dg6JlPkn KFRkzOdkx+Pm8kDtKs9uzk0= X-Google-Smtp-Source: ABdhPJzhTbvtO4ZwrmPQsre5rqtAsDFI18VHHvME1k3pO9MoICY6ZIObN4CZS3O2FXh1Pr4zGymsOg== X-Received: by 2002:a17:906:7687:: with SMTP id o7mr7948000ejm.209.1613039555927; Thu, 11 Feb 2021 02:32:35 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:35 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 15/27] kernel-shark: Search for font with Cmake at pre-build Date: Thu, 11 Feb 2021 12:31:53 +0200 Message-Id: <20210211103205.418588-16-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Being able to load the Truetype font is compulsory for the functioning of the visualization, hence the font must be considered as critical external dependency. Add a search for the font file next to the search of the other third party dependencies and have this file added as definition in the Cmake-generated header file. This way we do not need to search for the font every time when we open KernelShark. Signed-off-by: Yordan Karadzhov (VMware) --- .github/workflows/main.yml | 1 + CMakeLists.txt | 14 ++++++++++++++ README | 1 + build/deff.h.cmake | 3 +++ examples/CMakeLists.txt | 4 ++-- src/CMakeLists.txt | 4 ++-- tests/CMakeLists.txt | 22 +++++++++++++--------- tests/libkshark-tests.cpp | 9 +++++++++ 8 files changed, 45 insertions(+), 13 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2cce624..4125354 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,6 +19,7 @@ jobs: sudo apt-get update sudo apt-get install build-essential git cmake libjson-c-dev -y sudo apt-get install freeglut3-dev libxmu-dev libxi-dev -y + sudo apt-get install fonts-freefont-ttf sudo apt-get install qtbase5-dev libboost-all-dev -y git clone https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/ cd libtraceevent diff --git a/CMakeLists.txt b/CMakeLists.txt index b9b947e..8ca33fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,20 @@ set(OpenGL_GL_PREFERENCE LEGACY) find_package(OpenGL) find_package(GLUT) +set(KS_FONT FreeSans) +execute_process(COMMAND bash "-c" "fc-list '${KS_FONT}' |grep ${KS_FONT}.ttf | cut -d':' -f 1 -z" + OUTPUT_VARIABLE TT_FONT_FILE) + +if (TT_FONT_FILE) + + message(STATUS "Found font: ${TT_FONT_FILE}") + +else (TT_FONT_FILE) + + message(WARNING "\nCould not find font ${KS_FONT}!\n") + +endif (TT_FONT_FILE) + find_package(Qt5Widgets 5.7.1) find_package(Qt5Network) if (Qt5Widgets_FOUND) diff --git a/README b/README index d7efd96..a7e66df 100644 --- a/README +++ b/README @@ -12,6 +12,7 @@ KernelShark has the following external dependencies: 1. In order to install the packages on Ubuntu do the following: sudo apt-get install build-essential git cmake libjson-c-dev -y sudo apt-get install freeglut3-dev libxmu-dev libxi-dev -y + sudo apt-get install fonts-freefont-ttf sudo apt-get install qtbase5-dev -y 1.1 I you want to be able to generate Doxygen documentation: diff --git a/build/deff.h.cmake b/build/deff.h.cmake index 423a2fd..06cbf16 100644 --- a/build/deff.h.cmake +++ b/build/deff.h.cmake @@ -26,6 +26,9 @@ /** GLUT has been found. */ #cmakedefine GLUT_FOUND +/** Truetype font file. */ +#cmakedefine TT_FONT_FILE "@TT_FONT_FILE@" + /** Qt - old version detected. */ #cmakedefine QT_VERSION_LESS_5_11 diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e6af5f2..bc17635 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -24,7 +24,7 @@ message(STATUS "dataplot") add_executable(dplot dataplot.cpp) target_link_libraries(dplot kshark-plot) -if (Qt5Widgets_FOUND) +if (Qt5Widgets_FOUND AND TT_FONT_FILE) message(STATUS "widgetdemo") add_executable(widgetdemo widgetdemo.cpp) @@ -34,4 +34,4 @@ if (Qt5Widgets_FOUND) add_executable(cmd_split cmd_split.cpp) target_link_libraries(cmd_split kshark-gui) -endif (Qt5Widgets_FOUND) +endif (Qt5Widgets_FOUND AND TT_FONT_FILE) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 140fed8..6c02d82 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -63,7 +63,7 @@ if (OPENGL_FOUND) endif (OPENGL_FOUND) -if (Qt5Widgets_FOUND AND Qt5Network_FOUND) +if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) message(STATUS "libkshark-gui") set (ks-guiLib_hdr KsUtils.hpp @@ -134,7 +134,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) DESTINATION ${_INSTALL_PREFIX}/bin/ COMPONENT kernelshark) -endif (Qt5Widgets_FOUND AND Qt5Network_FOUND) +endif (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) add_subdirectory(plugins) set(PLUGINS ${PLUGINS} PARENT_SCOPE) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 28f711b..1814c72 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -38,13 +38,17 @@ add_test(NAME "libkshark_tests" COMMAND ${KS_TEST_DIR}/kshark-tests --log_format=HRF WORKING_DIRECTORY ${KS_TEST_DIR}) -add_executable(kshark-gui-tests libkshark-gui-tests.cpp) -target_include_directories(kshark-gui-tests PRIVATE ${Boost_INCLUDE_DIRS}) -target_compile_definitions(kshark-gui-tests PRIVATE "BOOST_TEST_DYN_LINK=1") -target_link_libraries(kshark-gui-tests kshark-gui - ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) +if (Qt5Widgets_FOUND AND TT_FONT_FILE) -message(STATUS "libkshark-gui_tests") -add_test(NAME "libkshark-gui_tests" - COMMAND ${KS_TEST_DIR}/kshark-gui-tests --log_format=HRF - WORKING_DIRECTORY ${KS_TEST_DIR}) + add_executable(kshark-gui-tests libkshark-gui-tests.cpp) + target_include_directories(kshark-gui-tests PRIVATE ${Boost_INCLUDE_DIRS}) + target_compile_definitions(kshark-gui-tests PRIVATE "BOOST_TEST_DYN_LINK=1") + target_link_libraries(kshark-gui-tests kshark-gui + ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) + + message(STATUS "libkshark-gui_tests") + add_test(NAME "libkshark-gui_tests" + COMMAND ${KS_TEST_DIR}/kshark-gui-tests --log_format=HRF + WORKING_DIRECTORY ${KS_TEST_DIR}) + +endif (Qt5Widgets_FOUND AND TT_FONT_FILE) diff --git a/tests/libkshark-tests.cpp b/tests/libkshark-tests.cpp index a22c1e5..5f7c88a 100644 --- a/tests/libkshark-tests.cpp +++ b/tests/libkshark-tests.cpp @@ -435,3 +435,12 @@ BOOST_AUTO_TEST_CASE(readout_plugins) kshark_free(kshark_ctx); } + +BOOST_AUTO_TEST_CASE(check_font_found) +{ +#ifdef TT_FONT_FILE +BOOST_REQUIRE(true); +#else +BOOST_REQUIRE(false); +#endif +} From patchwork Thu Feb 11 10:31:54 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082743 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.7 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 ED3D9C433E0 for ; Thu, 11 Feb 2021 10:38:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8D9BF64E9A for ; Thu, 11 Feb 2021 10:38:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230209AbhBKKig (ORCPT ); Thu, 11 Feb 2021 05:38:36 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46422 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230191AbhBKKfs (ORCPT ); Thu, 11 Feb 2021 05:35:48 -0500 Received: from mail-ej1-x630.google.com (mail-ej1-x630.google.com [IPv6:2a00:1450:4864:20::630]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BE9E4C06121D for ; Thu, 11 Feb 2021 02:32:38 -0800 (PST) Received: by mail-ej1-x630.google.com with SMTP id i8so9257107ejc.7 for ; Thu, 11 Feb 2021 02:32: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=CTTjv0HS6rHH6gl/Dq9BngtCA6ve2sCn45fKULW5A6w=; b=KpeYVy/KXMSdL1wrAcVXjf/YG5iMpBEPGjkMAr5kENgCBKP1g+g8G5plD7do3Nlsut FHsUAwRXvCxBgj3wQUTcAq8mAU3g3rrk1TkDr7pFDV+RXK7hJ8tivhLhRbnWOaCpaT5Z SwJSKYvZIO6SRLTYr19BRt7CJd16S7S0qGztPXZR8/20HOgOMq1CY/fcrEKhrfueAwav hIHgoVXDMycK5rcaLAWiB7cUXIe8iMGxcWxD90YUbpEAnkfDzfCgwt0IhoKOVTMNM2Gq kEY5+o5xcCB/L+SGAkdW9Pt0I17J4tF7znO0LNVwl2lwhLiWqyYbX381kKZq5yNYf2yC BtbQ== 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=CTTjv0HS6rHH6gl/Dq9BngtCA6ve2sCn45fKULW5A6w=; b=hnx6auZGgcgs04Cp40BXEXWewYtelsYIwYK9rucQ91rlu7E7bIawkAeNzSsvRcD4Q/ 1Ukv3YfiWhM0zKQuuYFRqP07W6WjpHQ0UeASI+OT6/XMkBFbxhpk3zVhqE0rGLxRwPob 9nErdV+TZUEgHZq1K1xXJlCgtxcWZmzV5vQ+cxQJjfmrsKcXDnlVq/TWXyTTl52IJRGU CDpsiLS78JqumKqZDtveKvLO5mwum4OQG99vYWACfM17Gu3h1KUa3fH6E8Q6w66r3EFh gDPxmou0DW77Q/Sc44tqaUGI7PWbq4coOa6CkKWlGcXjCbEuRIoAC/xVirA9QhjHw2sd otFw== X-Gm-Message-State: AOAM531wOwzJBJXSDTqFfSOCTci40m9TImrRZYgXz0J+44zacmRIooX/ QPMlALJKXNHj1xM2z0Q82yo= X-Google-Smtp-Source: ABdhPJzjnIhLfEJW+qo5nEwKpNR0w9blgJqXZjaOxJSy875mS6s7nBMiUVNfCXiqKiIf5X0bXzaQQA== X-Received: by 2002:a17:907:96aa:: with SMTP id hd42mr7651011ejc.526.1613039557053; Thu, 11 Feb 2021 02:32:37 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:36 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 16/27] kernel-shark: Update KsDualMarker and KsGLWidget Date: Thu, 11 Feb 2021 12:31:54 +0200 Message-Id: <20210211103205.418588-17-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The compilation of KsDualMarker.cpp and KsGLWidget.cpp is re-enabled and all functionalities are made compatible with the new version of the C API of libkshark (KernelShark 2.0). The two source files are updated in a single patch because of their interdependence. Signed-off-by: Yordan Karadzhov (VMware) --- src/CMakeLists.txt | 8 +- src/KsDualMarker.cpp | 23 +- src/KsDualMarker.hpp | 16 +- src/KsGLWidget.cpp | 696 +++++++++++++++++++++++++++++-------------- src/KsGLWidget.hpp | 187 +++++++++--- 5 files changed, 629 insertions(+), 301 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6c02d82..3dc7213 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -68,9 +68,9 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) message(STATUS "libkshark-gui") set (ks-guiLib_hdr KsUtils.hpp KsModels.hpp -# KsGLWidget.hpp + KsGLWidget.hpp KsSearchFSM.hpp -# KsDualMarker.hpp + KsDualMarker.hpp KsWidgetsLib.hpp) # KsTraceGraph.hpp # KsTraceViewer.hpp @@ -84,9 +84,9 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) add_library(kshark-gui SHARED ${ks-guiLib_hdr_moc} KsUtils.cpp KsModels.cpp # KsSession.cpp -# KsGLWidget.cpp + KsGLWidget.cpp KsSearchFSM.cpp -# KsDualMarker.cpp + KsDualMarker.cpp KsWidgetsLib.cpp) # KsTraceGraph.cpp # KsTraceViewer.cpp diff --git a/src/KsDualMarker.cpp b/src/KsDualMarker.cpp index 90c5373..9fb68e7 100644 --- a/src/KsDualMarker.cpp +++ b/src/KsDualMarker.cpp @@ -59,10 +59,8 @@ void KsGraphMark::reset() { _isSet = false; _bin = -1; - _cpu = -1; - _task = -1; _pos = 0; - + _sd = 0; _mark._visible = false; } @@ -72,17 +70,17 @@ void KsGraphMark::reset() * @param data: Input location for the Data Store object. * @param histo: Input location for the model descriptor. * @param pos: The index inside the data array this marker will points to. - * @param cpuGraph: The index of the CPU Graph this marker points to. - * @param taskGraph: The index of the Task Graph this marker points to. + * @param sd: Data stream identifier. */ bool KsGraphMark::set(const KsDataStore &data, kshark_trace_histo *histo, - size_t pos, int cpuGraph, int taskGraph) + ssize_t pos, int sd) { uint8_t visFlags; _isSet = true; _pos = pos; + _sd = sd; _ts = data.rows()[_pos]->ts; visFlags = data.rows()[_pos]->visible; @@ -92,9 +90,6 @@ bool KsGraphMark::set(const KsDataStore &data, else _mark.setDashed(true); - _cpu = cpuGraph; - _task = taskGraph; - if (_ts > histo->max || _ts < histo->min) { _bin = -1; _mark._visible = false; @@ -119,7 +114,7 @@ bool KsGraphMark::update(const KsDataStore &data, kshark_trace_histo *histo) if (!_isSet) return false; - return set(data, histo, this->_pos, this->_cpu, this->_task); + return set(data, histo, this->_pos, this->_sd); } /** Unset the Marker and make it invisible. */ @@ -151,8 +146,8 @@ KsDualMarkerSM::KsDualMarkerSM(QWidget *parent) { QString styleSheetA, styleSheetB; - _buttonA.setFixedWidth(STRING_WIDTH(" Marker A ")); - _buttonB.setFixedWidth(STRING_WIDTH(" Marker B ")); + _buttonA.setFixedWidth(STRING_WIDTH(" Marker A ") + FONT_WIDTH); + _buttonB.setFixedWidth(STRING_WIDTH(" Marker B ") + FONT_WIDTH); for (auto const &l: {&_labelMA, &_labelMB, &_labelDelta}) { l->setFrameStyle(QFrame::Panel | QFrame::Sunken); @@ -318,10 +313,10 @@ void KsDualMarkerSM::updateMarkers(const KsDataStore &data, KsGLWidget *glw) { if(_markA.update(data, glw->model()->histo())) - glw->setMark(&_markA); + glw->setMarkPoints(data, &_markA); if(_markB.update(data, glw->model()->histo())) - glw->setMark(&_markB); + glw->setMarkPoints(data, &_markB); updateLabels(); } diff --git a/src/KsDualMarker.hpp b/src/KsDualMarker.hpp index 597bddb..0dcaf93 100644 --- a/src/KsDualMarker.hpp +++ b/src/KsDualMarker.hpp @@ -66,9 +66,7 @@ public: bool set(const KsDataStore &data, kshark_trace_histo *histo, - size_t pos, - int cpuGraph, - int taskGraph); + ssize_t pos, int sd); bool update(const KsDataStore &data, kshark_trace_histo *histo); @@ -83,24 +81,20 @@ public: void remove(); -public: /** Is this marker set. */ bool _isSet; /** The number of the bin this marker points to. */ int _bin; - /** The index of the CPU Graph this marker points to. */ - int _cpu; - - /** The index of the Task Graph this marker points to. */ - int _task; + /** Data stream identifier of the Graph this marker points to. */ + int _sd; /** The index inside the data array this marker points to. */ - size_t _pos; + ssize_t _pos; /** The timestamp of the marker. */ - uint64_t _ts; + int64_t _ts; /** The RGB color of the marker. */ QColor _color; diff --git a/src/KsGLWidget.cpp b/src/KsGLWidget.cpp index 78ded33..9f8e43b 100644 --- a/src/KsGLWidget.cpp +++ b/src/KsGLWidget.cpp @@ -14,16 +14,35 @@ #include // KernelShark +#include "libkshark-plugin.h" #include "KsGLWidget.hpp" #include "KsUtils.hpp" #include "KsPlugins.hpp" -#include "KsDualMarker.hpp" + +/** A stream operator for converting vector of integers into KsPlotEntry. */ +KsPlotEntry &operator <<(KsPlotEntry &plot, QVector &v) +{ + plot._streamId = v.takeFirst(); + plot._type = v.takeFirst(); + plot._id = v.takeFirst(); + + return plot; +} + +/** A stream operator for converting KsPlotEntry into vector of integers. */ +void operator >>(const KsPlotEntry &plot, QVector &v) +{ + v.append(plot._streamId); + v.append(plot._type); + v.append(plot._id); +} /** Create a default (empty) OpenGL widget. */ KsGLWidget::KsGLWidget(QWidget *parent) : QOpenGLWidget(parent), - _hMargin(20), - _vMargin(30), + _labelSize(100), + _hMargin(15), + _vMargin(25), _vSpacing(20), _mState(nullptr), _data(nullptr), @@ -40,10 +59,28 @@ KsGLWidget::KsGLWidget(QWidget *parent) connect(&_model, SIGNAL(modelReset()), this, SLOT(update())); } +void KsGLWidget::_freeGraphs() +{ + for (auto &stream: _graphs) { + for (auto &g: stream) + delete g; + stream.resize(0); + } +} + +void KsGLWidget::freePluginShapes() +{ + while (!_shapes.empty()) { + auto s = _shapes.front(); + _shapes.pop_front(); + delete s; + } +} + KsGLWidget::~KsGLWidget() { - for (auto &g: _graphs) - delete g; + _freeGraphs(); + freePluginShapes(); } /** Reimplemented function used to set up all required OpenGL resources. */ @@ -51,6 +88,11 @@ void KsGLWidget::initializeGL() { _dpr = QApplication::desktop()->devicePixelRatio(); ksplot_init_opengl(_dpr); + + ksplot_init_font(&_font, 15, TT_FONT_FILE); + + _labelSize = _getMaxLabelSize() + FONT_WIDTH * 2; + update(); } /** @@ -67,7 +109,9 @@ void KsGLWidget::resizeGL(int w, int h) * From the size of the widget, calculate the number of bins. * One bin will correspond to one pixel. */ - int nBins = width() - _hMargin * 2; + int nBins = width() - _bin0Offset() - _hMargin; + if (nBins <= 0) + return; /* * Reload the data. The range of the histogram is the same @@ -78,7 +122,7 @@ void KsGLWidget::resizeGL(int w, int h) _model.histo()->min, _model.histo()->max); - _model.fill(_data->rows(), _data->size()); + _model.fill(_data); } /** Reimplemented function used to plot trace graphs. */ @@ -91,24 +135,23 @@ void KsGLWidget::paintGL() if (isEmpty()) return; + render(); + /* Draw the time axis. */ _drawAxisX(size); - /* Process and draw all graphs by using the built-in logic. */ - _makeGraphs(_cpuList, _taskList); - for (auto const &g: _graphs) - g->draw(size); + for (auto const &stream: _graphs) + for (auto const &g: stream) + g->draw(size); - /* Process and draw all plugin-specific shapes. */ - _makePluginShapes(_cpuList, _taskList); - while (!_shapes.empty()) { - auto s = _shapes.front(); - _shapes.pop_front(); + for (auto const &s: _shapes) { + if (!s) + continue; - s->_size = size; - s->draw(); + if (s->_size < 0) + s->_size = size + abs(s->_size + 1); - delete s; + s->draw(); } /* @@ -120,22 +163,25 @@ void KsGLWidget::paintGL() _mState->activeMarker().draw(); } +/** Process and draw all graphs. */ +void KsGLWidget::render() +{ + /* Process and draw all graphs by using the built-in logic. */ + _makeGraphs(); + + /* Process and draw all plugin-specific shapes. */ + _makePluginShapes(); +}; + /** Reset (empty) the widget. */ void KsGLWidget::reset() { - _cpuList = {}; - _taskList = {}; + _streamPlots.clear(); + _comboPlots.clear(); _data = nullptr; _model.reset(); } -/** Check if the widget is empty (not showing anything). */ -bool KsGLWidget::isEmpty() const { - return !_data || - !_data->size() || - (!_cpuList.size() && !_taskList.size()); -} - /** Reimplemented event handler used to receive mouse press events. */ void KsGLWidget::mousePressEvent(QMouseEvent *event) { @@ -146,7 +192,7 @@ void KsGLWidget::mousePressEvent(QMouseEvent *event) } int KsGLWidget::_getLastTask(struct kshark_trace_histo *histo, - int bin, int cpu) + int bin, int sd, int cpu) { kshark_context *kshark_ctx(nullptr); kshark_entry_collection *col; @@ -157,15 +203,17 @@ int KsGLWidget::_getLastTask(struct kshark_trace_histo *histo, col = kshark_find_data_collection(kshark_ctx->collections, KsUtils::matchCPUVisible, - cpu); + sd, &cpu, 1); for (int b = bin; b >= 0; --b) { - pid = ksmodel_get_pid_back(histo, b, cpu, false, col, nullptr); + pid = ksmodel_get_pid_back(histo, b, sd, cpu, + false, col, nullptr); if (pid >= 0) return pid; } return ksmodel_get_pid_back(histo, LOWER_OVERFLOW_BIN, + sd, cpu, false, col, @@ -173,7 +221,7 @@ int KsGLWidget::_getLastTask(struct kshark_trace_histo *histo, } int KsGLWidget::_getLastCPU(struct kshark_trace_histo *histo, - int bin, int pid) + int bin, int sd, int pid) { kshark_context *kshark_ctx(nullptr); kshark_entry_collection *col; @@ -184,15 +232,17 @@ int KsGLWidget::_getLastCPU(struct kshark_trace_histo *histo, col = kshark_find_data_collection(kshark_ctx->collections, kshark_match_pid, - pid); + sd, &pid, 1); for (int b = bin; b >= 0; --b) { - cpu = ksmodel_get_cpu_back(histo, b, pid, false, col, nullptr); + cpu = ksmodel_get_cpu_back(histo, b, sd, pid, + false, col, nullptr); if (cpu >= 0) return cpu; } return ksmodel_get_cpu_back(histo, LOWER_OVERFLOW_BIN, + sd, pid, false, col, @@ -203,7 +253,7 @@ int KsGLWidget::_getLastCPU(struct kshark_trace_histo *histo, /** Reimplemented event handler used to receive mouse move events. */ void KsGLWidget::mouseMoveEvent(QMouseEvent *event) { - int bin, cpu, pid; + int bin, sd, cpu, pid; size_t row; bool ret; @@ -213,23 +263,22 @@ void KsGLWidget::mouseMoveEvent(QMouseEvent *event) if (_rubberBand.isVisible()) _rangeBoundStretched(_posInRange(event->pos().x())); - bin = event->pos().x() - _hMargin; - cpu = getPlotCPU(event->pos()); - pid = getPlotPid(event->pos()); + bin = event->pos().x() - _bin0Offset(); + getPlotInfo(event->pos(), &sd, &cpu, &pid); - ret = _find(bin, cpu, pid, 5, false, &row); + ret = _find(bin, sd, cpu, pid, 5, false, &row); if (ret) { emit found(row); } else { if (cpu >= 0) { - pid = _getLastTask(_model.histo(), bin, cpu); + pid = _getLastTask(_model.histo(), bin, sd, cpu); } if (pid > 0) { - cpu = _getLastCPU(_model.histo(), bin, pid); + cpu = _getLastCPU(_model.histo(), bin, sd, pid); } - emit notFound(ksmodel_bin_ts(_model.histo(), bin), cpu, pid); + emit notFound(ksmodel_bin_ts(_model.histo(), bin), sd, cpu, pid); } } @@ -243,11 +292,11 @@ void KsGLWidget::mouseReleaseEvent(QMouseEvent *event) size_t posMouseRel = _posInRange(event->pos().x()); int min, max; if (_posMousePress < posMouseRel) { - min = _posMousePress - _hMargin; - max = posMouseRel - _hMargin; + min = _posMousePress - _bin0Offset(); + max = posMouseRel - _bin0Offset(); } else { - max = _posMousePress - _hMargin; - min = posMouseRel - _hMargin; + max = _posMousePress - _bin0Offset(); + min = posMouseRel - _bin0Offset(); } _rangeChanged(min, max); @@ -257,7 +306,21 @@ void KsGLWidget::mouseReleaseEvent(QMouseEvent *event) /** Reimplemented event handler used to receive mouse double click events. */ void KsGLWidget::mouseDoubleClickEvent(QMouseEvent *event) { - if (event->button() == Qt::LeftButton) + KsPlot::PlotObject *pluginClicked(nullptr); + double distance, distanceMin = FONT_HEIGHT; + + for (auto const &s: _shapes) { + distance = s->distance(event->pos().x(), event->pos().y()); + if (distance < distanceMin) { + distanceMin = distance; + pluginClicked = s; + } + } + + if (pluginClicked) + pluginClicked->doubleClick(); + + else if (event->button() == Qt::LeftButton) _findAndSelect(event); } @@ -266,7 +329,8 @@ void KsGLWidget::wheelEvent(QWheelEvent * event) { int zoomFocus; - if (isEmpty()) + if (QApplication::keyboardModifiers() != Qt::ControlModifier || + isEmpty()) return; if (_mState->activeMarker()._isSet && @@ -281,7 +345,7 @@ void KsGLWidget::wheelEvent(QWheelEvent * event) * Use the position of the mouse as a focus point for the * zoom. */ - zoomFocus = event->pos().x() - _hMargin; + zoomFocus = event->pos().x() - _bin0Offset(); } if (event->delta() > 0) { @@ -353,40 +417,53 @@ void KsGLWidget::keyReleaseEvent(QKeyEvent *event) */ void KsGLWidget::loadData(KsDataStore *data) { + kshark_context *kshark_ctx(nullptr); + QVector streamIds, plotVec; uint64_t tMin, tMax; int nCPUs, nBins; + if (!kshark_instance(&kshark_ctx) || !kshark_ctx->n_streams) + return; + + loadColors(); + _data = data; + _model.reset(); + _streamPlots.clear(); + + /* + * Make default CPU and Task lists. All CPUs from all Data streams will + * be plotted. No tasks will be plotted. + */ + streamIds = KsUtils::getStreamIdList(kshark_ctx); + for (auto const &sd: streamIds) { + nCPUs = kshark_ctx->stream[sd]->n_cpus; + plotVec.clear(); + + /* If the number of CPUs is too big show only the first 16. */ + if (nCPUs > KS_MAX_START_PLOTS / kshark_ctx->n_streams) + nCPUs = KS_MAX_START_PLOTS / kshark_ctx->n_streams; + + for (int i = 0; i < nCPUs; ++i) + plotVec.append(i); + + _streamPlots[sd]._cpuList = plotVec; + _streamPlots[sd]._taskList = {}; + } /* * From the size of the widget, calculate the number of bins. * One bin will correspond to one pixel. */ - nBins = width() - _hMargin * 2; - - _model.reset(); + nBins = width() - _bin0Offset() - _hMargin; + if (nBins < 0) + nBins = 0; /* Now load the entire set of trace data. */ tMin = _data->rows()[0]->ts; tMax = _data->rows()[_data->size() - 1]->ts; ksmodel_set_bining(_model.histo(), nBins, tMin, tMax); - _model.fill(_data->rows(), _data->size()); - - /* Make a default CPU list. All CPUs (or the first N_max) will be plotted. */ - _cpuList = {}; - - nCPUs = tep_get_cpus(_data->tep()); - if (nCPUs > KS_MAX_START_PLOTS) - nCPUs = KS_MAX_START_PLOTS; - - for (int i = 0; i < nCPUs; ++i) - _cpuList.append(i); - - /* Make a default task list. No tasks will be plotted. */ - _taskList = {}; - - loadColors(); - _makeGraphs(_cpuList, _taskList); + _model.fill(_data); } /** @@ -396,96 +473,78 @@ void KsGLWidget::loadData(KsDataStore *data) void KsGLWidget::loadColors() { _pidColors.clear(); - _pidColors = KsPlot::getTaskColorTable(); + _pidColors = KsPlot::taskColorTable(); _cpuColors.clear(); - _cpuColors = KsPlot::getCPUColorTable(); + _cpuColors = KsPlot::CPUColorTable(); + _streamColors.clear(); + _streamColors = KsPlot::streamColorTable(); } /** * Position the graphical elements of the marker according to the current * position of the graphs inside the GL widget. */ -void KsGLWidget::setMark(KsGraphMark *mark) +void KsGLWidget::setMarkPoints(const KsDataStore &data, KsGraphMark *mark) { - mark->_mark.setDPR(_dpr); - mark->_mark.setX(mark->_bin + _hMargin); - mark->_mark.setY(_vMargin / 2 + 2, height() - _vMargin); - - if (mark->_cpu >= 0) { - mark->_mark.setCPUY(_graphs[mark->_cpu]->getBase()); - mark->_mark.setCPUVisible(true); - } else { - mark->_mark.setCPUVisible(false); - } + const kshark_entry *e = data.rows()[mark->_pos]; + int sd = e->stream_id; - if (mark->_task >= 0) { - mark->_mark.setTaskY(_graphs[mark->_task]->getBase()); - mark->_mark.setTaskVisible(true); - } else { - mark->_mark.setTaskVisible(false); - } -} + mark->_mark.setDPR(_dpr); + mark->_mark.setX(mark->_bin + _bin0Offset()); + mark->_mark.setY(_vMargin * 3 / 2 + 2, height() - _vMargin / 4); -/** - * @brief Check if a given KernelShark entry is ploted. - * - * @param e: Input location for the KernelShark entry. - * @param graphCPU: Output location for index of the CPU graph to which this - * entry belongs. If such a graph does not exist the outputted - * value is "-1". - * @param graphTask: Output location for index of the Task graph to which this - * entry belongs. If such a graph does not exist the - * outputted value is "-1". - */ -void KsGLWidget::findGraphIds(const kshark_entry &e, - int *graphCPU, - int *graphTask) -{ - int graph(0); - bool cpuFound(false), taskFound(false); + mark->_mark.setCPUVisible(false); + mark->_mark.setTaskVisible(false); + mark->_mark.setComboVisible(false); - /* - * Loop over all CPU graphs and try to find the one that - * contains the entry. - */ - for (auto const &c: _cpuList) { - if (c == e.cpu) { - cpuFound = true; - break; + for (int i = 0; i < _streamPlots[sd]._cpuList.count(); ++i) { + if (_streamPlots[sd]._cpuList[i] == e->cpu) { + mark->_mark.setCPUY(_streamPlots[sd]._cpuGraphs[i]->base()); + mark->_mark.setCPUVisible(true); } - ++graph; } - if (cpuFound) - *graphCPU = graph; - else - *graphCPU = -1; - - /* - * Loop over all Task graphs and try to find the one that - * contains the entry. - */ - graph = _cpuList.count(); - for (auto const &p: _taskList) { - if (p == e.pid) { - taskFound = true; - break; + for (int i = 0; i < _streamPlots[sd]._taskList.count(); ++i) { + if (_streamPlots[sd]._taskList[i] == e->pid) { + mark->_mark.setTaskY(_streamPlots[sd]._taskGraphs[i]->base()); + mark->_mark.setTaskVisible(true); } - ++graph; } - if (taskFound) - *graphTask = graph; - else - *graphTask = -1; + for (auto const &c: _comboPlots) + for (auto const &p: c) { + if (p._streamId != e->stream_id) + continue; + + if (p._type & KSHARK_CPU_DRAW && + p._id == e->cpu) { + mark->_mark.setComboY(p.base()); + mark->_mark.setComboVisible(true); + } else if (p._type & KSHARK_TASK_DRAW && + p._id == e->pid) { + mark->_mark.setComboY(p.base()); + mark->_mark.setComboVisible(true); + } + } } void KsGLWidget::_drawAxisX(float size) { - KsPlot::Point a0(_hMargin, _vMargin / 4), a1(_hMargin, _vMargin / 2); - KsPlot::Point b0(width() / 2, _vMargin / 4), b1(width() / 2, _vMargin / 2); - KsPlot::Point c0(width() - _hMargin, _vMargin / 4), - c1(width() - _hMargin, _vMargin / 2); + int64_t model_min = model()->histo()->min; + int64_t model_max = model()->histo()->max; + uint64_t sec, usec, tsMid; + char *tMin, *tMid, *tMax; + int mid = (width() - _bin0Offset() - _hMargin) / 2; + int y_1 = _vMargin * 5 / 4; + int y_2 = _vMargin * 6 / 4; + int count; + + KsPlot::Point a0(_bin0Offset(), y_1); + KsPlot::Point a1(_bin0Offset(), y_2); + KsPlot::Point b0(_bin0Offset() + mid, y_1); + KsPlot::Point b1(_bin0Offset() + mid, y_2); + KsPlot::Point c0(width() - _hMargin, y_1); + KsPlot::Point c1(width() - _hMargin, y_2); a0._size = c0._size = _dpr; @@ -495,109 +554,265 @@ void KsGLWidget::_drawAxisX(float size) KsPlot::drawLine(b0, b1, {}, size); KsPlot::drawLine(c0, c1, {}, size); KsPlot::drawLine(a0, c0, {}, size); + + if (model_min < 0) + model_min = 0; + + kshark_convert_nano(model_min, &sec, &usec); + count = asprintf(&tMin,"%" PRIu64 ".%06" PRIu64 "", sec, usec); + if (count <= 0) + return; + + tsMid = (model_min + model_max) / 2; + kshark_convert_nano(tsMid, &sec, &usec); + count = asprintf(&tMid, "%" PRIu64 ".%06" PRIu64 "", sec, usec); + if (count <= 0) + return; + + kshark_convert_nano(model_max, &sec, &usec); + count = asprintf(&tMax, "%" PRIu64 ".%06" PRIu64 "", sec, usec); + if (count <= 0) + return; + + ksplot_print_text(&_font, nullptr, + a0.x(), + a0.y() - _hMargin / 2, + tMin); + + ksplot_print_text(&_font, nullptr, + b0.x() - _font.char_width * count / 2, + b0.y() - _hMargin / 2, + tMid); + + ksplot_print_text(&_font, nullptr, + c0.x() - _font.char_width * count, + c0.y() - _hMargin / 2, + tMax); + + free(tMin); + free(tMid); + free(tMax); } -void KsGLWidget::_makeGraphs(QVector cpuList, QVector taskList) +int KsGLWidget::_getMaxLabelSize() { + int size, max(0); + + for (auto it = _streamPlots.begin(); it != _streamPlots.end(); ++it) { + int sd = it.key(); + for (auto const &pid: it.value()._taskList) { + size = _font.char_width * + KsUtils::taskPlotName(sd, pid).count(); + max = (size > max) ? size : max; + } + + for (auto const &cpu: it.value()._cpuList) { + size = _font.char_width * KsUtils::cpuPlotName(cpu).count(); + max = (size > max) ? size : max; + } + } + + for (auto &c: _comboPlots) + for (auto const &p: c) { + if (p._type & KSHARK_TASK_DRAW) { + size = _font.char_width * + KsUtils::taskPlotName(p._streamId, p._id).count(); + + max = (size > max) ? size : max; + } else if (p._type & KSHARK_CPU_DRAW) { + size = _font.char_width * + KsUtils::cpuPlotName(p._id).count(); + + max = (size > max) ? size : max; + } + } + + return max; +} + +void KsGLWidget::_makeGraphs() +{ + int base(_vMargin * 2 + KS_GRAPH_HEIGHT), sd; + KsPlot::Graph *g; + /* The very first thing to do is to clean up. */ - for (auto &g: _graphs) - delete g; - _graphs.resize(0); + _freeGraphs(); if (!_data || !_data->size()) return; - auto lamAddGraph = [&](KsPlot::Graph *graph) { - /* - * Calculate the base level of the CPU graph inside the widget. - * Remember that the "Y" coordinate is inverted. - */ + _labelSize = _getMaxLabelSize() + FONT_WIDTH * 2; + + auto lamAddGraph = [&](int sd, KsPlot::Graph *graph, int vSpace=0) { if (!graph) - return; + return graph; - int base = _vMargin + - _vSpacing * _graphs.count() + - KS_GRAPH_HEIGHT * (_graphs.count() + 1); + KsPlot::Color color = {255, 255, 255}; // White + /* + * Calculate the base level of the CPU graph inside the widget. + * Remember that the "Y" coordinate is inverted. + */ graph->setBase(base); - _graphs.append(graph); + + /* + * If we have multiple Data streams use the color of the stream + * for the label of the graph. + */ + if (KsUtils::getNStreams() > 1) + color = KsPlot::getColor(&_streamColors, sd); + + graph->setLabelAppearance(&_font, + color, + _labelSize, + _hMargin); + + _graphs[sd].append(graph); + base += graph->height() + vSpace; + + return graph; }; - /* Create CPU graphs according to the cpuList. */ - for (auto const &cpu: cpuList) - lamAddGraph(_newCPUGraph(cpu)); + for (auto it = _streamPlots.begin(); it != _streamPlots.end(); ++it) { + sd = it.key(); + /* Create CPU graphs according to the cpuList. */ + it.value()._cpuGraphs = {}; + for (auto const &cpu: it.value()._cpuList) { + g = lamAddGraph(sd, _newCPUGraph(sd, cpu), _vSpacing); + it.value()._cpuGraphs.append(g); + } + + /* Create Task graphs according to the taskList. */ + it.value()._taskGraphs = {}; + for (auto const &pid: it.value()._taskList) { + g = lamAddGraph(sd, _newTaskGraph(sd, pid), _vSpacing); + it.value()._taskGraphs.append(g); + } + } - /* Create Task graphs taskList to the taskList. */ - for (auto const &pid: taskList) - lamAddGraph(_newTaskGraph(pid)); + for (auto &c: _comboPlots) { + int n = c.count(); + for (int i = 0; i < n; ++i) { + sd = c[i]._streamId; + if (c[i]._type & KSHARK_TASK_DRAW) { + c[i]._graph = lamAddGraph(sd, _newTaskGraph(sd, c[i]._id)); + } else if (c[i]._type & KSHARK_CPU_DRAW) { + c[i]._graph = lamAddGraph(sd, _newCPUGraph(sd, c[i]._id)); + } else { + c[i]._graph = nullptr; + } + + if (c[i]._graph && i < n - 1) + c[i]._graph->setDrawBase(false); + } + + base += _vSpacing; + } } -void KsGLWidget::_makePluginShapes(QVector cpuList, QVector taskList) +void KsGLWidget::_makePluginShapes() { kshark_context *kshark_ctx(nullptr); - kshark_event_handler *evt_handlers; + kshark_draw_handler *draw_handlers; + struct kshark_data_stream *stream; KsCppArgV cppArgv; + int sd; if (!kshark_instance(&kshark_ctx)) return; + /* The very first thing to do is to clean up. */ + freePluginShapes(); + cppArgv._histo = _model.histo(); cppArgv._shapes = &_shapes; - for (int g = 0; g < cpuList.count(); ++g) { - cppArgv._graph = _graphs[g]; - evt_handlers = kshark_ctx->event_handlers; - while (evt_handlers) { - evt_handlers->draw_func(cppArgv.toC(), - cpuList[g], - KSHARK_PLUGIN_CPU_DRAW); + for (auto it = _streamPlots.constBegin(); it != _streamPlots.constEnd(); ++it) { + sd = it.key(); + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + continue; + + for (int g = 0; g < it.value()._cpuList.count(); ++g) { + cppArgv._graph = it.value()._cpuGraphs[g]; + draw_handlers = stream->draw_handlers; + while (draw_handlers) { + draw_handlers->draw_func(cppArgv.toC(), + sd, + it.value()._cpuList[g], + KSHARK_CPU_DRAW); + + draw_handlers = draw_handlers->next; + } + } - evt_handlers = evt_handlers->next; + for (int g = 0; g < it.value()._taskList.count(); ++g) { + cppArgv._graph = it.value()._taskGraphs[g]; + draw_handlers = stream->draw_handlers; + while (draw_handlers) { + draw_handlers->draw_func(cppArgv.toC(), + sd, + it.value()._taskList[g], + KSHARK_TASK_DRAW); + + draw_handlers = draw_handlers->next; + } } } - for (int g = 0; g < taskList.count(); ++g) { - cppArgv._graph = _graphs[cpuList.count() + g]; - evt_handlers = kshark_ctx->event_handlers; - while (evt_handlers) { - evt_handlers->draw_func(cppArgv.toC(), - taskList[g], - KSHARK_PLUGIN_TASK_DRAW); - - evt_handlers = evt_handlers->next; + for (auto const &c: _comboPlots) { + for (auto const &p: c) { + stream = kshark_get_data_stream(kshark_ctx, p._streamId); + draw_handlers = stream->draw_handlers; + cppArgv._graph = p._graph; + while (draw_handlers) { + draw_handlers->draw_func(cppArgv.toC(), + p._streamId, + p._id, + p._type); + + draw_handlers = draw_handlers->next; + } } } } -KsPlot::Graph *KsGLWidget::_newCPUGraph(int cpu) +KsPlot::Graph *KsGLWidget::_newCPUGraph(int sd, int cpu) { + QString name; /* The CPU graph needs to know only the colors of the tasks. */ KsPlot::Graph *graph = new KsPlot::Graph(_model.histo(), &_pidColors, &_pidColors); - graph->setZeroSuppressed(true); kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; kshark_entry_collection *col; if (!kshark_instance(&kshark_ctx)) return nullptr; - graph->setHMargin(_hMargin); + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return nullptr; + + graph->setIdleSuppressed(true, stream->idle_pid); graph->setHeight(KS_GRAPH_HEIGHT); + graph->setLabelText(KsUtils::cpuPlotName(cpu).toStdString()); col = kshark_find_data_collection(kshark_ctx->collections, KsUtils::matchCPUVisible, - cpu); + sd, &cpu, 1); graph->setDataCollectionPtr(col); - graph->fillCPUGraph(cpu); + graph->fillCPUGraph(sd, cpu); return graph; } -KsPlot::Graph *KsGLWidget::_newTaskGraph(int pid) +KsPlot::Graph *KsGLWidget::_newTaskGraph(int sd, int pid) { + QString name; /* * The Task graph needs to know the colors of the tasks and the colors * of the CPUs. @@ -607,15 +822,21 @@ KsPlot::Graph *KsGLWidget::_newTaskGraph(int pid) &_cpuColors); kshark_context *kshark_ctx(nullptr); kshark_entry_collection *col; + kshark_data_stream *stream; if (!kshark_instance(&kshark_ctx)) return nullptr; - graph->setHMargin(_hMargin); + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return nullptr; + graph->setHeight(KS_GRAPH_HEIGHT); + graph->setLabelText(KsUtils::taskPlotName(sd, pid).toStdString()); col = kshark_find_data_collection(kshark_ctx->collections, - kshark_match_pid, pid); + kshark_match_pid, sd, &pid, 1); + if (!col) { /* * If a data collection for this task does not exist, @@ -624,7 +845,8 @@ KsPlot::Graph *KsGLWidget::_newTaskGraph(int pid) col = kshark_register_data_collection(kshark_ctx, _data->rows(), _data->size(), - kshark_match_pid, pid, + kshark_match_pid, + sd, &pid, 1, 25); } @@ -647,7 +869,7 @@ KsPlot::Graph *KsGLWidget::_newTaskGraph(int pid) } graph->setDataCollectionPtr(col); - graph->fillTaskGraph(pid); + graph->fillTaskGraph(sd, pid); return graph; } @@ -667,18 +889,19 @@ KsPlot::Graph *KsGLWidget::_newTaskGraph(int pid) bool KsGLWidget::find(const QPoint &point, int variance, bool joined, size_t *index) { + int bin, sd, cpu, pid; + /* * Get the bin, pid and cpu numbers. * Remember that one bin corresponds to one pixel. */ - int bin = point.x() - _hMargin; - int cpu = getPlotCPU(point); - int pid = getPlotPid(point); + bin = point.x() - _bin0Offset(); + getPlotInfo(point, &sd, &cpu, &pid); - return _find(bin, cpu, pid, variance, joined, index); + return _find(bin, sd, cpu, pid, variance, joined, index); } -int KsGLWidget::_getNextCPU(int pid, int bin) +int KsGLWidget::_getNextCPU(int bin, int sd, int pid) { kshark_context *kshark_ctx(nullptr); kshark_entry_collection *col; @@ -689,12 +912,12 @@ int KsGLWidget::_getNextCPU(int pid, int bin) col = kshark_find_data_collection(kshark_ctx->collections, kshark_match_pid, - pid); + sd, &pid, 1); if (!col) return KS_EMPTY_BIN; for (int i = bin; i < _model.histo()->n_bins; ++i) { - cpu = ksmodel_get_cpu_front(_model.histo(), i, pid, + cpu = ksmodel_get_cpu_front(_model.histo(), i, sd, pid, false, col, nullptr); if (cpu >= 0) return cpu; @@ -703,7 +926,7 @@ int KsGLWidget::_getNextCPU(int pid, int bin) return KS_EMPTY_BIN; } -bool KsGLWidget::_find(int bin, int cpu, int pid, +bool KsGLWidget::_find(int bin, int sd, int cpu, int pid, int variance, bool joined, size_t *row) { int hSize = _model.histo()->n_bins; @@ -721,7 +944,7 @@ bool KsGLWidget::_find(int bin, int cpu, int pid, auto lamGetEntryByCPU = [&](int b) { /* Get the first data entry in this bin. */ found = ksmodel_first_index_at_cpu(_model.histo(), - b, cpu); + b, sd, cpu); if (found < 0) { /* * The bin is empty or the entire connect of the bin @@ -737,7 +960,7 @@ bool KsGLWidget::_find(int bin, int cpu, int pid, auto lamGetEntryByPid = [&](int b) { /* Get the first data entry in this bin. */ found = ksmodel_first_index_at_pid(_model.histo(), - b, pid); + b, sd, pid); if (found < 0) { /* * The bin is empty or the entire connect of the bin @@ -803,7 +1026,7 @@ bool KsGLWidget::_find(int bin, int cpu, int pid, * for an entry on the next CPU used by this task. */ if (!ret && joined) { - cpu = _getNextCPU(pid, bin); + cpu = _getNextCPU(sd, bin, pid); ret = lamFindEntryByCPU(bin); } @@ -901,7 +1124,7 @@ void KsGLWidget::_rangeChanged(int binMin, int binMax) /* Recalculate the model and update the markers. */ ksmodel_set_bining(_model.histo(), nBins, min, max); - _model.fill(_data->rows(), _data->size()); + _model.fill(_data); _mState->updateMarkers(*_data, this); /* @@ -932,8 +1155,8 @@ void KsGLWidget::_rangeChanged(int binMin, int binMax) int KsGLWidget::_posInRange(int x) { int posX; - if (x < _hMargin) - posX = _hMargin; + if (x < _bin0Offset()) + posX = _bin0Offset(); else if (x > (width() - _hMargin)) posX = width() - _hMargin; else @@ -942,35 +1165,62 @@ int KsGLWidget::_posInRange(int x) return posX; } -/** Get the CPU Id of the Graph plotted at given position. */ -int KsGLWidget::getPlotCPU(const QPoint &point) +/** + * @brief Get information about the graph plotted at given position (under the mouse). + * + * @param point: The position to be inspected. + * @param sd: Output location for the Data stream Identifier of the graph. + * @param cpu: Output location for the CPU Id of the graph, or -1 if this is + * a Task graph. + * @param pid: Output location for the Process Id of the graph, or -1 if this is + * a CPU graph. + */ +bool KsGLWidget::getPlotInfo(const QPoint &point, int *sd, int *cpu, int *pid) { - int cpuId, y = point.y(); + int base, n; - if (_cpuList.count() == 0) - return -1; + *sd = *cpu = *pid = -1; - cpuId = (y - _vMargin + _vSpacing / 2) / (_vSpacing + KS_GRAPH_HEIGHT); - if (cpuId < 0 || cpuId >= _cpuList.count()) - return -1; + for (auto it = _streamPlots.constBegin(); it != _streamPlots.constEnd(); ++it) { + n = it.value()._cpuList.count(); + for (int i = 0; i < n; ++i) { + base = it.value()._cpuGraphs[i]->base(); + if (base - KS_GRAPH_HEIGHT < point.y() && + point.y() < base) { + *sd = it.key(); + *cpu = it.value()._cpuList[i]; - return _cpuList[cpuId]; -} + return true; + } + } -/** Get the CPU Id of the Graph plotted at given position. */ -int KsGLWidget::getPlotPid(const QPoint &point) -{ - int pidId, y = point.y(); + n = it.value()._taskList.count(); + for (int i = 0; i < n; ++i) { + base = it.value()._taskGraphs[i]->base(); + if (base - KS_GRAPH_HEIGHT < point.y() && + point.y() < base) { + *sd = it.key(); + *pid = it.value()._taskList[i]; - if (_taskList.count() == 0) - return -1; + return true; + } + } + } - pidId = (y - _vMargin - - _cpuList.count()*(KS_GRAPH_HEIGHT + _vSpacing) + - _vSpacing / 2) / (_vSpacing + KS_GRAPH_HEIGHT); + for (auto const &c: _comboPlots) { + for (auto const &p: c) { + base = p.base(); + if (base - KS_GRAPH_HEIGHT < point.y() && point.y() < base) { + *sd = p._streamId; + if (p._type & KSHARK_CPU_DRAW) + *cpu = p._id; + else if (p._type & KSHARK_TASK_DRAW) + *pid = p._id; - if (pidId < 0 || pidId >= _taskList.count()) - return -1; + return true; + } + } + } - return _taskList[pidId]; + return false; } diff --git a/src/KsGLWidget.hpp b/src/KsGLWidget.hpp index c6fd787..629ae37 100644 --- a/src/KsGLWidget.hpp +++ b/src/KsGLWidget.hpp @@ -17,10 +17,51 @@ // KernelShark #include "KsUtils.hpp" +#include "KsWidgetsLib.hpp" #include "KsPlotTools.hpp" #include "KsModels.hpp" #include "KsDualMarker.hpp" +/** Structure describing all graphs to be plotted for a given Data stream. */ +struct KsPerStreamPlots { + /** CPUs to be plotted. */ + QVector _cpuList; + + /** "Y" coordinates of the bases of all CPU plots for this stream. */ + QVector _cpuGraphs; + + /** Tasks to be plotted. */ + QVector _taskList; + + /** "Y" coordinates of the bases of all CPU plots for this stream. */ + QVector _taskGraphs; +}; + +/** Structure describing a plot. */ +struct KsPlotEntry { + /** The Data stream identifier of the plot. */ + int _streamId; + + /** Plotting action identifier (Task or CPU plot). */ + int _type; + + /** Identifier of the plot (can be PID or CPU number). */ + int _id; + + /** Graph pointer. */ + KsPlot::Graph *_graph; + + /** "Y" coordinates of the bases of the plot. */ + int base() const {return _graph->base();} +}; + +KsPlotEntry &operator <<(KsPlotEntry &plot, QVector &v); + +void operator >>(const KsPlotEntry &plot, QVector &v); + +/** Vector of KsPlotEntry used to describe a Combo plot. */ +typedef QVector KsComboPlot; + /** * The KsGLWidget class provides a widget for rendering OpenGL graphics used * to plot trace graphs. @@ -39,9 +80,9 @@ public: void paintGL() override; - void reset(); + void render(); - bool isEmpty() const; + void reset(); /** Reprocess all graphs. */ void update() {resizeGL(width(), height());} @@ -64,24 +105,6 @@ public: void loadColors(); - /** - * Reimplementing the event handler of the focus event, in order to - * avoid the update (redrawing) of the graphs every time when the - * widget grabs the focus of the keyboard. This is done because we do - * not need to redraw, while on the other hand on large data-sets, - * redrawing can take a lot of time. - */ - void focusInEvent(QFocusEvent* e) override {} - - /** - * Reimplementing the event handler of the focus event, in order to - * avoid the update (redrawing) of the graphs every time when the - * widget releases the focus of the keyboard. This is done because we - * do not need to redraw, while on the other hand on large data-sets, - * redrawing can take a lot of time. - */ - void focusOutEvent(QFocusEvent* e) override {} - /** * Provide the widget with a pointer to the Dual Marker state machine * object. @@ -91,19 +114,68 @@ public: /** Get the KsGraphModel object. */ KsGraphModel *model() {return &_model;} - /** Get the number of CPU graphs. */ - int cpuGraphCount() const {return _cpuList.count();} + /** Get the number of CPU graphs for a given Data stream. */ + int cpuGraphCount(int sd) const + { + auto it = _streamPlots.find(sd); + if (it != _streamPlots.end()) + return it.value()._cpuList.count(); + return 0; + } + + /** Get the number of Task graphs for a given Data stream. */ + int taskGraphCount(int sd) const + { + auto it = _streamPlots.find(sd); + if (it != _streamPlots.end()) + return it.value()._taskList.count(); + return 0; + } - /** Get the number of Task graphs. */ - int taskGraphCount() const {return _taskList.count();} + /** Get the total number of graphs for a given Data stream. */ + int graphCount(int sd) const + { + auto it = _streamPlots.find(sd); + if (it != _streamPlots.end()) + return it.value()._taskList.count() + + it.value()._cpuList.count(); + return 0; + } - /** Get the total number of graphs. */ - int graphCount() const {return _cpuList.count() + _taskList.count();} + /** + * Get the total number of graphs for all Data stream. The Combo plots + * are not counted. + */ + int totGraphCount() const + { + int count(0); + for (auto const &s: _streamPlots) + count += s._taskList.count() + + s._cpuList.count(); + return count; + } + + /** Get the number of plots in Combos. */ + int comboGraphCount() const { + int count(0); + for (auto const &c: _comboPlots) + count += c.count(); + return count; + } + + /** Check if the widget is empty (not showing anything). */ + bool isEmpty() const + { + return !_data || !_data->size() || + (!totGraphCount() && !comboGraphCount()); + } /** Get the height of the widget. */ int height() const { - return graphCount() * (KS_GRAPH_HEIGHT + _vSpacing) + + return totGraphCount() * (KS_GRAPH_HEIGHT + _vSpacing) + + comboGraphCount() * KS_GRAPH_HEIGHT + + _comboPlots.count() * _vSpacing + _vMargin * 2; } @@ -119,24 +191,27 @@ public: /** Get the size of the vertical spaceing between the graphs. */ int vSpacing() const {return _vSpacing;} - void setMark(KsGraphMark *mark); - - void findGraphIds(const kshark_entry &e, - int *graphCPU, - int *graphTask); + void setMarkPoints(const KsDataStore &data, KsGraphMark *mark); bool find(const QPoint &point, int variance, bool joined, size_t *index); - int getPlotCPU(const QPoint &point); + bool getPlotInfo(const QPoint &point, int *sd, int *cpu, int *pid); - int getPlotPid(const QPoint &point); + /** CPUs and Tasks graphs (per data stream) to be plotted. */ + QMap _streamPlots; - /** CPUs to be plotted. */ - QVector _cpuList; + /** Combo graphs to be plotted. */ + QVector _comboPlots; - /** Tasks to be plotted. */ - QVector _taskList; + /** Set the pointer to the WorkInProgress widget. */ + void setWipPtr(KsWidgetsLib::KsWorkInProgress *wip) + { + _workInProgress = wip; + } + + /** Free the list of plugin-defined shapes. */ + void freePluginShapes(); signals: /** @@ -149,7 +224,7 @@ signals: * This signal is emitted when the mouse moves but there is no visible * KernelShark entry under the cursor. */ - void notFound(uint64_t ts, int cpu, int pid); + void notFound(uint64_t ts, int sd, int cpu, int pid); /** This signal is emitted when the Plus key is pressed. */ void zoomIn(); @@ -182,7 +257,7 @@ signals: void updateView(size_t pos, bool mark); private: - QVector _graphs; + QMap> _graphs; KsPlot::PlotObjList _shapes; @@ -190,7 +265,11 @@ private: KsPlot::ColorTable _cpuColors; - int _hMargin, _vMargin; + KsPlot::ColorTable _streamColors; + + KsWidgetsLib::KsWorkInProgress *_workInProgress; + + int _labelSize, _hMargin, _vMargin; unsigned int _vSpacing; @@ -210,15 +289,21 @@ private: int _dpr; + ksplot_font _font; + + void _freeGraphs(); + void _drawAxisX(float size); - void _makeGraphs(QVector cpuMask, QVector taskMask); + int _getMaxLabelSize(); + + void _makeGraphs(); - KsPlot::Graph *_newCPUGraph(int cpu); + KsPlot::Graph *_newCPUGraph(int sd, int cpu); - KsPlot::Graph *_newTaskGraph(int pid); + KsPlot::Graph *_newTaskGraph(int sd, int pid); - void _makePluginShapes(QVector cpuMask, QVector taskMask); + void _makePluginShapes(); int _posInRange(int x); @@ -230,16 +315,20 @@ private: bool _findAndSelect(QMouseEvent *event); - bool _find(int bin, int cpu, int pid, + bool _find(int bin, int sd, int cpu, int pid, int variance, bool joined, size_t *row); - int _getNextCPU(int pid, int bin); + int _getNextCPU(int bin, int sd, int pid); - int _getLastTask(struct kshark_trace_histo *histo, int bin, int cpu); + int _getLastTask(struct kshark_trace_histo *histo, + int bin, int sd, int cpu); - int _getLastCPU(struct kshark_trace_histo *histo, int bin, int pid); + int _getLastCPU(struct kshark_trace_histo *histo, + int bin, int sd, int pid); void _deselect(); + + int _bin0Offset() {return _labelSize + 2 * _hMargin;} }; #endif From patchwork Thu Feb 11 10:31:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082747 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.7 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 8E252C433E0 for ; Thu, 11 Feb 2021 10:39:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5261B64EA1 for ; Thu, 11 Feb 2021 10:39:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230051AbhBKKin (ORCPT ); Thu, 11 Feb 2021 05:38:43 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46424 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230201AbhBKKfs (ORCPT ); Thu, 11 Feb 2021 05:35:48 -0500 Received: from mail-ed1-x52e.google.com (mail-ed1-x52e.google.com [IPv6:2a00:1450:4864:20::52e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A3A06C06121E for ; Thu, 11 Feb 2021 02:32:39 -0800 (PST) Received: by mail-ed1-x52e.google.com with SMTP id g10so6439368eds.2 for ; Thu, 11 Feb 2021 02:32: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=bkdmWIdCmbnxoM09kYt4KbcVRvSRAF+e9vpBFySBZSo=; b=DzPx31XcDqCUJbw1BY/Mvp2aJePYSTzNgCNOahne68wjj4HWxA0zScKDIewoEK3Uc7 vyGKegCtom4E0K6sLX44e5OP1cXdJpZRZ/oANglZCn2Ic74eADl74/UtOv6XoAdnD1Fy gdQKsaFyI+EWpEMBv2/yq+fH5YtjWChWztzCuyX8RY62/g8dkZL8lU56FL4zc/TU/Ebw wlFcTl4dTDjPijyj6CtWPDycHsz2hNuOTgT2q7DK5TfBhG6yxX3PESPwAVjq7Fec3zzb aY4KJR9C4EU3C0NHjYVFEDi3C1jfzzxAgg9m2nEKc2ZlgHWP4E5g9l7H/WjPnJrghbrY caPg== 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=bkdmWIdCmbnxoM09kYt4KbcVRvSRAF+e9vpBFySBZSo=; b=fEI0qIrE5D95lXPR7eJmwqI73TbpyPdU8kdCeVwlevd6kUnNyoz3P6rXQBahkiI/fA eRlTWLTiiQMe3w9GBwj+pWdp9yD708NRw5jf4HlzmpMqCniVftLjqOTdgK/b2oK7DIiX fBETeFSzQzqgB116+7FSs5hbEgDbJA6RQngAi8NrEBY88EBJh+Kop7eByJw7eGZGVAhc 1jD22Dd+IdlszI0mujh2MXJjCgp5Uai7KMJFzXFa7sVjo1nf8Vo933OhF+dlCF1ldYcr 6FwmAtoB09D9S7ayVBeZtGgjCSKnoM9wwBzrQt7BNZkpYrO52yh2b6jPt4JLR7njdA6O ygmg== X-Gm-Message-State: AOAM530Bsqb6eaiTP7bEWowJz6Zpz5eDIEbm01kHNhOb6iJyJ7dRAS6n b2soqO8ozN5D+fbIQb75UUcYTRV0Acw= X-Google-Smtp-Source: ABdhPJyyts8cqiDrntBJVe0iWfwBZDx9rNjSduZ6/fKldlAhsmSIyneL6n4L49eixFqsZCchvY+SIQ== X-Received: by 2002:a05:6402:16dd:: with SMTP id r29mr7858697edx.212.1613039557956; Thu, 11 Feb 2021 02:32:37 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:37 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 17/27] kernel-shark: Update KsTraceGraph and KsQuickContextMenu Date: Thu, 11 Feb 2021 12:31:55 +0200 Message-Id: <20210211103205.418588-18-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The compilation of KsTraceGraph.cpp and KsQuickContextMenu.cpp is re-enabled and all functionalities are made compatible with the new version of the C API of libkshark (KernelShark 2.0). The two source files are updated in a single patch because of their interdependence. Signed-off-by: Yordan Karadzhov (VMware) --- src/CMakeLists.txt | 12 +- src/KsQuickContextMenu.cpp | 151 +++++++++---- src/KsQuickContextMenu.hpp | 26 ++- src/KsTraceGraph.cpp | 426 ++++++++++++++++++------------------- src/KsTraceGraph.hpp | 43 ++-- 5 files changed, 351 insertions(+), 307 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3dc7213..ab74d5a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -71,12 +71,12 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) KsGLWidget.hpp KsSearchFSM.hpp KsDualMarker.hpp - KsWidgetsLib.hpp) -# KsTraceGraph.hpp + KsWidgetsLib.hpp + KsTraceGraph.hpp # KsTraceViewer.hpp # KsMainWindow.hpp # KsCaptureDialog.hpp -# KsQuickContextMenu.hpp + KsQuickContextMenu.hpp) # KsAdvFilteringDialog.hpp) QT5_WRAP_CPP(ks-guiLib_hdr_moc ${ks-guiLib_hdr}) @@ -87,12 +87,12 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) KsGLWidget.cpp KsSearchFSM.cpp KsDualMarker.cpp - KsWidgetsLib.cpp) -# KsTraceGraph.cpp + KsWidgetsLib.cpp + KsTraceGraph.cpp # KsTraceViewer.cpp # KsMainWindow.cpp # KsCaptureDialog.cpp -# KsQuickContextMenu.cpp + KsQuickContextMenu.cpp) # KsAdvFilteringDialog.cpp) target_link_libraries(kshark-gui kshark-plot diff --git a/src/KsQuickContextMenu.cpp b/src/KsQuickContextMenu.cpp index a84444e..6fa242d 100644 --- a/src/KsQuickContextMenu.cpp +++ b/src/KsQuickContextMenu.cpp @@ -39,17 +39,19 @@ KsQuickMarkerMenu::KsQuickMarkerMenu(KsDualMarkerSM *dm, QWidget *parent) /** * @brief Create KsQuickContextMenu. * + * @param dm: The State machine of the Dual marker. * @param data: Input location for the KsDataStore object. * @param row: The index of the entry used to initialize the menu. - * @param dm: The State machine of the Dual marker. * @param parent: The parent of this widget. */ -KsQuickContextMenu::KsQuickContextMenu(KsDataStore *data, size_t row, - KsDualMarkerSM *dm, +KsQuickContextMenu::KsQuickContextMenu(KsDualMarkerSM *dm, + KsDataStore *data, size_t row, QWidget *parent) : KsQuickMarkerMenu(dm, parent), _data(data), _row(row), + _rawTime(this), + _rawEvent(this), _graphSyncCBox(nullptr), _listSyncCBox(nullptr), _hideTaskAction(this), @@ -65,16 +67,50 @@ KsQuickContextMenu::KsQuickContextMenu(KsDataStore *data, size_t row, _clearAllFilters(this) { typedef void (KsQuickContextMenu::*mfp)(); - QString taskName, parentName, descr; + QString time, taskName, parentName, descr; + kshark_entry *entry = _data->rows()[_row]; + kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; + QStringList eventFields; + int pid, cpu, sd, ret; KsTraceGraph *graphs; - int pid, cpu; + int64_t fieldVal; if (!parent || !_data) return; - taskName = kshark_get_task_easy(_data->rows()[_row]); - pid = kshark_get_pid_easy(_data->rows()[_row]); - cpu = _data->rows()[_row]->cpu; + if (!kshark_instance(&kshark_ctx)) + return; + + taskName = kshark_get_task(entry); + pid = kshark_get_pid(entry); + cpu = entry->cpu; + sd = entry->stream_id; + + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return; + + QString evtData("\t"), val; + eventFields = KsUtils::getEventFieldsList(entry->stream_id, + entry->event_id); + + for (auto const &field: eventFields) { + std::string buff = field.toStdString(); + ret = kshark_read_event_field_int(entry, buff.c_str(), &fieldVal); + if (ret < 0) + continue; + + evtData += field + ": " + val.setNum(fieldVal) + "\n\t"; + } + + addSection("Raw event"); + time = QString("\ttime: %1 [ns]").arg(entry->ts); + + _rawTime.setDefaultWidget(new QLabel(time)); + addAction(&_rawTime); + _rawEvent.setDefaultWidget(new QLabel(evtData)); + addAction(&_rawEvent); auto lamAddAction = [this, &descr] (QAction *action, mfp mf) { action->setText(descr); @@ -104,12 +140,12 @@ KsQuickContextMenu::KsQuickContextMenu(KsDataStore *data, size_t row, lamAddAction(&_hideTaskAction, &KsQuickContextMenu::_hideTask); descr = "Show event ["; - descr += kshark_get_event_name_easy(_data->rows()[_row]); + descr += kshark_get_event_name(entry); descr += "] only"; lamAddAction(&_showEventAction, &KsQuickContextMenu::_showEvent); descr = "Hide event ["; - descr += kshark_get_event_name_easy(_data->rows()[_row]); + descr += kshark_get_event_name(entry); descr += "]"; lamAddAction(&_hideEventAction, &KsQuickContextMenu::_hideEvent); @@ -118,7 +154,7 @@ KsQuickContextMenu::KsQuickContextMenu(KsDataStore *data, size_t row, lamAddAction(&_showCPUAction, &KsQuickContextMenu::_showCPU); } - descr = QString("Hide CPU [%1]").arg(_data->rows()[_row]->cpu); + descr = QString("Hide CPU [%1]").arg(entry->cpu); lamAddAction(&_hideCPUAction, &KsQuickContextMenu::_hideCPU); descr = "Clear all filters"; @@ -138,7 +174,7 @@ KsQuickContextMenu::KsQuickContextMenu(KsDataStore *data, size_t row, if (parentName == "KsTraceGraph" && (graphs = dynamic_cast(parent))) { - if (graphs->glPtr()->_taskList.contains(pid)) { + if (graphs->glPtr()->_streamPlots[sd]._taskList.contains(pid)) { descr = "Remove ["; descr += taskName; descr += "-"; @@ -156,7 +192,7 @@ KsQuickContextMenu::KsQuickContextMenu(KsDataStore *data, size_t row, &KsQuickContextMenu::_addTaskPlot); } - if (graphs->glPtr()->_cpuList.contains(cpu)) { + if (graphs->glPtr()->_streamPlots[sd]._cpuList.contains(cpu)) { descr = "Remove [CPU "; descr += QString("%1").arg(cpu); descr += "] plot"; @@ -174,66 +210,86 @@ KsQuickContextMenu::KsQuickContextMenu(KsDataStore *data, size_t row, void KsQuickContextMenu::_hideTask() { - int pid = kshark_get_pid_easy(_data->rows()[_row]); + int pid = kshark_get_pid(_data->rows()[_row]); + int sd = _data->rows()[_row]->stream_id; kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; QVector vec; if (!kshark_instance(&kshark_ctx)) return; - vec =_getFilterVector(kshark_ctx->hide_task_filter, pid); - _data->applyNegTaskFilter(vec); + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return; + + vec =_getFilterVector(stream->hide_task_filter, pid); + _data->applyNegTaskFilter(sd, vec); } void KsQuickContextMenu::_showTask() { - int pid = kshark_get_pid_easy(_data->rows()[_row]); - - _data->applyPosTaskFilter(QVector(1, pid)); + int pid = kshark_get_pid(_data->rows()[_row]); + int sd = _data->rows()[_row]->stream_id; + _data->applyPosTaskFilter(sd, QVector(1, pid)); } void KsQuickContextMenu::_hideEvent() { - int eventId = kshark_get_event_id_easy(_data->rows()[_row]); + int eventId = kshark_get_event_id(_data->rows()[_row]); + int sd = _data->rows()[_row]->stream_id; kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; QVector vec; if (!kshark_instance(&kshark_ctx)) return; - vec =_getFilterVector(kshark_ctx->hide_event_filter, eventId); - _data->applyNegEventFilter(vec); + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return; + + vec =_getFilterVector(stream->hide_event_filter, eventId); + _data->applyNegEventFilter(sd, vec); } void KsQuickContextMenu::_showEvent() { - int eventId = kshark_get_event_id_easy(_data->rows()[_row]); + int eventId = kshark_get_event_id(_data->rows()[_row]); + int sd = _data->rows()[_row]->stream_id; - _data->applyPosEventFilter(QVector(1, eventId)); + _data->applyPosEventFilter(sd, QVector(1, eventId)); } void KsQuickContextMenu::_showCPU() { int cpu = _data->rows()[_row]->cpu; + int sd = _data->rows()[_row]->stream_id; - _data->applyPosCPUFilter(QVector(1, cpu)); + _data->applyPosCPUFilter(sd, QVector(1, cpu)); } void KsQuickContextMenu::_hideCPU() { + int sd = _data->rows()[_row]->stream_id; kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; QVector vec; if (!kshark_instance(&kshark_ctx)) return; - vec =_getFilterVector(kshark_ctx->hide_cpu_filter, + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return; + + vec =_getFilterVector(stream->hide_cpu_filter, _data->rows()[_row]->cpu); - _data->applyNegCPUFilter(vec); + _data->applyNegCPUFilter(sd, vec); } -QVector KsQuickContextMenu::_getFilterVector(tracecmd_filter_id *filter, int newId) +QVector KsQuickContextMenu::_getFilterVector(kshark_hash_id *filter, int newId) { QVector vec = KsUtils::getFilterIds(filter); if (!vec.contains(newId)) @@ -244,38 +300,42 @@ QVector KsQuickContextMenu::_getFilterVector(tracecmd_filter_id *filter, in void KsQuickContextMenu::_addTaskPlot() { - int pid = kshark_get_pid_easy(_data->rows()[_row]); + int pid = kshark_get_pid(_data->rows()[_row]); + int sd = _data->rows()[_row]->stream_id; - emit addTaskPlot(pid); + emit addTaskPlot(sd, pid); } void KsQuickContextMenu::_addCPUPlot() { - emit addCPUPlot(_data->rows()[_row]->cpu); + emit addCPUPlot(_data->rows()[_row]->stream_id, _data->rows()[_row]->cpu); } void KsQuickContextMenu::_removeTaskPlot() { - int pid = kshark_get_pid_easy(_data->rows()[_row]); + int pid = kshark_get_pid(_data->rows()[_row]); + int sd = _data->rows()[_row]->stream_id; - emit removeTaskPlot(pid); + emit removeTaskPlot(sd, pid); } void KsQuickContextMenu::_removeCPUPlot() { - emit removeCPUPlot(_data->rows()[_row]->cpu); + emit removeCPUPlot(_data->rows()[_row]->stream_id, _data->rows()[_row]->cpu); } /** * @brief Create KsRmPlotContextMenu. * * @param dm: The State machine of the Dual marker. + * @param sd: Data stream identifier. * @param parent: The parent of this widget. */ -KsRmPlotContextMenu::KsRmPlotContextMenu(KsDualMarkerSM *dm, +KsRmPlotContextMenu::KsRmPlotContextMenu(KsDualMarkerSM *dm, int sd, QWidget *parent) : KsQuickMarkerMenu(dm, parent), - _removePlotAction(this) + _removePlotAction(this), + _sd(sd) { addSection("Plots"); @@ -289,12 +349,13 @@ KsRmPlotContextMenu::KsRmPlotContextMenu(KsDualMarkerSM *dm, * @brief Create KsRmCPUPlotMenu. * * @param dm: The State machine of the Dual marker. + * @param sd: Data stream identifier. * @param cpu : CPU Id. * @param parent: The parent of this widget. */ -KsRmCPUPlotMenu::KsRmCPUPlotMenu(KsDualMarkerSM *dm, int cpu, +KsRmCPUPlotMenu::KsRmCPUPlotMenu(KsDualMarkerSM *dm, int sd, int cpu, QWidget *parent) -: KsRmPlotContextMenu(dm, parent) +: KsRmPlotContextMenu(dm, sd, parent) { _removePlotAction.setText(QString("Remove [CPU %1]").arg(cpu)); } @@ -303,20 +364,18 @@ KsRmCPUPlotMenu::KsRmCPUPlotMenu(KsDualMarkerSM *dm, int cpu, * @brief Create KsRmTaskPlotMenu. * * @param dm: The State machine of the Dual marker. + * @param sd: Data stream identifier. * @param pid: Process Id. * @param parent: The parent of this widget. */ -KsRmTaskPlotMenu::KsRmTaskPlotMenu(KsDualMarkerSM *dm, int pid, +KsRmTaskPlotMenu::KsRmTaskPlotMenu(KsDualMarkerSM *dm, int sd, int pid, QWidget *parent) -: KsRmPlotContextMenu(dm, parent) +: KsRmPlotContextMenu(dm, sd, parent) { - kshark_context *kshark_ctx(nullptr); - QString descr("Remove [ "); - - if (!kshark_instance(&kshark_ctx)) - return; + QString descr; - descr += tep_data_comm_from_pid(kshark_ctx->pevent, pid); + descr = "Remove [ "; + descr += kshark_comm_from_pid(sd, pid); descr += "-"; descr += QString("%1").arg(pid); descr += "] plot"; diff --git a/src/KsQuickContextMenu.hpp b/src/KsQuickContextMenu.hpp index df8a65b..ca0b341 100644 --- a/src/KsQuickContextMenu.hpp +++ b/src/KsQuickContextMenu.hpp @@ -45,22 +45,22 @@ class KsQuickContextMenu : public KsQuickMarkerMenu { public: KsQuickContextMenu() = delete; - KsQuickContextMenu(KsDataStore *data, size_t row, - KsDualMarkerSM *dm, + KsQuickContextMenu(KsDualMarkerSM *dm, + KsDataStore *data, size_t row, QWidget *parent = nullptr); signals: /** Signal to add a task plot. */ - void addTaskPlot(int); + void addTaskPlot(int sd, int pid); /** Signal to add a CPU plot. */ - void addCPUPlot(int); + void addCPUPlot(int sd, int cpu); /** Signal to remove a task plot. */ - void removeTaskPlot(int); + void removeTaskPlot(int sd, int pid); /** Signal to remove a CPU plot. */ - void removeCPUPlot(int); + void removeCPUPlot(int sd, int cpu); private: void _hideTask(); @@ -83,7 +83,7 @@ private: void _removeTaskPlot(); - QVector _getFilterVector(tracecmd_filter_id *filter, int newId); + QVector _getFilterVector(kshark_hash_id *filter, int newId); void _clearFilters() {_data->clearAllFilters();} @@ -91,6 +91,8 @@ private: size_t _row; + QWidgetAction _rawTime, _rawEvent; + QCheckBox *_graphSyncCBox, *_listSyncCBox; QAction _hideTaskAction, _showTaskAction; @@ -118,7 +120,8 @@ class KsRmPlotContextMenu : public KsQuickMarkerMenu { public: KsRmPlotContextMenu() = delete; - KsRmPlotContextMenu(KsDualMarkerSM *dm, QWidget *parent = nullptr); + KsRmPlotContextMenu(KsDualMarkerSM *dm, int sd, + QWidget *parent = nullptr); signals: /** Signal to remove a plot. */ @@ -127,13 +130,16 @@ signals: protected: /** Menu action. */ QAction _removePlotAction; + + /** Data stream identifier. */ + int _sd; }; /** * The KsQuickMarkerMenu class provides CPU Plot remove menus. */ struct KsRmCPUPlotMenu : public KsRmPlotContextMenu { - KsRmCPUPlotMenu(KsDualMarkerSM *dm, int cpu, + KsRmCPUPlotMenu(KsDualMarkerSM *dm, int sd, int cpu, QWidget *parent = nullptr); }; @@ -141,7 +147,7 @@ struct KsRmCPUPlotMenu : public KsRmPlotContextMenu { * The KsQuickMarkerMenu class provides Task Plot remove menus. */ struct KsRmTaskPlotMenu : public KsRmPlotContextMenu { - KsRmTaskPlotMenu(KsDualMarkerSM *dm, int pid, + KsRmTaskPlotMenu(KsDualMarkerSM *dm, int sd, int pid, QWidget *parent = nullptr); }; diff --git a/src/KsTraceGraph.cpp b/src/KsTraceGraph.cpp index 7b656c0..fd9cfac 100644 --- a/src/KsTraceGraph.cpp +++ b/src/KsTraceGraph.cpp @@ -17,7 +17,7 @@ /** Create a default (empty) Trace graph widget. */ KsTraceGraph::KsTraceGraph(QWidget *parent) -: QWidget(parent), +: KsWidgetsLib::KsDataWidget(parent), _pointerBar(this), _navigationBar(this), _zoomInButton("+", this), @@ -34,13 +34,7 @@ KsTraceGraph::KsTraceGraph(QWidget *parent) _labelI4("", this), _labelI5("", this), _scrollArea(this), - _drawWindow(&_scrollArea), - _legendWindow(&_drawWindow), - _legendAxisX(&_drawWindow), - _labelXMin("", &_legendAxisX), - _labelXMid("", &_legendAxisX), - _labelXMax("", &_legendAxisX), - _glWindow(&_drawWindow), + _glWindow(&_scrollArea), _mState(nullptr), _data(nullptr), _keyPressed(false) @@ -62,7 +56,7 @@ KsTraceGraph::KsTraceGraph(QWidget *parent) _pointerBar.addWidget(&_labelP1); _labelP2.setFrameStyle(QFrame::Panel | QFrame::Sunken); - _labelP2.setStyleSheet("QLabel { background-color : white; color: black}"); + _labelP2.setStyleSheet("QLabel {background-color : white; color: black}"); _labelP2.setTextInteractionFlags(Qt::TextSelectableByMouse); _labelP2.setFixedWidth(FONT_WIDTH * 16); _pointerBar.addWidget(&_labelP2); @@ -84,31 +78,7 @@ KsTraceGraph::KsTraceGraph(QWidget *parent) _pointerBar.addSeparator(); _pointerBar.addWidget(&_labelI5); - _legendAxisX.setFixedHeight(FONT_HEIGHT * 1.5); - _legendAxisX.setLayout(new QHBoxLayout); - _legendAxisX.layout()->setSpacing(0); - _legendAxisX.layout()->setContentsMargins(0, 0, FONT_WIDTH, 0); - - _labelXMin.setAlignment(Qt::AlignLeft); - _labelXMid.setAlignment(Qt::AlignHCenter); - _labelXMax.setAlignment(Qt::AlignRight); - - _legendAxisX.layout()->addWidget(&_labelXMin); - _legendAxisX.layout()->addWidget(&_labelXMid); - _legendAxisX.layout()->addWidget(&_labelXMax); - _legendAxisX.setStyleSheet("QLabel { background-color : white; color: black}"); - - _drawWindow.setMinimumSize(100, 100); - _drawWindow.setStyleSheet("QWidget {background-color : white;}"); - - _drawLayout.setContentsMargins(0, 0, 0, 0); - _drawLayout.setSpacing(0); - _drawLayout.addWidget(&_legendAxisX, 0, 1); - _drawLayout.addWidget(&_legendWindow, 1, 0); - _drawLayout.addWidget(&_glWindow, 1, 1); - _drawWindow.setLayout(&_drawLayout); - - _drawWindow.installEventFilter(this); + _glWindow.installEventFilter(this); connect(&_glWindow, &KsGLWidget::select, this, &KsTraceGraph::markEntry); @@ -134,15 +104,12 @@ KsTraceGraph::KsTraceGraph(QWidget *parent) connect(&_glWindow, &KsGLWidget::stopUpdating, this, &KsTraceGraph::_stopUpdating); - connect(_glWindow.model(), &KsGraphModel::modelReset, - this, &KsTraceGraph::_updateTimeLegends); - _glWindow.setContextMenuPolicy(Qt::CustomContextMenu); connect(&_glWindow, &QWidget::customContextMenuRequested, this, &KsTraceGraph::_onCustomContextMenu); _scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - _scrollArea.setWidget(&_drawWindow); + _scrollArea.setWidget(&_glWindow); lamMakeNavButton(&_scrollLeftButton); connect(&_scrollLeftButton, &QPushButton::pressed, @@ -187,7 +154,6 @@ void KsTraceGraph::loadData(KsDataStore *data) { _data = data; _glWindow.loadData(data); - _updateGraphLegends(); updateGeom(); } @@ -211,14 +177,10 @@ void KsTraceGraph::reset() l1->setText(""); _selfUpdate(); - for (auto l2: {&_labelXMin, &_labelXMid, &_labelXMax}) - l2->setText(""); } void KsTraceGraph::_selfUpdate() { - _updateGraphLegends(); - _updateTimeLegends(); _markerReDraw(); _glWindow.model()->update(); updateGeom(); @@ -226,12 +188,20 @@ void KsTraceGraph::_selfUpdate() void KsTraceGraph::_zoomIn() { - _updateGraphs(GraphActions::ZoomIn); + KsWidgetsLib::KsDataWork action = KsWidgetsLib::KsDataWork::ZoomIn; + + startOfWork(action); + _updateGraphs(action); + endOfWork(action); } void KsTraceGraph::_zoomOut() { - _updateGraphs(GraphActions::ZoomOut); + KsWidgetsLib::KsDataWork action = KsWidgetsLib::KsDataWork::ZoomOut; + + startOfWork(action); + _updateGraphs(action); + endOfWork(action); } void KsTraceGraph::_quickZoomIn() @@ -239,6 +209,8 @@ void KsTraceGraph::_quickZoomIn() if (_glWindow.isEmpty()) return; + startOfWork(KsWidgetsLib::KsDataWork::QuickZoomIn); + /* Bin size will be 100 ns. */ _glWindow.model()->quickZoomIn(100); if (_mState->activeMarker()._isSet && @@ -249,7 +221,10 @@ void KsTraceGraph::_quickZoomIn() */ uint64_t ts = _mState->activeMarker()._ts; _glWindow.model()->jumpTo(ts); + _glWindow.render(); } + + endOfWork(KsWidgetsLib::KsDataWork::QuickZoomIn); } void KsTraceGraph::_quickZoomOut() @@ -257,17 +232,28 @@ void KsTraceGraph::_quickZoomOut() if (_glWindow.isEmpty()) return; + startOfWork(KsWidgetsLib::KsDataWork::QuickZoomOut); _glWindow.model()->quickZoomOut(); + _glWindow.render(); + endOfWork(KsWidgetsLib::KsDataWork::QuickZoomOut); } void KsTraceGraph::_scrollLeft() { - _updateGraphs(GraphActions::ScrollLeft); + KsWidgetsLib::KsDataWork action = KsWidgetsLib::KsDataWork::ScrollLeft; + + startOfWork(action); + _updateGraphs(action); + endOfWork(action); } void KsTraceGraph::_scrollRight() { - _updateGraphs(GraphActions::ScrollRight); + KsWidgetsLib::KsDataWork action = KsWidgetsLib::KsDataWork::ScrollRight; + + startOfWork(action); + _updateGraphs(action); + endOfWork(action); } void KsTraceGraph::_stopUpdating() @@ -292,10 +278,18 @@ QString KsTraceGraph::_t2str(uint64_t sec, uint64_t usec) { return QString::number(sec) + "." + usecStr; } -void KsTraceGraph::_resetPointer(uint64_t ts, int cpu, int pid) +void KsTraceGraph::_resetPointer(int64_t ts, int sd, int cpu, int pid) { + kshark_entry entry; uint64_t sec, usec; + entry.cpu = cpu; + entry.pid = pid; + entry.stream_id = sd; + + if (ts < 0) + ts = 0; + kshark_convert_nano(ts, &sec, &usec); _labelP2.setText(_t2str(sec, usec)); @@ -305,7 +299,7 @@ void KsTraceGraph::_resetPointer(uint64_t ts, int cpu, int pid) if (!kshark_instance(&kshark_ctx)) return; - QString comm(tep_data_comm_from_pid(kshark_ctx->pevent, pid)); + QString comm(kshark_get_task(&entry)); comm.append("-"); comm.append(QString("%1").arg(pid)); _labelI1.setText(comm); @@ -323,23 +317,30 @@ void KsTraceGraph::_resetPointer(uint64_t ts, int cpu, int pid) void KsTraceGraph::_setPointerInfo(size_t i) { kshark_entry *e = _data->rows()[i]; - QString event(kshark_get_event_name_easy(e)); - QString lat(kshark_get_latency_easy(e)); - QString info(kshark_get_info_easy(e)); - QString comm(kshark_get_task_easy(e)); - int labelWidth, width; - QString elidedText; + auto lanMakeString = [] (char *buffer) { + QString str(buffer); + free(buffer); + return str; + }; + + QString event(lanMakeString(kshark_get_event_name(e))); + QString aux(lanMakeString(kshark_get_aux_info(e))); + QString info(lanMakeString(kshark_get_info(e))); + QString comm(lanMakeString(kshark_get_task(e))); + QString pointer, elidedText; + int labelWidth; uint64_t sec, usec; kshark_convert_nano(e->ts, &sec, &usec); - _labelP2.setText(_t2str(sec, usec)); + pointer.sprintf("%" PRIu64 ".%06" PRIu64 "", sec, usec); + _labelP2.setText(pointer); comm.append("-"); - comm.append(QString("%1").arg(kshark_get_pid_easy(e))); + comm.append(QString("%1").arg(kshark_get_pid(e))); _labelI1.setText(comm); _labelI2.setText(QString("CPU %1").arg(e->cpu)); - _labelI3.setText(lat); + _labelI3.setText(aux); _labelI4.setText(event); _labelI5.setText(info); QCoreApplication::processEvents(); @@ -353,16 +354,7 @@ void KsTraceGraph::_setPointerInfo(size_t i) * The Info string is too long and cannot be displayed on the toolbar. * Try to fit the text in the available space. */ - QFontMetrics metrix(_labelI5.font()); - width = labelWidth - FONT_WIDTH * 3; - elidedText = metrix.elidedText(info, Qt::ElideRight, width); - - while(labelWidth < STRING_WIDTH(elidedText) + FONT_WIDTH * 5) { - width -= FONT_WIDTH * 3; - elidedText = metrix.elidedText(info, Qt::ElideRight, width); - } - - _labelI5.setText(elidedText); + KsUtils::setElidedText(&_labelI5, info, Qt::ElideRight, labelWidth); _labelI5.setVisible(true); QCoreApplication::processEvents(); } @@ -374,127 +366,188 @@ void KsTraceGraph::_setPointerInfo(size_t i) */ void KsTraceGraph::markEntry(size_t row) { - int graph, cpuGrId, taskGrId; - - _glWindow.findGraphIds(*_data->rows()[row], &cpuGrId, &taskGrId); - - /* - * If a Task graph has been found, this Task graph will be - * visible. If no Task graph has been found, make visible - * the corresponding CPU graph. - */ - if (taskGrId >= 0) - graph = taskGrId; - else - graph = cpuGrId; - - _scrollArea.ensureVisible(0, - _legendAxisX.height() + - _glWindow.vMargin() + - KS_GRAPH_HEIGHT / 2 + - graph*(KS_GRAPH_HEIGHT + _glWindow.vSpacing()), - 50, - KS_GRAPH_HEIGHT / 2 + _glWindow.vSpacing() / 2); + int yPosVis(-1); _glWindow.model()->jumpTo(_data->rows()[row]->ts); - _mState->activeMarker().set(*_data, - _glWindow.model()->histo(), - row, cpuGrId, taskGrId); + _mState->activeMarker().set(*_data, _glWindow.model()->histo(), + row, _data->rows()[row]->stream_id); _mState->updateMarkers(*_data, &_glWindow); + + /* + * If a Combo graph has been found, this Combo graph will be visible. + * Else the Task graph will be shown. If no Combo and no Task graph + * has been found, make visible the corresponding CPU graph. + */ + if (_mState->activeMarker()._mark.comboIsVisible()) + yPosVis = _mState->activeMarker()._mark.comboY(); + else if (_mState->activeMarker()._mark.taskIsVisible()) + yPosVis = _mState->activeMarker()._mark.taskY(); + else if (_mState->activeMarker()._mark.cpuIsVisible()) + yPosVis = _mState->activeMarker()._mark.cpuY(); + + if (yPosVis > 0) + _scrollArea.ensureVisible(0, yPosVis); } void KsTraceGraph::_markerReDraw() { - int cpuGrId, taskGrId; size_t row; if (_mState->markerA()._isSet) { row = _mState->markerA()._pos; - _glWindow.findGraphIds(*_data->rows()[row], &cpuGrId, &taskGrId); - _mState->markerA().set(*_data, - _glWindow.model()->histo(), - row, cpuGrId, taskGrId); + _mState->markerA().set(*_data, _glWindow.model()->histo(), + row, _data->rows()[row]->stream_id); } if (_mState->markerB()._isSet) { row = _mState->markerB()._pos; - _glWindow.findGraphIds(*_data->rows()[row], &cpuGrId, &taskGrId); - _mState->markerB().set(*_data, - _glWindow.model()->histo(), - row, cpuGrId, taskGrId); + _mState->markerB().set(*_data, _glWindow.model()->histo(), + row, _data->rows()[row]->stream_id); } } /** * @brief Redreaw all CPU graphs. * + * @param sd: Data stream identifier. * @param v: CPU ids to be plotted. */ -void KsTraceGraph::cpuReDraw(QVector v) +void KsTraceGraph::cpuReDraw(int sd, QVector v) { - _glWindow._cpuList = v; + startOfWork(KsWidgetsLib::KsDataWork::EditPlotList); + if (_glWindow._streamPlots.contains(sd)) + _glWindow._streamPlots[sd]._cpuList = v; + _selfUpdate(); + endOfWork(KsWidgetsLib::KsDataWork::EditPlotList); } /** * @brief Redreaw all Task graphs. * + * @param sd: Data stream identifier. * @param v: Process ids of the tasks to be plotted. */ -void KsTraceGraph::taskReDraw(QVector v) +void KsTraceGraph::taskReDraw(int sd, QVector v) +{ + startOfWork(KsWidgetsLib::KsDataWork::EditPlotList); + if (_glWindow._streamPlots.contains(sd)) + _glWindow._streamPlots[sd]._taskList = v; + + _selfUpdate(); + endOfWork(KsWidgetsLib::KsDataWork::EditPlotList); +} + +/** + * @brief Redreaw all virtCombo graphs. + * + * @param nCombos: Numver of Combo plots. + * @param v: Descriptor of the Combo to be plotted. + */ +void KsTraceGraph::comboReDraw(int nCombos, QVector v) { - _glWindow._taskList = v; + KsComboPlot combo; + + startOfWork(KsWidgetsLib::KsDataWork::EditPlotList); + + _glWindow._comboPlots.clear(); + + for (int i = 0; i < nCombos; ++i) { + combo.resize(v.takeFirst()); + for (auto &p: combo) + p << v; + + _glWindow._comboPlots.append(combo); + } + _selfUpdate(); + endOfWork(KsWidgetsLib::KsDataWork::EditPlotList); } /** Add (and plot) a CPU graph to the existing list of CPU graphs. */ -void KsTraceGraph::addCPUPlot(int cpu) +void KsTraceGraph::addCPUPlot(int sd, int cpu) { - if (_glWindow._cpuList.contains(cpu)) + startOfWork(KsWidgetsLib::KsDataWork::EditPlotList); + QVector &list = _glWindow._streamPlots[sd]._cpuList; + if (list.contains(cpu)) return; - _glWindow._cpuList.append(cpu); - std::sort(_glWindow._cpuList.begin(), _glWindow._cpuList.end()); + list.append(cpu); + std::sort(list.begin(), list.end()); + _selfUpdate(); + endOfWork(KsWidgetsLib::KsDataWork::EditPlotList); } /** Add (and plot) a Task graph to the existing list of Task graphs. */ -void KsTraceGraph::addTaskPlot(int pid) +void KsTraceGraph::addTaskPlot(int sd, int pid) { - if (_glWindow._taskList.contains(pid)) + startOfWork(KsWidgetsLib::KsDataWork::EditPlotList); + QVector &list = _glWindow._streamPlots[sd]._taskList; + if (list.contains(pid)) return; - _glWindow._taskList.append(pid); - std::sort(_glWindow._taskList.begin(), _glWindow._taskList.end()); + list.append(pid); + std::sort(list.begin(), list.end()); + _selfUpdate(); + endOfWork(KsWidgetsLib::KsDataWork::EditPlotList); } /** Remove a CPU graph from the existing list of CPU graphs. */ -void KsTraceGraph::removeCPUPlot(int cpu) +void KsTraceGraph::removeCPUPlot(int sd, int cpu) { - if (!_glWindow._cpuList.contains(cpu)) + startOfWork(KsWidgetsLib::KsDataWork::EditPlotList); + if (!_glWindow._streamPlots[sd]._cpuList.contains(cpu)) return; - _glWindow._cpuList.removeAll(cpu); + _glWindow._streamPlots[sd]._cpuList.removeAll(cpu); _selfUpdate(); + endOfWork(KsWidgetsLib::KsDataWork::EditPlotList); } /** Remove a Task graph from the existing list of Task graphs. */ -void KsTraceGraph::removeTaskPlot(int pid) +void KsTraceGraph::removeTaskPlot(int sd, int pid) { - if (!_glWindow._taskList.contains(pid)) + startOfWork(KsWidgetsLib::KsDataWork::EditPlotList); + if (!_glWindow._streamPlots[sd]._taskList.contains(pid)) return; - _glWindow._taskList.removeAll(pid); + _glWindow._streamPlots[sd]._taskList.removeAll(pid); _selfUpdate(); + endOfWork(KsWidgetsLib::KsDataWork::EditPlotList); } /** Update the content of all graphs. */ void KsTraceGraph::update(KsDataStore *data) { - _glWindow.model()->update(data); + kshark_context *kshark_ctx(nullptr); + QVector streamIds; + + if (!kshark_instance(&kshark_ctx)) + return; + + streamIds = KsUtils::getStreamIdList(kshark_ctx); + for (auto const &sd: streamIds) + for (auto &pid: _glWindow._streamPlots[sd]._taskList) { + kshark_unregister_data_collection(&kshark_ctx->collections, + kshark_match_pid, + sd, &pid, 1); + } + _selfUpdate(); + + streamIds = KsUtils::getStreamIdList(kshark_ctx); + for (auto const &sd: streamIds) + for (auto &pid: _glWindow._streamPlots[sd]._taskList) { + kshark_register_data_collection(kshark_ctx, + data->rows(), + data->size(), + kshark_match_pid, + sd, &pid, 1, + 25); + } } /** Update the geometry of the widget. */ @@ -519,19 +572,14 @@ void KsTraceGraph::updateGeom() * of the scroll bar. */ dwWidth = _scrollArea.width(); - if (_glWindow.height() + _legendAxisX.height() > _scrollArea.height()) + if (_glWindow.height() > _scrollArea.height()) dwWidth -= qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent); - /* - * Set the height of the Draw window according to the number of - * plotted graphs. - */ - _drawWindow.resize(dwWidth, - _glWindow.height() + _legendAxisX.height()); + _glWindow.resize(dwWidth, _glWindow.height()); /* Set the minimum height of the Graph widget. */ - hMin = _drawWindow.height() + + hMin = _glWindow.height() + _pointerBar.height() + _navigationBar.height() + _layout.contentsMargins().top() + @@ -546,7 +594,7 @@ void KsTraceGraph::updateGeom() * Now use the height of the Draw Window to fix the maximum height * of the Graph widget. */ - setMaximumHeight(_drawWindow.height() + + setMaximumHeight(_glWindow.height() + _pointerBar.height() + _navigationBar.height() + _layout.spacing() * 2 + @@ -560,75 +608,6 @@ void KsTraceGraph::updateGeom() _glWindow.update(); } -void KsTraceGraph::_updateGraphLegends() -{ - QString graphLegends, graphName; - QVBoxLayout *layout; - int width = 0; - - if (_legendWindow.layout()) { - /* - * Remove and delete the existing layout of the legend window. - */ - QLayoutItem *child; - while ((child = _legendWindow.layout()->takeAt(0)) != 0) { - delete child->widget(); - delete child; - } - - delete _legendWindow.layout(); - } - - layout = new QVBoxLayout; - layout->setContentsMargins(FONT_WIDTH, 0, 0, 0); - layout->setSpacing(_glWindow.vSpacing()); - layout->setAlignment(Qt::AlignTop); - layout->addSpacing(_glWindow.vMargin()); - - auto lamMakeName = [&]() { - QLabel *name = new QLabel(graphName); - - if (width < STRING_WIDTH(graphName)) - width = STRING_WIDTH(graphName); - - name->setAlignment(Qt::AlignBottom); - name->setStyleSheet("QLabel {background-color : white; color : black}"); - name->setFixedHeight(KS_GRAPH_HEIGHT); - layout->addWidget(name); - }; - - for (auto const &cpu: _glWindow._cpuList) { - graphName = QString("CPU %1").arg(cpu); - lamMakeName(); - } - - for (auto const &pid: _glWindow._taskList) { - graphName = QString(tep_data_comm_from_pid(_data->tep(), - pid)); - graphName.append(QString("-%1").arg(pid)); - lamMakeName(); - } - - _legendWindow.setLayout(layout); - _legendWindow.setMaximumWidth(width + FONT_WIDTH); -} - -void KsTraceGraph::_updateTimeLegends() -{ - uint64_t sec, usec, tsMid; - - kshark_convert_nano(_glWindow.model()->histo()->min, &sec, &usec); - _labelXMin.setText(_t2str(sec, usec)); - - tsMid = (_glWindow.model()->histo()->min + - _glWindow.model()->histo()->max) / 2; - kshark_convert_nano(tsMid, &sec, &usec); - _labelXMid.setText(_t2str(sec, usec)); - - kshark_convert_nano(_glWindow.model()->histo()->max, &sec, &usec); - _labelXMax.setText(_t2str(sec, usec)); -} - /** * Reimplemented event handler used to update the geometry of the widget on * resize events. @@ -646,16 +625,25 @@ void KsTraceGraph::resizeEvent(QResizeEvent* event) */ bool KsTraceGraph::eventFilter(QObject* obj, QEvent* evt) { - if (obj == &_drawWindow && evt->type() == QEvent::Enter) + /* Desable all mouse events for the OpenGL wiget when busy. */ + if (obj == &_glWindow && this->isBusy() && + (evt->type() == QEvent::MouseButtonDblClick || + evt->type() == QEvent::MouseButtonPress || + evt->type() == QEvent::MouseButtonRelease || + evt->type() == QEvent::MouseMove) + ) + return true; + + if (obj == &_glWindow && evt->type() == QEvent::Enter) _glWindow.setFocus(); - if (obj == &_drawWindow && evt->type() == QEvent::Leave) + if (obj == &_glWindow && evt->type() == QEvent::Leave) _glWindow.clearFocus(); return QWidget::eventFilter(obj, evt); } -void KsTraceGraph::_updateGraphs(GraphActions action) +void KsTraceGraph::_updateGraphs(KsWidgetsLib::KsDataWork action) { double k; int bin; @@ -673,7 +661,7 @@ void KsTraceGraph::_updateGraphs(GraphActions action) k = .01; while (_keyPressed) { switch (action) { - case GraphActions::ZoomIn: + case KsWidgetsLib::KsDataWork::ZoomIn: if (_mState->activeMarker()._isSet && _mState->activeMarker().isVisible()) { /* @@ -692,7 +680,7 @@ void KsTraceGraph::_updateGraphs(GraphActions action) break; - case GraphActions::ZoomOut: + case KsWidgetsLib::KsDataWork::ZoomOut: if (_mState->activeMarker()._isSet && _mState->activeMarker().isVisible()) { /* @@ -711,13 +699,16 @@ void KsTraceGraph::_updateGraphs(GraphActions action) break; - case GraphActions::ScrollLeft: + case KsWidgetsLib::KsDataWork::ScrollLeft: _glWindow.model()->shiftBackward(10); break; - case GraphActions::ScrollRight: + case KsWidgetsLib::KsDataWork::ScrollRight: _glWindow.model()->shiftForward(10); break; + + default: + return; } /* @@ -729,7 +720,7 @@ void KsTraceGraph::_updateGraphs(GraphActions action) k *= 1.02; _mState->updateMarkers(*_data, &_glWindow); - _updateTimeLegends(); + _glWindow.render(); QCoreApplication::processEvents(); } } @@ -737,7 +728,7 @@ void KsTraceGraph::_updateGraphs(GraphActions action) void KsTraceGraph::_onCustomContextMenu(const QPoint &point) { KsQuickMarkerMenu *menu(nullptr); - int cpu, pid; + int sd, cpu, pid; size_t row; bool found; @@ -745,8 +736,8 @@ void KsTraceGraph::_onCustomContextMenu(const QPoint &point) if (found) { /* KernelShark entry has been found under the cursor. */ KsQuickContextMenu *entryMenu; - menu = entryMenu = new KsQuickContextMenu(_data, row, - _mState, this); + menu = entryMenu = new KsQuickContextMenu(_mState, _data, row, + this); connect(entryMenu, &KsQuickContextMenu::addTaskPlot, this, &KsTraceGraph::addTaskPlot); @@ -760,34 +751,35 @@ void KsTraceGraph::_onCustomContextMenu(const QPoint &point) connect(entryMenu, &KsQuickContextMenu::removeCPUPlot, this, &KsTraceGraph::removeCPUPlot); } else { - cpu = _glWindow.getPlotCPU(point); + if (!_glWindow.getPlotInfo(point, &sd, &cpu, &pid)) + return; + if (cpu >= 0) { /* * This is a CPU plot, but we do not have an entry * under the cursor. */ KsRmCPUPlotMenu *rmMenu; - menu = rmMenu = new KsRmCPUPlotMenu(_mState, cpu, this); + menu = rmMenu = new KsRmCPUPlotMenu(_mState, sd, cpu, this); - auto lamRmPlot = [&cpu, this] () { - removeCPUPlot(cpu); + auto lamRmPlot = [&sd, &cpu, this] () { + removeCPUPlot(sd, cpu); }; connect(rmMenu, &KsRmPlotContextMenu::removePlot, lamRmPlot); } - pid = _glWindow.getPlotPid(point); if (pid >= 0) { /* * This is a Task plot, but we do not have an entry * under the cursor. */ KsRmTaskPlotMenu *rmMenu; - menu = rmMenu = new KsRmTaskPlotMenu(_mState, pid, this); + menu = rmMenu = new KsRmTaskPlotMenu(_mState, sd, pid, this); - auto lamRmPlot = [&pid, this] () { - removeTaskPlot(pid); + auto lamRmPlot = [&sd, &pid, this] () { + removeTaskPlot(sd, pid); }; connect(rmMenu, &KsRmPlotContextMenu::removePlot, diff --git a/src/KsTraceGraph.hpp b/src/KsTraceGraph.hpp index 0eeef14..0e31b88 100644 --- a/src/KsTraceGraph.hpp +++ b/src/KsTraceGraph.hpp @@ -12,6 +12,7 @@ #define _KS_TRACEGRAPH_H // KernelShark +#include "KsWidgetsLib.hpp" #include "KsGLWidget.hpp" /** @@ -35,7 +36,7 @@ public: * The KsTraceViewer class provides a widget for interactive visualization of * trace data shown as time-series. */ -class KsTraceGraph : public QWidget +class KsTraceGraph : public KsWidgetsLib::KsDataWidget { Q_OBJECT public: @@ -52,17 +53,19 @@ public: void markEntry(size_t); - void cpuReDraw(QVector); + void cpuReDraw(int sd, QVector cpus); - void taskReDraw(QVector); + void taskReDraw(int sd, QVector pids); - void addCPUPlot(int); + void comboReDraw(int sd, QVector v); - void addTaskPlot(int); + void addCPUPlot(int sd, int cpu); - void removeCPUPlot(int); + void addTaskPlot(int sd, int pid); - void removeTaskPlot(int); + void removeCPUPlot(int sd, int cpu); + + void removeTaskPlot(int sd, int pid); void update(KsDataStore *data); @@ -96,34 +99,24 @@ private: void _stopUpdating(); - void _resetPointer(uint64_t ts, int cpu, int pid); + void _resetPointer(int64_t ts, int sd, int cpu, int pid); void _setPointerInfo(size_t); - void _updateTimeLegends(); - - void _updateGraphLegends(); - void _selfUpdate(); void _markerReDraw(); - QString _t2str(uint64_t sec, uint64_t usec); - - enum class GraphActions { - ZoomIn, - ZoomOut, - ScrollLeft, - ScrollRight - }; - - void _updateGraphs(GraphActions action); + void _updateGraphs(KsWidgetsLib::KsDataWork action); void _onCustomContextMenu(const QPoint &point); + QString _t2str(uint64_t sec, uint64_t usec); + QToolBar _pointerBar, _navigationBar; QPushButton _zoomInButton, _quickZoomInButton; + QPushButton _zoomOutButton, _quickZoomOutButton; QPushButton _scrollLeftButton, _scrollRightButton; @@ -133,14 +126,8 @@ private: KsGraphScrollArea _scrollArea; - QWidget _drawWindow, _legendWindow, _legendAxisX; - - QLabel _labelXMin, _labelXMid, _labelXMax; - KsGLWidget _glWindow; - QGridLayout _drawLayout; - QVBoxLayout _layout; KsDualMarkerSM *_mState; From patchwork Thu Feb 11 10:31:56 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082741 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.7 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 490F4C433DB for ; Thu, 11 Feb 2021 10:38:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E61DB64E95 for ; Thu, 11 Feb 2021 10:38:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230281AbhBKKic (ORCPT ); Thu, 11 Feb 2021 05:38:32 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46426 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230209AbhBKKfs (ORCPT ); Thu, 11 Feb 2021 05:35:48 -0500 Received: from mail-ej1-x630.google.com (mail-ej1-x630.google.com [IPv6:2a00:1450:4864:20::630]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 37355C06121F for ; Thu, 11 Feb 2021 02:32:40 -0800 (PST) Received: by mail-ej1-x630.google.com with SMTP id b9so9214553ejy.12 for ; Thu, 11 Feb 2021 02:32: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=WBhagRs6pIZGEyxRjdwErefVL8BSm6/FZN1XY85vENw=; b=CIYjETQCVPB2aNax62h2VMUkM4GCIuSx0kRMmB4he3Scj/4de9qeLILm04Nk7zekI5 uwhshn1iHw+Hb1zwv3hLKrVeYo2rTmxD7r5K+sqIl7L6r/mD49Tl8Y3eGczuHS3meitn GhO/xHIPOEoCcMIQhPQqrNySmZx6/sEMMuA5YlR9ZBsln9SgnLtTq7XLNyDpKXjonGnl k1Bl+vJt79PBK3g6npOZosXS0qySGIdXy9J2YvzUcPcXhNDuS96OdpS/Mh1L4/v6Jykt VVAkXSdM61sizKrf7VmUgGeUHaq6hF7NzSp76H5bu/apDGqWo7PJSPG9yojCWhGph/n1 G+uw== 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=WBhagRs6pIZGEyxRjdwErefVL8BSm6/FZN1XY85vENw=; b=U9dyliKKxe5EVN+WYpF8dtdOYZAaBWS1Fa7Npw5wsvDxcwlyoEQb7ZzoITHaTnzYWs Zt6UQFR/5DSNSNRjlokR8d0wTl06G6ZkWYLpD5ftDJNq28rBppygbPdI3vC9JN+/ULG5 QscdtDUtCgfBPB+MsWt+3+h/7YRWL3c2mjrYTAVizuhDMtUim0OAM/B3T05mmquCBhQl /iQEjzRF4Jiyol62R4B8qRQyToOaaj4fkbldwtd+UFbk0UF3c27/n/ocZh7TYJeGR17m D1TfUqp1HRGKq3ag9gx8ixe/qrcQh52flNyqRsPdsYit39CmWaK9NY3BXHTSH63BDKpG F6cQ== X-Gm-Message-State: AOAM531Xtt8XIuPpGgcNcvOs0Pt2cF1q6m75biCwqU20RSPjqNyKvuAO 8wdBKS3nxvXkEzYQHXMQ9jg= X-Google-Smtp-Source: ABdhPJzS4kLABEfCprPdPQpyVqHauCf86WIxbX39D8B+4/DsH8UHjdEXOS5LAQPf3kTug09pe6CViw== X-Received: by 2002:a17:906:1447:: with SMTP id q7mr8168354ejc.27.1613039558936; Thu, 11 Feb 2021 02:32:38 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:38 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 18/27] kernel-shark: Update KsTraceViewer Date: Thu, 11 Feb 2021 12:31:56 +0200 Message-Id: <20210211103205.418588-19-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The compilation of KsTraceViewer.cpp is re-enabled and all functionalities are made compatible with the new version of the C API of libkshark (KernelShark 2.0). Signed-off-by: Yordan Karadzhov (VMware) --- src/CMakeLists.txt | 4 +-- src/KsTraceGraph.hpp | 5 +++- src/KsTraceViewer.cpp | 57 +++++++++++++++++++++++++++++-------------- src/KsTraceViewer.hpp | 13 +++++++--- 4 files changed, 54 insertions(+), 25 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ab74d5a..e09deb7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -73,7 +73,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) KsDualMarker.hpp KsWidgetsLib.hpp KsTraceGraph.hpp -# KsTraceViewer.hpp + KsTraceViewer.hpp # KsMainWindow.hpp # KsCaptureDialog.hpp KsQuickContextMenu.hpp) @@ -89,7 +89,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) KsDualMarker.cpp KsWidgetsLib.cpp KsTraceGraph.cpp -# KsTraceViewer.cpp + KsTraceViewer.cpp # KsMainWindow.cpp # KsCaptureDialog.cpp KsQuickContextMenu.cpp) diff --git a/src/KsTraceGraph.hpp b/src/KsTraceGraph.hpp index 0e31b88..6e83f21 100644 --- a/src/KsTraceGraph.hpp +++ b/src/KsTraceGraph.hpp @@ -29,7 +29,10 @@ public: * Reimplemented handler for mouse wheel events. All mouse wheel * events will be ignored. */ - void wheelEvent(QWheelEvent *evt) {evt->ignore();} + void wheelEvent(QWheelEvent *evt) { + if (QApplication::keyboardModifiers() != Qt::ControlModifier) + QScrollArea::wheelEvent(evt); + } }; /** diff --git a/src/KsTraceViewer.cpp b/src/KsTraceViewer.cpp index 0e0e3d4..afd5a85 100644 --- a/src/KsTraceViewer.cpp +++ b/src/KsTraceViewer.cpp @@ -9,7 +9,7 @@ * @brief KernelShark Trace Viewer widget. */ -// C++11 +// C++ #include #include #include @@ -50,11 +50,10 @@ void KsTableView::scrollTo(const QModelIndex &index, ScrollHint hint) /** Create a default (empty) Trace viewer widget. */ KsTraceViewer::KsTraceViewer(QWidget *parent) -: QWidget(parent), +: KsWidgetsLib::KsDataWidget(parent), _view(this), _model(this), _proxyModel(this), - _tableHeader(_model.header()), _toolbar(this), _labelSearch("Search: Column", this), _labelGrFollows("Graph follows ", this), @@ -72,7 +71,7 @@ KsTraceViewer::KsTraceViewer(QWidget *parent) /* On the toolbar make two Combo boxes for the search settings. */ _toolbar.addWidget(&_labelSearch); - _searchFSM._columnComboBox.addItems(_tableHeader); + _searchFSM._columnComboBox.addItems(_model.header()); /* * Using the old Signal-Slot syntax because @@ -163,6 +162,9 @@ void KsTraceViewer::loadData(KsDataStore *data) _model.fill(data); this->_resizeToContents(); + _searchFSM._columnComboBox.clear(); + _searchFSM._columnComboBox.addItems(_model.header()); + this->setMinimumHeight(SCREEN_HEIGHT / 5); } @@ -172,8 +174,8 @@ void KsTraceViewer::setMarkerSM(KsDualMarkerSM *m) QString styleSheetA, styleSheetB; _mState = m; - _model.setColors(_mState->markerA()._color, - _mState->markerB()._color); + _model.setMarkerColors(_mState->markerA()._color, + _mState->markerB()._color); /* * Assign a property to State A of the Dual marker state machine. When @@ -234,6 +236,7 @@ void KsTraceViewer::update(KsDataStore *data) _data = data; if (_mState->activeMarker()._isSet) showRow(_mState->activeMarker()._pos, true); + _resizeToContents(); } void KsTraceViewer::_onCustomContextMenu(const QPoint &point) @@ -246,7 +249,7 @@ void KsTraceViewer::_onCustomContextMenu(const QPoint &point) * of the row number in the source model. */ size_t row = _proxyModel.mapRowFromSource(i.row()); - KsQuickContextMenu menu(_data, row, _mState, this); + KsQuickContextMenu menu(_mState, _data, row, this); /* * Note that this slot was connected to the @@ -290,7 +293,7 @@ void KsTraceViewer::_graphFollowsChanged(int state) _graphFollows = (bool) state; if (_graphFollows && row != KS_NO_ROW_SELECTED) - emit select(row); // Send a signal to the Graph widget. + emit select(*_it); // Send a signal to the Graph widget. } void KsTraceViewer::_search() @@ -459,7 +462,7 @@ void KsTraceViewer::clearSelection() /** Switch the Dual marker. */ void KsTraceViewer::markSwitch() { - int row; + ssize_t row; /* The state of the Dual marker has changed. Get the new active marker. */ DualMarkerState state = _mState->getState(); @@ -490,7 +493,7 @@ void KsTraceViewer::markSwitch() * The index in the source model is used to retrieve the value * of the row number in the proxy model. */ - size_t row =_mState->getMarker(state)._pos; + row =_mState->getMarker(state)._pos; QModelIndex index = _proxyModel.mapFromSource(_model.index(row, 0)); @@ -525,7 +528,7 @@ void KsTraceViewer::markSwitch() */ void KsTraceViewer::resizeEvent(QResizeEvent* event) { - int nColumns = _tableHeader.count(); + int nColumns = _model.header().count(); int tableSize(0), viewSize, freeSpace; _resizeToContents(); @@ -564,7 +567,7 @@ void KsTraceViewer::keyReleaseEvent(QKeyEvent *event) void KsTraceViewer::_resizeToContents() { - int rows, columnSize, markRow = selectedRow(); + int col, rows, columnSize, markRow = selectedRow(); _view.setVisible(false); _view.resizeColumnsToContents(); @@ -579,13 +582,22 @@ void KsTraceViewer::_resizeToContents() _view.clearSelection(); /* - * Because of some unknown reason the first column doesn't get + * Because of some unknown reason some of the columns doesn't get * resized properly by the code above. We will resize this * column by hand. */ + col = KsViewModel::TRACE_VIEW_COL_STREAM; + columnSize = STRING_WIDTH(_model.header()[col]) + FONT_WIDTH; + _view.setColumnWidth(col, columnSize); + + col = KsViewModel::TRACE_VIEW_COL_CPU; + columnSize = STRING_WIDTH(_model.header()[col]) + FONT_WIDTH * 2; + _view.setColumnWidth(col, columnSize); + + col = KsViewModel::TRACE_VIEW_COL_INDEX; rows = _model.rowCount({}); columnSize = STRING_WIDTH(QString("%1").arg(rows)) + FONT_WIDTH; - _view.setColumnWidth(0, columnSize); + _view.setColumnWidth(col, columnSize); } //! @cond Doxygen_Suppress @@ -598,7 +610,16 @@ size_t KsTraceViewer::_searchItems() { int column = _searchFSM._columnComboBox.currentIndex(); QString searchText = _searchFSM._searchLineEdit.text(); - int count, dataRow; + int count, dataRow, columnIndex = column; + + if (_model.singleStream()) { + /* + * If only one Data stream (file) is loaded, the first column + * (TRACE_VIEW_COL_STREAM) is not shown. The column index has + * to be corrected. + */ + ++columnIndex; + } if (searchText.isEmpty()) { /* @@ -620,8 +641,8 @@ size_t KsTraceViewer::_searchItems() } else { _searchFSM.handleInput(sm_input_t::Start); - if (column == KsViewModel::TRACE_VIEW_COL_INFO || - column == KsViewModel::TRACE_VIEW_COL_LAT) + if (columnIndex == KsViewModel::TRACE_VIEW_COL_INFO || + columnIndex == KsViewModel::TRACE_VIEW_COL_AUX) _searchItemsST(); else _searchItemsMT(); @@ -761,7 +782,7 @@ void KsTraceViewer::_searchItemsMT() }; for (int i = 0; i < mapList.size(); ++i) - if ( mapList[i].count()) { + if (mapList[i].count()) { queue.push(std::make_pair(i, mapList[i].front())); mapList[i].pop_front(); } diff --git a/src/KsTraceViewer.hpp b/src/KsTraceViewer.hpp index 6080d0d..f3979a6 100644 --- a/src/KsTraceViewer.hpp +++ b/src/KsTraceViewer.hpp @@ -20,6 +20,7 @@ #include "KsModels.hpp" #include "KsSearchFSM.hpp" #include "KsDualMarker.hpp" +#include "KsWidgetsLib.hpp" /** * Table View class, needed in order to reimplemented the handler for mouse @@ -42,7 +43,7 @@ public: * The KsTraceViewer class provides a widget for browsing in the trace data * shown in a text form. */ -class KsTraceViewer : public QWidget +class KsTraceViewer : public KsWidgetsLib::KsDataWidget { Q_OBJECT public: @@ -74,6 +75,12 @@ public: void update(KsDataStore *data); + /** Update the color scheme used by the model. */ + void loadColors() + { + _model.loadColors(); + } + signals: /** Signal emitted when new row is selected. */ void select(size_t); @@ -82,7 +89,7 @@ signals: * This signal is used to re-emitted the addTaskPlot signal of the * KsQuickContextMenu. */ - void addTaskPlot(int pid); + void addTaskPlot(int sd, int pid); /** * This signal is used to re-emitted the deselect signal of the @@ -99,8 +106,6 @@ private: KsFilterProxyModel _proxyModel; - QStringList _tableHeader; - QToolBar _toolbar; QLabel _labelSearch, _labelGrFollows; From patchwork Thu Feb 11 10:31:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082749 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.7 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 3AFA7C433E6 for ; Thu, 11 Feb 2021 10:39:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0761D64E9A for ; Thu, 11 Feb 2021 10:39:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230311AbhBKKit (ORCPT ); Thu, 11 Feb 2021 05:38:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46428 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230219AbhBKKfs (ORCPT ); Thu, 11 Feb 2021 05:35:48 -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 3B7C4C061221 for ; Thu, 11 Feb 2021 02:32:41 -0800 (PST) Received: by mail-ed1-x532.google.com with SMTP id v7so6371367eds.10 for ; Thu, 11 Feb 2021 02:32:41 -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=0qe5EANYiV0g2mhPh7z4awjgB9+F2mKtrWrK20/JraI=; b=gRGhi3QQ+XCH9yJ5EJguGq3sF4G45sgTrRgLhi52nL17I1mGDgNlOqnO/YjqfQ3Omt Ro5OrbHKioPBDfVPkkA7beqf7XHhw/HBWHCOgNG4zXeuHutc+bcXABLpjZU+71+cW2Uo gKLgIzZ25ertKSp0RhSp8v/ZKeV8i+IOxKaa58NC9nf8lDxa09zFSdsuIBJzzvVkUbmP 3Exz1a2z4fIkuAbUXbFXe+Zvowqgl/tAULGm52xg53jDAiPDEaK+I6lim2U8GUNE7zfQ E5pykEbGLlWlGqEwsQ/p96VBy7QV4NONxRbFDLHBdBgn0aZRVdm3MOguaz9TbuatCuWk a1Pw== 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=0qe5EANYiV0g2mhPh7z4awjgB9+F2mKtrWrK20/JraI=; b=DG/5kz7mr16Sd/zMQl+SU2ewhtA6QZA/gdYi84XmAmrC7UmHw8LWwZLzMw4MI3fC1s Oi2G3tIohu7108JKzN2OGAqGzTu6yQu2BhYVAI6km2f9A4+Lv8M+qiJFSHvKk7y/wGe/ 4oohVGHF33oJAdlVfmRrJJAmnskc2SAbCUFg+2E3ewQS7AGqkOM0sefHB0JRcEP+Smud JMCyyZygR/Le4bWXIdxsZ6/rN7xK/ideC1HG4KhNe1/IYaulJrOVA25VS3XqF5d/EEaL EAW23dsF0PKxYe94wvT/32fJsisU2Ksg7oCEc8wi81Ral1aGuJhZSFwkuHxkEE4cofE6 wUWw== X-Gm-Message-State: AOAM532hh3zbZ9xDdZq+ag++pMP6DR56aserT3gTQmb+6t57ffBGaJG2 L4WOeSxX4faZm9hDChqp7Rg= X-Google-Smtp-Source: ABdhPJzVDEBwrAs8swYHH3Fkbm4p6mHkXDg44I2nFWIyjcRXA0tfZWtG2klyeh9/Asxi+CGfJ00irQ== X-Received: by 2002:aa7:de82:: with SMTP id j2mr7731059edv.313.1613039559955; Thu, 11 Feb 2021 02:32:39 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:39 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 19/27] kernel-shark: Update KsAdvFilteringDialog Date: Thu, 11 Feb 2021 12:31:57 +0200 Message-Id: <20210211103205.418588-20-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The compilation ofKsAdvFilteringDialog .cpp is re-enabled and all functionalities are made compatible with the new version of the C API of libkshark (KernelShark 2.0). Signed-off-by: Yordan Karadzhov (VMware) --- src/CMakeLists.txt | 8 +- src/KsAdvFilteringDialog.cpp | 200 ++++++++++++++++++++++------------- src/KsAdvFilteringDialog.hpp | 16 ++- 3 files changed, 144 insertions(+), 80 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e09deb7..6bb94d6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -76,8 +76,8 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) KsTraceViewer.hpp # KsMainWindow.hpp # KsCaptureDialog.hpp - KsQuickContextMenu.hpp) -# KsAdvFilteringDialog.hpp) + KsQuickContextMenu.hpp + KsAdvFilteringDialog.hpp) QT5_WRAP_CPP(ks-guiLib_hdr_moc ${ks-guiLib_hdr}) @@ -92,8 +92,8 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) KsTraceViewer.cpp # KsMainWindow.cpp # KsCaptureDialog.cpp - KsQuickContextMenu.cpp) -# KsAdvFilteringDialog.cpp) + KsQuickContextMenu.cpp + KsAdvFilteringDialog.cpp) target_link_libraries(kshark-gui kshark-plot Qt5::Widgets diff --git a/src/KsAdvFilteringDialog.cpp b/src/KsAdvFilteringDialog.cpp index 8dc53bb..2fdb624 100644 --- a/src/KsAdvFilteringDialog.cpp +++ b/src/KsAdvFilteringDialog.cpp @@ -9,10 +9,16 @@ * @brief GUI Dialog for Advanced filtering settings. */ +// trace-cmd +#include "trace-cmd/trace-cmd.h" + // KernelShark -#include "KsAdvFilteringDialog.hpp" #include "libkshark.h" +#include "libkshark-tepdata.h" #include "KsUtils.hpp" +#include "KsAdvFilteringDialog.hpp" + +using namespace KsWidgetsLib; /** Create dialog for Advanced Filtering. */ KsAdvFilteringDialog::KsAdvFilteringDialog(QWidget *parent) @@ -71,6 +77,9 @@ KsAdvFilteringDialog::KsAdvFilteringDialog(QWidget *parent) lamAddLine(); + _topLayout.addWidget(&_streamComboBox); + _getFtraceStreams(kshark_ctx); + _getFilters(kshark_ctx); if (_filters.count()) { @@ -149,23 +158,38 @@ KsAdvFilteringDialog::KsAdvFilteringDialog(QWidget *parent) this, &QWidget::close); } -void KsAdvFilteringDialog::_setSystemCombo(struct kshark_context *kshark_ctx) +kshark_data_stream * +KsAdvFilteringDialog::_getCurrentStream(kshark_context *kshark_ctx) { + int sd = _streamComboBox.currentData().toInt(); + + return kshark_get_data_stream(kshark_ctx, sd); +} + +void KsAdvFilteringDialog::_setSystemCombo(kshark_context *kshark_ctx) +{ + kshark_data_stream *stream; + QVector eventIds; QStringList sysList; - tep_event **events; - int i(0), nEvts(0); + int i(0); - if (kshark_ctx->pevent) { - nEvts = tep_get_events_count(kshark_ctx->pevent); - events = tep_list_events(kshark_ctx->pevent, - TEP_EVENT_SORT_SYSTEM); - } + stream = _getCurrentStream(kshark_ctx); + if (!stream || !kshark_is_tep(stream)) + return; + + eventIds = KsUtils::getEventIdList(stream->stream_id); + + auto lamGetSysName = [&stream] (int eventId) { + QStringList name = KsUtils::getTepEvtName(stream->stream_id, + eventId); + return name[0]; + }; - while (i < nEvts) { - QString sysName(events[i]->system); + while (i < stream->n_events) { + QString sysName = lamGetSysName(eventIds[i]); sysList << sysName; - while (sysName == events[i]->system) { - if (++i == nEvts) + while (sysName == lamGetSysName(eventIds[i])) { + if (++i == stream->n_events) break; } } @@ -202,24 +226,48 @@ QStringList KsAdvFilteringDialog::_operators() return OpsList; } -void KsAdvFilteringDialog::_getFilters(struct kshark_context *kshark_ctx) +void KsAdvFilteringDialog::_getFtraceStreams(kshark_context *kshark_ctx) { - tep_event **events; - char *str; + kshark_data_stream *stream; + QVector streamIds; + + _streamComboBox.clear(); + streamIds = KsUtils::getStreamIdList(kshark_ctx); + for (auto const &sd: streamIds) { + stream = kshark_ctx->stream[sd]; + if (kshark_is_tep(stream)) + _streamComboBox.addItem(KsUtils::streamDescription(stream), sd); + } - events = tep_list_events(kshark_ctx->pevent, TEP_EVENT_SORT_SYSTEM); + if (!_streamComboBox.count()) + _streamComboBox.addItem("No FTRACE data loaded", -1); +} - for (int i = 0; events[i]; i++) { - str = tep_filter_make_string(kshark_ctx->advanced_event_filter, - events[i]->id); - if (!str) +void KsAdvFilteringDialog::_getFilters(kshark_context *kshark_ctx) +{ + kshark_data_stream *stream; + QVector eventIds; + QStringList eventName; + char *filterStr; + + stream = _getCurrentStream(kshark_ctx); + if (!stream || !kshark_is_tep(stream)) + return; + + eventIds = KsUtils::getEventIdList(stream->stream_id); + for (int i = 0; i < stream->n_events; ++i) { + eventName = KsUtils::getTepEvtName(stream->stream_id, eventIds[i]); + filterStr = kshark_tep_filter_make_string(stream, eventIds[i]); + if (!filterStr) continue; - _filters.insert(events[i]->id, - QString("%1/%2:%3").arg(events[i]->system, - events[i]->name, str)); + _filters.insert(eventIds[i], + QString("%1:%2/%3:%4").arg(QString::number(stream->stream_id), + eventName[0], + eventName[1], + filterStr)); - free(str); + free(filterStr); } } @@ -232,7 +280,7 @@ void KsAdvFilteringDialog::_makeFilterTable(struct kshark_context *kshark_ctx) _table = new KsCheckBoxTable(this); _table->setSelectionMode(QAbstractItemView::SingleSelection); - headers << "Delete" << "Event" << " Id" << "Filter"; + headers << "Delete" << "Stream" << "Event" << " Id" << "Filter"; _table->init(headers, _filters.count()); for(auto f : _filters.keys()) { @@ -241,11 +289,14 @@ void KsAdvFilteringDialog::_makeFilterTable(struct kshark_context *kshark_ctx) i1 = new QTableWidgetItem(thisFilter[0]); _table->setItem(count, 1, i1); + i1 = new QTableWidgetItem(thisFilter[1]); + _table->setItem(count, 2, i1); + i2 = new QTableWidgetItem(tr("%1").arg(f)); - _table->setItem(count, 2, i2); + _table->setItem(count, 3, i2); - i3 = new QTableWidgetItem(thisFilter[1]); - _table->setItem(count, 3, i3); + i3 = new QTableWidgetItem(thisFilter[2]); + _table->setItem(count, 4, i3); ++count; } @@ -275,20 +326,25 @@ void KsAdvFilteringDialog::_help() void KsAdvFilteringDialog::_systemChanged(const QString &sysName) { kshark_context *kshark_ctx(NULL); - QStringList evtsList; - tep_event **events; - int i, nEvts; + kshark_data_stream *stream; + QStringList evtsList, name; + QVector eventIds; + int i; - _eventComboBox.clear(); - if (!kshark_instance(&kshark_ctx) || !kshark_ctx->pevent) + if (!kshark_instance(&kshark_ctx)) return; - nEvts = tep_get_events_count(kshark_ctx->pevent); - events = tep_list_events(kshark_ctx->pevent, TEP_EVENT_SORT_SYSTEM); + _eventComboBox.clear(); + + stream = _getCurrentStream(kshark_ctx); + if (!stream || !kshark_is_tep(stream)) + return; - for (i = 0; i < nEvts; ++i) { - if (sysName == events[i]->system) - evtsList << events[i]->name; + eventIds = KsUtils::getEventIdList(stream->stream_id); + for (i = 0; i < stream->n_events; ++i) { + name = KsUtils::getTepEvtName(stream->stream_id, eventIds[i]); + if (sysName == name[0]) + evtsList << name[1]; } std::sort(evtsList.begin(), evtsList.end()); @@ -300,15 +356,20 @@ void KsAdvFilteringDialog::_systemChanged(const QString &sysName) } QStringList -KsAdvFilteringDialog::_getEventFormatFields(struct tep_event *event) +KsAdvFilteringDialog::_getEventFields(int eventId) { - tep_format_field *field, **fields = tep_event_fields(event); + kshark_context *kshark_ctx(NULL); + kshark_data_stream *stream; QStringList fieldList; - for (field = *fields; field; field = field->next) - fieldList << field->name; + if (!kshark_instance(&kshark_ctx)) + return {}; + + stream = _getCurrentStream(kshark_ctx); + if (!stream || !kshark_is_tep(stream)) + return {}; - free(fields); + fieldList = KsUtils::getEventFieldsList(stream->stream_id, eventId); std::sort(fieldList.begin(), fieldList.end()); return fieldList; @@ -317,22 +378,24 @@ KsAdvFilteringDialog::_getEventFormatFields(struct tep_event *event) void KsAdvFilteringDialog::_eventChanged(const QString &evtName) { QString sysName = _systemComboBox.currentText(); + QStringList fieldList, eventName; kshark_context *kshark_ctx(NULL); - QStringList fieldList; - tep_event **events; - int nEvts; + kshark_data_stream *stream; + QVector eventIds; _fieldComboBox.clear(); - if (!kshark_instance(&kshark_ctx) || !kshark_ctx->pevent) + if (!kshark_instance(&kshark_ctx)) return; - nEvts = tep_get_events_count(kshark_ctx->pevent); - events = tep_list_events(kshark_ctx->pevent, TEP_EVENT_SORT_SYSTEM); + stream = _getCurrentStream(kshark_ctx); + if (!stream || !kshark_is_tep(stream)) + return; - for (int i = 0; i < nEvts; ++i) { - if (evtName == events[i]->name && - sysName == events[i]->system) { - fieldList = _getEventFormatFields(events[i]); + eventIds = KsUtils::getEventIdList(stream->stream_id); + for (int i = 0; i < stream->n_events; ++i) { + eventName = KsUtils::getTepEvtName(stream->stream_id, eventIds[i]); + if (sysName == eventName[0] && evtName == eventName[1]) { + fieldList = _getEventFields(eventIds[i]); _fieldComboBox.addItems(fieldList); return; @@ -384,20 +447,28 @@ void KsAdvFilteringDialog::_applyPress() { QMapIterator f(_filters); kshark_context *kshark_ctx(NULL); + kshark_data_stream *stream; const char *text; - tep_errno ret; char *filter; int i(0); if (!kshark_instance(&kshark_ctx)) return; + stream = _getCurrentStream(kshark_ctx); + if (!stream || !kshark_is_tep(stream)) + return; + while (f.hasNext()) { f.next(); if (_table->_cb[i]->checkState() == Qt::Checked) { - tep_filter_remove_event(kshark_ctx->advanced_event_filter, - f.key()); + kshark_data_stream *filter_stream; + int sd = f.value().split(":").at(0).toInt(); + + filter_stream = kshark_get_data_stream(kshark_ctx, sd); + kshark_tep_filter_remove_event(filter_stream, f.key()); } + ++i; } @@ -419,20 +490,7 @@ void KsAdvFilteringDialog::_applyPress() filter = (char*) malloc(strlen(text) + 1); strcpy(filter, text); - ret = tep_filter_add_filter_str(kshark_ctx->advanced_event_filter, - filter); - - if (ret < 0) { - char error_str[200]; - - tep_strerror(kshark_ctx->pevent, ret, error_str, - sizeof(error_str)); - - fprintf(stderr, "filter failed due to: %s\n", error_str); - free(filter); - - return; - } + kshark_tep_add_filter_str(stream, filter); free(filter); diff --git a/src/KsAdvFilteringDialog.hpp b/src/KsAdvFilteringDialog.hpp index 2a534d0..a1db90b 100644 --- a/src/KsAdvFilteringDialog.hpp +++ b/src/KsAdvFilteringDialog.hpp @@ -36,7 +36,7 @@ private: QMap _filters; - KsCheckBoxTable *_table; + KsWidgetsLib::KsCheckBoxTable *_table; QVBoxLayout _topLayout; @@ -46,6 +46,8 @@ private: QLabel _descrLabel, _sysEvLabel, _opsLabel, _fieldLabel; + QComboBox _streamComboBox; + QComboBox _systemComboBox, _eventComboBox; QComboBox _opsComboBox, _fieldComboBox; @@ -74,13 +76,17 @@ private: QStringList _operators(); - void _getFilters(struct kshark_context *kshark_ctx); + void _getFtraceStreams(kshark_context *kshark_ctx); + + void _getFilters(kshark_context *kshark_ctx); + + void _makeFilterTable(kshark_context *kshark_ctx); - void _makeFilterTable(struct kshark_context *kshark_ctx); + QStringList _getEventFields(int eventId); - QStringList _getEventFormatFields(struct tep_event *event); + void _setSystemCombo(kshark_context *kshark_ctx); - void _setSystemCombo(struct kshark_context *kshark_ctx); + kshark_data_stream *_getCurrentStream(kshark_context *kshark_ctx); private slots: void _systemChanged(const QString&); From patchwork Thu Feb 11 10:31:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082753 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.7 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 ACA80C433DB for ; Thu, 11 Feb 2021 10:39:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 776E764E95 for ; Thu, 11 Feb 2021 10:39:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230186AbhBKKjH (ORCPT ); Thu, 11 Feb 2021 05:39:07 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46438 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229952AbhBKKfv (ORCPT ); Thu, 11 Feb 2021 05:35:51 -0500 Received: from mail-ej1-x62c.google.com (mail-ej1-x62c.google.com [IPv6:2a00:1450:4864:20::62c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1CB71C061222 for ; Thu, 11 Feb 2021 02:32:42 -0800 (PST) Received: by mail-ej1-x62c.google.com with SMTP id f14so9257486ejc.8 for ; Thu, 11 Feb 2021 02:32:42 -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=GEWdWhfigjURshT9Ltb3Sznhioj3zu5UHyKnmx94g8E=; b=GhNL5Yn76/C3InCTSxcdkqRHxhx/KFfVmFViQjGTXqoddPjk2ct3pW2yuj6f7otUq7 hhiGZJrBFj4oF97s7uijPTAItx1J6mU59SeY2oEcP4KjpshyYkJUYqrJVIYiDIp0CxXt W6IAFBoOVokvo5WjU6U0ijfL7YcZ29yYQJy3olNR9iDpDwFmgEuxloZ4OQed7TLW4A22 U7X5h1pIxJ+tNBZfOfDiOtqSLHkAlOvuLn8j1rqI5AlkY/XLvuFljAR6nuhp2AkYF9q2 i533e6eF0cU9qQa7MlCx+pwzeDzA+s2busLGUbWBv5fci1t5e96G56kbFPwgFcsEX3Mt Iqqg== 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=GEWdWhfigjURshT9Ltb3Sznhioj3zu5UHyKnmx94g8E=; b=IIRpV2o+u6iQO83i09AS1yXZi1k5WzwuG2MuVOV6sYVjdBZ4Q3havE/nkr0NpZFl0j LyPThqKKy41/pg+oiNrAj8TNHoMIDWsoYvCAmdl/q2afRbX80Q9vS2wqOxAdPNZkbFU7 Oj8252pEXsOqgsUnBz/cw02KFDH/hKe7qm7yW9qXknc05ta34Wr0j/vaXWLvNbRrhCb0 iC1FRpfwuqcdaNc9fkdGhLK5SudPHSeQLACGGyx9haYNtGUoPuJsTTAN5JCH7bJ9YckZ ew4Do7dtY2WfPcMC0cTow7dUDw5Ffnq9LT7+NQcXPfLMWZD6asdLa8Qd1SB+cw0NQVVH M62A== X-Gm-Message-State: AOAM5306SOJ4VdN1Vl+hT246iHyMLhYv7excaVktRlnLqvUmUKfW3CuJ cuabuEXKoRI14fylEI0WNrE= X-Google-Smtp-Source: ABdhPJxTJKHJFY72gO0FC4+Xr/fA76q17w/iU8qsUr9HvlCep2v1xlGluR/IQdgxHKcuK7576TmQZA== X-Received: by 2002:a17:906:6b1b:: with SMTP id q27mr7580880ejr.508.1613039560861; Thu, 11 Feb 2021 02:32:40 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:40 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 20/27] kernel-shark: Update KsCaptureDialog Date: Thu, 11 Feb 2021 12:31:58 +0200 Message-Id: <20210211103205.418588-21-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The compilation of KsCaptureDialog.cpp and kshark-record.cpp is re-enabled and all functionalities are made compatible with the new version of the C API of libkshark (KernelShark 2.0). Signed-off-by: Yordan Karadzhov (VMware) --- src/CMakeLists.txt | 10 ++--- src/KsCaptureDialog.cpp | 90 ++++++++++++++++++++++------------------- src/KsCaptureDialog.hpp | 4 +- 3 files changed, 56 insertions(+), 48 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6bb94d6..28f44fe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -75,7 +75,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) KsTraceGraph.hpp KsTraceViewer.hpp # KsMainWindow.hpp -# KsCaptureDialog.hpp + KsCaptureDialog.hpp KsQuickContextMenu.hpp KsAdvFilteringDialog.hpp) @@ -91,7 +91,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) KsTraceGraph.cpp KsTraceViewer.cpp # KsMainWindow.cpp -# KsCaptureDialog.cpp + KsCaptureDialog.cpp KsQuickContextMenu.cpp KsAdvFilteringDialog.cpp) @@ -106,9 +106,9 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) # add_executable(${KS_APP_NAME} kernelshark.cpp) # target_link_libraries(${KS_APP_NAME} kshark-gui) -# message(STATUS "kshark-record") -# add_executable(kshark-record kshark-record.cpp) -# target_link_libraries(kshark-record kshark-gui) + message(STATUS "kshark-record") + add_executable(kshark-record kshark-record.cpp) + target_link_libraries(kshark-record kshark-gui) # install(TARGETS ${KS_APP_NAME} kshark-record kshark-gui # RUNTIME DESTINATION ${_INSTALL_PREFIX}/bin/ diff --git a/src/KsCaptureDialog.cpp b/src/KsCaptureDialog.cpp index 7253ab6..ca4c2bc 100644 --- a/src/KsCaptureDialog.cpp +++ b/src/KsCaptureDialog.cpp @@ -14,6 +14,7 @@ // KernelShark #include "libkshark.h" +#include "libkshark-tepdata.h" #include "KsUtils.hpp" #include "KsCmakeDef.hpp" #include "KsCaptureDialog.hpp" @@ -24,11 +25,6 @@ extern "C" { #include } -static inline tep_handle *local_events() -{ - return tracefs_local_events(tracefs_tracing_dir()); -} - /** * @brief Create KsCommandLineEdit. * @@ -48,11 +44,28 @@ QSize KsCommandLineEdit::sizeHint() const return {FONT_WIDTH * 30, FONT_HEIGHT * 3}; } +static kshark_data_stream *_initLocalStream() +{ + kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; + int sd; + + if (!kshark_instance(&kshark_ctx)) + return nullptr; + + sd = kshark_add_stream(kshark_ctx); + stream = kshark_ctx->stream[sd]; + + kshark_tep_init_local(stream); + + return stream; +} + /** @brief Create KsCaptureControl widget. */ KsCaptureControl::KsCaptureControl(QWidget *parent) : QWidget(parent), - _localTEP(local_events()), - _eventsWidget(_localTEP, this), + _stream(_initLocalStream()), + _eventsWidget(_stream), _pluginsLabel("Plugin: ", this), _outputLabel("Output file: ", this), _commandLabel("Command: ", this), @@ -80,7 +93,7 @@ KsCaptureControl::KsCaptureControl(QWidget *parent) _topLayout.addWidget(line); }; - if (pluginList.count() == 0 || !_localTEP) { + if (pluginList.count() == 0 || !kshark_get_tep(_stream)) { /* * No plugins or events have been found. Most likely this is * because the process has no Root privileges or because @@ -88,7 +101,7 @@ KsCaptureControl::KsCaptureControl(QWidget *parent) */ QString message("Error: No events or plugins found.\n"); - if (!_localTEP) + if (!kshark_get_tep(_stream)) message += "Cannot find or mount tracing directory.\n"; // geteuid() returns 0 if running as effective id of root @@ -202,23 +215,19 @@ QStringList KsCaptureControl::getArgs() QStringList KsCaptureControl::_getPlugins() { QStringList pluginList; - char **all_plugins; + char **all_tracers; - all_plugins = tracefs_tracers(tracefs_tracing_dir()); + all_tracers = kshark_tracecmd_local_plugins(); - if (!all_plugins) + if (!all_tracers) return pluginList; - for (int i = 0; all_plugins[i]; ++i) { - /* - * TODO plugin selection here. - * printf("plugin %i %s\n", i, all_plugins[i]); - */ - pluginList << all_plugins[i]; - free(all_plugins[i]); + for (int i = 0; all_tracers[i]; ++i) { + pluginList << all_tracers[i]; + free(all_tracers[i]); } - free (all_plugins); + free(all_tracers); std::sort(pluginList.begin(), pluginList.end()); return pluginList; @@ -226,20 +235,17 @@ QStringList KsCaptureControl::_getPlugins() void KsCaptureControl::_importSettings() { - int nEvts = tep_get_events_count(_localTEP), nIds; + QVector event_ids = _eventsWidget.getIds(); + QVector status(_stream->n_events, 0); kshark_config_doc *conf, *jevents, *temp; - QVector v(nEvts, false); - tracecmd_filter_id *eventHash; - QVector eventIds; + kshark_hash_id *eventHash; QString fileName; + int nIds; auto lamImportError = [this] () { emit print("ERROR: Unable to load the configuration file.\n"); }; - /** Get all available events. */ - eventIds = KsUtils::getEventIdList(TEP_EVENT_SORT_SYSTEM); - /* Get the configuration document. */ fileName = KsUtils::getFile(this, "Import from Filter", "Kernel Shark Config files (*.json);;", @@ -267,8 +273,9 @@ void KsCaptureControl::_importSettings() return; } - eventHash = tracecmd_filter_id_hash_alloc(); - nIds = kshark_import_event_filter(_localTEP, eventHash, "Events", jevents); + eventHash = kshark_get_filter(_stream, KS_SHOW_EVENT_FILTER); + nIds = kshark_import_event_filter(_stream, KS_SHOW_EVENT_FILTER, + "Events", jevents); if (nIds < 0) { QString err("WARNING: "); err += "Some of the imported events are not available on this system.\n"; @@ -276,13 +283,12 @@ void KsCaptureControl::_importSettings() emit print(err); } - for (int i = 0; i < nEvts; ++i) { - if (tracecmd_filter_id_find(eventHash, eventIds[i])) - v[i] = true; + for (int i = 0; i < _stream->n_events; ++i) { + if (kshark_hash_id_find(eventHash, event_ids[i])) + status[i] = true; } - _eventsWidget.set(v); - tracecmd_filter_id_hash_free(eventHash); + _eventsWidget.set(status); /** Get all available plugins. */ temp = kshark_string_config_alloc(); @@ -294,9 +300,9 @@ void KsCaptureControl::_importSettings() if (pluginIndex >= 0) { _pluginsComboBox.setCurrentText(KS_C_STR_CAST(temp->conf_doc)); } else { - QString err("WARNING: The traceer plugin \""); + QString err("WARNING: The tracer plugin \""); err += plugin; - err += "\" is not available on this machine\n"; + err += "\" is not available on this machine!\n"; emit print(err); } } @@ -329,18 +335,20 @@ void KsCaptureControl::_exportSettings() events = kshark_filter_config_new(KS_CONFIG_JSON); /* - * Use the tracecmd_filter_id to save all selected events in the + * Use the kshark_hash_id to save all selected events in the * configuration file. */ ids = _eventsWidget.getCheckedIds(); - tracecmd_filter_id *eventHash = tracecmd_filter_id_hash_alloc(); + kshark_hash_id *eventHash = kshark_get_filter(_stream, + KS_SHOW_EVENT_FILTER); + for (auto const &id: ids) - tracecmd_filter_id_add(eventHash, id); + kshark_hash_id_add(eventHash, id); - kshark_export_event_filter(_localTEP, eventHash, "Events", events); + kshark_export_event_filter(_stream, KS_SHOW_EVENT_FILTER, "Events", events); kshark_config_doc_add(conf, "Events", events); - tracecmd_filter_id_hash_free(eventHash); + kshark_hash_id_free(eventHash); /* Save the plugin. */ plugin = _pluginsComboBox.currentText(); diff --git a/src/KsCaptureDialog.hpp b/src/KsCaptureDialog.hpp index 3fd3d8d..0c85101 100644 --- a/src/KsCaptureDialog.hpp +++ b/src/KsCaptureDialog.hpp @@ -61,9 +61,9 @@ signals: void print(const QString &message); private: - tep_handle *_localTEP; + kshark_data_stream *_stream; - KsEventsCheckBoxWidget _eventsWidget; + KsWidgetsLib::KsEventsCheckBoxWidget _eventsWidget; QVBoxLayout _topLayout; From patchwork Thu Feb 11 10:31:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082751 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.7 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 43793C433E0 for ; Thu, 11 Feb 2021 10:39:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 06E9864E95 for ; Thu, 11 Feb 2021 10:39:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230034AbhBKKi7 (ORCPT ); Thu, 11 Feb 2021 05:38:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46440 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230228AbhBKKfv (ORCPT ); Thu, 11 Feb 2021 05:35:51 -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 3C99AC061223 for ; Thu, 11 Feb 2021 02:32:43 -0800 (PST) Received: by mail-ej1-x632.google.com with SMTP id f14so9257560ejc.8 for ; Thu, 11 Feb 2021 02:32:43 -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=7Ri1xXSmL1vhifAG+FG67oYdnXRt4tXmTmiE9SRHhws=; b=mEKSZJCS07nD3iFFo3VFAo3d8GLLovpY/MrC39I9ham3Bb0iebYyOvzkURG1Q3Zue0 IzhYe4WDisVj4ru/YpYH+JKVyDHuTsZlubOOMokuCGWEfEN/OEzVHWz6SyQF3HzbXrAS FYAPAjYj6UqwUAzTNvxjZxRUUF4XQsqpN9g7U7SwN6VxfamvRCvX0OQlwzarCfuhMbdq PBjfD7Ha7ezQCfjPgHMxtR1bLXzQuB+ftPhHrEVJDXNozNbp1Lje8GC1byUetygtwNsD riKxMfEsEIbRtZqrXuPSYz6m2I7nBgsF7hHQaWoPXfm0zcw99/Rp2ILXASbAx8khRdr8 klrw== 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=7Ri1xXSmL1vhifAG+FG67oYdnXRt4tXmTmiE9SRHhws=; b=FCK4FD9R1qgDdxF2bdyNM/lKTV9WF0K69ejy6Daanc+JqTFK7BdNtRA3i8niNPOjxP 3dGGQ0ELLMGZrXPDxewS+K0CvarxvGWeIfep++r+2uqlFYe1xi5VK4pr8xWJyItLPtw0 bmq/IBu40QeMbJQZ6FWO/mMJ1DkpVtG/oKh/KUGCuZ0Jd5lKH4ATGC8DHndoi6Cxo2Wk KAqZ/Bqpn3knaspVN2mYUCNoHBY0E/wZQ4oKVkAwh2zIPbLedAl+w0P9dseF68zPkTbP HAA+/HriYflOzzrktc0o0NiJKjGBN/UYy8yxOmD12aQ1yBYsQOVQfYTN7BFoN2XyygM3 /wNQ== X-Gm-Message-State: AOAM532h0VeTpd/6Dh7iXOFtdi6TUl8NcRdKt8Gy7cAyZ7DkZHvZfCpB 6VG03N4EaO5jWCN3S6y7ZTw= X-Google-Smtp-Source: ABdhPJzRAgZAwRsiCvAEl5KnCFlHK+wMf97xHI298dLYFnFJMA0epYn4YrpWSeWYacHGukleCVAgVg== X-Received: by 2002:a17:906:f259:: with SMTP id gy25mr2352805ejb.330.1613039561878; Thu, 11 Feb 2021 02:32:41 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:41 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 21/27] kernel-shark: Update KsSession Date: Thu, 11 Feb 2021 12:31:59 +0200 Message-Id: <20210211103205.418588-22-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The compilation KsSession.cpp is re-enabled and all functionalities are made compatible with the new version of the C API of libkshark (KernelShark 2.0). Signed-off-by: Yordan Karadzhov (VMware) --- src/CMakeLists.txt | 2 +- src/KsSession.cpp | 415 +++++++++++++++++++++++++++------------------ src/KsSession.hpp | 37 ++-- 3 files changed, 269 insertions(+), 185 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 28f44fe..5ea34ed 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -83,7 +83,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) add_library(kshark-gui SHARED ${ks-guiLib_hdr_moc} KsUtils.cpp KsModels.cpp -# KsSession.cpp + KsSession.cpp KsGLWidget.cpp KsSearchFSM.cpp KsDualMarker.cpp diff --git a/src/KsSession.cpp b/src/KsSession.cpp index a581bbf..786aa3e 100644 --- a/src/KsSession.cpp +++ b/src/KsSession.cpp @@ -11,14 +11,13 @@ // KernelShark #include "libkshark.h" +#include "libkshark-tepdata.h" #include "KsSession.hpp" -#include "KsMainWindow.hpp" /** Create a KsSession object. */ KsSession::KsSession() { - _config = kshark_config_new("kshark.config.session", - KS_CONFIG_JSON); + _config = kshark_session_config_new(KS_CONFIG_JSON); } /** Destroy a KsSession object. */ @@ -79,10 +78,11 @@ void KsSession::loadVisModel(KsGraphModel *model) } /** Save the trace data file. */ -void KsSession::saveDataFile(QString fileName) +void KsSession::saveDataFile(QString fileName, QString dataSetName) { kshark_config_doc *file = kshark_export_trace_file(fileName.toStdString().c_str(), + dataSetName.toStdString().c_str(), KS_CONFIG_JSON); kshark_config_doc_add(_config, "Data", file); @@ -92,54 +92,51 @@ void KsSession::saveDataFile(QString fileName) QString KsSession::getDataFile(kshark_context *kshark_ctx) { kshark_config_doc *file = kshark_config_alloc(KS_CONFIG_JSON); - const char *file_str; + int sd; if (!kshark_config_doc_get(_config, "Data", file)) return QString(); - file_str = kshark_import_trace_file(kshark_ctx, file); - if (file_str) - return QString(file_str); + sd = kshark_import_trace_file(kshark_ctx, file); + if (sd) + return QString(kshark_ctx->stream[sd]->file); return QString(); } /** - * @brief Save the configuration of the filters. + * @brief Save the configuration information for all load Data streams. * * @param kshark_ctx: Input location for context pointer. */ -void KsSession::saveFilters(kshark_context *kshark_ctx) +void KsSession::saveDataStreams(kshark_context *kshark_ctx) { - kshark_config_doc *filters = - kshark_export_all_filters(kshark_ctx, KS_CONFIG_JSON); - - kshark_config_doc_add(_config, "Filters", filters); + kshark_export_all_dstreams(kshark_ctx, &_config); } /** - * @brief Load the configuration of the filters and filter the data. + * @brief Load Data streams. * * @param kshark_ctx: Input location for context pointer. - * @param data: Input location for KsDataStore object; + * @param data: Input location for KsDataStore object; */ -void KsSession::loadFilters(kshark_context *kshark_ctx, KsDataStore *data) +void KsSession::loadDataStreams(kshark_context *kshark_ctx, + KsDataStore *data) { - kshark_config_doc *filters = kshark_config_alloc(KS_CONFIG_JSON); - - if (!kshark_config_doc_get(_config, "Filters", filters)) - return; + ssize_t dataSize; - kshark_import_all_filters(kshark_ctx, filters); + data->unregisterCPUCollections(); - if (kshark_ctx->advanced_event_filter->filters) - data->reload(); - else - kshark_filter_entries(kshark_ctx, data->rows(), data->size()); + dataSize = kshark_import_all_dstreams(kshark_ctx, + _config, + data->rows_r()); + if (dataSize < 0) { + data->clear(); + return; + } + data->setSize(dataSize); data->registerCPUCollections(); - - emit data->updateWidgets(data); } /** @@ -152,7 +149,7 @@ void KsSession::saveTable(const KsTraceViewer &view) { int64_t r = view.getTopRow(); topRow->conf_doc = json_object_new_int64(r); - kshark_config_doc_add(_config, "ViewTop",topRow); + kshark_config_doc_add(_config, "ViewTop", topRow); } /** @@ -196,39 +193,6 @@ void KsSession::saveMainWindowSize(const QMainWindow &window) kshark_config_doc_add(_config, "MainWindow", windowConf); } -/** - * @brief Load the KernelShark Main window size. - * - * @param window: Input location for the KsMainWindow widget. - */ -void KsSession::loadMainWindowSize(KsMainWindow *window) -{ - kshark_config_doc *windowConf = kshark_config_alloc(KS_CONFIG_JSON); - json_object *jwindow, *jwidth, *jheight; - int width, height; - - if (!kshark_config_doc_get(_config, "MainWindow", windowConf)) - return; - - if (_config->format == KS_CONFIG_JSON) { - jwindow = KS_JSON_CAST(windowConf->conf_doc); - if (json_object_get_type(jwindow) == json_type_string && - QString(json_object_get_string(jwindow)) == "FullScreen") { - window->setFullScreenMode(true); - return; - } - - jwidth = json_object_array_get_idx(jwindow, 0); - jheight = json_object_array_get_idx(jwindow, 1); - - width = json_object_get_int(jwidth); - height = json_object_get_int(jheight); - - window->setFullScreenMode(false); - window->resize(width, height); - } -} - /** * @brief Save the state of the Main window spliter. * @@ -269,6 +233,7 @@ void KsSession::loadSplitterSize(QSplitter *splitter) graphSize = json_object_get_int(jgraphsize); viewSize = json_object_get_int(jviewsize); + if (graphSize == 0 && viewSize == 0) { /* 0/0 spliter ratio is undefined. Make it 1/1. */ viewSize = graphSize = 1; @@ -282,7 +247,7 @@ void KsSession::loadSplitterSize(QSplitter *splitter) /** @brief Save the Color scheme used. */ void KsSession::saveColorScheme() { kshark_config_doc *colSch = kshark_config_alloc(KS_CONFIG_JSON); - double s = KsPlot::Color::getRainbowFrequency(); + double s = KsPlot::Color::rainbowFrequency(); colSch->conf_doc = json_object_new_double(s); kshark_config_doc_add(_config, "ColorScheme", colSch); @@ -307,97 +272,235 @@ float KsSession::getColorScheme() { /** * @brief Save the list of the graphs plotted. * - * @param glw: Input location for the KsGLWidget widget. + * @param kshark_ctx: Input location for context pointer. + * @param graphs: Input location for the KsTraceGraph widget.. */ -void KsSession::saveGraphs(const KsGLWidget &glw) +void KsSession::saveGraphs(kshark_context *kshark_ctx, + KsTraceGraph &graphs) { - _saveCPUPlots(glw._cpuList); - _saveTaskPlots(glw._taskList); + QVector streamIds = KsUtils::getStreamIdList(kshark_ctx); + for (auto const &sd: streamIds) { + _saveCPUPlots(sd, graphs.glPtr()); + _saveTaskPlots(sd, graphs.glPtr()); + } + + _saveComboPlots(graphs.glPtr()); } /** * @brief Load the list of the graphs and plot. * + * @param kshark_ctx: Input location for context pointer. * @param graphs: Input location for the KsTraceGraph widget. */ -void KsSession::loadGraphs(KsTraceGraph *graphs) +void KsSession::loadGraphs(kshark_context *kshark_ctx, + KsTraceGraph &graphs) { - graphs->cpuReDraw(_getCPUPlots()); - graphs->taskReDraw(_getTaskPlots()); + QVector combos, streamIds; + int nCombos; + + streamIds = KsUtils::getStreamIdList(kshark_ctx); + for (auto const &sd: streamIds) { + graphs.cpuReDraw(sd, _getCPUPlots(sd)); + graphs.taskReDraw(sd, _getTaskPlots(sd)); + } + + combos = _getComboPlots(&nCombos); + if (nCombos > 0) + graphs.comboReDraw(nCombos, combos); } -void KsSession::_saveCPUPlots(const QVector &cpus) +void KsSession::_savePlots(int sd, KsGLWidget *glw, bool cpu) { - kshark_config_doc *cpuPlts = kshark_config_alloc(KS_CONFIG_JSON); - json_object *jcpus = json_object_new_array(); + kshark_config_doc *streamsConf = kshark_config_alloc(KS_CONFIG_JSON); + json_object *jallStreams, *jstream, *jstreamId, *jplots; + QVector plotIds; + int nStreams; - for (int i = 0; i < cpus.count(); ++i) { - json_object *jcpu = json_object_new_int(cpus[i]); - json_object_array_put_idx(jcpus, i, jcpu); + if (cpu) { + plotIds = glw->_streamPlots[sd]._cpuList; + } else { + plotIds = glw->_streamPlots[sd]._taskList; } - cpuPlts->conf_doc = jcpus; - kshark_config_doc_add(_config, "CPUPlots", cpuPlts); + if (!kshark_config_doc_get(_config, "data streams", streamsConf) || + streamsConf->format != KS_CONFIG_JSON) + return; + + jallStreams = KS_JSON_CAST(streamsConf->conf_doc); + if (json_object_get_type(jallStreams) != json_type_array) + return; + + nStreams = json_object_array_length(jallStreams); + for (int i = 0; i < nStreams; ++i) { + jstream = json_object_array_get_idx(jallStreams, i); + if (json_object_object_get_ex(jstream, "stream id", &jstreamId) && + json_object_get_int(jstreamId) == sd) + break; + + jstream = nullptr; + } + + free(streamsConf); + if (!jstream) + return; + + jplots = json_object_new_array(); + for (int i = 0; i < plotIds.count(); ++i) { + json_object *jcpu = json_object_new_int(plotIds[i]); + json_object_array_put_idx(jplots, i, jcpu); + } + + if (cpu) + json_object_object_add(jstream, "CPUPlots", jplots); + else + json_object_object_add(jstream, "TaskPlots", jplots); } -QVector KsSession::_getCPUPlots() +void KsSession::_saveCPUPlots(int sd, KsGLWidget *glw) { - kshark_config_doc *cpuPlts = kshark_config_alloc(KS_CONFIG_JSON); - json_object *jcpus; - QVector cpus; - size_t length; + _savePlots(sd, glw, true); +} - if (!kshark_config_doc_get(_config, "CPUPlots", cpuPlts)) - return cpus; +void KsSession::_saveTaskPlots(int sd, KsGLWidget *glw) +{ + _savePlots(sd, glw, false); +} - if (_config->format == KS_CONFIG_JSON) { - jcpus = KS_JSON_CAST(cpuPlts->conf_doc); - length = json_object_array_length(jcpus); - for (size_t i = 0; i < length; ++i) { - int cpu = json_object_get_int(json_object_array_get_idx(jcpus, - i)); - cpus.append(cpu); +void KsSession::_saveComboPlots(KsGLWidget *glw) +{ + kshark_config_doc *combos = kshark_config_alloc(KS_CONFIG_JSON); + json_object *jcombos, *jplots, *jplt; + int var; + + jcombos = json_object_new_array(); + for (auto const &c: glw->_comboPlots) { + jplots = json_object_new_array(); + for (auto const &p: c) { + jplt = json_object_new_array(); + var = p._streamId; + json_object_array_put_idx(jplt, 0, + json_object_new_int(var)); + + var = p._type; + json_object_array_put_idx(jplt, 1, + json_object_new_int(var)); + + var = p._id; + json_object_array_put_idx(jplt, 2, + json_object_new_int(var)); + + json_object_array_add(jplots, jplt); } + + json_object_array_add(jcombos, jplots); } - return cpus; + combos->conf_doc = jcombos; + kshark_config_doc_add(_config, "ComboPlots", combos); } -void KsSession::_saveTaskPlots(const QVector &tasks) +QVector KsSession::_getPlots(int sd, bool cpu) { - kshark_config_doc *taskPlts = kshark_config_alloc(KS_CONFIG_JSON); - json_object *jtasks = json_object_new_array(); + kshark_config_doc *streamsConf = kshark_config_alloc(KS_CONFIG_JSON); + json_object *jallStreams, *jstream, *jstreamId, *jplots; + int nStreams, nPlots, id; + const char *plotKey; + QVector plots; + + if (!kshark_config_doc_get(_config, "data streams", streamsConf) || + streamsConf->format != KS_CONFIG_JSON) + return plots; + + jallStreams = KS_JSON_CAST(streamsConf->conf_doc); + if (json_object_get_type(jallStreams) != json_type_array) + return plots; + + nStreams = json_object_array_length(jallStreams); + for (int i = 0; i < nStreams; ++i) { + jstream = json_object_array_get_idx(jallStreams, i); + if (json_object_object_get_ex(jstream, "stream id", &jstreamId) && + json_object_get_int(jstreamId) == sd) + break; + + jstream = nullptr; + } + + if (!jstream) + return plots; + + if (cpu) + plotKey = "CPUPlots"; + else + plotKey = "TaskPlots"; - for (int i = 0; i < tasks.count(); ++i) { - json_object *jtask = json_object_new_int(tasks[i]); - json_object_array_put_idx(jtasks, i, jtask); + if (!json_object_object_get_ex(jstream, plotKey, &jplots) || + json_object_get_type(jplots) != json_type_array) + return plots; + + nPlots = json_object_array_length(jplots); + for (int i = 0; i < nPlots; ++i) { + id = json_object_get_int(json_object_array_get_idx(jplots, i)); + plots.append(id); } - taskPlts->conf_doc = jtasks; - kshark_config_doc_add(_config, "TaskPlots", taskPlts); + return plots; +} + +QVector KsSession::_getCPUPlots(int sd) +{ + return _getPlots(sd, true); +} + +QVector KsSession::_getTaskPlots(int sd) +{ + return _getPlots(sd, false); } -QVector KsSession::_getTaskPlots() +QVector KsSession::_getComboPlots(int *n) { - kshark_config_doc *taskPlts = kshark_config_alloc(KS_CONFIG_JSON); - json_object *jtasks; - QVector tasks; - size_t length; + kshark_config_doc *combos = kshark_config_alloc(KS_CONFIG_JSON); + int nCombos, nPlots, sd, type, id; + json_object *jcombos, *jplots, *jplt, *jvar; + QVector vec; - if (!kshark_config_doc_get(_config, "TaskPlots", taskPlts)) - return tasks; + *n = 0; + if (!kshark_config_doc_get(_config, "ComboPlots", combos)) + return {}; if (_config->format == KS_CONFIG_JSON) { - jtasks = KS_JSON_CAST(taskPlts->conf_doc); - length = json_object_array_length(jtasks); - for (size_t i = 0; i < length; ++i) { - int pid = json_object_get_int(json_object_array_get_idx(jtasks, - i)); - tasks.append(pid); + jcombos = KS_JSON_CAST(combos->conf_doc); + if (json_object_get_type(jcombos) != json_type_array) + return {}; + + *n = nCombos = json_object_array_length(jcombos); + for (int i = 0; i < nCombos; ++i) { + jplots = json_object_array_get_idx(jcombos, i); + if (json_object_get_type(jplots) != json_type_array) + return {}; + + nPlots = json_object_array_length(jplots); + vec.append(nPlots); + for (int j = 0; j < nPlots; ++j) { + jplt = json_object_array_get_idx(jplots, j); + if (json_object_get_type(jplt) != json_type_array) + return {}; + + jvar = json_object_array_get_idx(jplt, 0); + sd = json_object_get_int(jvar); + + jvar = json_object_array_get_idx(jplt, 1); + type = json_object_get_int(jvar); + + jvar = json_object_array_get_idx(jplt, 2); + id = json_object_get_int(jvar); + + vec.append({sd, type, id}); + } } } - return tasks; + return vec; } /** @@ -407,7 +510,7 @@ QVector KsSession::_getTaskPlots() */ void KsSession::saveDualMarker(KsDualMarkerSM *dm) { - struct kshark_config_doc *markers = + kshark_config_doc *markers = kshark_config_new("kshark.config.markers", KS_CONFIG_JSON); json_object *jd_mark = KS_JSON_CAST(markers->conf_doc); @@ -450,7 +553,7 @@ void KsSession::saveDualMarker(KsDualMarkerSM *dm) */ void KsSession::loadDualMarker(KsDualMarkerSM *dm, KsTraceGraph *graphs) { - size_t pos; + uint64_t pos; dm->reset(); dm->setState(DualMarkerState::A); @@ -476,7 +579,7 @@ void KsSession::loadDualMarker(KsDualMarkerSM *dm, KsTraceGraph *graphs) json_object *KsSession::_getMarkerJson() { - struct kshark_config_doc *markers = + kshark_config_doc *markers = kshark_config_alloc(KS_CONFIG_JSON); if (!kshark_config_doc_get(_config, "Markers", markers) || @@ -529,33 +632,23 @@ DualMarkerState KsSession::_getMarkerState() * * @param pm: Input location for the KsPluginManager object. */ -void KsSession::savePlugins(const KsPluginManager &pm) +void KsSession::saveUserPlugins(const KsPluginManager &pm) { - struct kshark_config_doc *plugins = + kshark_config_doc *plugins = kshark_config_new("kshark.config.plugins", KS_CONFIG_JSON); json_object *jplugins = KS_JSON_CAST(plugins->conf_doc); - const QVector ®isteredPlugins = pm._registeredKsPlugins; - const QStringList &pluginList = pm._ksPluginList; - int nPlugins = pluginList.length(); - json_object *jlist, *jpl; - QByteArray array; - char* buffer; - bool active; - - jlist = json_object_new_array(); - for (int i = 0; i < nPlugins; ++i) { - array = pluginList[i].toLocal8Bit(); - buffer = array.data(); - jpl = json_object_new_array(); - json_object_array_put_idx(jpl, 0, json_object_new_string(buffer)); - - active = registeredPlugins[i]; - json_object_array_put_idx(jpl, 1, json_object_new_boolean(active)); - json_object_array_put_idx(jlist, i, jpl); + json_object *jplg, *jlist = json_object_new_array(); + + for (auto const p: pm.getUserPlugins()) { + kshark_config_doc *lib = + kshark_export_plugin_file(p, KS_CONFIG_JSON); + jplg = KS_JSON_CAST(lib->conf_doc); + json_object_array_add(jlist, jplg); + free(lib); } - json_object_object_add(jplugins, "Plugin List", jlist); - kshark_config_doc_add(_config, "Plugins", plugins); + json_object_object_add(jplugins, "obj. files", jlist); + kshark_config_doc_add(_config, "User Plugins", plugins); } /** @@ -564,37 +657,21 @@ void KsSession::savePlugins(const KsPluginManager &pm) * @param kshark_ctx: Input location for context pointer. * @param pm: Input location for the KsPluginManager object. */ -void KsSession::loadPlugins(kshark_context *kshark_ctx, KsPluginManager *pm) +void KsSession::loadUserPlugins(kshark_context *kshark_ctx, KsPluginManager *pm) { - kshark_config_doc *plugins = kshark_config_alloc(KS_CONFIG_JSON); - json_object *jplugins, *jlist, *jpl; - const char *pluginName; - QVector pluginIds; - int length, index; - bool loaded; - - if (!kshark_config_doc_get(_config, "Plugins", plugins) || - !kshark_type_check(plugins, "kshark.config.plugins")) + kshark_config_doc *plugins = + kshark_config_alloc(KS_CONFIG_JSON); + kshark_plugin_list *list, **last; + + if (!kshark_config_doc_get(_config, "User Plugins", plugins)) return; - if (plugins->format == KS_CONFIG_JSON) { - jplugins = KS_JSON_CAST(plugins->conf_doc); - json_object_object_get_ex(jplugins, "Plugin List", &jlist); - if (!jlist || - json_object_get_type(jlist) != json_type_array || - !json_object_array_length(jlist)) - return; - - length = json_object_array_length(jlist); - for (int i = 0; i < length; ++i) { - jpl = json_object_array_get_idx(jlist, i); - pluginName = json_object_get_string(json_object_array_get_idx(jpl, 0)); - index = pm->_ksPluginList.indexOf(pluginName); - loaded = json_object_get_boolean(json_object_array_get_idx(jpl, 1)); - if (index >= 0 && loaded) - pluginIds.append(index); - } - } + /* Get the list of already loaded plugins. */ + list = kshark_ctx->plugins; + + kshark_import_all_plugins(kshark_ctx, plugins); - pm->updatePlugins(pluginIds); + /* Loop until the beginning of the old list. */ + for (last = &kshark_ctx->plugins; *last != list; last = &(*last)->next) + pm->addUserPluginToList(*last); } diff --git a/src/KsSession.hpp b/src/KsSession.hpp index b07c810..e1b7fd4 100644 --- a/src/KsSession.hpp +++ b/src/KsSession.hpp @@ -20,8 +20,6 @@ #include "KsTraceGraph.hpp" #include "KsTraceViewer.hpp" -class KsMainWindow; - /** * The KsSession class provides instruments for importing/exporting the state * of the different components of the GUI from/to Json documents. These @@ -41,7 +39,7 @@ public: void exportToFile(QString jfileName); - void saveDataFile(QString fileName); + void saveDataFile(QString fileName, QString dataSetName); QString getDataFile(kshark_context *kshark_ctx); @@ -49,18 +47,19 @@ public: void loadVisModel(KsGraphModel *model); - void saveGraphs(const KsGLWidget &glw); + void saveGraphs(kshark_context *kshark_ctx, + KsTraceGraph &graphs); - void loadGraphs(KsTraceGraph *graphs); + void loadGraphs(kshark_context *kshark_ctx, + KsTraceGraph &graphs); - void saveFilters(kshark_context *kshark_ctx); + void saveDataStreams(kshark_context *kshark_ctx); - void loadFilters(kshark_context *kshark_ctx, KsDataStore *data); + void loadDataStreams(kshark_context *kshark_ctx, + KsDataStore *data); void saveMainWindowSize(const QMainWindow &window); - void loadMainWindowSize(KsMainWindow *window); - void saveSplitterSize(const QSplitter &splitter); void loadSplitterSize(QSplitter *splitter); @@ -69,9 +68,9 @@ public: void loadDualMarker(KsDualMarkerSM *dmm, KsTraceGraph *graphs); - void savePlugins(const KsPluginManager &pm); + void saveUserPlugins(const KsPluginManager &pm); - void loadPlugins(kshark_context *kshark_ctx, KsPluginManager *pm); + void loadUserPlugins(kshark_context *kshark_ctx, KsPluginManager *pm); void saveTable(const KsTraceViewer &view); @@ -86,13 +85,21 @@ private: json_object *_getMarkerJson(); - void _saveCPUPlots(const QVector &cpus); + void _savePlots(int sd, KsGLWidget *glw, bool cpu); + + QVector _getPlots(int sd, bool cpu); + + void _saveCPUPlots(int sd, KsGLWidget *glw); + + QVector _getCPUPlots(int sd); + + void _saveTaskPlots(int sd, KsGLWidget *glw); - QVector _getCPUPlots(); + QVector _getTaskPlots(int sd); - void _saveTaskPlots(const QVector &tasks); + void _saveComboPlots(KsGLWidget *glw); - QVector _getTaskPlots(); + QVector _getComboPlots(int *nCombos); bool _getMarker(const char* name, size_t *pos); From patchwork Thu Feb 11 10:32:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082755 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.7 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 80D68C433E0 for ; Thu, 11 Feb 2021 10:39:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3BE0364E95 for ; Thu, 11 Feb 2021 10:39:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230228AbhBKKjL (ORCPT ); Thu, 11 Feb 2021 05:39:11 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46442 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230232AbhBKKfv (ORCPT ); Thu, 11 Feb 2021 05:35:51 -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 1BD57C061224 for ; Thu, 11 Feb 2021 02:32:44 -0800 (PST) Received: by mail-ej1-x635.google.com with SMTP id f14so9257634ejc.8 for ; Thu, 11 Feb 2021 02:32:44 -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=UjZajoxQn2imqdEFUY/RNy6CMLza2kPjVs4uI9lZQCI=; b=TWOnNW3N9oAmFpmL36B49jskFI+X0mLRp9nmsSf6uwKxMcA1Oa/sp4Pc2+hywupI9P 3esDBabqWsgfYwoClIS/3J7hnlr1VPXMn9oE4YpfrP8yYoiRE3UepIJCg5WXIQiIqRxD a+xAvSfNGSSRwLuBUf8OXba48P6XXegVxVaLuNg4tm4AH0Lu+F3IhBf2u2SKS1YKy2V/ kFAyEv/ypCAinvOe7VHIPdJpCG5kuLLgjDDQRUKEAiFQENrDse5v2t66jzmqz5gB0kFT xA7+nrP3sB9JM9HLjj/oPTbssNWU0yuNtCXZHDGZeiZZJ1OoT9UTj9m0G8ldGmdk/VDX J90w== 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=UjZajoxQn2imqdEFUY/RNy6CMLza2kPjVs4uI9lZQCI=; b=gkmkfG89w6ddtT9HxvkQrdjx03+Qv84RchubMNz7RiL6Du/TQnepm6FaOGoNLMDPEY 9PGg65BEk0T2g8ees+5Tn4GHJir+OSXtgCnIE6+uIwqUiaWhuZb2/qqZQGHzHliSP2/F rxRqck08NfygLvES6z8QeKIJvg4Ozv5zx4+HSUjn6D01uJAHGGRW7abaMLsm3YzFz8ve nsQJiFxeXqTUbB8qSPSGHNG6zUyO/RNAx37nE7N8DHPHZmL1B2+ktoLg3WvcOv2PcCWP n2uuLHXPaLN2i6ipBVUG9fgUyDAHgxoWn6bGuaUVqBd+8xhwUkYnoj7peoayKA1hQpas r9iA== X-Gm-Message-State: AOAM533qye8IQR8ArCPY4hqNB7+bEjyqkmQ0ZPKVV4EldNyeDFygXfGD XhX8F3DAuQrxuIay+tU5mlI= X-Google-Smtp-Source: ABdhPJyLC2OWUc4KnpJe1EznKCiwRMrZ4RruSp5Uiq4RjmezaxH9f0gsDckZLlM29ayelAXGC8Ac4g== X-Received: by 2002:a17:906:3603:: with SMTP id q3mr7440299ejb.201.1613039562816; Thu, 11 Feb 2021 02:32:42 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:42 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 22/27] kernel-shark: Update MissedEvents plugin Date: Thu, 11 Feb 2021 12:32:00 +0200 Message-Id: <20210211103205.418588-23-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-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 MissedEvents plugin that uses the new generic methods for visualization of trace event. Signed-off-by: Yordan Karadzhov (VMware) --- src/plugins/CMakeLists.txt | 6 +- src/plugins/MissedEvents.cpp | 105 ++++++++++++++-------------------- src/plugins/missed_events.c | 25 ++++---- src/plugins/missed_events.h | 4 +- tests/libkshark-gui-tests.cpp | 4 +- 5 files changed, 62 insertions(+), 82 deletions(-) diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 108bc5f..dc0c320 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -22,9 +22,9 @@ BUILD_PLUGIN(NAME sched_events SOURCE sched_events.c SchedEvents.cpp) list(APPEND PLUGIN_LIST "sched_events") -# BUILD_PLUGIN(NAME missed_events -# SOURCE missed_events.c MissedEvents.cpp) -# list(APPEND PLUGIN_LIST "missed_events") +BUILD_PLUGIN(NAME missed_events + SOURCE missed_events.c MissedEvents.cpp) +list(APPEND PLUGIN_LIST "missed_events") install(TARGETS ${PLUGIN_LIST} LIBRARY DESTINATION ${KS_PLUGIN_INSTALL_PREFIX} diff --git a/src/plugins/MissedEvents.cpp b/src/plugins/MissedEvents.cpp index 05dfcb5..cf0ed34 100644 --- a/src/plugins/MissedEvents.cpp +++ b/src/plugins/MissedEvents.cpp @@ -26,12 +26,8 @@ using namespace KsPlot; */ class MissedEventsMark : public PlotObject { public: - /** Create a default Missed events marker. */ - MissedEventsMark() : _base(0, 0), _height(0) - { - _color = {0, 0, 255}; - _size = 2; - } + /** No default constructor. */ + MissedEventsMark() = delete; /** * @brief Create and position a Missed events marker. @@ -40,17 +36,7 @@ public: * @param h: vertical size (height) of the marker. */ MissedEventsMark(const Point &p, int h) - : _base(p.x(), p.y()), _height(h) - { - _color = {0, 0, 255}; - _size = 2; - } - - /** Set the Base point of the marker. */ - void setBase(const Point &p) {_base.set(p.x(), p.y());} - - /** Set the vertical size (height) point of the marker. */ - void setHeight(int h) {_height = h;} + : _base(p.x(), p.y()), _height(h) {} private: /** Base point of the Mark's line. */ @@ -76,61 +62,38 @@ void MissedEventsMark::_draw(const Color &col, float size) const rec.draw(); } +static PlotObject *makeShape(std::vector graph, + std::vector bin, + std::vector, + Color col, float size) +{ + MissedEventsMark *mark = new MissedEventsMark(graph[0]->bin(bin[0])._base, + graph[0]->height()); + mark->_size = size; + mark->_color = col; + + return mark; +} + //! @cond Doxygen_Suppress #define PLUGIN_MAX_ENTRIES 10000 -#define KS_TASK_COLLECTION_MARGIN 25 - //! @endcond -static void pluginDraw(kshark_context *kshark_ctx, - KsCppArgV *argvCpp, - int val, int draw_action) -{ - int height = argvCpp->_graph->getHeight(); - const kshark_entry *entry(nullptr); - MissedEventsMark *mark; - ssize_t index; - - int nBins = argvCpp->_graph->size(); - for (int bin = 0; bin < nBins; ++bin) { - if (draw_action == KSHARK_PLUGIN_TASK_DRAW) - entry = ksmodel_get_task_missed_events(argvCpp->_histo, - bin, val, - nullptr, - &index); - if (draw_action == KSHARK_PLUGIN_CPU_DRAW) - entry = ksmodel_get_cpu_missed_events(argvCpp->_histo, - bin, val, - nullptr, - &index); - - if (entry) { - mark = new MissedEventsMark(argvCpp->_graph->getBin(bin)._base, - height); - - argvCpp->_shapes->push_front(mark); - } - } -} - /** * @brief Plugin's draw function. * * @param argv_c: A C pointer to be converted to KsCppArgV (C++ struct). + * @param sd: Data stream identifier. * @param val: Process or CPU Id value. * @param draw_action: Draw action identifier. */ void draw_missed_events(kshark_cpp_argv *argv_c, - int val, int draw_action) + int sd, int val, int draw_action) { - kshark_context *kshark_ctx(NULL); - - if (!kshark_instance(&kshark_ctx)) - return; - KsCppArgV *argvCpp = KS_ARGV_TO_CPP(argv_c); + IsApplicableFunc checkEntry; /* * Plotting the "Missed events" makes sense only in the case of a deep @@ -141,9 +104,29 @@ void draw_missed_events(kshark_cpp_argv *argv_c, if (argvCpp->_histo->tot_count > PLUGIN_MAX_ENTRIES) return; - try { - pluginDraw(kshark_ctx, argvCpp, val, draw_action); - } catch (const std::exception &exc) { - std::cerr << "Exception in MissedEvents\n" << exc.what(); - } + if (!(draw_action & KSHARK_CPU_DRAW) && + !(draw_action & KSHARK_TASK_DRAW)) + return; + + if (draw_action & KSHARK_CPU_DRAW) + checkEntry = [=] (kshark_data_container *, ssize_t bin) { + return !!ksmodel_get_cpu_missed_events(argvCpp->_histo, + bin, sd, val, + nullptr, + nullptr); + }; + + else if (draw_action & KSHARK_TASK_DRAW) + checkEntry = [=] (kshark_data_container *, ssize_t bin) { + return !!ksmodel_get_task_missed_events(argvCpp->_histo, + bin, sd, val, + nullptr, + nullptr); + }; + + eventPlot(argvCpp, + checkEntry, + makeShape, + {0, 0, 255}, // Blue + -1); // Default size } diff --git a/src/plugins/missed_events.c b/src/plugins/missed_events.c index cf652bf..8fe9780 100644 --- a/src/plugins/missed_events.c +++ b/src/plugins/missed_events.c @@ -10,32 +10,27 @@ * ring buffer. */ +// C +#include + // KernelShark +#include "libkshark.h" #include "plugins/missed_events.h" -static void nop_action(struct kshark_context *kshark_ctx, - struct tep_record *record, - struct kshark_entry *entry) -{} - /** Load this plugin. */ -int KSHARK_PLUGIN_INITIALIZER(struct kshark_context *kshark_ctx) +int KSHARK_PLOT_PLUGIN_INITIALIZER(struct kshark_data_stream *stream) { - kshark_register_event_handler(&kshark_ctx->event_handlers, - KS_EVENT_OVERFLOW, - nop_action, - draw_missed_events); + printf("--> missed_events init %i\n", stream->stream_id); + kshark_register_draw_handler(stream, draw_missed_events); return 1; } /** Unload this plugin. */ -int KSHARK_PLUGIN_DEINITIALIZER(struct kshark_context *kshark_ctx) +int KSHARK_PLOT_PLUGIN_DEINITIALIZER(struct kshark_data_stream *stream) { - kshark_unregister_event_handler(&kshark_ctx->event_handlers, - KS_EVENT_OVERFLOW, - nop_action, - draw_missed_events); + printf("<-- missed_events close %i\n", stream->stream_id); + kshark_unregister_draw_handler(stream, draw_missed_events); return 1; } diff --git a/src/plugins/missed_events.h b/src/plugins/missed_events.h index e05d79a..10bc549 100644 --- a/src/plugins/missed_events.h +++ b/src/plugins/missed_events.h @@ -14,14 +14,14 @@ #define _KS_PLUGIN_M_EVTS_H // KernelShark -#include "libkshark.h" +#include "libkshark-plugin.h" #ifdef __cplusplus extern "C" { #endif void draw_missed_events(struct kshark_cpp_argv *argv, - int pid, int draw_action); + int sd, int pid, int draw_action); #ifdef __cplusplus } diff --git a/tests/libkshark-gui-tests.cpp b/tests/libkshark-gui-tests.cpp index dedd69f..5a0ca01 100644 --- a/tests/libkshark-gui-tests.cpp +++ b/tests/libkshark-gui-tests.cpp @@ -146,7 +146,9 @@ BOOST_AUTO_TEST_CASE(KsUtils_KsDataStore) BOOST_AUTO_TEST_CASE(KsUtils_getPluginList) { - QStringList plugins{"sched_events"}; + QStringList plugins{"sched_events", + "missed_events" + }; BOOST_CHECK(getPluginList() == plugins); } From patchwork Thu Feb 11 10:32:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082757 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.7 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,URIBL_BLOCKED,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 C74B5C433DB for ; Thu, 11 Feb 2021 10:39:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7F1E664E9A for ; Thu, 11 Feb 2021 10:39:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230315AbhBKKjX (ORCPT ); Thu, 11 Feb 2021 05:39:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46448 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230239AbhBKKfv (ORCPT ); Thu, 11 Feb 2021 05:35:51 -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 ECE32C061225 for ; Thu, 11 Feb 2021 02:32:45 -0800 (PST) Received: by mail-ej1-x635.google.com with SMTP id l25so9256086eja.9 for ; Thu, 11 Feb 2021 02:32:45 -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=t7+/sAocjRfq5fLfRAhz9c05UYu8hEGN+A+DQH2akc4=; b=Hd6EMbF5j0TBo91yAo6nxqYcI3h1lOTg6T0vg07hN5FJYevESEcZt5F0Ymojdl/hnc dighdBWZ8NAZ3BS4oOtPO5dvfZWPBplRA1vmxswHUVmC/NxkqFLYvGholOdpNnYajRUs n7ZngGc0UzuiJI0aeBw2TPxRNJ7MTAdOl9KQu98W4GCA5YCfi0Pfbc50xtnz8cOFsquv MHDcJSvMvSvGgx98Ahe/8ribbJVtuWzulU7dNt0pANUBxvvVjAw0GlbjB4s7vuSzjqgY OGURLNeTF60MksKcsgXYhEzKMiXeCRRgloUObWrhkAHM/p4yGyjdPy0ptf69nvt3UEkF qxgg== 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=t7+/sAocjRfq5fLfRAhz9c05UYu8hEGN+A+DQH2akc4=; b=nWB1p15dh/Ymosi6d5QKMdBgdn0fhQULvEdqjkdXZEuhtaAx+tdCr72+xPDZxD4hxH ZUzXd1Pgjt6lB7NPtFpRqhqUm7kqUIegieUlyejtYImzA6LTk4YavTf0Vkdx41wv/Xef Kx5tuXEnN3QhL5sNUk5qyze7r6Pblc4wvCoBV5iqg6GAu2xO5vj0fF7QNMPcJ2vjpXpq xIhn0C/hxudvi0VG+bH8215hXhvAHMJ3kTIcA37KR7NVmFdDA/WA4ROY3cn13W38TqzN 4og+pM/THG3pG6fXlUYO8+N9sdCltJi506mPWKdnNHDmQ+IR7XLlbcRkVQ1s2cTROICq zhDw== X-Gm-Message-State: AOAM532nxzdATemhkp9I/1asV2ipU/i2d6Qe4ipuqdgaWEut4HupFFfy CH80UnmD9eSJln+mNac/cR4= X-Google-Smtp-Source: ABdhPJyalXoetguQ2jRX5QAUkNFZRMFPLD8e3KMxAPYv2gNCzV/UeSlTLpFJVRAx4D6V4Lx+8FxQEQ== X-Received: by 2002:a17:906:b50:: with SMTP id v16mr7537639ejg.298.1613039564222; Thu, 11 Feb 2021 02:32:44 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:43 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 23/27] kernel-shark: Update KsMainWindow and kernelshark.cpp Date: Thu, 11 Feb 2021 12:32:01 +0200 Message-Id: <20210211103205.418588-24-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The compilation of KsMainWindow.cpp and kernelshark.cpp is re-enabled and all functionalities are made compatible with the new version of the C API of libkshark (KernelShark 2.0). This patch completes the destructive part of the transformation and the GUI is finally fully functional again. Signed-off-by: Yordan Karadzhov (VMware) --- src/CMakeLists.txt | 21 +- src/KsMainWindow.cpp | 786 +++++++++++++++++++++++++++++-------------- src/KsMainWindow.hpp | 108 ++++-- src/KsPlugins.hpp | 5 + src/KsSession.cpp | 34 ++ src/KsSession.hpp | 4 + src/kernelshark.cpp | 49 +-- 7 files changed, 695 insertions(+), 312 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5ea34ed..4158901 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -74,7 +74,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) KsWidgetsLib.hpp KsTraceGraph.hpp KsTraceViewer.hpp -# KsMainWindow.hpp + KsMainWindow.hpp KsCaptureDialog.hpp KsQuickContextMenu.hpp KsAdvFilteringDialog.hpp) @@ -90,7 +90,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) KsWidgetsLib.cpp KsTraceGraph.cpp KsTraceViewer.cpp -# KsMainWindow.cpp + KsMainWindow.cpp KsCaptureDialog.cpp KsQuickContextMenu.cpp KsAdvFilteringDialog.cpp) @@ -102,20 +102,19 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) set_target_properties(kshark-gui PROPERTIES SUFFIX ".so.${KS_VERSION_STRING}") -# message(STATUS ${KS_APP_NAME}) -# add_executable(${KS_APP_NAME} kernelshark.cpp) -# target_link_libraries(${KS_APP_NAME} kshark-gui) + message(STATUS ${KS_APP_NAME}) + add_executable(${KS_APP_NAME} kernelshark.cpp) + target_link_libraries(${KS_APP_NAME} kshark-gui) message(STATUS "kshark-record") add_executable(kshark-record kshark-record.cpp) target_link_libraries(kshark-record kshark-gui) -# install(TARGETS ${KS_APP_NAME} kshark-record kshark-gui -# RUNTIME DESTINATION ${_INSTALL_PREFIX}/bin/ -# COMPONENT kernelshark -# LIBRARY DESTINATION ${_LIBDIR} -# COMPONENT kernelshark) - + install(TARGETS ${KS_APP_NAME} kshark-record kshark-gui + RUNTIME DESTINATION ${_INSTALL_PREFIX}/bin/ + COMPONENT kernelshark + LIBRARY DESTINATION ${_LIBDIR} + COMPONENT kernelshark) install(FILES "${KS_DIR}/${KS_APP_NAME}.desktop" DESTINATION ${_INSTALL_PREFIX}/share/applications/ diff --git a/src/KsMainWindow.cpp b/src/KsMainWindow.cpp index fc4e9a9..e830c5e 100644 --- a/src/KsMainWindow.cpp +++ b/src/KsMainWindow.cpp @@ -26,11 +26,13 @@ // KernelShark #include "libkshark.h" +#include "libkshark-tepdata.h" #include "KsCmakeDef.hpp" #include "KsMainWindow.hpp" -#include "KsCaptureDialog.hpp" #include "KsAdvFilteringDialog.hpp" +using namespace KsWidgetsLib; + /** Create KernelShark Main window. */ KsMainWindow::KsMainWindow(QWidget *parent) : QMainWindow(parent), @@ -42,25 +44,25 @@ KsMainWindow::KsMainWindow(QWidget *parent) _plugins(this), _capture(this), _captureLocalServer(this), - _openAction("Open", this), + _openAction("Open Trace File", this), + _appendAction("Append Trace File", this), _restoreSessionAction("Restore Last Session", this), _importSessionAction("Import Session", this), _exportSessionAction("Export Session", this), _quitAction("Quit", this), - _importFilterAction("Import Filter", this), - _exportFilterAction("Export Filter", this), _graphFilterSyncCBox(nullptr), _listFilterSyncCBox(nullptr), _showEventsAction("Show events", this), _showTasksAction("Show tasks", this), _showCPUsAction("Show CPUs", this), - _advanceFilterAction("Advance Filtering", this), + _advanceFilterAction("TEP Advance Filtering", this), _clearAllFilters("Clear all filters", this), _cpuSelectAction("CPUs", this), _taskSelectAction("Tasks", this), - _managePluginsAction("Manage plugins", this), + _managePluginsAction("Manage Plotting plugins", this), _addPluginsAction("Add plugins", this), _captureAction("Record", this), + _addOffcetAction("Add Time Offset", this), _colorAction(this), _colSlider(this), _colorPhaseSlider(Qt::Horizontal, this), @@ -69,12 +71,15 @@ KsMainWindow::KsMainWindow(QWidget *parent) _contentsAction("Contents", this), _bugReportAction("Report a bug", this), _deselectShortcut(this), - _settings(_getCacheDir() + "/setting.ini", QSettings::IniFormat) + _settings(_getCacheDir() + "/setting.ini", QSettings::IniFormat), + _workInProgress(this), + _updateSessionSize(true) { setWindowTitle("Kernel Shark"); _createActions(); _createMenus(); _initCapture(); + _plugins.registerPluginMenues(); if (geteuid() == 0) _rootWarning(); @@ -82,6 +87,24 @@ KsMainWindow::KsMainWindow(QWidget *parent) _splitter.addWidget(&_graph); _splitter.addWidget(&_view); setCentralWidget(&_splitter); + + /* + * Add Status bar. First of all remove the bottom margins of the table + * so that the Status bar can nicely stick to it. + */ + QMargins m = _view.layout()->contentsMargins(); + m.setBottom(0); + _view.layout()->setContentsMargins(m); + + /* Now create the Status bar and the "Work In Progress" Widget. */ + QStatusBar *sb = statusBar(); + sb->setFixedHeight(1.2 * FONT_HEIGHT); + _workInProgress.addToStatusBar(sb); + + _graph.setWipPtr(&_workInProgress); + _graph.glPtr()->setWipPtr(&_workInProgress); + _view.setWipPtr(&_workInProgress); + connect(&_splitter, &QSplitter::splitterMoved, this, &KsMainWindow::_splitterMoved); @@ -157,6 +180,7 @@ KsMainWindow::~KsMainWindow() _settings.setValue("pluginPath", _lastPluginFilePath); _data.clear(); + _plugins.deletePluginDialogs(); /* * Do not show error messages if the "capture" process is still @@ -168,14 +192,32 @@ KsMainWindow::~KsMainWindow() _capture.waitForFinished(); } + /** + * The list of shapes generated by the plugins may contain objects + * defined inside the plugins. Make sure to delete these objects now, + * because after closing the plugins, the destructors of the + * plugins-defined objects will no longer be available. + */ + _graph.glPtr()->freePluginShapes(); + if (kshark_instance(&kshark_ctx)) kshark_free(kshark_ctx); } /** Set the list ot CPU cores to be plotted. */ -void KsMainWindow::setCPUPlots(QVector cpus) +void KsMainWindow::setCPUPlots(int sd, QVector cpus) { - int nCPUs = tep_get_cpus(_data.tep()); + kshark_context *kshark_ctx(nullptr); + kshark_data_stream *stream; + + if (!kshark_instance(&kshark_ctx)) + return; + + stream = kshark_get_data_stream(kshark_ctx, sd); + if (!stream) + return; + + int nCPUs = stream->n_cpus; auto lamCPUCheck = [=] (int cpu) { if (cpu >= nCPUs) { qWarning() << "Warning: No CPU" << cpu << "found in the data."; @@ -188,13 +230,13 @@ void KsMainWindow::setCPUPlots(QVector cpus) cpus.erase(std::remove_if(cpus.begin(), cpus.end(), lamCPUCheck), cpus.end()); - _graph.cpuReDraw(cpus); + _graph.cpuReDraw(sd, cpus); } /** Set the list ot tasks (pids) to be plotted. */ -void KsMainWindow::setTaskPlots(QVector pids) +void KsMainWindow::setTaskPlots(int sd, QVector pids) { - QVector allPids = KsUtils::getPidList(); + QVector allPids = KsUtils::getPidList(sd); auto lamPidCheck = [=] (int pid) { int i = allPids.indexOf(pid); if (i < 0) { @@ -208,7 +250,7 @@ void KsMainWindow::setTaskPlots(QVector pids) pids.erase(std::remove_if(pids.begin(), pids.end(), lamPidCheck), pids.end()); - _graph.taskReDraw(pids); + _graph.taskReDraw(sd, pids); } /** @@ -219,8 +261,10 @@ void KsMainWindow::resizeEvent(QResizeEvent* event) { QMainWindow::resizeEvent(event); - _session.saveMainWindowSize(*this); - _session.saveSplitterSize(_splitter); + if (_updateSessionSize) { + _session.saveMainWindowSize(*this); + _session.saveSplitterSize(_splitter); + } } void KsMainWindow::_createActions() @@ -233,6 +277,13 @@ void KsMainWindow::_createActions() connect(&_openAction, &QAction::triggered, this, &KsMainWindow::_open); + _appendAction.setIcon(QIcon::fromTheme("document-open")); + _appendAction.setShortcut(tr("Ctrl+A")); + _appendAction.setStatusTip("Append an existing data file"); + + connect(&_appendAction, &QAction::triggered, + this, &KsMainWindow::_append); + _restoreSessionAction.setIcon(QIcon::fromTheme("document-open-recent")); connect(&_restoreSessionAction, &QAction::triggered, this, &KsMainWindow::_restoreSession); @@ -257,18 +308,6 @@ void KsMainWindow::_createActions() this, &KsMainWindow::close); /* Filter menu */ - _importFilterAction.setIcon(QIcon::fromTheme("document-send")); - _importFilterAction.setStatusTip("Load a filter"); - - connect(&_importFilterAction, &QAction::triggered, - this, &KsMainWindow::_importFilter); - - _exportFilterAction.setIcon(QIcon::fromTheme("document-revert")); - _exportFilterAction.setStatusTip("Export a filter"); - - connect(&_exportFilterAction, &QAction::triggered, - this, &KsMainWindow::_exportFilter); - connect(&_showEventsAction, &QAction::triggered, this, &KsMainWindow::_showEvents); @@ -312,14 +351,24 @@ void KsMainWindow::_createActions() connect(&_captureAction, &QAction::triggered, this, &KsMainWindow::_record); + connect(&_addOffcetAction, &QAction::triggered, + this, &KsMainWindow::_offset); + _colorPhaseSlider.setMinimum(20); _colorPhaseSlider.setMaximum(180); - _colorPhaseSlider.setValue(KsPlot::Color::getRainbowFrequency() * 100); + _colorPhaseSlider.setValue(KsPlot::Color::rainbowFrequency() * 100); _colorPhaseSlider.setFixedWidth(FONT_WIDTH * 15); connect(&_colorPhaseSlider, &QSlider::valueChanged, this, &KsMainWindow::_setColorPhase); + /* + * Updating the colors of the table can be slow. Do this only when + * the slider is released. + */ + connect(&_colorPhaseSlider, &QSlider::sliderReleased, + &_view, &KsTraceViewer::loadColors); + _colSlider.setLayout(new QHBoxLayout); _colSlider.layout()->addWidget(new QLabel("Color scheme", this)); _colSlider.layout()->addWidget(&_colorPhaseSlider); @@ -357,6 +406,7 @@ void KsMainWindow::_createMenus() /* File menu */ file = menuBar()->addMenu("File"); file->addAction(&_openAction); + file->addAction(&_appendAction); sessions = file->addMenu("Sessions"); sessions->setIcon(QIcon::fromTheme("document-properties")); @@ -365,15 +415,30 @@ void KsMainWindow::_createMenus() sessions->addAction(&_exportSessionAction); file->addAction(&_quitAction); + /* + * Enable the "Append Trace File" menu only in the case of multiple + * data streams. + */ + auto lamEnableAppendAction = [this] () { + kshark_context *kshark_ctx(nullptr); + + if (!kshark_instance(&kshark_ctx)) + return; + + if (kshark_ctx->n_streams > 0) + _appendAction.setEnabled(true); + else + _appendAction.setEnabled(false); + }; + + connect(file, &QMenu::aboutToShow, lamEnableAppendAction); + /* Filter menu */ filter = menuBar()->addMenu("Filter"); connect(filter, &QMenu::aboutToShow, this, &KsMainWindow::_updateFilterMenu); - filter->addAction(&_importFilterAction); - filter->addAction(&_exportFilterAction); - /* * Set the default filter mask. Filter will apply to both View and * Graph. @@ -403,6 +468,29 @@ void KsMainWindow::_createMenus() filter->addAction(&_advanceFilterAction); filter->addAction(&_clearAllFilters); + /* + * Enable the "TEP Advance Filtering" menu only in the case when TEP + * data is loaded. + */ + auto lamEnableAdvFilterAction = [this] () { + kshark_context *kshark_ctx(nullptr); + QVector streamIds; + + if (!kshark_instance(&kshark_ctx)) + return; + + _advanceFilterAction.setEnabled(false); + streamIds = KsUtils::getStreamIdList(kshark_ctx); + for (auto const &sd: streamIds) { + if (kshark_is_tep(kshark_ctx->stream[sd])) { + _advanceFilterAction.setEnabled(true); + break; + } + } + }; + + connect(filter, &QMenu::aboutToShow, lamEnableAdvFilterAction); + /* Plot menu */ plots = menuBar()->addMenu("Plots"); plots->addAction(&_cpuSelectAction); @@ -410,12 +498,31 @@ void KsMainWindow::_createMenus() /* Tools menu */ tools = menuBar()->addMenu("Tools"); - tools->addAction(&_managePluginsAction); - tools->addAction(&_addPluginsAction); - tools->addAction(&_captureAction); - tools->addSeparator(); tools->addAction(&_colorAction); tools->addAction(&_fullScreenModeAction); + tools->addSeparator(); + tools->addAction(&_captureAction); + tools->addAction(&_managePluginsAction); + tools->addAction(&_addPluginsAction); + tools->addAction(&_addOffcetAction); + + /* + * Enable the "Add Time Offset" menu only in the case of multiple + * data streams. + */ + auto lamEnableOffcetAction = [this] () { + kshark_context *kshark_ctx(nullptr); + + if (!kshark_instance(&kshark_ctx)) + return; + + if (kshark_ctx->n_streams > 1) + _addOffcetAction.setEnabled(true); + else + _addOffcetAction.setEnabled(false); + }; + + connect(tools, &QMenu::aboutToShow, lamEnableOffcetAction); /* Help menu */ help = menuBar()->addMenu("Help"); @@ -424,6 +531,53 @@ void KsMainWindow::_createMenus() help->addAction(&_bugReportAction); } +/** + * @brief Add a plugin configuration/control menu. + * + * @param place: String describing the place to add the menu. For example + * "Tools/Plot Latency". + * @param func: Function that will launch of plugin control menus. + */ +void KsMainWindow::addPluginMenu(QString place, pluginActionFunc func) +{ + QStringList dialogPath = place.split("/"); + QAction *pluginAction; + + auto lamAddMenu = [this, func] () { + func(this); + }; + + for (auto &m: menuBar()->findChildren()) { + if(dialogPath[0] == m->menuAction()->text()) { + pluginAction = new QAction(dialogPath[1], this); + m->addAction(pluginAction); + + connect(pluginAction, &QAction::triggered, + lamAddMenu); + } + } +} + +/** Select the kshark_entry having given index with a given maker. */ +void KsMainWindow::markEntry(ssize_t row, DualMarkerState st) +{ + if (row >= 0) { + _mState.setState(st); + _graph.markEntry(row); + _view.showRow(row, true); + } +} + +/** Select given kshark_entry with a given maker. */ +void KsMainWindow::markEntry(const kshark_entry *e, DualMarkerState st) +{ + ssize_t row = kshark_find_entry_by_time(e->ts, _data.rows(), + 0, _data.size() - 1); + + markEntry(row, st); +} + + void KsMainWindow::_open() { QString fileName; @@ -436,6 +590,17 @@ void KsMainWindow::_open() loadDataFile(fileName); } +void KsMainWindow::_append() +{ + QString fileName = KsUtils::getFile(this, + "Append File", + "trace-cmd files (*.dat);;Text files (*.txt);;All files (*)", + _lastDataFilePath); + + if (!fileName.isEmpty()) + appendDataFile(fileName); +} + QString KsMainWindow::_getCacheDir() { QString dir; @@ -524,13 +689,13 @@ void KsMainWindow::_updateSession() if (!kshark_instance(&kshark_ctx)) return; - _session.saveGraphs(*_graph.glPtr()); _session.saveVisModel(_graph.glPtr()->model()->histo()); - _session.saveFilters(kshark_ctx); + _session.saveDataStreams(kshark_ctx); + _session.saveGraphs(kshark_ctx, _graph); _session.saveDualMarker(&_mState); _session.saveTable(_view); _session.saveColorScheme(); - _session.savePlugins(_plugins); + _session.saveUserPlugins(_plugins); } void KsMainWindow::_exportSession() @@ -570,57 +735,6 @@ void KsMainWindow::_updateFilterMenu() _filterSyncCBoxUpdate(kshark_ctx); } -void KsMainWindow::_importFilter() -{ - kshark_context *kshark_ctx(nullptr); - kshark_config_doc *conf; - QString fileName; - - if (!kshark_instance(&kshark_ctx) || _data.size() < 1) - return; - - fileName = KsUtils::getFile(this, "Import Filter", - "Kernel Shark Config files (*.json);;", - _lastConfFilePath); - - if (fileName.isEmpty()) - return; - - conf = kshark_open_config_file(fileName.toStdString().c_str(), - "kshark.config.filter"); - if (!conf) - return; - - kshark_import_all_event_filters(kshark_ctx, conf); - kshark_free_config_doc(conf); - - kshark_filter_entries(kshark_ctx, _data.rows(), _data.size()); - _filterSyncCBoxUpdate(kshark_ctx); - emit _data.updateWidgets(&_data); -} - -void KsMainWindow::_exportFilter() -{ - kshark_context *kshark_ctx(nullptr); - kshark_config_doc *conf(nullptr); - QString fileName; - - if (!kshark_instance(&kshark_ctx)) - return; - - fileName = KsUtils::getSaveFile(this, "Export Filter", - "Kernel Shark Config files (*.json);;", - ".json", - _lastConfFilePath); - - if (fileName.isEmpty()) - return; - - kshark_export_all_event_filters(kshark_ctx, &conf); - kshark_save_config_file(fileName.toStdString().c_str(), conf); - kshark_free_config_doc(conf); -} - void KsMainWindow::_listFilterSync(int state) { KsUtils::listFilterSync(state); @@ -633,8 +747,8 @@ void KsMainWindow::_graphFilterSync(int state) _data.update(); } -void KsMainWindow::_presetCBWidget(tracecmd_filter_id *showFilter, - tracecmd_filter_id *hideFilter, +void KsMainWindow::_presetCBWidget(kshark_hash_id *showFilter, + kshark_hash_id *hideFilter, KsCheckBoxWidget *cbw) { if (!kshark_this_filter_is_set(showFilter) && @@ -646,7 +760,7 @@ void KsMainWindow::_presetCBWidget(tracecmd_filter_id *showFilter, cbw->setDefault(true); } else { QVector ids = cbw->getIds(); - QVector status; + QVector status; int n = ids.count(); bool show, hide; @@ -655,12 +769,12 @@ void KsMainWindow::_presetCBWidget(tracecmd_filter_id *showFilter, * The "show only" filter is set. The default status * of all CheckBoxes will be "unchecked". */ - status = QVector(n, false); + status = QVector(n, false); for (int i = 0; i < n; ++i) { - show = !!tracecmd_filter_id_find(showFilter, + show = !!kshark_hash_id_find(showFilter, ids[i]); - hide = !!tracecmd_filter_id_find(hideFilter, + hide = !!kshark_hash_id_find(hideFilter, ids[i]); if (show && !hide) { @@ -677,9 +791,9 @@ void KsMainWindow::_presetCBWidget(tracecmd_filter_id *showFilter, * Only the "do not show" filter is set. The default * status of all CheckBoxes will be "checked". */ - status = QVector(n, true); + status = QVector(n, true); for (int i = 0; i < n; ++i) { - hide = !!tracecmd_filter_id_find(hideFilter, + hide = !!kshark_hash_id_find(hideFilter, ids[i]); if (hide) @@ -691,12 +805,12 @@ void KsMainWindow::_presetCBWidget(tracecmd_filter_id *showFilter, } } -void KsMainWindow::_applyFilter(QVector all, QVector show, - std::function)> posFilter, - std::function)> negFilter) +void KsMainWindow::_applyFilter(int sd, QVector all, QVector show, + std::function)> posFilter, + std::function)> negFilter) { - if (show.count() < all.count() / 2) { - posFilter(show); + if (show.count() != 0 && show.count() < all.count() / 2) { + posFilter(sd, show); } else { /* * It is more efficiant to apply negative (do not show) filter. @@ -719,38 +833,46 @@ void KsMainWindow::_applyFilter(QVector all, QVector show, show.begin(), show.end(), std::inserter(diff, diff.begin())); - negFilter(diff); + negFilter(sd, diff); } } /* Quiet warnings over documenting simple structures */ //! @cond Doxygen_Suppress -#define LAMDA_FILTER(method) [=] (QVector vec) {method(vec);} +#define LAMBDA_FILTER(method) [=] (int sd, QVector vec) {method(sd, vec);} //! @endcond void KsMainWindow::_showEvents() { kshark_context *kshark_ctx(nullptr); - KsCheckBoxWidget *events_cb; + QVector cbws; + KsCheckBoxWidget *events_cbw; KsCheckBoxDialog *dialog; - QVector v; + kshark_data_stream *stream; + QVector streamIds; if (!kshark_instance(&kshark_ctx)) return; - events_cb = new KsEventsCheckBoxWidget(_data.tep(), this); - dialog = new KsCheckBoxDialog(events_cb, this); - _presetCBWidget(kshark_ctx->show_event_filter, - kshark_ctx->hide_event_filter, - events_cb); - - auto lamFilter = [=] (QVector show) { - QVector all = KsUtils::getEventIdList(); - _applyFilter(all, show, - LAMDA_FILTER(_data.applyPosEventFilter), - LAMDA_FILTER(_data.applyNegEventFilter)); + streamIds = KsUtils::getStreamIdList(kshark_ctx); + for (auto const &sd: streamIds) { + stream = kshark_ctx->stream[sd]; + events_cbw = new KsEventsCheckBoxWidget(stream, this); + cbws.append(events_cbw); + _presetCBWidget(stream->show_event_filter, + stream->hide_event_filter, + events_cbw); + } + + dialog = new KsCheckBoxDialog(cbws, this); + + auto lamFilter = [=] (int sd, QVector show) { + QVector all = KsUtils::getEventIdList(sd); + _applyFilter(sd, all, show, + LAMBDA_FILTER(_data.applyPosEventFilter), + LAMBDA_FILTER(_data.applyNegEventFilter)); }; connect(dialog, &KsCheckBoxDialog::apply, lamFilter); @@ -761,24 +883,32 @@ void KsMainWindow::_showEvents() void KsMainWindow::_showTasks() { kshark_context *kshark_ctx(nullptr); - KsCheckBoxWidget *tasks_cbd; + QVector cbws; + kshark_data_stream *stream; + KsCheckBoxWidget *tasks_cbw; KsCheckBoxDialog *dialog; - QVector v; + QVector streamIds; if (!kshark_instance(&kshark_ctx)) return; - tasks_cbd = new KsTasksCheckBoxWidget(_data.tep(), true, this); - dialog = new KsCheckBoxDialog(tasks_cbd, this); - _presetCBWidget(kshark_ctx->show_task_filter, - kshark_ctx->hide_task_filter, - tasks_cbd); - - auto lamFilter = [=] (QVector show) { - QVector all = KsUtils::getEventIdList(); - _applyFilter(all, show, - LAMDA_FILTER(_data.applyPosTaskFilter), - LAMDA_FILTER(_data.applyNegTaskFilter)); + streamIds = KsUtils::getStreamIdList(kshark_ctx); + for (auto const &sd: streamIds) { + stream = kshark_ctx->stream[sd]; + tasks_cbw = new KsTasksCheckBoxWidget(stream, true, this); + cbws.append(tasks_cbw); + _presetCBWidget(stream->show_task_filter, + stream->hide_task_filter, + tasks_cbw); + } + + dialog = new KsCheckBoxDialog(cbws, this); + + auto lamFilter = [=] (int sd, QVector show) { + QVector all = KsUtils::getPidList(sd); + _applyFilter(sd, all, show, + LAMBDA_FILTER(_data.applyPosTaskFilter), + LAMBDA_FILTER(_data.applyNegTaskFilter)); }; connect(dialog, &KsCheckBoxDialog::apply, lamFilter); @@ -789,24 +919,32 @@ void KsMainWindow::_showTasks() void KsMainWindow::_showCPUs() { kshark_context *kshark_ctx(nullptr); - KsCheckBoxWidget *cpu_cbd; + QVector cbws; + kshark_data_stream *stream; + KsCheckBoxWidget *cpus_cbw; KsCheckBoxDialog *dialog; - QVector v; + QVector streamIds; if (!kshark_instance(&kshark_ctx)) return; - cpu_cbd = new KsCPUCheckBoxWidget(_data.tep(), this); - dialog = new KsCheckBoxDialog(cpu_cbd, this); - _presetCBWidget(kshark_ctx->show_cpu_filter, - kshark_ctx->hide_cpu_filter, - cpu_cbd); - - auto lamFilter = [=] (QVector show) { - QVector all = KsUtils::getEventIdList(); - _applyFilter(all, show, - LAMDA_FILTER(_data.applyPosCPUFilter), - LAMDA_FILTER(_data.applyNegCPUFilter)); + streamIds = KsUtils::getStreamIdList(kshark_ctx); + for (auto const &sd: streamIds) { + stream = kshark_ctx->stream[sd]; + cpus_cbw = new KsCPUCheckBoxWidget(stream, this); + cbws.append(cpus_cbw); + _presetCBWidget(stream->show_task_filter, + stream->hide_task_filter, + cpus_cbw); + } + + dialog = new KsCheckBoxDialog(cbws, this); + + auto lamFilter = [=] (int sd, QVector show) { + QVector all = KsUtils::getCPUList(sd); + _applyFilter(sd, all, show, + LAMBDA_FILTER(_data.applyPosCPUFilter), + LAMBDA_FILTER(_data.applyNegCPUFilter)); }; connect(dialog, &KsCheckBoxDialog::apply, lamFilter); @@ -818,18 +956,6 @@ void KsMainWindow::_advancedFiltering() { KsAdvFilteringDialog *dialog; - if (!_data.tep()) { - QErrorMessage *em = new QErrorMessage(this); - QString text("Unable to open Advanced filtering dialog."); - - text += " Tracing data has to be loaded first."; - - em->showMessage(text, "advancedFiltering"); - qCritical() << "ERROR: " << text; - - return; - } - dialog = new KsAdvFilteringDialog(this); connect(dialog, &KsAdvFilteringDialog::dataReload, &_data, &KsDataStore::reload); @@ -844,23 +970,37 @@ void KsMainWindow::_clearFilters() void KsMainWindow::_cpuSelect() { - KsCheckBoxWidget *cpus_cbd = new KsCPUCheckBoxWidget(_data.tep(), this); - KsCheckBoxDialog *dialog = new KsCheckBoxDialog(cpus_cbd, this); + kshark_context *kshark_ctx(nullptr); + QVector cbws; + kshark_data_stream *stream; + KsCheckBoxWidget *cpus_cbd; + KsCheckBoxDialog *dialog; + QVector streamIds; + int nCPUs; + + if (!kshark_instance(&kshark_ctx)) + return; - if(_data.tep()) { - int nCPUs = tep_get_cpus(_data.tep()); - if (nCPUs == _graph.glPtr()->cpuGraphCount()) { + streamIds = KsUtils::getStreamIdList(kshark_ctx); + for (auto const &sd: streamIds) { + stream = kshark_ctx->stream[sd]; + cpus_cbd = new KsCPUCheckBoxWidget(stream, this); + cbws.append(cpus_cbd); + + nCPUs = stream->n_cpus; + if (nCPUs == _graph.glPtr()->cpuGraphCount(sd)) { cpus_cbd->setDefault(true); } else { - QVector v(nCPUs, false); - - for (auto const &cpu: _graph.glPtr()->_cpuList) + QVector v(nCPUs, false); + for (auto const &cpu: _graph.glPtr()->_streamPlots[sd]._cpuList) v[cpu] = true; cpus_cbd->set(v); } } + dialog = new KsCheckBoxDialog(cbws, this); + connect(dialog, &KsCheckBoxDialog::apply, &_graph, &KsTraceGraph::cpuReDraw); @@ -869,29 +1009,46 @@ void KsMainWindow::_cpuSelect() void KsMainWindow::_taskSelect() { - KsCheckBoxWidget *tasks_cbd = new KsTasksCheckBoxWidget(_data.tep(), - true, - this); - KsCheckBoxDialog *dialog = new KsCheckBoxDialog(tasks_cbd, this); - QVector pids = KsUtils::getPidList(); - int nPids = pids.count(); - - if (nPids == _graph.glPtr()->taskGraphCount()) { - tasks_cbd->setDefault(true); - } else { - QVector v(nPids, false); - for (int i = 0; i < nPids; ++i) { - for (auto const &pid: _graph.glPtr()->_taskList) { - if (pids[i] == pid) { - v[i] = true; - break; + kshark_context *kshark_ctx(nullptr); + QVector cbws; + QVector streamIds, pids; + kshark_data_stream *stream; + KsCheckBoxWidget *tasks_cbd; + KsCheckBoxDialog *dialog; + int nPids; + + if (!kshark_instance(&kshark_ctx)) + return; + + streamIds = KsUtils::getStreamIdList(kshark_ctx); + for (auto const &sd: streamIds) { + stream = kshark_ctx->stream[sd]; + tasks_cbd = new KsTasksCheckBoxWidget(stream, true, this); + cbws.append(tasks_cbd); + + pids = KsUtils::getPidList(sd); + nPids = pids.count(); + if (nPids == _graph.glPtr()->taskGraphCount(sd)) { + tasks_cbd->setDefault(true); + } else { + QVector v(nPids, false); + for (int i = 0; i < nPids; ++i) { + QVector plots = + _graph.glPtr()->_streamPlots[sd]._taskList; + for (auto const &pid: plots) { + if (pids[i] == pid) { + v[i] = true; + break; + } } } - } - tasks_cbd->set(v); + tasks_cbd->set(v); + } } + dialog = new KsCheckBoxDialog(cbws, this); + connect(dialog, &KsCheckBoxDialog::apply, &_graph, &KsTraceGraph::taskReDraw); @@ -900,37 +1057,106 @@ void KsMainWindow::_taskSelect() void KsMainWindow::_pluginSelect() { - KsCheckBoxWidget *plugin_cbd; + QVector streamIds, enabledPlugins, failedPlugins; + kshark_context *kshark_ctx(nullptr); + QVector cbws; + KsPluginCheckBoxWidget *plugin_cbw; KsCheckBoxDialog *dialog; - QVector registeredPlugins; - QStringList plugins; + QStringList pluginList; - plugins << _plugins._ksPluginList << _plugins._userPluginList; + if (!kshark_instance(&kshark_ctx)) + return; + + if (kshark_ctx->n_streams == 0) { + QString err("Data has to be loaded first."); + QMessageBox msgBox; + msgBox.critical(nullptr, "Error", err); + + return; + } + + streamIds = KsUtils::getStreamIdList(kshark_ctx); + for (auto const &sd: streamIds) { + pluginList = _plugins.getStreamPluginList(sd); + enabledPlugins = _plugins.getActivePlugins(sd); + failedPlugins = + _plugins.getPluginsByStatus(sd, KSHARK_PLUGIN_FAILED); - registeredPlugins << _plugins._registeredKsPlugins - << _plugins._registeredUserPlugins; + plugin_cbw = new KsPluginCheckBoxWidget(sd, pluginList, this); + plugin_cbw->set(enabledPlugins); + plugin_cbw->setActive(failedPlugins, false); - plugin_cbd = new KsPluginCheckBoxWidget(plugins, this); - plugin_cbd->set(registeredPlugins); + cbws.append(plugin_cbw); + } - dialog = new KsCheckBoxDialog(plugin_cbd, this); + dialog = new KsPluginsCheckBoxDialog(cbws, &_data, this); + dialog->applyStatus(); connect(dialog, &KsCheckBoxDialog::apply, - &_plugins, &KsPluginManager::updatePlugins); + this, &KsMainWindow::_pluginUpdate); dialog->show(); + + _graph.update(&_data); +} + +void KsMainWindow::_pluginUpdate(int sd, QVector pluginStates) +{ + kshark_context *kshark_ctx(nullptr); + QVector streamIds; + + if (!kshark_instance(&kshark_ctx)) + return; + + _plugins.updatePlugins(sd, pluginStates); + streamIds = KsUtils::getStreamIdList(kshark_ctx); + if (streamIds.size() && streamIds.last() == sd) { + /* This is the last stream. Reload the data. */ + if (_data.size()) + _data.reload(); + } } void KsMainWindow::_pluginAdd() { + kshark_context *kshark_ctx(nullptr); QStringList fileNames; + QVector streams; + + if (!kshark_instance(&kshark_ctx)) + return; + + fileNames = KsUtils::getFiles(this, + "Add KernelShark plugins", + "KernelShark Plugins (*.so);;", + _lastPluginFilePath); + + if (!fileNames.isEmpty()) { + if (kshark_ctx->n_streams > 1) { + KsDStreamCheckBoxWidget *stream_cbw; + QVector cbws; + KsCheckBoxDialog *dialog; + + stream_cbw = new KsDStreamCheckBoxWidget(); + cbws.append(stream_cbw); + dialog = new KsCheckBoxDialog(cbws, this); - fileNames = KsUtils::getFiles(this, "Add KernelShark plugins", - "KernelShark Plugins (*.so);;", - _lastPluginFilePath); + auto lamStreams = [&streams] (int, QVector s) { + streams = s; + }; - if (!fileNames.isEmpty()) - _plugins.addPlugins(fileNames); + connect(dialog, &KsCheckBoxDialog::apply, lamStreams); + dialog->exec(); + } + + _graph.startOfWork(KsDataWork::UpdatePlugins); + + _plugins.addPlugins(fileNames, streams); + if (_data.size()) + _data.reload(); + + _graph.endOfWork(KsDataWork::UpdatePlugins); + } } void KsMainWindow::_record() @@ -950,13 +1176,25 @@ void KsMainWindow::_record() message += " ./cmake_clean.sh
cmake ..
make
"; message += " sudo make install"; - _error(message, "recordCantStart", false, false); + _error(message, "recordCantStart", false); return; } _capture.start(); } +void KsMainWindow::_offset() +{ + KsTimeOffsetDialog *dialog = new KsTimeOffsetDialog(this); + + auto lamApplyOffset = [&] (int sd, double ms) { + _data.setClockOffset(sd, ms * 1000); + _graph.update(&_data); + }; + + connect(dialog, &KsTimeOffsetDialog::apply, lamApplyOffset); +} + void KsMainWindow::_setColorPhase(int f) { KsPlot::Color::setRainbowFrequency(f / 100.); @@ -1005,14 +1243,13 @@ void KsMainWindow::_bugReport() QDesktopServices::openUrl(bugs); } -/** Load trace data for file. */ -void KsMainWindow::loadDataFile(const QString& fileName) +void KsMainWindow::_load(const QString& fileName, bool append) { - char buff[FILENAME_MAX]; QString pbLabel("Loading "); bool loadDone = false; struct stat st; - int ret; + double shift; + int ret, sd; ret = stat(fileName.toStdString().c_str(), &st); if (ret != 0) { @@ -1020,16 +1257,21 @@ void KsMainWindow::loadDataFile(const QString& fileName) text.append(fileName); text.append("."); - _error(text, "loadDataErr1", true, true); + _error(text, "loadDataErr1", true); return; } qInfo() << "Loading " << fileName; - _mState.reset(); - _view.reset(); - _graph.reset(); + if (append) { + bool ok; + shift = KsTimeOffsetDialog::getValueNanoSec(fileName, &ok); + if (ok) + shift *= 1000.; + else + shift = 0.; + } if (fileName.size() < 40) { pbLabel += fileName; @@ -1039,14 +1281,34 @@ void KsMainWindow::loadDataFile(const QString& fileName) } setWindowTitle("Kernel Shark"); - KsProgressBar pb(pbLabel); + KsWidgetsLib::KsProgressBar pb(pbLabel); QApplication::processEvents(); - auto lamLoadJob = [&](KsDataStore *d) { - d->loadDataFile(fileName); + _view.reset(); + _graph.reset(); + + auto lamLoadJob = [&, this] () { + QVector v; + for (auto const p: _plugins.getUserPlugins()) { + if (p->process_interface) + v.append(p->process_interface); + } + + sd = _data.loadDataFile(fileName, v); loadDone = true; }; - std::thread tload(lamLoadJob, &_data); + + auto lamAppendJob = [&, this] () { + sd = _data.appendDataFile(fileName, shift); + loadDone = true; + }; + + std::thread job; + if (append) { + job = std::thread(lamAppendJob); + } else { + job = std::thread(lamLoadJob); + } for (int i = 0; i < 160; ++i) { /* @@ -1060,33 +1322,40 @@ void KsMainWindow::loadDataFile(const QString& fileName) usleep(150000); } - tload.join(); + job.join(); - if (_data.size() < 1) { - QString text("No data was loaded from file "); + if (sd < 0 || !_data.size()) { + QString text("File "); - text.append(fileName + "."); - _error(text, "loadDataErr2", true, true); - - return; + text.append(fileName); + text.append(" contains no data."); + _error(text, "loadDataErr2", true); } - pb.setValue(165); _view.loadData(&_data); + pb.setValue(175); - pb.setValue(180); _graph.loadData(&_data); pb.setValue(195); +} + +/** Load trace data for file. */ +void KsMainWindow::loadDataFile(const QString& fileName) +{ + _mState.reset(); + _load(fileName, false); setWindowTitle("Kernel Shark (" + fileName + ")"); +} - if (realpath(fileName.toStdString().c_str(), buff)) { - QString path(buff); - _session.saveDataFile(path); - } +/** Append trace data for file. */ +void KsMainWindow::appendDataFile(const QString& fileName) +{ + _load(fileName, true); } -void KsMainWindow::_error(const QString &mesg, const QString &errCode, - bool resize, bool unloadPlugins) +void KsMainWindow::_error(const QString &mesg, + const QString &errCode, + bool resize) { QErrorMessage *em = new QErrorMessage(this); QString text = mesg; @@ -1095,13 +1364,10 @@ void KsMainWindow::_error(const QString &mesg, const QString &errCode, if (resize) _resizeEmpty(); - if (unloadPlugins) - _plugins.unloadAll(); - text.replace("
", "\n", Qt::CaseInsensitive); html.replace("\n", "
", Qt::CaseInsensitive); - qCritical().noquote() << "ERROR: " << text; + qCritical().noquote() << "ERROR:" << text; em->showMessage(html, errCode); em->exec(); } @@ -1114,6 +1380,7 @@ void KsMainWindow::_error(const QString &mesg, const QString &errCode, void KsMainWindow::loadSession(const QString &fileName) { kshark_context *kshark_ctx(nullptr); + bool loadDone = false; struct stat st; int ret; @@ -1126,59 +1393,70 @@ void KsMainWindow::loadSession(const QString &fileName) text.append(fileName); text.append("\n"); - _error(text, "loadSessErr0", true, true); + _error(text, "loadSessErr0", true); return; } + KsWidgetsLib::KsProgressBar pb("Loading session settings ..."); + pb.setValue(10); + + _updateSessionSize = false; if (!_session.importFromFile(fileName)) { QString text("Unable to open session description file "); text.append(fileName); text.append(".\n"); - _error(text, "loadSessErr1", true, true); + _error(text, "loadSessErr1", true); return; } - _session.loadPlugins(kshark_ctx, &_plugins); + _view.reset(); + _graph.reset(); + _data.clear(); - QString dataFile(_session.getDataFile(kshark_ctx)); - if (dataFile.isEmpty()) { - QString text("Unable to open trace data file for session "); + _session.loadUserPlugins(kshark_ctx, &_plugins); + pb.setValue(20); - text.append(fileName); - text.append("\n"); - _error(text, "loadSessErr1", true, true); + auto lamLoadJob = [&] (KsDataStore *d) { + _session.loadDataStreams(kshark_ctx, &_data); + loadDone = true; + }; - return; - } + std::thread job = std::thread(lamLoadJob, &_data); - loadDataFile(dataFile); - if (!_data.tep()) { - _plugins.unloadAll(); - return; + for (int i = 0; i < 150; ++i) { + /* + * TODO: The way this progress bar gets updated here is a pure + * cheat. See if this can be implemented better. + */ + if (loadDone) + break; + + pb.setValue(i); + usleep(300000); } - KsProgressBar pb("Loading session settings ..."); - pb.setValue(10); + job.join(); - _session.loadGraphs(&_graph); - pb.setValue(20); + _view.loadData(&_data); + pb.setValue(155); - _session.loadFilters(kshark_ctx, &_data); + _graph.loadData(&_data); _filterSyncCBoxUpdate(kshark_ctx); - pb.setValue(130); + pb.setValue(175); _session.loadSplitterSize(&_splitter); _session.loadMainWindowSize(this); - this->show(); - pb.setValue(140); + _updateSessionSize = true; + pb.setValue(180); _session.loadDualMarker(&_mState, &_graph); _session.loadVisModel(_graph.glPtr()->model()); _mState.updateMarkers(_data, _graph.glPtr()); - pb.setValue(170); + _session.loadGraphs(kshark_ctx, _graph); + pb.setValue(190); _session.loadTable(&_view); _colorPhaseSlider.setValue(_session.getColorScheme() * 100); @@ -1268,7 +1546,7 @@ void KsMainWindow::_captureErrorMessage(QProcess *capture) message += capture->errorString(); message += "
Standard Error: "; message += capture->readAllStandardError(); - _error(message, "captureFinishedErr", false, false); + _error(message, "captureFinishedErr", false); } void KsMainWindow::_readSocket() @@ -1280,7 +1558,7 @@ void KsMainWindow::_readSocket() auto lamSocketError = [&](QString message) { message = "ERROR from Local Server: " + message; - _error(message, "readSocketErr", false, false); + _error(message, "readSocketErr", false); }; socket = _captureLocalServer.nextPendingConnection(); diff --git a/src/KsMainWindow.hpp b/src/KsMainWindow.hpp index 2fac107..952a2ad 100644 --- a/src/KsMainWindow.hpp +++ b/src/KsMainWindow.hpp @@ -20,6 +20,7 @@ #include "KsTraceViewer.hpp" #include "KsTraceGraph.hpp" #include "KsWidgetsLib.hpp" +#include "KsPlugins.hpp" #include "KsSession.hpp" #include "KsUtils.hpp" @@ -36,35 +37,61 @@ public: void loadDataFile(const QString &fileName); + void appendDataFile(const QString &fileName); + void loadSession(const QString &fileName); QString lastSessionFile(); /** - * @brief + * @brief Register a list of plugins. + * + * @param plugins: Provide here the names of the plugin (as in the + * CMake-generated header file) or the names of the + * plugin's library files (.so including path). + * The names must be comma separated. + */ + void registerPlugins(const QString &plugins) + { + _plugins.registerPlugins(plugins); + } + + /** + * @brief Unregister a list pf plugins. + * + * @param pluginNames: Provide here a comma separated list of plugin + * names (as in the CMake-generated header file). + */ + void unregisterPlugins(const QString &pluginNames) + { + _plugins.unregisterPlugins(pluginNames); + } + + /** + * @brief Register a given plugin to given Data streams. * - * @param plugin: can be the name of the plugin or the plugin's library - * file (including absolute or relative path). + * @param pluginName: The name of the plugin to register. + * @param streamIds: Vector of Data stream identifiers. */ - void registerPlugin(const QString &plugin) + void registerPluginToStream(const QString &pluginName, QVector streamIds) { - _plugins.registerPlugin(plugin); + _plugins.registerPluginToStream(pluginName, streamIds); } /** - * @brief + * @brief Unregister a given plugin from given Data streams. * - * @param plugin: can be the name of the plugin or the plugin's library - * file (including absolute path). + * @param pluginName: The name of the plugin to unregister. + * @param streamIds: Vector of Data stream identifiers. */ - void unregisterPlugin(const QString &plugin) + void unregisterPluginFromStream(const QString &pluginName, QVector streamIds) { - _plugins.unregisterPlugin(plugin); + _plugins.unregisterPluginFromStream(pluginName, streamIds); } - void setCPUPlots(QVector cpus); + void setCPUPlots(int sd, QVector cpus); - void setTaskPlots(QVector pids); + void setTaskPlots(int sd, QVector pids); void resizeEvent(QResizeEvent* event); @@ -74,6 +101,21 @@ public: _changeScreenMode(); } + void addPluginMenu(QString place, pluginActionFunc action); + + /** Get the KsTraceGraph object. */ + KsTraceGraph *graphPtr() {return &_graph;} + + /** Get the KsTraceViewer object. */ + KsTraceViewer *viewPtr() {return &_view;} + + /** Get the KsWorkInProgress object. */ + KsWidgetsLib::KsWorkInProgress *wipPtr() {return &_workInProgress;} + + void markEntry(ssize_t row, DualMarkerState st); + + void markEntry(const kshark_entry *e, DualMarkerState st); + private: QSplitter _splitter; @@ -104,6 +146,8 @@ private: // File menu. QAction _openAction; + QAction _appendAction; + QAction _restoreSessionAction; QAction _importSessionAction; @@ -113,10 +157,6 @@ private: QAction _quitAction; // Filter menu. - QAction _importFilterAction; - - QAction _exportFilterAction; - QCheckBox *_graphFilterSyncCBox; QCheckBox *_listFilterSyncCBox; @@ -143,6 +183,8 @@ private: QAction _captureAction; + QAction _addOffcetAction; + QWidgetAction _colorAction; QWidget _colSlider; @@ -166,29 +208,34 @@ private: QMetaObject::Connection _captureErrorConnection; + // Status bar. + KsWidgetsLib::KsWorkInProgress _workInProgress; + + bool _updateSessionSize; + + void _load(const QString& fileName, bool append); + void _open(); + void _append(); + void _restoreSession(); void _importSession(); void _exportSession(); - void _importFilter(); - - void _exportFilter(); - void _listFilterSync(int state); void _graphFilterSync(int state); - void _presetCBWidget(tracecmd_filter_id *showFilter, - tracecmd_filter_id *hideFilter, - KsCheckBoxWidget *cbw); + void _presetCBWidget(kshark_hash_id *showFilter, + kshark_hash_id *hideFilter, + KsWidgetsLib::KsCheckBoxWidget *cbw); - void _applyFilter(QVector all, QVector show, - std::function)> posFilter, - std::function)> negFilter); + void _applyFilter(int sd, QVector all, QVector show, + std::function)> posFilter, + std::function)> negFilter); void _showEvents(); @@ -206,10 +253,14 @@ private: void _pluginSelect(); + void _pluginUpdate(int sd, QVector pluginStates); + void _pluginAdd(); void _record(); + void _offset(); + void _setColorPhase(int); void _changeScreenMode(); @@ -240,8 +291,9 @@ private: inline void _resizeEmpty() {resize(SCREEN_WIDTH * .5, FONT_HEIGHT * 3);} - void _error(const QString &text, const QString &errCode, - bool resize, bool unloadPlugins); + void _error(const QString &text, + const QString &errCode, + bool resize); void _deselectActive(); diff --git a/src/KsPlugins.hpp b/src/KsPlugins.hpp index a19bb9d..d41d094 100644 --- a/src/KsPlugins.hpp +++ b/src/KsPlugins.hpp @@ -16,9 +16,14 @@ #include // KernelShark +#include "libkshark-plugin.h" #include "libkshark-model.h" #include "KsPlotTools.hpp" +class KsMainWindow; +/** Function type used for launching of plugin control menus. */ +typedef void (pluginActionFunc) (KsMainWindow *); + /** * Structure representing the vector of C++ arguments of the drawing function * of a plugin. diff --git a/src/KsSession.cpp b/src/KsSession.cpp index 786aa3e..8d489f7 100644 --- a/src/KsSession.cpp +++ b/src/KsSession.cpp @@ -13,6 +13,7 @@ #include "libkshark.h" #include "libkshark-tepdata.h" #include "KsSession.hpp" +#include "KsMainWindow.hpp" /** Create a KsSession object. */ KsSession::KsSession() @@ -193,6 +194,39 @@ void KsSession::saveMainWindowSize(const QMainWindow &window) kshark_config_doc_add(_config, "MainWindow", windowConf); } +/** + * @brief Load the KernelShark Main window size. + * + * @param window: Input location for the KsMainWindow widget. + */ +void KsSession::loadMainWindowSize(KsMainWindow *window) +{ + kshark_config_doc *windowConf = kshark_config_alloc(KS_CONFIG_JSON); + json_object *jwindow, *jwidth, *jheight; + int width, height; + + if (!kshark_config_doc_get(_config, "MainWindow", windowConf)) + return; + + if (_config->format == KS_CONFIG_JSON) { + jwindow = KS_JSON_CAST(windowConf->conf_doc); + if (json_object_get_type(jwindow) == json_type_string && + QString(json_object_get_string(jwindow)) == "FullScreen") { + window->setFullScreenMode(true); + return; + } + + jwidth = json_object_array_get_idx(jwindow, 0); + jheight = json_object_array_get_idx(jwindow, 1); + + width = json_object_get_int(jwidth); + height = json_object_get_int(jheight); + + window->setFullScreenMode(false); + window->resize(width, height); + } +} + /** * @brief Save the state of the Main window spliter. * diff --git a/src/KsSession.hpp b/src/KsSession.hpp index e1b7fd4..fd45270 100644 --- a/src/KsSession.hpp +++ b/src/KsSession.hpp @@ -20,6 +20,8 @@ #include "KsTraceGraph.hpp" #include "KsTraceViewer.hpp" +class KsMainWindow; + /** * The KsSession class provides instruments for importing/exporting the state * of the different components of the GUI from/to Json documents. These @@ -60,6 +62,8 @@ public: void saveMainWindowSize(const QMainWindow &window); + void loadMainWindowSize(KsMainWindow *window); + void saveSplitterSize(const QSplitter &splitter); void loadSplitterSize(QSplitter *splitter); diff --git a/src/kernelshark.cpp b/src/kernelshark.cpp index 0de80af..41ffbe7 100644 --- a/src/kernelshark.cpp +++ b/src/kernelshark.cpp @@ -17,14 +17,16 @@ #define default_input_file (char*)"trace.dat" -static char *input_file; +static char *prior_input_file; +QStringList appInputFiles; void usage(const char *prog) { printf("Usage: %s\n", prog); printf(" -h Display this help message\n"); printf(" -v Display version and exit\n"); - printf(" -i input_file, default is %s\n", default_input_file); + printf(" -i prior input file, default is %s\n", default_input_file); + printf(" -a input file to append to the prior\n"); printf(" -p register plugin, use plugin name, absolute or relative path\n"); printf(" -u unregister plugin, use plugin name or absolute path\n"); printf(" -s import a session\n"); @@ -45,16 +47,18 @@ static option longOptions[] = { int main(int argc, char **argv) { - QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - QApplication a(argc, argv); - QVector cpuPlots, taskPlots; bool fromSession = false; int optionIndex = 0; - KsMainWindow ks; int c; - while ((c = getopt_long(argc, argv, "hvi:p:u:s:l", + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication a(argc, argv); + + KsMainWindow ks; + ks.show(); + + while ((c = getopt_long(argc, argv, "hvi:a:p:u:s:l", longOptions, &optionIndex)) != -1) { switch(c) { @@ -75,15 +79,19 @@ int main(int argc, char **argv) return 0; case 'i': - input_file = optarg; + prior_input_file = optarg; + break; + + case 'a': + appInputFiles << QString(optarg).split(" ", QString::SkipEmptyParts); break; case 'p': - ks.registerPlugin(QString(optarg)); + ks.registerPlugins(QString(optarg)); break; case 'u': - ks.unregisterPlugin(QString(optarg)); + ks.unregisterPlugins(QString(optarg)); break; case 's': @@ -103,19 +111,22 @@ int main(int argc, char **argv) if (!fromSession) { if ((argc - optind) >= 1) { - if (input_file) + if (prior_input_file) usage(argv[0]); - input_file = argv[optind]; + prior_input_file = argv[optind]; } - if (!input_file) { + if (!prior_input_file) { struct stat st; if (stat(default_input_file, &st) == 0) - input_file = default_input_file; + prior_input_file = default_input_file; } - if (input_file) - ks.loadDataFile(QString(input_file)); + if (prior_input_file) + ks.loadDataFile(QString(prior_input_file)); + + for (auto const &f: appInputFiles) + ks.appendDataFile(f); } auto lamOrderIds = [] (QVector &ids) { @@ -126,10 +137,10 @@ int main(int argc, char **argv) }; if (cpuPlots.count() || taskPlots.count()) { - ks.setCPUPlots(lamOrderIds(cpuPlots)); - ks.setTaskPlots(lamOrderIds(taskPlots)); + ks.setCPUPlots(0, lamOrderIds(cpuPlots)); + ks.setTaskPlots(0, lamOrderIds(taskPlots)); } - ks.show(); + ks.raise(); return a.exec(); } From patchwork Thu Feb 11 10:32:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082759 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.7 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 5C07EC433E0 for ; Thu, 11 Feb 2021 10:39:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 286D164E9A for ; Thu, 11 Feb 2021 10:39:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229725AbhBKKjb (ORCPT ); Thu, 11 Feb 2021 05:39:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46464 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230244AbhBKKf4 (ORCPT ); Thu, 11 Feb 2021 05:35:56 -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 4963BC061226 for ; Thu, 11 Feb 2021 02:32:46 -0800 (PST) Received: by mail-ej1-x629.google.com with SMTP id w2so9208803ejk.13 for ; Thu, 11 Feb 2021 02:32:46 -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=kkLjfQ6M3bLvsQcENjzj/wcN9hwZ8/IhXzWlIK3/UrE=; b=vgUAhZdGEoGKxhwnQKNEkPCOhxapydlK7fZZMGtLJnu5fCRJ38O1dP4v5CDGmUkYUB 5JzV7C8EdKxmm7vzvgtLQO/V1giVETFlh0jxw6s7yWccb2mmI2SMK+LpRJ8RHtreta31 v6N3ZMTbRSlVI8BMWTIW7GR+xfj3Xls9F/1GJAQeIz8tx2++yJvGbRjPaLmI9ku9Kkq2 UwPe/6IT3lmLvQ++3ceMy81gD2MIXPeOrGt65xebxmo35bZGrrs795auDqrVPwjyQ5yl WAvsa353VvQ2q8uvXwDlHPOuh/RadmkyjddagT6PeZt66iIYxDiQKJGFqEK/ilKcE+Rt roJQ== 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=kkLjfQ6M3bLvsQcENjzj/wcN9hwZ8/IhXzWlIK3/UrE=; b=g9mlkITvdcJ6JHIxj+N9h6ge+r/cySOHCEBOw8qMuV898/5nZTItR89xISnpgU5Gt8 vTocP1dc/xkjpNa0Ag/ngNUEM+poVlA3DbTn3MuoiAvFOVW4x6kJkf2CcooEUNeEp0pI UBoiPORgGnjV2ZN/P5V6GFwb5qoE4Qzvljjm33Tx//far4xcpF0PzoD4zsn6g/A/M0/1 jK8Nl8CKTNlidNgGHISsdQ4+h/p2XE+8TECXvGHmV3DWtBabPABGIbGlbN7+eyhGg/E8 qI6VlFg0qEJfmhytj5CeIeGwbt/NLpaJAYANo0alvmEMAMEj7/OMBmIO1fczjiCiI6MH QSVg== X-Gm-Message-State: AOAM532XI+/XT0aQUHBl0nqt5aktHPpCWnqPknDlgm8WtDFwc5IfR0be S3Kh/foJ7VuUf+X3LgqklV2YtvmEuk0= X-Google-Smtp-Source: ABdhPJw2CnlEAPWcl3NKPsK+eYHadKwTaywOBGwychzBSR1gya64//3MXEe4PRbHoXG/Lhjl55C2tg== X-Received: by 2002:a17:906:1bf2:: with SMTP id t18mr8136677ejg.166.1613039565069; Thu, 11 Feb 2021 02:32:45 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:44 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 24/27] kernel-shark: Clickable sched_event plugin shapes Date: Thu, 11 Feb 2021 12:32:02 +0200 Message-Id: <20210211103205.418588-25-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Here we make the latency boxes plotted by the sched_event plugin clickable. When the box is clicked, the two events determining the latency (sched_waking and sched_switch) are selected with the markers. This is achieved by providing an implementation of the corresponding interface of virtual functions in the definition of the LatencyBox class. We also need to provide the plugin with a pointer to the KsMainWindow object (the GUI itself) such that the plugin can manipulate the markers. --- src/plugins/CMakeLists.txt | 30 +++++++++++++++++-- src/plugins/SchedEvents.cpp | 58 +++++++++++++++++++++++++++++++++++-- src/plugins/sched_events.c | 7 +++++ src/plugins/sched_events.h | 3 ++ 4 files changed, 93 insertions(+), 5 deletions(-) diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index dc0c320..5e28368 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -17,10 +17,34 @@ function(BUILD_PLUGIN) endfunction() +function(BUILD_GUI_PLUGIN) + set(options) + set(oneValueArgs NAME MOC) + set(multiValueArgs SOURCE) + cmake_parse_arguments(ADD_PLUGIN "${options}" + "${oneValueArgs}" + "${multiValueArgs}" + ${ARGN}) + + message(STATUS ${ADD_PLUGIN_NAME}) + + QT5_WRAP_CPP(plugin_moc ${ADD_PLUGIN_MOC}) + + add_library(${ADD_PLUGIN_NAME} SHARED ${plugin_moc} ${ADD_PLUGIN_SOURCE}) + set_target_properties(${ADD_PLUGIN_NAME} PROPERTIES PREFIX "plugin-") + target_link_libraries(${ADD_PLUGIN_NAME} kshark kshark-gui) + +endfunction() + set(PLUGIN_LIST "") -BUILD_PLUGIN(NAME sched_events - SOURCE sched_events.c SchedEvents.cpp) -list(APPEND PLUGIN_LIST "sched_events") + +if (Qt5Widgets_FOUND AND TT_FONT_FILE) + + BUILD_GUI_PLUGIN(NAME sched_events + SOURCE sched_events.c SchedEvents.cpp) + list(APPEND PLUGIN_LIST "sched_events") + +endif (Qt5Widgets_FOUND AND TT_FONT_FILE) BUILD_PLUGIN(NAME missed_events SOURCE missed_events.c MissedEvents.cpp) diff --git a/src/plugins/SchedEvents.cpp b/src/plugins/SchedEvents.cpp index c85a059..a81182e 100644 --- a/src/plugins/SchedEvents.cpp +++ b/src/plugins/SchedEvents.cpp @@ -20,15 +20,69 @@ #include "plugins/sched_events.h" #include "KsPlotTools.hpp" #include "KsPlugins.hpp" +#include "KsMainWindow.hpp" using namespace KsPlot; +static KsMainWindow *ks_ptr; + +/** + * @brief Provide the plugin with a pointer to the KsMainWindow object (the GUI + * itself) such that the plugin can manipulate the GUI. + */ +void *plugin_set_gui_ptr(void *gui_ptr) +{ + ks_ptr = static_cast(gui_ptr); + return nullptr; +} + +/** + * This class represents the graphical element visualizing the latency between + * sched_waking and sched_switch events. + */ +class LatencyBox : public Rectangle +{ + /** On double click do. */ + void _doubleClick() const override + { + ks_ptr->markEntry(_data[1]->entry, DualMarkerState::B); + ks_ptr->markEntry(_data[0]->entry, DualMarkerState::A); + } + +public: + /** The trace record data that corresponds to this LatencyBox. */ + std::vector _data; + + /** + * @brief Distance between the click and the shape. Used to decide if + * the double click action must be executed. + * + * @param x: X coordinate of the click. + * @param y: Y coordinate of the click. + * + * @returns If the click is inside the box, the distance is zero. + * Otherwise infinity. + */ + double distance(int x, int y) const override + { + if (x < pointX(0) || x > pointX(2)) + return std::numeric_limits::max(); + + if (y < pointY(0) || y > pointY(1)) + return std::numeric_limits::max(); + + return 0; + } +}; + static PlotObject *makeShape(std::vector graph, std::vector bins, - std::vector, + std::vector data, Color col, float size) { - Rectangle *rec = new KsPlot::Rectangle; + LatencyBox *rec = new LatencyBox; + rec->_data = data; + Point p0 = graph[0]->bin(bins[0])._base; Point p1 = graph[0]->bin(bins[1])._base; int height = graph[0]->height() * .3; diff --git a/src/plugins/sched_events.c b/src/plugins/sched_events.c index 1596880..ac4a7bf 100644 --- a/src/plugins/sched_events.c +++ b/src/plugins/sched_events.c @@ -216,3 +216,10 @@ int KSHARK_PLOT_PLUGIN_DEINITIALIZER(struct kshark_data_stream *stream) return 1; } + +/** Initialize the control interface of the plugin. */ +void *KSHARK_MENU_PLUGIN_INITIALIZER(void *gui_ptr) +{ + printf("--> sched init menu\n"); + return plugin_set_gui_ptr(gui_ptr); +} diff --git a/src/plugins/sched_events.h b/src/plugins/sched_events.h index 4c57606..78cfda0 100644 --- a/src/plugins/sched_events.h +++ b/src/plugins/sched_events.h @@ -53,6 +53,7 @@ struct plugin_sched_context { struct kshark_data_container *sw_data; }; +/** A general purpose macro is used to define plugin context. */ KS_DEFINE_PLUGIN_CONTEXT(struct plugin_sched_context); /** The type of the data field stored in the kshark_data_container object. */ @@ -65,6 +66,8 @@ int plugin_sched_get_prev_state(ks_num_field_t field); void plugin_draw(struct kshark_cpp_argv *argv, int sd, int pid, int draw_action); +void *plugin_set_gui_ptr(void *gui_ptr); + #ifdef __cplusplus } #endif From patchwork Thu Feb 11 10:32:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082761 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.7 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 00DF2C433E0 for ; Thu, 11 Feb 2021 10:39:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BFED564E95 for ; Thu, 11 Feb 2021 10:39:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229708AbhBKKjq (ORCPT ); Thu, 11 Feb 2021 05:39:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46466 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230253AbhBKKf4 (ORCPT ); Thu, 11 Feb 2021 05:35:56 -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 63EB5C0611C0 for ; Thu, 11 Feb 2021 02:32:47 -0800 (PST) Received: by mail-ej1-x632.google.com with SMTP id w2so9208886ejk.13 for ; Thu, 11 Feb 2021 02:32:47 -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=kR+y9XBolf2uKxjrop4eTTdx9fwxjJy7j/QO0D/zDdY=; b=nrCggwzFteQ9HNCDwdO9zLxlx5Z3B94qHp5laNyKZMTAr19mEpsIa/FVU+0vw4eoND WMhIp0TNfSOMFiJHAb6ZEbN7GwknHTUVo77z9PjyfaK+U8UL6uXp8oHuKxhozPiXTy8i ggIXzv6SZ0LQxDjGqai3AYY47XlqQbei6Gnv6Z0gGRTqhLhzKth/EN3olpHzyBHNy/oT Mx618iAOLtFAn2pTd5APp3KjEWylYQmkuaMjUxcbbBJvaHVpZ0xcGsFkgkDAsOkWksfz ipYEgITI/glx2RvTRamhcHXsxsSIb1JaskXw3b5WbYCw3e94WB2XKscJfxIuij/iYRGq iBYA== 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=kR+y9XBolf2uKxjrop4eTTdx9fwxjJy7j/QO0D/zDdY=; b=qoe07GTDhjS4ut5vsxKEFYUGKqVMKENFqKTWSATLMJKXd7Y8tetuvGIC4R9TEHaZJ1 I3HK33ymIHJNy1AHuUSNyIRDmWv79VcJCKanX0qmyZmmKFBBRj9t2e0N56DX6GgZuzOz PgpfkkfKNe07domTbqvfHWQuLmEBxod3LW3Udi53gRNVyMiCeRdSnRMudXKB3ShsGoRo w1Rny4SASH267ZiIqRTewOqzHyRggMYQmi14/0eH/GWrTd2lVGZ2TI49FwRh6vz0Msc+ eNALvnuJ1CrsmKnC47css8jmSuRfiU+kj4bFDlXVALz8lIOw4awotdI2GEEYN+B9xy6B cg0A== X-Gm-Message-State: AOAM531mKfyC5rRlWcD+BJQT7VfMEhiAAcewZ+mquK97vFxvN0m5mPI/ PhI0cYrnlQiRYJSmTAOy93c= X-Google-Smtp-Source: ABdhPJxkLl+kdiNno4n+lQB4EYVhwuXHMbZWcQTaruZPmPDXIySTf2Wkr8JgMQ/K9W8/712xcCvK/w== X-Received: by 2002:a17:906:a2d2:: with SMTP id by18mr7573350ejb.262.1613039566181; Thu, 11 Feb 2021 02:32:46 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:45 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 25/27] kernel-shark: Show Task plots from command lime Date: Thu, 11 Feb 2021 12:32:03 +0200 Message-Id: <20210211103205.418588-26-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org We add a new command line option for starting KernelShark that allows the user to select Task plots to be shown. The new option is similar to "--pid" but the tasks can be specified by name. Signed-off-by: Yordan Karadzhov (VMware) --- src/KsUtils.cpp | 32 ++++++++++++++++++++++++++++++++ src/KsUtils.hpp | 2 ++ src/kernelshark.cpp | 17 +++++++++++++---- tests/libkshark-gui-tests.cpp | 25 +++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/KsUtils.cpp b/src/KsUtils.cpp index 27cda55..ec53267 100644 --- a/src/KsUtils.cpp +++ b/src/KsUtils.cpp @@ -548,6 +548,38 @@ QVector parseIdList(QString v_str) return v; } +/** + * @brief Convert a string containing task names into a list of PID numbers. + */ +QMap> parseTaskList(QString v_str) +{ + QStringList taskList = v_str.split(",", QString::SkipEmptyParts); + QVector streamIds, allPids; + kshark_context *kshark_ctx(nullptr); + QMap> ret; + QString name; + + if (!kshark_instance(&kshark_ctx)) + return {}; + + streamIds = getStreamIdList(kshark_ctx); + for (auto const sd: streamIds) { + allPids = getPidList(sd); + for (auto const pid: allPids) { + name = kshark_comm_from_pid(sd, pid); + if (name.isEmpty()) + continue; + + for (auto const task: taskList) { + if(name == task) + ret[sd].append(pid); + } + } + } + + return ret; +} + /** * @brief Split the ststem name from the actual name of the event itself. * diff --git a/src/KsUtils.hpp b/src/KsUtils.hpp index 0d2c9c3..cf209bc 100644 --- a/src/KsUtils.hpp +++ b/src/KsUtils.hpp @@ -161,6 +161,8 @@ QStringList splitArguments(QString cmd); QVector parseIdList(QString v_str); +QMap> parseTaskList(QString v_str); + QStringList getTepEvtName(int sd, int eventId); /** Get a string to be used as a standard name of a CPU graph. */ diff --git a/src/kernelshark.cpp b/src/kernelshark.cpp index 41ffbe7..8ed4948 100644 --- a/src/kernelshark.cpp +++ b/src/kernelshark.cpp @@ -32,7 +32,8 @@ void usage(const char *prog) printf(" -s import a session\n"); printf(" -l import the last session\n"); puts(" --cpu show plots for CPU cores, default is \"show all\""); - puts(" --pid show plots for tasks, default is \"do not show\""); + puts(" --pid show plots for tasks (by PID), default is \"do not show\""); + puts(" --task show plots for tasks (by name), default is \"do not show\""); puts("\n example:"); puts(" kernelshark -i mytrace.dat --cpu 1,4-7 --pid 11 -p path/to/my/plugin/myplugin.so\n"); } @@ -42,6 +43,7 @@ static option longOptions[] = { {"help", no_argument, nullptr, 'h'}, {"pid", required_argument, nullptr, KS_LONG_OPTS}, {"cpu", required_argument, nullptr, KS_LONG_OPTS}, + {"task", required_argument, nullptr, KS_LONG_OPTS}, {nullptr, 0, nullptr, 0} }; @@ -50,6 +52,7 @@ int main(int argc, char **argv) QVector cpuPlots, taskPlots; bool fromSession = false; int optionIndex = 0; + QString taskList; int c; QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); @@ -67,7 +70,8 @@ int main(int argc, char **argv) cpuPlots.append(KsUtils::parseIdList(QString(optarg))); else if (strcmp(longOptions[optionIndex].name, "pid") == 0) taskPlots.append(KsUtils::parseIdList(QString(optarg))); - + else if (strcmp(longOptions[optionIndex].name, "task") == 0) + taskList = QString(optarg); break; case 'h': @@ -136,9 +140,14 @@ int main(int argc, char **argv) return ids; }; - if (cpuPlots.count() || taskPlots.count()) { + if (cpuPlots.count() || taskPlots.count() || taskList.size()) { ks.setCPUPlots(0, lamOrderIds(cpuPlots)); - ks.setTaskPlots(0, lamOrderIds(taskPlots)); + + auto pidMap = KsUtils::parseTaskList(taskList); + pidMap[0].append(taskPlots); + for (auto it = pidMap.begin(); it != pidMap.end(); ++it) { + ks.setTaskPlots(it.key(), lamOrderIds(it.value())); + } } ks.raise(); diff --git a/tests/libkshark-gui-tests.cpp b/tests/libkshark-gui-tests.cpp index 5a0ca01..bc49194 100644 --- a/tests/libkshark-gui-tests.cpp +++ b/tests/libkshark-gui-tests.cpp @@ -286,3 +286,28 @@ BOOST_AUTO_TEST_CASE(GraphModel) model.reset(); BOOST_CHECK_EQUAL(model.rowCount({}), 0); } + +BOOST_AUTO_TEST_CASE(KsUtils_parseTasks) +{ + QVector pids{28121, 28137, 28141, 28199, 28201, 205666, 267481}; + kshark_context *kshark_ctx{nullptr}; + kshark_entry **data{nullptr}; + std::string file(KS_TEST_DIR); + ssize_t n_rows; + int sd; + + kshark_instance(&kshark_ctx); + file += "/trace_test1.dat"; + sd = kshark_open(kshark_ctx, file.c_str()); + n_rows = kshark_load_entries(kshark_ctx, sd, &data); + + auto pids_test = parseTaskList("zoom,sleep"); + BOOST_CHECK(pids == pids_test[0]); + + for (ssize_t r = 0; r < n_rows; ++r) + free(data[r]); + free(data); + + kshark_close(kshark_ctx, sd); + kshark_free(kshark_ctx); +} From patchwork Thu Feb 11 10:32:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082765 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=-20.7 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,MENTIONS_GIT_HOSTING,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, 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 9BF70C433E0 for ; Thu, 11 Feb 2021 10:40:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6591264E95 for ; Thu, 11 Feb 2021 10:40:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229752AbhBKKjz (ORCPT ); Thu, 11 Feb 2021 05:39:55 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46042 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230317AbhBKKgT (ORCPT ); Thu, 11 Feb 2021 05:36:19 -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 3FA04C0611C1 for ; Thu, 11 Feb 2021 02:32:48 -0800 (PST) Received: by mail-ej1-x635.google.com with SMTP id w2so9208953ejk.13 for ; Thu, 11 Feb 2021 02:32:48 -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=Zj1DNil3jwdXpEyehXx8Fo3ynzMWgMuMAEs4HlY43MY=; b=T7/COb2c+DJ5kjaxNLDAorOQIiKHLD4Lj/mLHOb9momyCsQx+bkzcsSkm5hcc1ZVbP SjHA5/AbronaKbt3O1pKxmi6471LJqLuGyQUxR8R3P+IAUL+t32OmZTgrEPcsrVXhok0 9msJjXJNQgsJFcDd1ZJtWahv4dBumSwzwO6FBp9dRtqULhfOrQWA0MLsgqlRrkMK0oop i4ukd6JPbjp28o5jVLK0+fsszQoAIEbYvZZNoFL0ZG+BIc3XEg7hZOpw3Qrxbmd8/g87 TAw36uzAySplVBREomSYWSFZG+rJ5/lBWUwKtQCXKSqNKrdATXtDfRmudfWrMf/ycURX D0Rg== 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=Zj1DNil3jwdXpEyehXx8Fo3ynzMWgMuMAEs4HlY43MY=; b=WepT0QEhuD8zVJHXeJxkTXkD08ORQ0zcTdRFz+zvHg05i+B09N0RnqBkC8qqQ5wwjq nxcbZxWwYoOfLiEPuWnhCjQJ2x826f1N7zeF/zsE0VZAXJGjF9KOgsO87EoxVdcwgXNa bHEi9dGahgYA+w7IXbe+LP5u4YTegAcKpPaAgY+aOJ1VJYqw74iX8LGl9ro4yry1Q4qe BwoUSmV1gBpyHS3pYupY86XPQp1wAWz7Uq+UmTGeSkbqmNPenC5xy64d/xC7Fdez8A90 Y8Gb0Sia1YAfnxMXfa0hM6OB+9fCpvx2VYvW9tOr3RGAv7A3f9sB3/1J5BiQ0wsJG15p jHaw== X-Gm-Message-State: AOAM530ToYXzdIAfTEVrwtWAFLOVljFsYJW6cImO2ZqzROA5b+D5ILje tipsydHtaRgDJnybbYdfCok= X-Google-Smtp-Source: ABdhPJyzKqqvTqeYwlPKHBZ2Uea05vXfjZ1ZVOHeVP3U7Y0mbEEpq958GhC5o+YLsoz+uEhvpgbJJw== X-Received: by 2002:a17:906:80b:: with SMTP id e11mr7780660ejd.269.1613039567005; Thu, 11 Feb 2021 02:32:47 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:46 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 26/27] kernel-shark: Add pkg-config configuration for libkshark Date: Thu, 11 Feb 2021 12:32:04 +0200 Message-Id: <20210211103205.418588-27-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Add auto-generated pkg-config setup file to install for pkg-config. To be used for building against libkshark. Signed-off-by: Yordan Karadzhov (VMware) --- CMakeLists.txt | 3 +++ build/cmake_clean.sh | 1 + build/libkshark.pc.cmake | 10 ++++++++++ src/CMakeLists.txt | 6 ++++++ 4 files changed, 20 insertions(+) create mode 100644 build/libkshark.pc.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ca33fd..efcccb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -167,4 +167,7 @@ configure_file(${KS_DIR}/build/ks.desktop.cmake configure_file(${KS_DIR}/build/org.freedesktop.kshark-record.policy.cmake ${KS_DIR}/org.freedesktop.kshark-record.policy) +configure_file(${KS_DIR}/build/libkshark.pc.cmake + ${KS_DIR}/libkshark.pc @ONLY) + message("") diff --git a/build/cmake_clean.sh b/build/cmake_clean.sh index 2ca1136..d645c32 100755 --- a/build/cmake_clean.sh +++ b/build/cmake_clean.sh @@ -12,6 +12,7 @@ rm -rf Testing/ rm -f ../tests/*.dat rm -f ../lib/* rm ../kernelshark.desktop +rm ../libkshark.pc rm ../org.freedesktop.kshark-record.policy rm -f ../src/KsCmakeDef.hpp rm -f CMakeDoxyfile.in diff --git a/build/libkshark.pc.cmake b/build/libkshark.pc.cmake new file mode 100644 index 0000000..ad4ce34 --- /dev/null +++ b/build/libkshark.pc.cmake @@ -0,0 +1,10 @@ +prefix=@_INSTALL_PREFIX@ +libdir=@_LIBDIR@ +includedir=${prefix}/include/@KS_APP_NAME@ + +Name: libkshark +URL: https://git.kernel.org/pub/scm/utils/trace-cmd/kernel-shark.git/ +Description: Library for accessing ftrace file system +Version: @KS_VERSION_STRING@ +Cflags: -I${includedir} +Libs: -L${libdir} -lkshark diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4158901..6a6eda1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -133,6 +133,12 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) DESTINATION ${_INSTALL_PREFIX}/bin/ COMPONENT kernelshark) + execute_process(COMMAND bash "-c" "pkg-config --variable pc_path pkg-config | cut -f 1 -d: -z" + OUTPUT_VARIABLE PKG_CONGIG_DIR) + install(FILES "${KS_DIR}/libkshark.pc" + DESTINATION ${PKG_CONGIG_DIR} + COMPONENT libkshark-devel) + endif (Qt5Widgets_FOUND AND Qt5Network_FOUND AND TT_FONT_FILE) add_subdirectory(plugins) From patchwork Thu Feb 11 10:32:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12082763 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.7 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 369B2C433E6 for ; Thu, 11 Feb 2021 10:39:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E2C6164E95 for ; Thu, 11 Feb 2021 10:39:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229983AbhBKKjt (ORCPT ); Thu, 11 Feb 2021 05:39:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46044 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230318AbhBKKgT (ORCPT ); Thu, 11 Feb 2021 05:36:19 -0500 Received: from mail-ej1-x630.google.com (mail-ej1-x630.google.com [IPv6:2a00:1450:4864:20::630]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 70A10C0611C2 for ; Thu, 11 Feb 2021 02:32:49 -0800 (PST) Received: by mail-ej1-x630.google.com with SMTP id sa23so9314120ejb.0 for ; Thu, 11 Feb 2021 02:32:49 -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=BmQZYI+QNLd5YGfrxG4vJDZu8NObfohhVBHG+0tRPxk=; b=gixl6VHFPI/WIyRCvCtY3U1h9XMvhLXkUl3JnUGwsPDNCse61yC+ZxBU2cmnkXZuL6 c2praCYHTWUwaJvFWER4Mvhgz1ahQJ7wPsHUbXSImvCndTYWQjxI9gAeqs7WVcngz6Rh tBlYsXa+lT0A2kfwn797OKpix7zS8muXNINjT6L+Z9Ig2Hf6XJYsoxv7HDAIPWwN0Ryh dxK8KOw1/ZXga46kwDgxxqAXqEVG101cpdfEN+cVmIlMm5n8Y/0c+mtNKmBl5O0/jYoA f9Oxx+jrM2zPZ8AWfjeBPEnllGNzF47QaRwTq0gu2CAxtr0/OeCwq0q7NlFsqHvh2QM7 fSJA== 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=BmQZYI+QNLd5YGfrxG4vJDZu8NObfohhVBHG+0tRPxk=; b=HDQJ02ykNIUTeLHlH047E6qwz7ez5I3olHBTUp90evNAMfwIfNhYrSi+TNGE60rE6d zqF/AB+HUL3udPHY6o+/dCQNOr6guudKk11eKBKVX0OmHV5S16pSVxSx51B73syLWf4C znLLrq3kDaR/8GSAzEvopfSf9khuy3UEfMJkPsQbKK8EPkqBTgNjf499095z6iI0lZ2d Nee53nX/Rf6C3NpnlVFqfVanuICzGK2Ogs08fF0XrO+zJyGMNqRQMT9nRdQDqqSZBgUg dvMnkcTxP1ghItf7aEtXUbUNeN1xOVq84opzGmjVM4vobMSeANPq2vOqo6mVjGsYoSax KdBA== X-Gm-Message-State: AOAM530mISSpCwkbVw8D9gUIXsz10HsfucWhzCVYRv+6hz7M6Gt+U74T ZodZIpWiCSmEj5RMO3apIPI= X-Google-Smtp-Source: ABdhPJx1kVUg60claxiubtjJvxGyxLsHcxtDHFMBA3+khjLZdtXOR4aQOrD2JYKox+3e+L8boqJEQw== X-Received: by 2002:a17:906:37c1:: with SMTP id o1mr7702217ejc.488.1613039568276; Thu, 11 Feb 2021 02:32:48 -0800 (PST) Received: from localhost.localdomain (212-39-89-223.ip.btc-net.bg. [212.39.89.223]) by smtp.gmail.com with ESMTPSA id bd27sm3514031edb.37.2021.02.11.02.32.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 02:32:47 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH v2 27/27] kernel-shark: Install libkshark-tepdata.h Date: Thu, 11 Feb 2021 12:32:05 +0200 Message-Id: <20210211103205.418588-28-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210211103205.418588-1-y.karadz@gmail.com> References: <20210211103205.418588-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org The header wull be installed as part of the "libkshark-devel" component. It can be useful for applications dealing with data from trace-cmd. In particular, the header is needed whene building trace-cruncher. Signed-off-by: Yordan Karadzhov (VMware) --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6a6eda1..1e86e9c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,6 +34,7 @@ install(TARGETS kshark install(FILES "${KS_DIR}/src/libkshark.h" "${KS_DIR}/src/libkshark-model.h" "${KS_DIR}/src/libkshark-plugin.h" + "${KS_DIR}/src/libkshark-tepdata.h" DESTINATION ${KS_INCLUDS_DESTINATION} COMPONENT libkshark-devel)