From patchwork Mon Feb 1 17:23:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12059517 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 6E958C43381 for ; Mon, 1 Feb 2021 17:25:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2895164E54 for ; Mon, 1 Feb 2021 17:25:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231191AbhBARZC (ORCPT ); Mon, 1 Feb 2021 12:25:02 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38204 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231134AbhBARYy (ORCPT ); Mon, 1 Feb 2021 12:24:54 -0500 Received: from mail-ej1-x62e.google.com (mail-ej1-x62e.google.com [IPv6:2a00:1450:4864:20::62e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2AF44C06174A for ; Mon, 1 Feb 2021 09:24:14 -0800 (PST) Received: by mail-ej1-x62e.google.com with SMTP id f14so1337916ejc.8 for ; Mon, 01 Feb 2021 09:24:14 -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=oI9A6J6Jk+2xf916uVTFdGwLxxqIhbudfhQs3Xne5SJCS7Btxi/vg+J9Vqx75+e2s1 CWS0FXPi25dd0BIrgfhVmXcIinU3cbQlRZatq2TmPfZG4guQ79MTPR5RMNyihKeX+vDp aADo43CL506nFDqATrJSl5FThwufnOfRKr9qHnM1G0bEcP2iN1rllFFcy0F6aAiPJI5o WapF2DUhd8Q3z1L/cPzAFhUOIfqG85dvtQ3haLnNm7xTliCqvH1TkYNwgLVX+fgQUk1s yoOiNSmxhDBOJfG8hG4POMUgQhbsgvMsFAbJ7PbGLjRcCmyuVKrxyOlFUm+aHOi6Eb+d MX0g== 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=VXbdNwtD+oqFwJ/KVYvx9BBpp0RNer+5Lh2UCaEeD0gDYqo8YMEz8HK1epQcxBLZin Kfq+dkmrz8oqxbOewoZqHZQpGTgYIF1Zxyx1M/olNSF/vz4Fg+mjAzfzc67SIotPCRCb D1LxKwMLVpObNQWZzQUlfcyaRpJXqJHEUnleatY2LpwRahd3t2lXdLf6aybQXnetxl2k 5zggzpCtwchZAeFQxF721lV7BKKXSDWucrTHvynt3OJxVXCsJ87iQTyGpB6DIVRc/wk3 pxDIMS7QF3uvTWu/TjJLfkPubfpxYX0CXqlUPcFDVTxsgJuG/CpdYHpvgQy1q36wEjTD s9lg== X-Gm-Message-State: AOAM5301N9ZwN7OlboxDcLNLUrDx9ij4SJuKhZEx342QibGO+9j00piT DqUnpeIXMx/+NJKNZXm/Myc= X-Google-Smtp-Source: ABdhPJwZn6V9pJ1u9anr09UHZrFfnTGdC8X37bISn9f8fs0Hedw7nO182oXH493Jd9jZ8xEl7Eg+sQ== X-Received: by 2002:a17:906:e203:: with SMTP id gf3mr18748896ejb.117.1612200252928; Mon, 01 Feb 2021 09:24:12 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:12 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 01/24] kernel-shark: Add get_stream_object() Date: Mon, 1 Feb 2021 19:23:35 +0200 Message-Id: <20210201172358.175407-2-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12059523 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 D6326C433DB for ; Mon, 1 Feb 2021 17:25:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 92E1964E54 for ; Mon, 1 Feb 2021 17:25:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231219AbhBARZN (ORCPT ); Mon, 1 Feb 2021 12:25:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38210 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231150AbhBARY5 (ORCPT ); Mon, 1 Feb 2021 12:24:57 -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 1279EC061756 for ; Mon, 1 Feb 2021 09:24:15 -0800 (PST) Received: by mail-ej1-x633.google.com with SMTP id kg20so25634900ejc.4 for ; Mon, 01 Feb 2021 09:24:14 -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=cbXJxF4k3MUbRW5hTTdIfUOv93gs9koqFP4ermPTR8ItqW6HGi6qv5C4V61Vj5EXfI 6hDI85R9m7mtfyVmk4qlMDCuvOCf6K0lGjwPuaHh3C4Z37h5+00rws+Ke7EI+SFXpCok yGpVMkQTqC8LtO0nNKQKh2Ntl973Abxz2u8e8YoAbjfjlYTHp0oRF8Wf0HaHte9O+Woq sz1iFEWua2NQ8MnbI9s+ou/TAkfVzSiO6IXH/YR8dxrMt+oT7YC4SGmIkEEjseAEuvQe 7fyIPXKNAO+gkVth2SQyi6um3tYje1VEzhrPlUhTlGJurI82e0tS0W/ZzztSmJRtYpnz Sa5Q== 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=UT0QxOAbvtp4vAuBCSjBiQ+ptpVIQzUAoKuKz1yWv/9HMyXEuGObdBwP3OgkpnIwkT BeSFPg8grj797gjBIzJfmfqJqDBmtxjb2vTEGqooH8aFurELlpFNPEwjEC8sblIMy/zH a/880dfPJGkmyeDVCYYYoPhZoerD7E3XiKgUT0BZSLJ5j65b7u57x3aDW0k7lr5XaBNG /91v81oovvoL5RqT/EFhK5fkMhY2QqLMF+0yRtpJydYGG+WvgWlrIDHzWrPyOKrdd8mT Na7PN48dW06hZJ28kUFLnSN8PkE6mSRrpIFFePP4UUGigPa3iOWyPbn+yCp+Tj0ZGvjy dleg== X-Gm-Message-State: AOAM533ZoMl506VTQvo4wQ+p0IvKvvj+va/AM4cfQa4CKAA36PfQoQTo g9AUvM+dyscCw0eMBwNHWznd4BcKMEs= X-Google-Smtp-Source: ABdhPJwwEVuIycGJCYlVs9+D0WpffGBpGUur4Y4GsCN7oKQj0QIODVRPVbU1DnXCIWCHAfrdQnV63g== X-Received: by 2002:a17:907:7295:: with SMTP id dt21mr19114150ejc.518.1612200253851; Mon, 01 Feb 2021 09:24:13 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:13 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 02/24] kernel-shark: Do proper reset in kshark_close_all() Date: Mon, 1 Feb 2021 19:23:36 +0200 Message-Id: <20210201172358.175407-3-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12059521 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 A1E58C433E0 for ; Mon, 1 Feb 2021 17:25:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 568FF64EA2 for ; Mon, 1 Feb 2021 17:25:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231134AbhBARZF (ORCPT ); Mon, 1 Feb 2021 12:25:05 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38216 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231175AbhBARY5 (ORCPT ); Mon, 1 Feb 2021 12:24:57 -0500 Received: from mail-ej1-x636.google.com (mail-ej1-x636.google.com [IPv6:2a00:1450:4864:20::636]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DC89AC0613D6 for ; Mon, 1 Feb 2021 09:24:15 -0800 (PST) Received: by mail-ej1-x636.google.com with SMTP id w1so25566650ejf.11 for ; Mon, 01 Feb 2021 09:24:15 -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=uahrmy9rLO/it4LPyFBVhJzAItiMovvPrUuEaxEcplTOls822pjAPzl4CYfDmHuP82 WQ5WovbO/epIn+lxFroIga5zPoYtupRRBGVYS3ZJT7YJSQ0OUCOCujVmbU1DR1Oti3as FyoD7LZuRn9q5NXq2PMqS09xCQcQAz5tRT6SJ9l+cc8WcTyE4qCoInaIf4LSEHNAC2zc 2aHUJ5v5E9vNqWE9RVVmzjx2Q65+71hJ5XDg714sSIZkNXrVxKwyGSb3KExKCRsTzopD L278u7W9XdYnresthQpJzBDdYX4/QLXwtEeAm4UQpyJyh+of50vYEwHYmGl6khgcX+v2 7gew== 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=aW4DjsVZ7uolm6Bkap8/pmL28E4QUUav9HgjTwgBrG/5TpsMjYIQLYJm0FFDrSTSyX f2vsnzn4Ylzh8FeNiZCI6myRXuW9jeIn3tc+ae339s8aoYt8nPBKMi/0USJeheGtwpTY tEr6upmAOtc8f8HWKZadp0DG+1g5cQGXjZou/Wdqql2Xf5vEHwtuSY6U4pG6H/cn+JYs Dmkx12p3ybbr6XAaj6cElkyp0QjQdMuWahQLcaZjJzUIENOUQiHwuXK5TXffyt1/mhbi PXaqfq0U9cOJDkAJcm5lvhtVYgE4HKxStcR8cYsHCAbQnWvHKA02h8jSwWUBC6i6P+4o ytsA== X-Gm-Message-State: AOAM532M9rqHl7JJSd3/11ARi2NUDbCdGF6+8CHL+r0UoDRfFPOayajq 5OtWq3+lRmQ5BmWyTZge67Q= X-Google-Smtp-Source: ABdhPJxEx4NF2IVddKswKP1UC0prQeVOnMJ6B216anCGZi4+As5k4HPfDdx+j/IhTkJFQeujzGWMdw== X-Received: by 2002:a17:906:3a13:: with SMTP id z19mr19476008eje.317.1612200254682; Mon, 01 Feb 2021 09:24:14 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:14 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 03/24] kernel-shark: Restore the counting of event handlers Date: Mon, 1 Feb 2021 19:23:37 +0200 Message-Id: <20210201172358.175407-4-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12059515 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 6873DC433E9 for ; Mon, 1 Feb 2021 17:25:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3B4C364EA2 for ; Mon, 1 Feb 2021 17:25:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230470AbhBARZB (ORCPT ); Mon, 1 Feb 2021 12:25:01 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38220 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231191AbhBARY5 (ORCPT ); Mon, 1 Feb 2021 12:24:57 -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 1979FC0613ED for ; Mon, 1 Feb 2021 09:24:17 -0800 (PST) Received: by mail-ed1-x534.google.com with SMTP id g10so1516569eds.2 for ; Mon, 01 Feb 2021 09:24:17 -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=II4A0WqeN7FDhjZDv8LSKb0Wq6hNZKw2f9Di8wk1qu58eoLPlis9XcGDrXvEmkzdVN vPn4y3qfk9dnZ72x9Ej7S+GMcPJuC34jKN4fR9KT4P+HAdiR8rMBdr/yIbJnYfWvOkn2 4/ffP7nHMKv/X+JfhaNqfM5FjdwrTVMvmJeNs9DPzQ+FCrT+hoWVFrRmC0roy5tQIQZJ uhDPgxC9+zyEbeVZQcxkzV56dIDDL9rlIjE72RggTqNE+EH39Cehz60agoee4awJZPtM p7zC6cElqHKB12rzhITYTVXgrJ4y1iUED2paxlpIdc7JU1rLEtUKNwHar/FM7Hsh/tBT odBA== 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=aAHT5PDU83MBr5JN7QUfr8591WiezH9FrLCt4v1Fkmn1oK1aJTGrBxBux9kl93fZmB P2l6puO9eQvHKAjajTcpT478h5zpGpaewxu0rMCkKnG7ii4YM5xFJUFnWI2lPVK3lVLl oOqTt3LNO93Uj5JnQUXMQ4FOQXZW0Es8LdJhOyR7LzMzmDAQBEHQEhDu4hrHxldjIViY n4n6/24wq2QW13b2FQfG1qR8zDHBksobB56nQNsSEzaFiyn69hYlpyiX1yx42zaaW44h GE8nhWqZYNR0SHFmalliag9iNy/XqyYojVuXsOgIV0wogxQ26QOOUp//0/6TKttCEd5F qRSg== X-Gm-Message-State: AOAM533XAFM8Bu+TJLMN9wJifFGsR2eAZ2IDv8UvtdlJSnQ9SfA+5UsG ipD6HCS/rLGBcoLTFVDp1mKMjkVaViQ= X-Google-Smtp-Source: ABdhPJyiqElxR7cDd3KBaNgoDEDl7oa41FHz8bbO+nRltbtaoVzz844k1p0czwxlToTp60wqwgi4aA== X-Received: by 2002:aa7:de0f:: with SMTP id h15mr6908201edv.198.1612200255905; Mon, 01 Feb 2021 09:24:15 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:15 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 04/24] kernel-shark: Fix a misleading comment Date: Mon, 1 Feb 2021 19:23:38 +0200 Message-Id: <20210201172358.175407-5-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23: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: 12059525 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 DE4B2C433E0 for ; Mon, 1 Feb 2021 17:25:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7E90A64EA9 for ; Mon, 1 Feb 2021 17:25:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229612AbhBARZj (ORCPT ); Mon, 1 Feb 2021 12:25:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38368 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229513AbhBARZh (ORCPT ); Mon, 1 Feb 2021 12:25:37 -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 F0266C061786 for ; Mon, 1 Feb 2021 09:24:17 -0800 (PST) Received: by mail-ej1-x630.google.com with SMTP id r12so25598424ejb.9 for ; Mon, 01 Feb 2021 09:24:17 -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=IiYocfPf2WS7mSieCxyvxChdv6o1liCoij/Z34rqHJGb42PdxDYUjG5qrZ7immXRu7 k8nwYoVCacN4WOuULuhQORxxxUeHmy9PkS1YvzabobqwFGvXf5bMN/FTVvxidRO1zoT2 LUEj82wAvAEwzoIMl7nGVCgriXRA64hpxOFdEBL8plI93KzNNxyifFPiLIzR2QM+HvGg zAvwIfzOF7HS0sy8sGJCkEZv6PpzBQBJZhNPM6zKJ+LhSB2Q55tbtYwKWJvzP8nLfx8g JoPV9p8tCY/M7itS2W2esrWhQWaLcGeqfLEllpagIYNriDCjjDfawgnPW6YWTfdPu1ul qC9Q== 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=mGPzaJ9/sZTQAOxyvFEAbiQdM5SBgneDBC8vZi8f59xglPRcMnZ0qIgx5LBE3zh+gQ 6g+CDi/+qTQyyKkI6hX2/kkuzH9hXFNFRMKZaWQvOK6gBxdbr4bBwE27ZiTpsosxTa32 A4PB8tIw5dtKL3qdRTveRGLZ2UgKP69YxNmVsq3cZgOXLKzjAeQaFdPnNfzK8quhn3jm QpsB27JAzxcvTTJzCgRey6t1fw0M3ep0AEY3kGeo55VEOSbqpFEvtDxZqX7TYHVUizYw wHaXbe6cDgun43w9zLxX2LitxdEL1eK4wKPpgs05UT2fIhmUSW9WVkvLGzNdlCPXxr5i hwoA== X-Gm-Message-State: AOAM533ngGecEWd6lRtDtRmMWINwKoxfe6FcTO7Hqbplua/AJZx02giu 2a6fVWvqmK6PlZw5QCqfkh0= X-Google-Smtp-Source: ABdhPJx0YCp7QVmmz8vTq9ph90jJz49tnKyQLk8J411lP5qy/uBQ2Eeo2bt6unGhvPdFGS+HXOoYWw== X-Received: by 2002:a17:906:3146:: with SMTP id e6mr18057202eje.363.1612200256739; Mon, 01 Feb 2021 09:24:16 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:16 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 05/24] kernel-shark: Count the number of readout interfaces Date: Mon, 1 Feb 2021 19:23:39 +0200 Message-Id: <20210201172358.175407-6-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23: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: 12059535 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 DCAF0C433E6 for ; Mon, 1 Feb 2021 17:25:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8F33D64EAA for ; Mon, 1 Feb 2021 17:25:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229957AbhBARZr (ORCPT ); Mon, 1 Feb 2021 12:25:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38382 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229692AbhBARZk (ORCPT ); Mon, 1 Feb 2021 12:25:40 -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 C332BC06178A for ; Mon, 1 Feb 2021 09:24:20 -0800 (PST) Received: by mail-ej1-x635.google.com with SMTP id w1so25567075ejf.11 for ; Mon, 01 Feb 2021 09:24:20 -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=ioZRG4d2/fwuTs7OBQvTAfyx7oPqzaXEStI8xYpjD1n/DlJprrGoBi/XuNXls+jOPV hVEQixjYtSqoVVYhJXY2/ucnUec0viozM7794L05dFsg2y21P08vtqJj0wkzmnnj6UYG b4l+y3hnnAHL4N5PuXVeQDTlmbItfQzRa1HwmitbFKkqp4k0PWEqQWS0DxDnk6ATkR3A 0CVXttJY+N+ml2iWJLIo+85zhpBDcizVFlLLh1NVfzoov7DnFG0YPGiOkiRYp4mqHzJH pz4tsG4w0j+N+eQjTSlyjgmrvMkdC3DA7DL9dsnuYuDo/cG6zPhxURLedw/umy9krQXm Ckcg== 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=ofddsHceug0MNMEUMUzihzjZC1l9r6EbFKWisai2KGnw2sTK0f5kme/w077Ziu0o6u 4VFlO7yCjPooUPpOGeE97K6NEFma7lpgyALiPbWNSsRurhrR0YYtYnYnL9imFkY9wsNG RkmtjzxUh1zcv+b+4xID8K5ICBot6cmiKDlvwohMQerIvX32lyy4MbPSFf4LRLJN0d9F ijpWOhZoEBsn7F/49uNAuNWkl5QMhW74lWMpNEjmRzntcCICIRyrch3fgRMNYbobpoLF s15AgOypGVJ6vlP2ELI85vmZWzcpYRfSdt/9b3Ylfz7fUfue4619bcDKuFUqxBg2W1Z6 Xe0w== X-Gm-Message-State: AOAM530WSOe3SF3c55V3B5N+VqlmXx9WMzruwKVn258vmUSl/krnFXLX lMj1/D/BcS97tEMsJJ3xFbQ= X-Google-Smtp-Source: ABdhPJyjMV+q350G27Yk3uJAgbwg7yE7EFL8KXSWkCrlBher9Ub1JevomO7Xtn43+0gO5BMptO9AKA== X-Received: by 2002:a17:907:20bb:: with SMTP id pw27mr18402408ejb.102.1612200257890; Mon, 01 Feb 2021 09:24:17 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:17 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 06/24] kernel-shark: Update KsUtils Date: Mon, 1 Feb 2021 19:23:40 +0200 Message-Id: <20210201172358.175407-7-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23: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: 12059527 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 2092BC433E0 for ; Mon, 1 Feb 2021 17:25:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CC22D64EA9 for ; Mon, 1 Feb 2021 17:25:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229915AbhBARZj (ORCPT ); Mon, 1 Feb 2021 12:25:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38370 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229534AbhBARZh (ORCPT ); Mon, 1 Feb 2021 12:25:37 -0500 Received: from mail-ed1-x535.google.com (mail-ed1-x535.google.com [IPv6:2a00:1450:4864:20::535]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0ACFEC061788 for ; Mon, 1 Feb 2021 09:24:20 -0800 (PST) Received: by mail-ed1-x535.google.com with SMTP id d2so19816636edz.3 for ; Mon, 01 Feb 2021 09:24:19 -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=lWLOAA6o7NSTSM75mvNu2Z2Uzn6CsE30g6v1FbOUHxZCHQ0rR6uM8SWKVto8nY49pI XDHQaTz8233Gs7adKVrnzYK5LmmQh72UgfACB2Hpf4oHo+fPAl6szdVsRjisxOOuKfqU 9JueD3H5PKkgV8iEdm0Hn0nmlBwtHliOKCSKZJfgeHzEPXuCw3CfQJ3mGuEv9Em/F8Ct 9vTxq18Avo+rND1QtcuHc2DCtvhb04hZ0qU3MRlPsggTOW+eAZ84kU6lfMK6bQ4aMH0l BAYXk727n6thCW7Ygbj/auRB0RI/CABPygsX8HDM6PoeGKw/aXQClgMErFhMynjxGsw5 gbwQ== 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=S5lw25jrdbJ5CnEEl5IHgO5KbeK5lu0UMJ/rQ+eiLmNLAnkTWhPytXUMjUjqRT6qDO H0XOJPlmHpFOQAg4/2bJv69pV4Opg06CYs3A3OOJE2/eJJofNbPiaFfN4GPQkma8F7bX c/xipnvEoQKD4xmp8Jepq6JRWQIs48EO/szxszAB4/WcGgRj0QS27tHR2SKBF1cD42yj eat2Jjr5/glgrG/KqcDbX1GYId6MIseB5bfnUrci1+KNlhzEbd5k09fdiGunU/cZnE39 yhzCc6Z6aj9IId+TEWJK1kUI8FFdxe+oMGJKcD8VAiefxKnFFuUR7KS8717JNdYVn2+4 gwJg== X-Gm-Message-State: AOAM530vUzO4BJYPqyypMY8ffNwhBrQNn8jWpmu3Rv/iHeFOO/lTtOmG /JtMC9Tw54oUPYqKnDu7giLAC8mnMX4= X-Google-Smtp-Source: ABdhPJzItx51I4CZU2wn6cIVja14INdVI24NS+Ck4MK5X0sQ4GRVDzbzcsmt3OMPDXUCKu5QppiaQQ== X-Received: by 2002:a05:6402:6:: with SMTP id d6mr4299838edu.218.1612200258681; Mon, 01 Feb 2021 09:24:18 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:18 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 07/24] kernel-shark: Update KsModels and KsSearchFSM Date: Mon, 1 Feb 2021 19:23:41 +0200 Message-Id: <20210201172358.175407-8-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23: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: 12059529 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 C7348C433DB for ; Mon, 1 Feb 2021 17:25:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 864DF64EA9 for ; Mon, 1 Feb 2021 17:25:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231175AbhBARZn (ORCPT ); Mon, 1 Feb 2021 12:25:43 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38380 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229513AbhBARZj (ORCPT ); Mon, 1 Feb 2021 12:25:39 -0500 Received: from mail-ej1-x62e.google.com (mail-ej1-x62e.google.com [IPv6:2a00:1450:4864:20::62e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EBE04C06178B for ; Mon, 1 Feb 2021 09:24:20 -0800 (PST) Received: by mail-ej1-x62e.google.com with SMTP id bl23so25604096ejb.5 for ; Mon, 01 Feb 2021 09:24:20 -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=dhDUfHcHugQHCgFIgfzmNfgGTa6Za9gIv8hsI5E+yXc0SheliIOVTS/KQcYO/uSX4W Nh5Jl4RLSmaQ7OsYMYgTdLGZVrZX2R9XIVeowIp3ENafo69I4+zlncKFWHSKLkM9OC0D QqWJcmlgw2xEw48vJ2JTuw8vjASwMNGlfwqAdK9lEgGblbL6VyxCDkjL6SbrRKYK5x0I +KSPVriedvqP4asyp4r0OCsiUEBslVESNlfJ6zU3MoFtunyxtzqxoaigg0k0ACHqrtCo Q9EVH1/nwEiZ/Ok5sV5MPH13pz+DlvOn/Res+viFPs/YVqdTbTJY6lIy2Qhsa56+Ypg8 qyTQ== 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=q3TFLUzO+Mup+qSvj7ig7umFWqJb/n0tuCVn+Kh2AXzMdE45AxCHu57f97fr/du+GX 4lU2gba+6HoH1S0mQCLPr+dDEEZ7zfXDDoQ/4Yy3bUKDJpPV4/CGuoAtMHll/4wTdzC4 fHGU81Wqz7hs89IVpiTHjboNpLeoQ9DeRLxiRUCvFPVwGNix2u0wmN8OfVcJG5ZS9XbQ K6j7ZDkmMciMm39Y15jDOUBYjkTRlHwuJBIvNHQEdVKYjJlEBXUBHpvSCmj0T+fnLwAj dfpczapbBx4UCuuBUmjTydwtJs2xMWF5MU1qI4er2PvyWsnPCY6HVscgz5v7Sz9bMG2w jhPQ== X-Gm-Message-State: AOAM533uKl0UJ1FsN+M7v02L5dpNEH7H/ndq6IVBMqLceJsgjWtXDyvN NbNBSPurofb1NB8FWezLiD4= X-Google-Smtp-Source: ABdhPJzyfJlNe0uBVNfURNHBRd52M2w4hmjHJeTkFLl4oPSWJSKw4/SigTjnH+3uLnKWDsjPVCM94Q== X-Received: by 2002:a17:906:9588:: with SMTP id r8mr7233359ejx.167.1612200259654; Mon, 01 Feb 2021 09:24:19 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:19 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 08/24] kernel-shark: Add trace data files for CI testing Date: Mon, 1 Feb 2021 19:23:42 +0200 Message-Id: <20210201172358.175407-9-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23: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: 12059533 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 61B61C433E0 for ; Mon, 1 Feb 2021 17:25:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 24AA564EA9 for ; Mon, 1 Feb 2021 17:25:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229984AbhBARZq (ORCPT ); Mon, 1 Feb 2021 12:25:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38384 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229957AbhBARZj (ORCPT ); Mon, 1 Feb 2021 12:25:39 -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 56494C06178C for ; Mon, 1 Feb 2021 09:24:22 -0800 (PST) Received: by mail-ed1-x531.google.com with SMTP id q2so5054854edi.4 for ; Mon, 01 Feb 2021 09:24: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=r2Eg+rhQmizGC96oY5Jr30a7ek1kvD8HlbsfC/4YcRI=; b=uc1NkL0E4QlKBXvK9B1cXATgFkUMNymOOgFGq3GiVacQ/fNhqAGKQ9qXXX0Gup0dJw Vw/2l+nS/7zSmtfvIcjCy9Dch+0vRftjR3qUk55cVv2BeHfpGuGkEmQ0QecnFwWUS33w Yw84xD71CjQotox3Djy/8tzmNKIlD4OGyEJiBQOIFUfeR/wMCeaqAZFX2uuEw6t+Yped 8k030QnYfLwmTNp+dGvIIumlTrbQm8xsJa337lvR4u4Ei+gfTm1D7L5SgDGFi51SWkMs ff0yfvzcZO/Yv7ijL0xrdQvgZH2IN0DhdmuEXZ0+xlJGPizZkcEM8g637N4VpXitChLt RcqA== 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=A2JFuR5bGSHK/sCzEYHxNThH1Z3cOIWDSd1c9RY6TmRvFO/nRa5DnqiDg5zk/Fe+TK cF32EQjr0c3c88F8OKYoPxYaRPEa0m9WEOpFWgSpE0c/kGM0Rqe3/GKLBMVfDb6N+o7V T5u4pz1Uac8R33nh+6FGj9Ff5EekfJk3MCFBUfSSThq5uZ5W40Dsjh/WuuV7a21D104f WspHZiNQiLOcWPzc85mQRPUCgA/T5nWSsDAkaFfRgTYCwN6OOQpXjiQmXxkipGyzqUxQ WMzlb2YKhVJNBCQUKTXfYhB9rd7K31QP2V+5mtgJIGK1hJY4jx1wPJYW+sYiufTUY0c8 oK1Q== X-Gm-Message-State: AOAM533Bu11+xRvl0KiYM9DZtH8YQTWs1QDRW52tRDhT0mIWqAqj+v3E TwawRPMUILiBfmsy+XtRGVgIjxp8Axc= X-Google-Smtp-Source: ABdhPJwYJ/os7u02o+1yQBmW4MQYdLZG+UzPlq8oktSYMkYOlkQKyAI9vM34yNTzPNgYd+xQ+yPcww== X-Received: by 2002:a05:6402:220e:: with SMTP id cq14mr19954798edb.240.1612200260920; Mon, 01 Feb 2021 09:24:20 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:20 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 09/24] kernel-shark: Add plugin tests Date: Mon, 1 Feb 2021 19:23:43 +0200 Message-Id: <20210201172358.175407-10-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23: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: 12059531 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 49FC5C433E9 for ; Mon, 1 Feb 2021 17:25:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 17EE664EA9 for ; Mon, 1 Feb 2021 17:25:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229557AbhBARZn (ORCPT ); Mon, 1 Feb 2021 12:25:43 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38386 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229984AbhBARZj (ORCPT ); Mon, 1 Feb 2021 12:25:39 -0500 Received: from mail-ed1-x535.google.com (mail-ed1-x535.google.com [IPv6:2a00:1450:4864:20::535]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DC934C061793 for ; Mon, 1 Feb 2021 09:24:22 -0800 (PST) Received: by mail-ed1-x535.google.com with SMTP id g10so1516895eds.2 for ; Mon, 01 Feb 2021 09:24: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=93Pyq9e2J5uu8aZ1e9+b7X1+knvIcOeiDFz4tedcvkY=; b=jEfJdQ2XuvIi/NtkLPnXZKrbWJ0H+5vmYNAFezkQLkytOVPT7EJEBT2cxwgUTwlB58 dqn+7vvQ6RhAtSyxv/kSfpbogrvejAQ6xfp2rMs9fWV11IVybp9IJFO8Ce2dlv3yd3zs 2wKzt+1YC+y56CR5eGLhHm+GYZIVWVKMgfU2ylNHR9wUjNAqAmxm23taoJ5E/8nh7fDy l045VSBs9Cv2PYYbmASjvruYpe3vz8PCTRVUFeVRkIveGuBxBIw5pb8G6RLbnByyAF2m wN9ymP5NLnd8Kc8b6ahWdHIdY/oydttw9sYGOpLsszEKuydbOnBCIHOOGAKLSK867tiJ Mk/Q== 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=YrbS9iWRUb7TxdWnq1rC6aE1NIh5ttY2JNzdTJxRpFgVtHPXUoKQcFbCcKsesBIVyu 2VoV95gDSA4xCeWucuJ7PwQ9VqDV1U6xeIh8myfT3hP7EssrA1MA0cN87Fnq2W33QpJg u391p3sO1cyfiRjtk5PzQJMe88kn8w3clIZGgssnM6DGA3DbvIyfp9y9FslpKQkZOgZr 4uPfNw+2bK+cGbXhGdBhPd/FfDjgdOMquqOH1Pf9idSK/u0mIRYcoGpxX0brIy8R6kBE ebntSN11RAcnWHuLuVdy4jvBcBI696ClpkiPnnJiyPfJ9115vKYIhLEu3cQy2ab6uoCe 4EUA== X-Gm-Message-State: AOAM5332NR6GCc65h8Y9l4W5fDoaQ8+RVoB7OP5aVQ/pcy3ROgQ9TGDa Zs+1/lh0u1y1/4GDQG5HFtNqICovhVg= X-Google-Smtp-Source: ABdhPJz/G9NRX3ERJxUxOc25CpVDKJVd++jfCbUrwvbpsofTgzzEgvfNFEg3cY099Yek3BvI570NSw== X-Received: by 2002:aa7:cd8c:: with SMTP id x12mr11745394edv.355.1612200261660; Mon, 01 Feb 2021 09:24:21 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:21 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 10/24] kernel-shark: Add model tests Date: Mon, 1 Feb 2021 19:23:44 +0200 Message-Id: <20210201172358.175407-11-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23: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: 12059541 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 4C08FC433E9 for ; Mon, 1 Feb 2021 17:25:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F029A64EA9 for ; Mon, 1 Feb 2021 17:25:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230124AbhBARZt (ORCPT ); Mon, 1 Feb 2021 12:25:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38394 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229534AbhBARZm (ORCPT ); Mon, 1 Feb 2021 12:25:42 -0500 Received: from mail-ed1-x533.google.com (mail-ed1-x533.google.com [IPv6:2a00:1450:4864:20::533]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BCBABC061794 for ; Mon, 1 Feb 2021 09:24:24 -0800 (PST) Received: by mail-ed1-x533.google.com with SMTP id n6so19754455edt.10 for ; Mon, 01 Feb 2021 09:24: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=aRGPnmVJ3x74ujs38CBBI0OlHVGEWkX91q8T7fnnn+E=; b=umhxP806u8eUdwfEmXniI5wf3SSRJoeJeAf9C8uk4Ok1MikVor9iDi7u9t5VnWFrZV pGBnCVZWDbAHidvSGIcsUhj9qxRHeO5oO8KKxrz9IAXHezoFgRzXwrQGLpUwLmZtcSU5 9fDoYMgb7FORk5/Kqck+e/LCDjBozqXkh4enTNhKU+h/EOeWifRwBC8KspQJyBUTOs5n 6N0ep/0RgpWI0HP8oAvhu7gDrZmwoGLO1mRcha0vqsjogVRJBcVotXQAsGgIiyxU5bvo QRM2OB64flSDD6AdASus81uoJ9MxaM7IAVQHT5ZpFVACL502e3PNg9ZF1QhAeFnHVmh7 qBuw== 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=TXwa2D6OL0N75A4+Q553yqpdpfYWVTWCo1yTkFEzfAhTLhNx0O16/hVrxkmiPDXMB1 PzSVhfThTmC9XSMLy2cDVt5erQ2I5hD/Kma1PvwHKQ3AmAU5XP8XYviPdxtcxDZernsJ 4urUPKaZs60JjozTDG7cK33H4xIe1iuXSvox3gOgzSIndAC19nf0vjyTM/FeRbtO8Cd8 iB2pcX3PUgd2OXjXDkN14gcfcqAMevLu0RIlNKTERri+FeK/8ap9u02F5h0VsNuY09ge In84YZu6dYf4nxL2cP9RMBrFYFkJu7VCRgG/YMb6nBoh1cZ0LWurS/IsDDLe5BJ8n3rd YpSQ== X-Gm-Message-State: AOAM531QBzAXN2xnyDC7Fgx1a7mfwHdZFMKvI6RhuW1zs5QfXjDtiWnN kHsNkejlGf3vRXx8MMcLV5A= X-Google-Smtp-Source: ABdhPJymitd5gHC5kFoMMiS0e0ZhURAsWgLorhz8vt4mk259Yq0is4TWK67pH7uzlC4GEBqaGjduFw== X-Received: by 2002:a05:6402:270e:: with SMTP id y14mr19525467edd.322.1612200262798; Mon, 01 Feb 2021 09:24:22 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:22 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 11/24] kernel-shark: Update KsWidgetsLib Date: Mon, 1 Feb 2021 19:23:45 +0200 Message-Id: <20210201172358.175407-12-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23: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: 12059537 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 528D8C433DB for ; Mon, 1 Feb 2021 17:25:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1E1E364E54 for ; Mon, 1 Feb 2021 17:25:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231225AbhBARZs (ORCPT ); Mon, 1 Feb 2021 12:25:48 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38396 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231152AbhBARZl (ORCPT ); Mon, 1 Feb 2021 12:25:41 -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 EEE12C061797 for ; Mon, 1 Feb 2021 09:24:24 -0800 (PST) Received: by mail-ej1-x633.google.com with SMTP id l9so25648683ejx.3 for ; Mon, 01 Feb 2021 09:24: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=m4+jUQ3tJ43/c+ftesBve5vHRlWZboe+bBaAh67cMdM=; b=cKwHelqG2359lBEm3zwAF/Zj45BIprbqktXkbYGSFoluUQnX1zkFsmwXlUi1re/AyP VFHPavvSQuciAzOmh7pLoyfpoxaMZL+MkRO12zK5W8dUImU6xmwjmGlHF0gO23Qg6RId Ftsiv0QcjPjBphVcsft6RwB7K52l2WOlNg5F7SqOWKdX33726QYuSaKfcxYtzuGzd6fy bM8FPijzJ2WvkLKPkhq+hUUFtPGf0Le8pQGmr+/dAJIKO3pHGMTSMlI53MyFA5nxtc7m G/h5M8/tHClN4hIt+Mfa55pCQG9EHuYJ3MQ+YBOf2tDJNPbUoh+GQGNZr+k30p4aN1gC A49g== 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=BOTNj91OGPLldKWBmWP8wZJixDCAG8zs5O9O86GGRCTPz/q6k5tafdKsLNZoQ30MR2 LVk/rYQsd5AXNGZeuaKXjO+CVZ6mhhiY4hRtmFa7JgI0/FzRp5LPjh0UpQulP6GyIppS WMSQ6lNEOzl22OIg6RAjeSY0Esl2lz8mryRepvG0cHDe2qkZtO+ljtLjbAGx01DBll6I +63D5vPbG5rRiK3+akMpuduWTOR1UDonQb4sIaG+rCmT093TG4WYtS58xOmZbYin0tmP HHaWfVIXCFH8AQCXSO4Kes2UjAJtn9UelscQyGBl8KOh8E59KiyE93mZY5dnpXhRPsPc nX/A== X-Gm-Message-State: AOAM531+MeFbHHbCSTO6nZ7KKH6xv6YduNh/i3mMgR7Gryg5t1J/URZV a8H2DnK/m1lcBWY3C6PBfTtld7YTJNg= X-Google-Smtp-Source: ABdhPJyxv6j9HO2GMnRApskRng+6liTgF4066m8LFo4WVThsS1hJ9vJ3Mkq3IiHh6QaDud9rhnoAjg== X-Received: by 2002:a17:907:aa9:: with SMTP id bz9mr2897439ejc.528.1612200263760; Mon, 01 Feb 2021 09:24:23 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:23 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 12/24] kernel-shark: Add combo point to Mark Date: Mon, 1 Feb 2021 19:23:46 +0200 Message-Id: <20210201172358.175407-13-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23: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: 12059539 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 D4094C433E0 for ; Mon, 1 Feb 2021 17:25:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8BA7164EA9 for ; Mon, 1 Feb 2021 17:25:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229534AbhBARZu (ORCPT ); Mon, 1 Feb 2021 12:25:50 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38406 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229513AbhBARZn (ORCPT ); Mon, 1 Feb 2021 12:25:43 -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 26CCCC0617A7 for ; Mon, 1 Feb 2021 09:24:26 -0800 (PST) Received: by mail-ej1-x62c.google.com with SMTP id p20so6260319ejb.6 for ; Mon, 01 Feb 2021 09:24: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=77/C7IL9bwjDIfN6W1HD95rM7DeBqtf9m1fmX4fHhKw=; b=XwMvJZh6GQ55s7pcMUUbw0I8PDoRmnN9TiibXKlwNBgpVvLBpB9ieHsj+MFFL98QgY AWzYkffD+qwIExo3G0ncqcfE/knSJbCD/W1KB78IlWKR9AuFNpX2njViZx2iQsv6ywe3 xTbCN35FkZF093IRZA+PXxa+KDnopVMF7CUxUBvLvO1bxup/lDnX7s5BNdEchrjBrvRs T6MHa3QduxxrxmVph1Ej/ZZSBRNdiB402y/19SJ6H/HnnUiM9rSZC5nYxzhgJB4Eh2Zk Aga6z8nLskz2BVZtcTUqSFn/uN0jNu0FC1NXJPa32PpST+lUKOICT2WfIT8bE6YmNDLf D5qw== 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=OODV3/4cObHrMimvSXjXQLVKmq3pEu5HTOHlAHkslnpWJMMWRJ0EF3YMxwoxV6rs+Z +pAPpfaAeEfwZcgwHb22uSzNv5vUNE6JoD78fMoKvLceH9FPhXAKJ2cro7haGgxj7ZDX ndke+Gf7Kr5nbGcERcykUTU26r/7iLysWUX362Uy8CKdS9WyaoxpixZSyABjeDA2FHix 3D55zLff4UIJYGfn3wgsbangihXTOr5r6TuJwurQx1ANdTeSS+fDh3bWfwJTK+/J2LE9 1x7PzviipnNevdYLWskf6/vnwX0BWsZpJvQUM5eqfFBB2GUWegcK9sg1zJ2ARRARoL+m JQag== X-Gm-Message-State: AOAM5317OhtW0nkmSvnMmr9X/Oa6oOKkLdgd9Lwaa9YfU7Wt5G2eREME sDmOk5eTzI7jbcdkntL1fHQ= X-Google-Smtp-Source: ABdhPJxj1H9F47lBSy4STWUa4qR4OTfuD8lCJ+osOvbSYHtrkTshV83uDhRzSA/R3o1oe5IcDTOPHQ== X-Received: by 2002:a17:906:8159:: with SMTP id z25mr3289476ejw.270.1612200264962; Mon, 01 Feb 2021 09:24:24 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:24 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 13/24] kernel-shark: Add new methods to KsPlot::Mark Date: Mon, 1 Feb 2021 19:23:47 +0200 Message-Id: <20210201172358.175407-14-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23: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: 12059543 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 B99EAC433E0 for ; Mon, 1 Feb 2021 17:25:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7BFF464EA9 for ; Mon, 1 Feb 2021 17:25:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231152AbhBARZw (ORCPT ); Mon, 1 Feb 2021 12:25:52 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38408 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229555AbhBARZn (ORCPT ); Mon, 1 Feb 2021 12:25:43 -0500 Received: from mail-ej1-x62f.google.com (mail-ej1-x62f.google.com [IPv6:2a00:1450:4864:20::62f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 42263C0617A9 for ; Mon, 1 Feb 2021 09:24:27 -0800 (PST) Received: by mail-ej1-x62f.google.com with SMTP id p20so6260424ejb.6 for ; Mon, 01 Feb 2021 09:24:27 -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=g8qIX5F+tBtohn5a3HxNyUmmKD2dAItgrxrvRhAKIifiW+LKo+wNT/1VgPM0pLP1y6 BArOy+gcJ7wpxnUcdOHg0J1oQ8W3hgtdC6LgobPWaeca1lALfndUx4/jKMpMIwiYwxof mAu4mO/8J0oWp9k5/Ne3XfOB+Z3XHCrlgHJ9SDISMNCq/ccrZcvY/MSCTMPb6ZPX8yMM m/fyIgFJLbNXtUcXjIDCjjkiOZv+ZjyGwMOyl8kXKqeIsoIkwiwpLbDCEP7vCx8DSQ12 Z4jELaCx9nd6z3LQDtOO5RC1qiyLW1cz4tj/oNkxkpo/PgXhi4M2dyLVcx0MkJKznPUk ZFOQ== 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=FC35xVRIHSwtnbU6Ex7BHc8PCq6Scfan+EtvLNJd/DfD3ddTBV7UY8jQTrU4uMmMkr Z2O6+7TO3rlFIQX+N+oeAapjyPztyMOSLkh+kZqIpObjmYUyTtip8JP9smKrDcvQckvS jTLNEKc92OwkDx95Ds1+uP7Eetm8BJoU4NlHE9QJ97LC7qyVXh6DEdQvcFW62Hz1+1Bz ZLLnyNqZHtzuV+KHYare7pxCBxSX+ldQONjbIlmqfYoiuNVkW0duUe1EQuAxFqXHtItX gkuWUW0nJFTpV5KovznB2uXU2fT7x6yF1YkJNW0wvq0lI/S8C9wSDGlhaSqWG5ovTHit p8bw== X-Gm-Message-State: AOAM533EV5eYOxjzuJgW0gdb2j6G9aYPUpzMFaVj8VFYAdJbAMMCfmPL wOEf9kyqKr6/ikjVM68ZE59RkCBqvdY= X-Google-Smtp-Source: ABdhPJzjBmgO+9Z5vfgmSMSh2sU+V7lAUtQhQBxCuxk/PJkfApWFBt9gwbqgXxYVtxd62CBi4QX1xw== X-Received: by 2002:a17:906:7a42:: with SMTP id i2mr19255417ejo.27.1612200265954; Mon, 01 Feb 2021 09:24:25 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:25 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 14/24] kernel-shark: Update the plotting example Date: Mon, 1 Feb 2021 19:23:48 +0200 Message-Id: <20210201172358.175407-15-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23: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: 12059551 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 570DDC433E6 for ; Mon, 1 Feb 2021 17:25:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1A43A64EA9 for ; Mon, 1 Feb 2021 17:25:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229831AbhBARZ5 (ORCPT ); Mon, 1 Feb 2021 12:25:57 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38368 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229663AbhBARZz (ORCPT ); Mon, 1 Feb 2021 12:25:55 -0500 Received: from mail-ej1-x636.google.com (mail-ej1-x636.google.com [IPv6:2a00:1450:4864:20::636]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 14407C0617AA for ; Mon, 1 Feb 2021 09:24:29 -0800 (PST) Received: by mail-ej1-x636.google.com with SMTP id bl23so25604760ejb.5 for ; Mon, 01 Feb 2021 09:24: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=UEYob8kFw/rX6KUC3x6LIth1SroJe6FkBpya9vUZzI0=; b=Z5s1/jarTu9HQrcnmHvaAjHHH/IEv3RKHJ4kFlhttqgNgjLThzxCUbL9Jy/pAC+rEz vVDx1fIC+1W9bgkL1po/0MsHOLaQ3eeVByiufZXvz3qOVPoEV93RziFqMBAkyiB33TjR qblRLdSe9W4n/0mEByEzj4NYmCkwjXHkoP/BW3DvlEuqvScmkq5VIVeOBB1vHUBVT9Dw 2EKvOczzAI5EcuxHOW2ha6P4O0p3wiaPaWxfAGfGbv4F7VQXX7/e5BRoFHkcxaidoS33 MkdFd6UHlIT7XBxLmxMaZMwrTXnSrpRriZ42AYzFlbsSWn0iNu314HqhPqmjzCCQM/HM 8I+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=UEYob8kFw/rX6KUC3x6LIth1SroJe6FkBpya9vUZzI0=; b=P5usG0zOKXNjzojIwb3oHvz+ddhYgTlOyAAidTrtpXnIvCK6pXUTEL2U+b4OcMS0Jd 1NfSbRllq0jvhSa4nFmLwFA90RFRoiyzj12+ZMeTucNdkTZ6zG5ySTHsoJoDEezA6tJX lDWgjxWlU1kxBLFMk+ibchFDknbsR/LI6lcYztxI0nH40w7lzz69jtWPqexTkYFHPTPh QTaiUzVZGmS1o1b4K3S8Hbnh9rM4qwjvjqxW+dWhWBCBk/FE0iWU8hhaVRemXajbqy7b aYI6SU6Hv6sMj7iX8eWAtkrzTdUYuI6be+h5qZ0VqfeGKu9Ff5JF3S08GaM8yL08UW7Q p4dQ== X-Gm-Message-State: AOAM5323Cy6cZwbEp+x9RxRicbfXmtmZ/auF5g/m3UgdHYLu1Mlw0RML JqP6B1cEZvfKtDpO0SvZyqs= X-Google-Smtp-Source: ABdhPJxLSZ+6rwCffQCR3zrWpCf8dl1Yv5IG0OCqgU/fiItUBVRi+IxCxwCFIqo0b/1X/8viIcTcIA== X-Received: by 2002:a17:906:fa18:: with SMTP id lo24mr6412907ejb.221.1612200267201; Mon, 01 Feb 2021 09:24:27 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:26 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 15/24] kernel-shark: Update KsDualMarker and KsGLWidget Date: Mon, 1 Feb 2021 19:23:49 +0200 Message-Id: <20210201172358.175407-16-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 | 718 +++++++++++++++++++++++++++++-------------- src/KsGLWidget.hpp | 187 ++++++++--- 5 files changed, 651 insertions(+), 301 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 140fed8..fa3f529 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -68,9 +68,9 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) 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) 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..4b5b9e2 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,17 +59,62 @@ 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(); } +/* Quiet warnings over documenting simple structures */ +//! @cond Doxygen_Suppress + +#define KS_FONT "FreeSans" + +//! @endcond + /** Reimplemented function used to set up all required OpenGL resources. */ void KsGLWidget::initializeGL() { + const char *family = KS_FONT, *name = "aaa";//KS_FONT; + char *font_file = ksplot_find_font_file(family, name); + if (!font_file) { + QErrorMessage *em = new QErrorMessage(this); + QString text("Unable to find "); + text += KS_FONT; + text += " font."; + + qCritical().noquote() << "ERROR:" << text; + em->showMessage(text); + + return; + } + _dpr = QApplication::desktop()->devicePixelRatio(); ksplot_init_opengl(_dpr); + + ksplot_init_font(&_font, 15, font_file); + free(font_file); + + _labelSize = _getMaxLabelSize() + FONT_WIDTH * 2; + update(); } /** @@ -67,7 +131,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 +144,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 +157,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 +185,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 +214,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 +225,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 +243,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 +254,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 +275,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 +285,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 +314,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 +328,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 +351,8 @@ void KsGLWidget::wheelEvent(QWheelEvent * event) { int zoomFocus; - if (isEmpty()) + if (QApplication::keyboardModifiers() != Qt::ControlModifier || + isEmpty()) return; if (_mState->activeMarker()._isSet && @@ -281,7 +367,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 +439,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 +495,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); + const kshark_entry *e = data.rows()[mark->_pos]; + int sd = e->stream_id; - if (mark->_cpu >= 0) { - mark->_mark.setCPUY(_graphs[mark->_cpu]->getBase()); - mark->_mark.setCPUVisible(true); - } else { - mark->_mark.setCPUVisible(false); - } - - 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 +576,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); +} + +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(QVector cpuList, QVector taskList) +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 +844,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 +867,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 +891,7 @@ KsPlot::Graph *KsGLWidget::_newTaskGraph(int pid) } graph->setDataCollectionPtr(col); - graph->fillTaskGraph(pid); + graph->fillTaskGraph(sd, pid); return graph; } @@ -667,18 +911,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 +934,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 +948,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 +966,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 +982,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 +1048,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 +1146,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 +1177,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 +1187,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 Mon Feb 1 17:23: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: 12059563 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 23C40C433E6 for ; Mon, 1 Feb 2021 17:26:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DE41A64E8F for ; Mon, 1 Feb 2021 17:26:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229963AbhBAR02 (ORCPT ); Mon, 1 Feb 2021 12:26:28 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38532 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231248AbhBAR0S (ORCPT ); Mon, 1 Feb 2021 12:26:18 -0500 Received: from mail-ed1-x52f.google.com (mail-ed1-x52f.google.com [IPv6:2a00:1450:4864:20::52f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D229DC0617AB for ; Mon, 1 Feb 2021 09:24:29 -0800 (PST) Received: by mail-ed1-x52f.google.com with SMTP id y18so2465143edw.13 for ; Mon, 01 Feb 2021 09:24: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=77n0VjDKz9hol2LKctAt0d46cdW57/1g5Ym3x+3aVvY=; b=o+ZCz7xvwx8KxrwEUoERevONSA4eM6+pHrXOxtmwfYkO9CF2FgD7gAxMiztWEUZii9 7YJhLTMoOtZ7H1OiecQz5LBAdl5lxfhA++amd2jdAMwCLxE0MGy2Wf5mmC3DSgbmbObg mWw2aRblwRZFRpZbJDyZeZBekIPiq0XRhXuf9XV5oHwh+Iv8bZaUPi87JJ8CWJ65zFDX jDQJlB1xBYa3Oej3VabwBTJ4RBSKUByZtuzzklsJNSV2Xa2t7Qdi7hjoLCymXZDKim0b CaIFqViP6xCjWsU4e5VSCECMuV/FeZCMrT3vCFrar/nEtOzIzdgIMxSQ0dRQ/hBD9wao TVCA== 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=77n0VjDKz9hol2LKctAt0d46cdW57/1g5Ym3x+3aVvY=; b=LMh1x+vitFL5R7N2TnpRRaNib8vBnkCKqH7UhjW4QPYqIQUyKMBBXylKEGotNXatOp KfAB7lhUicP4C0Zq1M5iU4zmUQcCAHS+PgEprrDwyJvpFd91Ooduj4CJl186aF+g1Hwx 9dfz5DzCVMUi9jgSkbYNnIYRjY9ypCCmO1CS6GraJh3UF4Pb5FdNu8c5gB5RXw3pVNLR K0P6+IwjtCZTtn/CYSSWWXt73pDwaKW/1J9Edy+QagYjZPsXwA+qlicqMgZPae3gxFME OBhra4l3Hynj9W0fyMmr8cIoYKf7MmgecLiDENodH/ebUXixeDISz8OQRNgcDVUW0W+Q SAwg== X-Gm-Message-State: AOAM530SY1KglCipsp4ZBEtUIkxtHIz/tukQilNGfJTF6+jF2qAW1bxh FhSjtLysBvKBZHlUIC3JvEQ= X-Google-Smtp-Source: ABdhPJzK323trghPNwFKOfr2SrXQUQYihcvtpSyJQzHsPkahflZ6edeFoNGATQuxktAfzo6udggrOg== X-Received: by 2002:aa7:da55:: with SMTP id w21mr1800152eds.138.1612200268101; Mon, 01 Feb 2021 09:24:28 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:27 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 16/24] kernel-shark: Update KsTraceGraph and KsQuickContextMenu Date: Mon, 1 Feb 2021 19:23:50 +0200 Message-Id: <20210201172358.175407-17-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 fa3f529..a745757 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -71,12 +71,12 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) 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) 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 Mon Feb 1 17:23: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: 12059545 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 D97ADC433DB for ; Mon, 1 Feb 2021 17:25:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9C0B264EA9 for ; Mon, 1 Feb 2021 17:25:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229555AbhBARZ4 (ORCPT ); Mon, 1 Feb 2021 12:25:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38370 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231237AbhBARZz (ORCPT ); Mon, 1 Feb 2021 12:25:55 -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 87BE6C061351 for ; Mon, 1 Feb 2021 09:24:30 -0800 (PST) Received: by mail-ed1-x52a.google.com with SMTP id df22so3836124edb.1 for ; Mon, 01 Feb 2021 09:24: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=u0QDleRYoNmfgNSAkirf89OEYrO9tTq3IBpU7nR9TSg=; b=EsJ0L3qJ8ncc+p0cdOkb67VyvX9jPoidx5JZxHjFe8y7JctlTReXU8mb2V/m0bIkvQ hzILwLkZt5pxvQHLE0hUblAFcaBkFPTgYEScxYDMFWUQ6yKvitVq7GyGDiRhcPcyHyFV B8HW0ko2atyXJY6MWmgDao5drZeRQGZ6abjRaQIUv7Vi5jO2Kf6J9bSOQF93mJMjvdA4 lpKnT6YloyCQrgJ1aKpMoCZb63cBcZg9jmTN/c+OV712FDGCTqaqh7fOr6E5Rb1Aevbf yaaH2CuYrmw03ENg9noUO4Ib2RdYlwHH1AR6aZYR2ssIo1p3RkG7q5tAW2P82oEcjKEJ dwig== 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=u0QDleRYoNmfgNSAkirf89OEYrO9tTq3IBpU7nR9TSg=; b=A9gzOIJBHBqw3dN+18j2ObP+zPOBzXiAC8kLMjiOql/fgoX1p7Dofjuwz6iMI0G4b3 1Modv7VkZLIhSiCQu0DT0+JQkRAuG4479tqm+IEfiCkYnKxeRzcnGExmBYKXgfMEEtd0 m1T8cje1aCaqJpy82FfjmjfJcTqJpN4tkTOSyqEyw8jK83s+D7phSJQ12PNhtbDuB4k6 6Far1BOIR4CBuKKpf2A4AVyGkdiL54NYIXtOfo41aMesKwNRuJZnVBECqpSBK5DWW7ky 0v0MWEoc/NzYI14Axklu8e8QSrQi0W1A+g/SE/JxHcYW3zu+XLAcAiELmiWwgBffUx+7 UXCw== X-Gm-Message-State: AOAM531b9abCtIb7HTchqC9T23LMCpc5h4Wtcx/YWK67tQTAdcxWZ5V+ ceXMCc09AJir7tspBlSY58HRuNrdmn8= X-Google-Smtp-Source: ABdhPJz/cBtd6Um3nL13khh3avyMaLZSzGuQh8XrO/h+ZE1uVEYvyaMVBI5hBgQVNMYXB5psk+M9JQ== X-Received: by 2002:a05:6402:4310:: with SMTP id m16mr20213059edc.207.1612200269093; Mon, 01 Feb 2021 09:24:29 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:28 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 17/24] kernel-shark: Update KsTraceViewer Date: Mon, 1 Feb 2021 19:23:51 +0200 Message-Id: <20210201172358.175407-18-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 a745757..209c57c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -73,7 +73,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) 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) 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 Mon Feb 1 17:23: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: 12059561 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 D3A67C433DB for ; Mon, 1 Feb 2021 17:26:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9409264E8F for ; Mon, 1 Feb 2021 17:26:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231237AbhBAR00 (ORCPT ); Mon, 1 Feb 2021 12:26:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38534 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231269AbhBAR0T (ORCPT ); Mon, 1 Feb 2021 12:26:19 -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 6E755C061352 for ; Mon, 1 Feb 2021 09:24:31 -0800 (PST) Received: by mail-ed1-x52d.google.com with SMTP id df22so3836189edb.1 for ; Mon, 01 Feb 2021 09:24: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=+gB2ykFChR518SYjaWPHdcz2CeIKMUt4KsXVzBrUMjA=; b=T34IqYXHk41y7YakA1jn2BUewAyyJm23TsB/3b4Wtxlr9MvCL82jy5rDWn9hyL0Nup xLBvQYDpbKhKXgawBX1ldUzgwaxIavn4J1t8dZ4Unq4VvNowey64XUVLVCBPVIWVrYKv olTO347X74o/wMNaFcJaPdSJ0Scpmtxr5EWvn9xlLEydkSr+Ux3lJod8igxUI6SigI50 Ky309p6HNT1B5WwnNapX71KbMdYR3djZajddFNFf6umvp6FQHKntzpMNPbCyDR6ahNki mDZkUh2v2pvuvd0TQ71hkEVFM/vVX5CcvsYlzvEO/kWCbSrmr8mMLksd5VRCfv9w2q4G Cetg== 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=+gB2ykFChR518SYjaWPHdcz2CeIKMUt4KsXVzBrUMjA=; b=hGpyrXYG5R57yevOjPcksU+hxr/p5dEgtLegiDYptQaKvgd04HYK/73wH0KcUQvD/f 8nUIJmkCRITXrhi9vKhX24YRmcUa2ERTTtnn/eNlTllq7vUxvQCPoqEuXcVWeAVwhBMp gSdbcMTCtGuTiAF/Lk9Rau0E9tVTait8lFwkzLinYcjTZG2P0O1M8GCiGbHjo1gld0Ls VvZ3ZoOosTlz4Sg+4ENhiUXo/ournrE21d0WSmJuXLQMpObQmcx2jIe7FwLLPDL8dpAY 6cXaIbOEA6YirfVg65JzGsevaQiXW3n1QIC1Fp5kXbnbEnZjErocxcscLCycQhx0S5Y/ jISw== X-Gm-Message-State: AOAM533oQ/h1RxD2IcLilu7643LOwHhxhymdMH4whFa/P3cr6G3Y93nm r632qAhRRQ495SWusWHgddA= X-Google-Smtp-Source: ABdhPJz6w1MNdpOP7W2aYpYcJOf/SFd6WNlHM7z62YOW/+aXnGNL0yZcQeB7UD9PQNn5qXCknmUuww== X-Received: by 2002:a50:ec06:: with SMTP id g6mr11006588edr.12.1612200270192; Mon, 01 Feb 2021 09:24:30 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:29 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 18/24] kernel-shark: Update KsAdvFilteringDialog Date: Mon, 1 Feb 2021 19:23:52 +0200 Message-Id: <20210201172358.175407-19-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 209c57c..c1d98d8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -76,8 +76,8 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) 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) 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 Mon Feb 1 17:23: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: 12059547 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 0EC5AC433E0 for ; Mon, 1 Feb 2021 17:26:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D0D5F64EA9 for ; Mon, 1 Feb 2021 17:25:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229663AbhBARZ6 (ORCPT ); Mon, 1 Feb 2021 12:25:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38380 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231177AbhBARZ5 (ORCPT ); Mon, 1 Feb 2021 12:25:57 -0500 Received: from mail-ed1-x529.google.com (mail-ed1-x529.google.com [IPv6:2a00:1450:4864:20::529]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C4112C061353 for ; Mon, 1 Feb 2021 09:24:32 -0800 (PST) Received: by mail-ed1-x529.google.com with SMTP id z22so19778553edb.9 for ; Mon, 01 Feb 2021 09:24: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=48CjVMJ+YprkTj1657C7k0JWmWC+8YkY09KyKQtxctU=; b=g79PmIbGUFYv4kEQDAX38OnzMu77BSzYC6ehhOR8SvUxAXzvBxekIp3bUoRFry2Iju U0+yN3okiEkImnoPePoBCu0k4QilTeF/Uc23l/kzijXTdL3xP9TJIR2eC/gTNV/RE7jB Oye7U+ZCunq2NzBNwPB/BLZAvPKvjgBsIPqFyMFu+HJ7ve7wb1oJ+b7e97lwxIU58Z/E 34eEsM5NgRu/GhhmIprsW/tvxII/dzwf4loVW2KqplzGi0nNAB5Sw/Z1AhQ1AVJ+o7HB QVljxlpFDc7mOq1i1hSl53oUV/ZqY42Md0067H5m4xyjnyoNJzVrsexGlIBkCK8zs8TZ fgrg== 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=48CjVMJ+YprkTj1657C7k0JWmWC+8YkY09KyKQtxctU=; b=tGwlQT8A55Zxg5D+E1Z2qZnM/i6luH13im4vGY5PnUGB2V7w2LQPfFYvKaGyI/uafO FlF7vtQB9//5pdGxo98nUnzwdB4/9UXTPnph+hFpUR70CA/DcQAVgubszZJgbigMw1tF dDaOS+Wi0wQA+Ue3OJfofPwmSEMz9lf2aPqpZn3lLt8dXN2hbkOK2zjkbp/4yrOwNO6p +5dfibJqHTPq59k4nczHyRSUh7geJyNI6aAnc6Jn2AW3+Y6SW+8QMkuLefqxmp/AKpZx t0R8aPa2Sl3q3pFWv7bzxuL+tthmeh205YVkyIV9p7/f02rrbB8N1iJNGxZBRds0Eq21 UHhw== X-Gm-Message-State: AOAM532qR5AaZCIU+oGA7lXw61HXUUIIxOtsR36KzKzVKPszBn22WCMT IRngMl5fc2z/VPpyhFMZzRM= X-Google-Smtp-Source: ABdhPJwFD+XUUdqydZT29VzuyMqDf2B+NsoMTGUsyVfZRwT/pewkCUChUm6lYwyrcF2e42bHCt+Zcg== X-Received: by 2002:aa7:c418:: with SMTP id j24mr7168132edq.293.1612200271507; Mon, 01 Feb 2021 09:24:31 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:30 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 19/24] kernel-shark: Update KsCaptureDialog Date: Mon, 1 Feb 2021 19:23:53 +0200 Message-Id: <20210201172358.175407-20-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 c1d98d8..c188849 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -75,7 +75,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) KsTraceGraph.hpp KsTraceViewer.hpp # KsMainWindow.hpp -# KsCaptureDialog.hpp + KsCaptureDialog.hpp KsQuickContextMenu.hpp KsAdvFilteringDialog.hpp) @@ -91,7 +91,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) KsTraceGraph.cpp KsTraceViewer.cpp # KsMainWindow.cpp -# KsCaptureDialog.cpp + KsCaptureDialog.cpp KsQuickContextMenu.cpp KsAdvFilteringDialog.cpp) @@ -106,9 +106,9 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) # 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 Mon Feb 1 17:23: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: 12059555 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 B2B36C433E0 for ; Mon, 1 Feb 2021 17:26:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 748BA64EA9 for ; Mon, 1 Feb 2021 17:26:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231344AbhBAR0X (ORCPT ); Mon, 1 Feb 2021 12:26:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38546 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229692AbhBAR0W (ORCPT ); Mon, 1 Feb 2021 12:26:22 -0500 Received: from mail-ed1-x530.google.com (mail-ed1-x530.google.com [IPv6:2a00:1450:4864:20::530]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 12B00C061354 for ; Mon, 1 Feb 2021 09:24:34 -0800 (PST) Received: by mail-ed1-x530.google.com with SMTP id z22so19778625edb.9 for ; Mon, 01 Feb 2021 09:24: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=AUYNqoH2/g6UnYvCMpLPkSeImOMd5thWNNX0httZfJ8=; b=BiEf3I2DlAZ0vT3X8+advXJwHe5X8PEYwC1nbK3ViGguP85Fmd7ZnYH4kuv3FKhM9o s9Izg6yF6V0QYR0fpXAwoQxUSnvwjd1J/7R3jEtr/pftG3Z9Cq/+ynnif4iJONMxYc+m 4WEMkwtmeVM3gjWIHrwmgSz3kuQ/NyuuvAvY9sKTZ8cmxYdTkePqoe4FybudweQetlxR OtFkQpyFDv2T2OyezAoyPphDqf5AEWI3Fl3THqHn0kEiej0XtSjYBcqTDOxm3Yg7xp5v jsp+IH1MpoEvm3lIH5yF2ia/Vkg51KixkyOcph1uESyuY1OXLrs9dG0283dLtX2Rmcd8 uhAw== 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=AUYNqoH2/g6UnYvCMpLPkSeImOMd5thWNNX0httZfJ8=; b=lluo69zo26/C76WCONRQ0Bet11IUC4G8FrkQBPngiomGWR7cGII1aY/KUVvv5U4wMH UANgXv9XOQF0S2UZ53Ynv++HVpKCV0Zrtt3IWCdkh2BqUrtJTijQoxCePhjyNXM2zWFZ Wkvv4FZZGqbYhQ80XFVz3mrrzWaRqLjlO8rhELbxO8vnNxcC187iEKWeEPh6W5puqGkI ohjDq6Vrj4NEYU4ebXHhp7DM9TmVAqWw97sOXO6BTEkCcP1kyVeg1c9mAJAgKpS1qVEl BwTODQ+6Giw7CwHKdaggX1Jh6lz2B1BJzxineB8z1OkZsm2SEOs+yMLmWVTpRKUIS9d3 X1hw== X-Gm-Message-State: AOAM532t9FOH8mocU5X3qUbZVNV6gaem1/0tW76YF+8NxLe8GmhQyLyX W6bcR23g+ek1kH11JTS+NMT0NOEtHLc= X-Google-Smtp-Source: ABdhPJwN7AGsWUnQL1n8UjM8JGAL0jYTvKHGs0bjQ5+O7U7eesvh/3PByKE2oFJyzi6QRGupHiC1NQ== X-Received: by 2002:a05:6402:ca9:: with SMTP id cn9mr20312900edb.208.1612200272686; Mon, 01 Feb 2021 09:24:32 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:32 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 20/24] kernel-shark: Update KsSession Date: Mon, 1 Feb 2021 19:23:54 +0200 Message-Id: <20210201172358.175407-21-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 c188849..e4ef7ca 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -83,7 +83,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) 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 Mon Feb 1 17:23: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: 12059549 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 C2C61C43381 for ; Mon, 1 Feb 2021 17:26:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 947CB64EAA for ; Mon, 1 Feb 2021 17:26:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231177AbhBARZ7 (ORCPT ); Mon, 1 Feb 2021 12:25:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38386 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229513AbhBARZ6 (ORCPT ); Mon, 1 Feb 2021 12:25:58 -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 2EAA1C061355 for ; Mon, 1 Feb 2021 09:24:35 -0800 (PST) Received: by mail-ed1-x52c.google.com with SMTP id c6so19819046ede.0 for ; Mon, 01 Feb 2021 09:24: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=UjZajoxQn2imqdEFUY/RNy6CMLza2kPjVs4uI9lZQCI=; b=Lhq9Roe4cckoXI5mIl7rQXZxyN7HPdBE32tsrOYiGjwhOS71gk49OfoLLLUFiWBcrG MMsUA97Hw+qaJeG2qmMkOvIO3SXb/duy2xOJIGq49iv/UxVcp2H5XLrZwdi+QnBJkWlt +HlOa35n63vDRZT601AHwSDX2ryUqPeB/aW/aU4+oXECij9p6ShZFew/5sdy+tAA8e2s YHRsnux0q0zD4oTW/Uj5G1meOwPVGI3Bq63IViwGmSIMmXJ4OwrGuTbCriy8QchOD1kK loZFmstQnXkVGjfO4OPEcQB3nk5sn8vhamAeluuEg7UYV8y6zHHMHM/uvcEEe+6UmQkZ 2NZw== 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=GhWtxJ/lxBhcUht0fn3/1xt21x7GYkhEipn9pyp5OBt58wXfER+Fe6rarLNk3+7IRz xzE7TXVj1rOuvao49aZPf0xo/Nw0TudeCD9jnE4mtxI7SkT2/Z+wUNeju78pfAvX9zt5 DdpDGpsO8f07jm4PZnBvP6Z5limn887WUSMNnrJ56noAboAHs6Zy7YBJZRQ9yh94pfMm wM3WXu1O4Mo4sxO/dMriD76qrgV2lLWirtjHlwS8PqI/RaBlNS+k29BY1D6Bpy08kEvd yCFdxo97AUDVkPIGKl8WbVM3RsVCAxd3o4ezjup0eB+LcppR9E5v8uewrhtkv0D4LV/U nPLg== X-Gm-Message-State: AOAM5331AzwmlcmLf+Ew04fFXIsmHvm7zH/+C3h6QBaO/dmu1KPW91RH 3QlHkH0CV5Q6p8vYtety0TA= X-Google-Smtp-Source: ABdhPJxl4syA7F6dLNCFTIq1vmCgh9e+qmjg8Ol+LUkfKRHJMkAe5wV737W+B4FO4rWjfN58u3vZ+g== X-Received: by 2002:a05:6402:b6f:: with SMTP id cb15mr19610469edb.277.1612200273942; Mon, 01 Feb 2021 09:24:33 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:33 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 21/24] kernel-shark: Update MissedEvents plugin Date: Mon, 1 Feb 2021 19:23:55 +0200 Message-Id: <20210201172358.175407-22-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 Mon Feb 1 17:23: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: 12059557 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 CA930C433E6 for ; Mon, 1 Feb 2021 17:26:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6BACE64EA2 for ; Mon, 1 Feb 2021 17:26:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229692AbhBAR0Y (ORCPT ); Mon, 1 Feb 2021 12:26:24 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38552 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231237AbhBAR0X (ORCPT ); Mon, 1 Feb 2021 12:26:23 -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 072D8C061356 for ; Mon, 1 Feb 2021 09:24:37 -0800 (PST) Received: by mail-ed1-x52e.google.com with SMTP id s5so6909041edw.8 for ; Mon, 01 Feb 2021 09:24: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=1QPfhNFPjDfwoMV7LqQ1x36uAMlb+gpTxf62Yh6Roag=; b=rkK4wZIsJH11c2dbzRFDvhjyHoN++pfHghT3g7gyP/2IipqFhfKBV6fWzZUCoR/oXO dNB9TkQhmuPjwnuVFHCdR482BCtwo8LGXkKAwFK2W4MZtvd/NnW1Zw41EFZQAgs1Wm5O 1BdlzHexdYfd/wZ4ZzoXpbwpjh065D2xonBcYuPphOa2mSSMUoGTibLkrv7IAxMApRWI +t1BcxaArTwiPCPnlLv82SzPRM1X42uvZYProti/p4lxWu0O1aExg4plO0BZZt17W8VR Xkff2QYqyIXJO0r4yqb0ca0p74VIK5juPLpMwxMlWONo8fk3DuC6TXRlyeNRip2oHOIV vD5A== 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=1QPfhNFPjDfwoMV7LqQ1x36uAMlb+gpTxf62Yh6Roag=; b=dW4RiTGP2MXSz42TKSopSplrMK7kYyyjUECVTUPMb2sOd8cKQ4OOB/UTRNIZ1H6/Ii DVFeXuml2lpsZf5rtdAUOiLD4+M4fCgRTI5t2w/U1OhsmFUVEKyxBD91GDvi68yzREmO mWE+ISdF9fKSEjtehNMlFho7ewzFy+bByhebXvvwgvAGRxgfphqazh2xBr2jlJdd55Mm RJvp8fWT8gCrhQNehJZ+yiLDqUmc85UHwI2mdXGntaLysEdiptHP/mo8Ng1J+23cZLF+ OQmzPHZMCgOBKDnsLjArC8Fd6gi9Y7d61MdVaa3z+oFDdiwS9k1bt2R26/DOqv+RvO/g szqQ== X-Gm-Message-State: AOAM532rUCm3/2qrQ3Wi3eZ9A9JXdmxkvhzZTlulWpUil/gw2K1CqmgX wQVAAoA/e5DzeJCY779Mmgc= X-Google-Smtp-Source: ABdhPJxPAEMKYW2lH89RcKstBtBuONkNaCclZhyH6cJ++P8/hbzcFPRUCMvmMKid8Gje9dHv3qO/ww== X-Received: by 2002:a05:6402:60a:: with SMTP id n10mr19426427edv.230.1612200275251; Mon, 01 Feb 2021 09:24:35 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:34 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 22/24] kernel-shark: Update KsMainWindow and kernelshark.cpp Date: Mon, 1 Feb 2021 19:23:56 +0200 Message-Id: <20210201172358.175407-23-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 e4ef7ca..e760f99 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -74,7 +74,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND) 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) 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) 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 Mon Feb 1 17:23: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: 12059553 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 5F5B0C433E0 for ; Mon, 1 Feb 2021 17:26:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2F76B64EB8 for ; Mon, 1 Feb 2021 17:26:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231226AbhBAR0C (ORCPT ); Mon, 1 Feb 2021 12:26:02 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38384 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229513AbhBAR0A (ORCPT ); Mon, 1 Feb 2021 12:26:00 -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 69594C0612F2 for ; Mon, 1 Feb 2021 09:24:37 -0800 (PST) Received: by mail-ed1-x52a.google.com with SMTP id f1so19765075edr.12 for ; Mon, 01 Feb 2021 09:24: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=xLf3Fl+xWuftd2VYf59QnU3QGZ3YTVp1f0ELakLs+/c=; b=nOQehYBOS+SYlG30x9lUiOnqabPtEvrDxprifGf9w361xAqUxeLL0pNkuoKVa7nJxj 6nCrJYAxDd7APeDCQJYThSDBmRcA2O8p9vfRk2Is91Ke6Kyp7LK1SSx3yfZlKz83DsJ3 zS1O/VcXyf+M/06NNEQhUz6Tbq0hvGNB12jdAKkjuSDuMlANgbuBxz7QSpYWj66ynat3 EqV8j4aMgvqhTQ6SspWUFmPEb2XLOl5DR9zORQ5XM/UmtEXdsXuC/F8LRsKUI6ES+VNN RxsdQIkSy7mlvYgmZH0VLjOdtUMIeZUtkngJtJvKdcyRhzma2lEkExz73EWAOUpHVhWL pNXw== 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=xLf3Fl+xWuftd2VYf59QnU3QGZ3YTVp1f0ELakLs+/c=; b=DOwkd7erMLDR+mMMqAcS8X08V2Ux9CZAmsT+UthM+H3pT6tPvaqXVyILd/YETVQxqQ GThE9xfqjOXS1nv9QumKUmT2oNtSk7Yl2viZMvU0pJVeur+jSjAdlOPnh2an5/GqZDZt YR+eqd12gJc5ak++ajvO/EYXRJ5lFEfplFGm7UL/1ZMP5INQqUTcGiYobN/2w2w2xNyI aqCRkeNed7X8HmUA5TJLBMbhWtmE0BO/jOoL3cMl67t3Awdd4h4f1PuBVAm6Dh6nkSWI 1oRc8uRNfEcA+Lij2UWm0s9a0ImhTxOQqqcII2oZCUU6N61jnieofjf48AhM1C8PWgkC XJCQ== X-Gm-Message-State: AOAM531pw+LftQwRzR4MfCNH3emDQJt+djgGKPlhg9XsESQdQ5BSRS8Q LoV0iyUt4+LpGT5JuwmpTZk= X-Google-Smtp-Source: ABdhPJw/x8nAv0IB1v39Q/nHZxAeQCKb/XzPJXF8ZkLrQF8PxQc9tQShw0Pq2wjuMPTeSz1c3FJjcg== X-Received: by 2002:aa7:c64a:: with SMTP id z10mr6776667edr.61.1612200276180; Mon, 01 Feb 2021 09:24:36 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:35 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 23/24] kernel-shark: Clickable sched_event plugin shapes Date: Mon, 1 Feb 2021 19:23:57 +0200 Message-Id: <20210201172358.175407-24-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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 | 25 ++++++++++++++-- src/plugins/SchedEvents.cpp | 58 +++++++++++++++++++++++++++++++++++-- src/plugins/sched_events.c | 7 +++++ src/plugins/sched_events.h | 3 ++ 4 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index dc0c320..f8ecba6 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -17,9 +17,30 @@ 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) + +BUILD_GUI_PLUGIN(NAME sched_events + SOURCE sched_events.c SchedEvents.cpp) + list(APPEND PLUGIN_LIST "sched_events") BUILD_PLUGIN(NAME missed_events 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 Mon Feb 1 17:23: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: 12059559 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 F4016C433E0 for ; Mon, 1 Feb 2021 17:26:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B906B64EA9 for ; Mon, 1 Feb 2021 17:26:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231250AbhBAR00 (ORCPT ); Mon, 1 Feb 2021 12:26:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38564 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231233AbhBAR0Z (ORCPT ); Mon, 1 Feb 2021 12:26:25 -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 9DCEBC06121C for ; Mon, 1 Feb 2021 09:24:38 -0800 (PST) Received: by mail-ed1-x52a.google.com with SMTP id c6so19819290ede.0 for ; Mon, 01 Feb 2021 09:24: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=kR+y9XBolf2uKxjrop4eTTdx9fwxjJy7j/QO0D/zDdY=; b=h3khJBviu6ZkMOpn5mnf8iUtLdNK8+Ye3JHSx6dwme4eAV0M+iSRxaZHXyKSi/5P51 ilwedu9JZIantabwQB4KYcGThqzuyayRYNYRiuoag6wqehSkVoL0Q/WV9DYMXP3sNHVU XK0ZagmfKh1t31nhJXbFssWozdLFid62badM2TgB/dFZxcx2xzKMlPFAK0Hf8Z7xNuLz 0deYKaVgobXVCmrVfieMkvxBxRoCt4gaQ4Vr90QubUNIdJT452cpmXIgFUiwN862EjKH oZkbYO8O4JUi9R0Ni1L0ylHlLxYOd9z9C7Q2C9cV35txMPfx9+6Zt4vGLneYetc3kKQV eEuQ== 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=W7GsoIo5JZ07VsUHi5V1mi/lHn4C13hG7FX7+KzKCtYS3hr5wKDAb8Khj2Yv+QK06+ Xpqnm9fNS0JJCoUJakLIVQiLtIv1hSO8U8xNf8dWYmdYAj8DB7HmF3x3nYZCvkNNQJRR eFD/Go19MpIHlDQ1B6s5PfprwuRRHNfrb0Fd4mQhbFoPqrmswnzhB42yAEnwo0SN2TKg R/+SUVjoQYrnPIuLvJR6lNw0lar1kuGaADZtx/lfonIxgU5kWSP0hXbu4H3gn+o5YiKs dq8IlfctbfCuF8XwBYWDFv5mYLSy9aiALXGnxF4FkTXs2lg34CRiQMNn2Ncd3K1AFd4h 32uA== X-Gm-Message-State: AOAM530qy68qY25rCEJagANni2gjM1/jBpojYk59kwYywEUGQ01+zosq jvxcQTviNPfoHn4W154gVcw= X-Google-Smtp-Source: ABdhPJxbaqyeruVjuuSqC5DZbtm+gycHkneLWHc3Usw/lXGbmrd0dhFEYJtMKCcw2hyKPFpXBqChVQ== X-Received: by 2002:aa7:c0cd:: with SMTP id j13mr1016556edp.156.1612200277341; Mon, 01 Feb 2021 09:24:37 -0800 (PST) Received: from localhost.localdomain ([95.87.199.218]) by smtp.gmail.com with ESMTPSA id bm9sm8312446ejb.14.2021.02.01.09.24.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 09:24:36 -0800 (PST) From: "Yordan Karadzhov (VMware)" To: rostedt@goodmis.org Cc: linux-trace-devel@vger.kernel.org, "Yordan Karadzhov (VMware)" Subject: [PATCH 24/24] kernel-shark: Show Task plots from command lime Date: Mon, 1 Feb 2021 19:23:58 +0200 Message-Id: <20210201172358.175407-25-y.karadz@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210201172358.175407-1-y.karadz@gmail.com> References: <20210201172358.175407-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); +}