From nobody Sat Sep 26 01:41:49 2026 Received: from mail-yx1-f46.google.com (mail-yx1-f46.google.com [74.125.224.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 797C9357D0D for ; Sun, 6 Sep 2026 15:03:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.224.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788707008; cv=none; b=ft3TvyHAx4ue3g0rblwsjzckypvcNRP5Z1nGfZR4p3jMnnP7aOkGxAcOyW9tC/mFNIVqSQ+MkH2hbHdnb3ex58imLws1ZWkq1ihRENGRujcN2ROLpgNNizpTZculPE9pyn83jvhs9IkQKHxsUa8my9dX2grUjHniiJSfxH0ajPY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788707008; c=relaxed/simple; bh=Z7PKO0uaSi3+YwcyXkKpNz8qtogiRophxKIDJJanxgw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=RtLszwZZeF+mdof8x1N03Vi6Qbk9XOYXmuPvpR9qlOP65/wetEI+2Np1dpKMCJbqxjYLcQ94ZingpupdO3JFzdfTwiFcygXzGeIDnWvnpOxP0xzS/XHks+m30RqaItA1AlRcy0DjYS1jiIB4abyuC7j9zCM7XHEfU43mhqYyupg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=CSBKMwVK; arc=none smtp.client-ip=74.125.224.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CSBKMwVK" Received: by mail-yx1-f46.google.com with SMTP id 956f58d0204a3-66fc2844f0eso2506425d50.1 for ; Sun, 06 Sep 2026 08:03:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788707005; x=1789311805; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=gpeT1eGEPWoF1gyD0TtDkNs5OBBSnFYXVEXReqCmoiA=; b=CSBKMwVKna4GOLBa9VkZUNMyM6LIfLeNAV2A8/Lhz34Ca+C0az4laNyjxW4wwLZG8Q DrWN5/bCykwZThc6mVIx/c54pJ7efi0U1CI5fm+o2LaD4WvxYKm30HQj4bNB1qxAOwk+ uKOXE7A7U64Pm/x3ERZ7SHj8t2lKGZAFjbqyCUdBXBKYPYJGKeMjB0PA1b18TpiL5t+5 ndHqtduagpHvnehL5DdhzaoNVXQikQHKSg3KE2fP6qqm06icYQT0r7XAFjmVgdCQ4Dz7 skCP0POr7lA9r0u4fnPA0LPytopFDnWS4Hjz3P6H8Sl+A8NDb+Djrh3hVaIlY2UqKkZe M7fQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788707005; x=1789311805; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=gpeT1eGEPWoF1gyD0TtDkNs5OBBSnFYXVEXReqCmoiA=; b=qTDweVM8c10PQ1wEhSOei/ox+HdgqN6s0uX0H9m84gMKIi3oZvFYeEyTq9Yr9EV/4g DuTF2ISZhYNwa+V6DIBEtTmk/RsMi6nhjenGHF/wFvN8OtDWdi+nWCEBjhiZvhr/t/di I34/mYKjtduWsvmhoy+cC3fsc5BmHJUpWXELe/wz10zT4tw4v5Fmt4hrPIj84vJv0JSr FqbLI3SCVN+4cJWc35s6hHqGUrrrWkvieum0N0nV6KLtmlUTCMUy2VGxvB2mwhATj6oP EWkBDmPUOjDetIHPdMpRmP6XnefrJKieVzjvQW1GELOJ7qAmW5UrLHdZHlFZaI3m3kbe kZtQ== X-Gm-Message-State: AFuF++naQojRCEZamBhD+3otEQ92lAiBCkVgcGWyQVHVtys21BO7NSyu wzgJhg8A7hyFFpeCZ1Gyo3Pn1hLkPwni0KrKRvW5JB7QLxbb6GT/hvzL X-Gm-Gg: AYBFou2HAYqx1YH8dMo2HbEX+92KwZoT4htWCVSW1W4kx3EkCtedM9YmOQpJwGEHeKG +0Z2vL8Zold72vp5/jJjfuH/m+r54pygQPXCMmab/p8vDnNLg9heSzKGSiyxIIK4bkpjeHCWkdF eseG27YtyX8nNHbpn+dEhaQs2Dn/eRknn4zBlB40bN+xMEA1dhFrfxhJXVOezt4T1XvxNNxI3TP Tsogm+ro56Fom2TUEv/WAtJ5rn95EktI3O68WgAyfEH8qUVuL20thkDR8V/TDjeSgjDbkWuASA8 cq+1Ob2DSzfNdLiCdxX1SC+ATclUh0QhqSILsguWRctVYdkHYFg+adRymyXn8nYGjev0B/EbhJ/ QGdHDjp1Dx1XDu9hQYDlkTg1Bseip+onpScH48S6y3PusjOf/mI+tMQmy4vXxUFDS6hu95uG7Ow 9s3g6D2AmPkBURCzEWtCdtjDuMgSaGBkSJFGaZhQNy0tDLtY3aWoYOWlqPKmVEDA== X-Received: by 2002:a05:690c:385:b0:873:5c0f:287 with SMTP id 00721157ae682-8735c0f0402mr38568167b3.49.1788707000575; Sun, 06 Sep 2026 08:03:20 -0700 (PDT) Received: from localhost ([2600:1702:7a90:6f9f:8bc4:8aec:108d:7a04]) by smtp.gmail.com with ESMTPSA id 00721157ae682-8714af5581bsm56307877b3.36.2026.09.06.08.03.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 06 Sep 2026 08:03:19 -0700 (PDT) From: Matt Turner Date: Sun, 06 Sep 2026 11:03:15 -0400 Subject: [PATCH v2 1/2] tools: port perf ui from GTK 2 to GTK 4 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260906-perf-gtk2-v2-1-3eccff053cd1@gmail.com> References: <20260906-perf-gtk2-v2-0-3eccff053cd1@gmail.com> In-Reply-To: <20260906-perf-gtk2-v2-0-3eccff053cd1@gmail.com> To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark Cc: linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, Matt Turner X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=30060; i=mattst88@gmail.com; h=from:subject:message-id; bh=Z7PKO0uaSi3+YwcyXkKpNz8qtogiRophxKIDJJanxgw=; b=owGbwMvMwCW25rVmCc8sv+mMp9WSGLLmNmxm/yu9XkIv/ci5n4GOL64Ju1ieMLy0Un2V6ouOs 4/uc77N7/jIwiDGxTBTTJElbr0iy6y2HUt9Tkv/gpnDygQyRFqkgQEIWBj4chPzSo10jPRMtQ31 DIEMHaN4iJweg0ZmcXFpapFuWkGRQ15+SWJJZn5esV5+QWpeQXqBXlpmWklGRn5RcSrQCL281BJ TV0c3I0MDE0tHCzMnC0dTE2dnJ0MnN0dHZ1cnI0tzEwNnS0cTV0tzBi5OAZhr9skzMtw0Fk/+VL 7HYKMjU6/glGdFJV/jDI8pyk8WmZIdznndLZuR4VjkpfyX16cb/+FYrSx9fb3Vxz+u93nWaPxbN uOHkvhfF14A X-Developer-Key: i=mattst88@gmail.com; a=openpgp; fpr=3BB639E56F861FA2E86505690FDD682D974CA72A Port straight to GTK 4 rather than the intermediate GTK 3, since GTK 4 is where new development happens and GTK 3 is now old itself. GTK 4 removes GtkContainer, GdkScreen, and the gtk_main()/ gtk_dialog_run() family perf's GTK UI relied on, so this is more than a mechanical rename: containers get per-widget setters (gtk_box_append() and friends), monitor geometry comes from GdkMonitor instead of GdkScreen, and the main and error-dialog loops become explicit GMainLoops, quit from the "close-request" and "response" signals since gtk_main_quit() and gtk_dialog_run() no longer exist. Widgets are visible by default now too, so gtk_widget_show_all()/set_no_show_all() go away. gtk_ui_progress__finish() also skips destroying a progress dialog that was never created, since gtk_window_destroy() asserts on NULL/non-window where the old plain widget destroy tolerated it. Two spots the GTK 2 to GTK 3 port had missed (builtin-annotate.c, ui/gtk/setup.c still using HAVE_GTK2_SUPPORT and gtk_main_quit()) are fixed to match. A few runtime issues come with the new signal-driven loops: the error dialog's nested loop hung if the parent window closed (GTK_DIALOG_DESTROY_WITH_PARENT destroys the dialog without emitting "response") or a signal arrived while the dialog was open; gtk_info_bar_get_content_area() is gone in GTK 4, breaking the build with GTK_INFO_BAR_SUPPORT; the progress dialog's static widget pointers dangled after a manual close; and perf_gtk__error() and the warning functions reused an exhausted va_list when vasprintf() failed. Signed-off-by: Matt Turner --- tools/build/Makefile.feature | 5 +- tools/build/feature/Makefile | 12 ++--- .../{test-gtk2-infobar.c =3D> test-gtk4-infobar.c} | 4 +- tools/build/feature/{test-gtk2.c =3D> test-gtk4.c} | 4 +- tools/perf/Documentation/perf-report.txt | 2 +- tools/perf/Makefile | 2 +- tools/perf/Makefile.config | 22 ++++----- tools/perf/Makefile.perf | 6 +-- tools/perf/builtin-annotate.c | 8 ++-- tools/perf/builtin-report.c | 8 ++-- tools/perf/scripts/install-build-deps.sh | 4 +- tools/perf/tests/make | 4 +- tools/perf/ui/gtk/annotate.c | 28 +++++------ tools/perf/ui/gtk/browser.c | 54 +++++++++++++++++-= ---- tools/perf/ui/gtk/gtk.h | 3 ++ tools/perf/ui/gtk/hists.c | 32 +++++-------- tools/perf/ui/gtk/progress.c | 39 +++++++++++----- tools/perf/ui/gtk/setup.c | 5 +- tools/perf/ui/gtk/util.c | 52 ++++++++++++++++++= +-- tools/perf/ui/setup.c | 2 +- 20 files changed, 188 insertions(+), 108 deletions(-) diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 99eb0ea09537..7ffeb75a01c7 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -113,8 +113,8 @@ FEATURE_TESTS_EXTRA :=3D \ compile-x32 \ cplus-demangle \ cxa-demangle \ - gtk2 \ - gtk2-infobar \ + gtk4 \ + gtk4-infobar \ hello \ babeltrace2-ctf-writer \ libcapstone \ @@ -143,6 +143,7 @@ endif FEATURE_DISPLAY ?=3D \ libdw \ glibc \ + gtk4 \ libelf \ libnuma \ numa_num_possible_cpus \ diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index 7d165018116a..2ca992fbb9ad 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -11,8 +11,8 @@ FILES=3D \ test-eventfd.bin \ test-fortify-source.bin \ test-glibc.bin \ - test-gtk2.bin \ - test-gtk2-infobar.bin \ + test-gtk4.bin \ + test-gtk4-infobar.bin \ test-hello.bin \ test-libbfd.bin \ test-libbfd-threadsafe.bin \ @@ -240,11 +240,11 @@ $(OUTPUT)test-libcpupower.bin: $(OUTPUT)test-libtracefs.bin: $(BUILD) $(shell $(PKG_CONFIG) --cflags libtracefs 2>/dev/null) -ltracefs =20 -$(OUTPUT)test-gtk2.bin: - $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) -Wno= -deprecated-declarations +$(OUTPUT)test-gtk4.bin: + $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk4 2>/dev/null) =20 -$(OUTPUT)test-gtk2-infobar.bin: - $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) +$(OUTPUT)test-gtk4-infobar.bin: + $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk4 2>/dev/null) =20 grep-libs =3D $(filter -l%,$(1)) strip-libs =3D $(filter-out -l%,$(1)) diff --git a/tools/build/feature/test-gtk2-infobar.c b/tools/build/feature/= test-gtk4-infobar.c similarity index 77% rename from tools/build/feature/test-gtk2-infobar.c rename to tools/build/feature/test-gtk4-infobar.c index b1b716dd5733..6c1bcee595a9 100644 --- a/tools/build/feature/test-gtk2-infobar.c +++ b/tools/build/feature/test-gtk4-infobar.c @@ -3,9 +3,9 @@ #include #pragma GCC diagnostic error "-Wstrict-prototypes" =20 -int main(int argc, char *argv[]) +int main(void) { - gtk_init(&argc, &argv); + gtk_init(); gtk_info_bar_new(); =20 return 0; diff --git a/tools/build/feature/test-gtk2.c b/tools/build/feature/test-gtk= 4.c similarity index 76% rename from tools/build/feature/test-gtk2.c rename to tools/build/feature/test-gtk4.c index 2aaf4bfc2055..b9520e7408b9 100644 --- a/tools/build/feature/test-gtk2.c +++ b/tools/build/feature/test-gtk4.c @@ -3,9 +3,9 @@ #include #pragma GCC diagnostic error "-Wstrict-prototypes" =20 -int main(int argc, char *argv[]) +int main(void) { - gtk_init(&argc, &argv); + gtk_init(); =20 return 0; } diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Document= ation/perf-report.txt index 22f87eaa3279..7af9b3f81c06 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -351,7 +351,7 @@ OPTIONS requires a tty, if one is not present, as when piping to other commands, the stdio interface is used. =20 ---gtk:: Use the GTK2 interface. +--gtk:: Use the GTK4 interface. =20 -k:: --vmlinux=3D:: diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 5b713837eede..56014106479a 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -106,7 +106,7 @@ clean: # make -C tools/perf -f tests/make # build-test: - @$(MAKE) SHUF=3D1 -f tests/make REUSE_FEATURES_DUMP=3D1 MK=3DMakefile SET= _PARALLEL=3D1 --no-print-directory tarpkg make_static make_with_gtk2 out + @$(MAKE) SHUF=3D1 -f tests/make REUSE_FEATURES_DUMP=3D1 MK=3DMakefile SET= _PARALLEL=3D1 --no-print-directory tarpkg make_static make_with_gtk4 out =20 build-test-tarball: @$(MAKE) -f tests/make REUSE_FEATURES_DUMP=3D1 MK=3DMakefile SET_PARALLEL= =3D1 --no-print-directory out diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 4d5993da9f94..3ac1826a0cbe 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -774,20 +774,20 @@ ifndef NO_SLANG endif endif =20 -ifdef GTK2 - FLAGS_GTK2=3D$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell $(PKG_CONFIG) --lib= s --cflags gtk+-2.0 2>/dev/null) - $(call feature_check,gtk2) - ifneq ($(feature-gtk2), 1) - $(warning GTK2 not found, disables GTK2 support. Please install gtk2-d= evel or libgtk2.0-dev) - NO_GTK2 :=3D 1 +ifdef GTK4 + FLAGS_GTK4=3D$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell $(PKG_CONFIG) --lib= s --cflags gtk4 2>/dev/null) + $(call feature_check,gtk4) + ifneq ($(feature-gtk4), 1) + $(warning GTK4 not found, disables GTK4 support. Please install gtk4-d= evel or libgtk-4-dev) + NO_GTK4 :=3D 1 else - $(call feature_check,gtk2-infobar) - ifeq ($(feature-gtk2-infobar), 1) + $(call feature_check,gtk4-infobar) + ifeq ($(feature-gtk4-infobar), 1) GTK_CFLAGS :=3D -DHAVE_GTK_INFO_BAR_SUPPORT endif - CFLAGS +=3D -DHAVE_GTK2_SUPPORT - GTK_CFLAGS +=3D $(shell $(PKG_CONFIG) --cflags gtk+-2.0 2>/dev/null) - GTK_LIBS :=3D $(shell $(PKG_CONFIG) --libs gtk+-2.0 2>/dev/null) + CFLAGS +=3D -DHAVE_GTK4_SUPPORT + GTK_CFLAGS +=3D $(shell $(PKG_CONFIG) --cflags gtk4 2>/dev/null) + GTK_LIBS :=3D $(shell $(PKG_CONFIG) --libs gtk4 2>/dev/null) EXTLIBS +=3D -ldl endif endif diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 29cfd44c427f..2438b40eaaec 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -49,7 +49,7 @@ include ../scripts/utilities.mak # # Define NO_SLANG if you do not want TUI support. # -# Define GTK2 if you want GTK+ GUI support. +# Define GTK4 if you want GTK+ GUI support. # # Define NO_DEMANGLE if you do not want C++ symbol demangling. # @@ -473,7 +473,7 @@ ifneq ($(OUTPUT),) CFLAGS +=3D -I$(OUTPUT) endif =20 -ifdef GTK2 +ifdef GTK4 ALL_PROGRAMS +=3D $(OUTPUT)libperf-gtk.so GTK_IN :=3D $(OUTPUT)gtk-in.o endif @@ -811,7 +811,7 @@ check: prepare =20 ### Installation rules =20 -ifdef GTK2 +ifdef GTK4 install-gtk: $(OUTPUT)libperf-gtk.so $(call QUIET_INSTALL, 'GTK UI') \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(libdir_SQ)'; \ diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 69cb72b2082a..15163e081a8c 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -52,7 +52,7 @@ struct perf_annotate { bool use_tui; #endif bool use_stdio, use_stdio2; -#ifdef HAVE_GTK2_SUPPORT +#ifdef HAVE_GTK4_SUPPORT bool use_gtk; #endif bool skip_missing; @@ -712,7 +712,7 @@ int cmd_annotate(int argc, const char **argv) OPT_BOOLEAN('q', "quiet", &quiet, "do now show any warnings or messages"), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), -#ifdef HAVE_GTK2_SUPPORT +#ifdef HAVE_GTK4_SUPPORT OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"), #endif #ifdef HAVE_SLANG_SUPPORT @@ -828,7 +828,7 @@ int cmd_annotate(int argc, const char **argv) if (annotate_check_args() < 0) return -EINVAL; =20 -#ifdef HAVE_GTK2_SUPPORT +#ifdef HAVE_GTK4_SUPPORT if (symbol_conf.show_nr_samples && annotate.use_gtk) { pr_err("--show-nr-samples is not available in --gtk mode at this time\n"= ); return ret; @@ -898,7 +898,7 @@ int cmd_annotate(int argc, const char **argv) else if (annotate.use_tui) use_browser =3D 1; #endif -#ifdef HAVE_GTK2_SUPPORT +#ifdef HAVE_GTK4_SUPPORT else if (annotate.use_gtk) use_browser =3D 2; #endif diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 60d1f166629e..d14384c58466 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -82,7 +82,7 @@ struct report { #ifdef HAVE_SLANG_SUPPORT bool use_tui; #endif -#ifdef HAVE_GTK2_SUPPORT +#ifdef HAVE_GTK4_SUPPORT bool use_gtk; #endif bool use_stdio; @@ -1359,8 +1359,8 @@ int cmd_report(int argc, const char **argv) #ifdef HAVE_SLANG_SUPPORT OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"), #endif -#ifdef HAVE_GTK2_SUPPORT - OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"), +#ifdef HAVE_GTK4_SUPPORT + OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK4 interface"), #endif OPT_BOOLEAN(0, "stdio", &report.use_stdio, "Use the stdio interface"), @@ -1710,7 +1710,7 @@ int cmd_report(int argc, const char **argv) else if (report.use_tui) use_browser =3D 1; #endif -#ifdef HAVE_GTK2_SUPPORT +#ifdef HAVE_GTK4_SUPPORT else if (report.use_gtk) use_browser =3D 2; #endif diff --git a/tools/perf/scripts/install-build-deps.sh b/tools/perf/scripts/= install-build-deps.sh index d003e7fab2be..a601a5260c17 100755 --- a/tools/perf/scripts/install-build-deps.sh +++ b/tools/perf/scripts/install-build-deps.sh @@ -199,8 +199,8 @@ fedora_pkg_for() { # opt-in features, which a default build does not enable: the libbfd # disassembler family (libbfd, libbfd-threadsafe, libbfd-liberty, # disassembler-*, cplus-demangle), only linked on BUILD_NONDISTRO - # builds and deprecated in favor of capstone, GTK2, LIBPERL and - # LIBUNWIND support (ifdef GTK2 / ifdef LIBPERL / LIBUNWIND=3D1), + # builds and deprecated in favor of capstone, GTK4, LIBPERL and + # LIBUNWIND support (ifdef GTK4 / ifdef LIBPERL / LIBUNWIND=3D1), # and CoreSight (ifdef CORESIGHT), are deliberately not mapped. # libaio is not mapped either: its # test uses the POSIX AIO API (aio.h, aio_*, -lrt), provided by diff --git a/tools/perf/tests/make b/tools/perf/tests/make index d2c2f526e1db..202ab5501916 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -95,7 +95,7 @@ make_no_babeltrace2 :=3D NO_BABELTRACE2=3D1 make_with_coresight :=3D CORESIGHT=3D1 make_no_sdt :=3D NO_SDT=3D1 make_no_libpfm4 :=3D NO_LIBPFM4=3D1 -make_with_gtk2 :=3D GTK2=3D1 +make_with_gtk4 :=3D GTK4=3D1 make_refcnt_check :=3D EXTRA_CFLAGS=3D"-DREFCNT_CHECKING=3D1" make_tags :=3D tags make_cscope :=3D cscope @@ -318,7 +318,7 @@ $(run): $(call test,$@) && \ rm -rf $@ $$TMP_DEST || (cat $@ ; false) =20 -make_with_gtk2: +make_with_gtk4: $(call clean) @TMP_DEST=3D$$(mktemp -d); \ cmd=3D"cd $(PERF) && $(MAKE_F) $($@) $(PARALLEL_OPT) $(O_OPT) DESTDIR=3D$= $TMP_DEST"; \ diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index 8920e298420a..fc46ac150408 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -161,7 +161,7 @@ static int perf_gtk__annotate_symbol(GtkWidget *window,= struct map_symbol *ms, gtk_list_store_set(store, &iter, ANN_COL__LINE, s, -1); } =20 - gtk_container_add(GTK_CONTAINER(window), view); + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(window), view); =20 list_for_each_entry_safe(pos, n, ¬es->src->source, al.node) { list_del_init(&pos->al.node); @@ -211,34 +211,31 @@ static int symbol__gtk_annotate(struct map_symbol *ms= , struct evsel *evsel, signal(SIGQUIT, perf_gtk__signal); signal(SIGTERM, perf_gtk__signal); =20 - window =3D gtk_window_new(GTK_WINDOW_TOPLEVEL); + window =3D gtk_window_new(); gtk_window_set_title(GTK_WINDOW(window), "perf annotate"); =20 - g_signal_connect(window, "delete_event", gtk_main_quit, NULL); - pgctx =3D perf_gtk__activate_context(window); if (!pgctx) return -1; =20 - vbox =3D gtk_vbox_new(FALSE, 0); + vbox =3D gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); notebook =3D gtk_notebook_new(); pgctx->notebook =3D notebook; =20 - gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); + gtk_widget_set_vexpand(notebook, TRUE); + gtk_box_append(GTK_BOX(vbox), notebook); =20 infobar =3D perf_gtk__setup_info_bar(); - if (infobar) { - gtk_box_pack_start(GTK_BOX(vbox), infobar, - FALSE, FALSE, 0); - } + if (infobar) + gtk_box_append(GTK_BOX(vbox), infobar); =20 statbar =3D perf_gtk__setup_statusbar(); - gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); + gtk_box_append(GTK_BOX(vbox), statbar); =20 - gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_window_set_child(GTK_WINDOW(window), vbox); } =20 - scrolled_window =3D gtk_scrolled_window_new(NULL, NULL); + scrolled_window =3D gtk_scrolled_window_new(); tab_label =3D gtk_label_new(sym->name); =20 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), @@ -267,12 +264,11 @@ void perf_gtk__show_annotations(void) return; =20 window =3D pgctx->main_window; - gtk_widget_show_all(window); =20 perf_gtk__resize_window(window); - gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); + gtk_widget_set_visible(window, TRUE); =20 - gtk_main(); + perf_gtk__run_main_loop(window); =20 perf_gtk__deactivate_context(&pgctx); } diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c index d2dadf3873fb..99bb0ea76d77 100644 --- a/tools/perf/ui/gtk/browser.c +++ b/tools/perf/ui/gtk/browser.c @@ -16,21 +16,53 @@ void perf_gtk__signal(int sig) void perf_gtk__resize_window(GtkWidget *window) { GdkRectangle rect; - GdkScreen *screen; - int monitor; + GdkMonitor *monitor; + GdkDisplay *display; + GListModel *monitors; int height; int width; =20 - screen =3D gtk_widget_get_screen(window); + display =3D gtk_widget_get_display(window); + monitors =3D gdk_display_get_monitors(display); + monitor =3D g_list_model_get_item(monitors, 0); + if (!monitor) { + gtk_window_set_default_size(GTK_WINDOW(window), 800, 600); + return; + } =20 - monitor =3D gdk_screen_get_monitor_at_window(screen, window->window); - - gdk_screen_get_monitor_geometry(screen, monitor, &rect); + gdk_monitor_get_geometry(monitor, &rect); + g_object_unref(monitor); =20 width =3D rect.width * 3 / 4; height =3D rect.height * 3 / 4; =20 - gtk_window_resize(GTK_WINDOW(window), width, height); + gtk_window_set_default_size(GTK_WINDOW(window), width, height); +} + +static GMainLoop *perf_gtk__main_loop; + +void perf_gtk__quit_main_loop(void) +{ + if (perf_gtk__main_loop) + g_main_loop_quit(perf_gtk__main_loop); +} + +static gboolean perf_gtk__close_request(GtkWidget *widget __maybe_unused, + gpointer data __maybe_unused) +{ + perf_gtk__quit_main_loop(); + + return FALSE; +} + +void perf_gtk__run_main_loop(GtkWidget *window) +{ + g_signal_connect(window, "close-request", + G_CALLBACK(perf_gtk__close_request), NULL); + + perf_gtk__main_loop =3D g_main_loop_new(NULL, FALSE); + g_main_loop_run(perf_gtk__main_loop); + g_clear_pointer(&perf_gtk__main_loop, g_main_loop_unref); } =20 const char *perf_gtk__get_percent_color(double percent) @@ -47,18 +79,16 @@ GtkWidget *perf_gtk__setup_info_bar(void) { GtkWidget *info_bar; GtkWidget *label; - GtkWidget *content_area; =20 info_bar =3D gtk_info_bar_new(); - gtk_widget_set_no_show_all(info_bar, TRUE); + gtk_widget_set_visible(info_bar, FALSE); =20 label =3D gtk_label_new(""); gtk_widget_show(label); =20 - content_area =3D gtk_info_bar_get_content_area(GTK_INFO_BAR(info_bar)); - gtk_container_add(GTK_CONTAINER(content_area), label); + gtk_info_bar_add_child(GTK_INFO_BAR(info_bar), label); =20 - gtk_info_bar_add_button(GTK_INFO_BAR(info_bar), GTK_STOCK_OK, + gtk_info_bar_add_button(GTK_INFO_BAR(info_bar), "_OK", GTK_RESPONSE_OK); g_signal_connect(info_bar, "response", G_CALLBACK(gtk_widget_hide), NULL); diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h index a2b497f03fd6..beea75d01955 100644 --- a/tools/perf/ui/gtk/gtk.h +++ b/tools/perf/ui/gtk/gtk.h @@ -40,6 +40,9 @@ void perf_gtk__init_hpp(void); =20 void perf_gtk__signal(int sig); void perf_gtk__resize_window(GtkWidget *window); +void perf_gtk__run_main_loop(GtkWidget *window); +void perf_gtk__quit_main_loop(void); +void perf_gtk__quit_error_dialog(void); const char *perf_gtk__get_percent_color(double percent); GtkWidget *perf_gtk__setup_statusbar(void); =20 diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index bae21f336ae6..f0053e3af077 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -395,11 +395,9 @@ static void perf_gtk__show_hists(GtkWidget *window, st= ruct hists *hists, } } =20 - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE); - g_signal_connect(view, "row-activated", G_CALLBACK(on_row_activated), NULL); - gtk_container_add(GTK_CONTAINER(window), view); + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(window), view); } =20 static void perf_gtk__add_hierarchy_entries(struct hists *hists, @@ -583,11 +581,9 @@ static void perf_gtk__show_hierarchy(GtkWidget *window= , struct hists *hists, perf_gtk__add_hierarchy_entries(hists, &hists->entries, store, NULL, &hpp, min_pcnt); =20 - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE); - g_signal_connect(view, "row-activated", G_CALLBACK(on_row_activated), NULL); - gtk_container_add(GTK_CONTAINER(window), view); + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(window), view); } =20 int evlist__gtk_browse_hists(struct evlist *evlist, const char *help, @@ -606,30 +602,29 @@ int evlist__gtk_browse_hists(struct evlist *evlist, c= onst char *help, signal(SIGQUIT, perf_gtk__signal); signal(SIGTERM, perf_gtk__signal); =20 - window =3D gtk_window_new(GTK_WINDOW_TOPLEVEL); + window =3D gtk_window_new(); =20 gtk_window_set_title(GTK_WINDOW(window), "perf report"); =20 - g_signal_connect(window, "delete_event", gtk_main_quit, NULL); - pgctx =3D perf_gtk__activate_context(window); if (!pgctx) return -1; =20 - vbox =3D gtk_vbox_new(FALSE, 0); + vbox =3D gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); =20 notebook =3D gtk_notebook_new(); =20 - gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); + gtk_widget_set_vexpand(notebook, TRUE); + gtk_box_append(GTK_BOX(vbox), notebook); =20 info_bar =3D perf_gtk__setup_info_bar(); if (info_bar) - gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0); + gtk_box_append(GTK_BOX(vbox), info_bar); =20 statbar =3D perf_gtk__setup_statusbar(); - gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); + gtk_box_append(GTK_BOX(vbox), statbar); =20 - gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_window_set_child(GTK_WINDOW(window), vbox); =20 evlist__for_each_entry(evlist, pos) { struct hists *hists =3D evsel__hists(pos); @@ -649,7 +644,7 @@ int evlist__gtk_browse_hists(struct evlist *evlist, con= st char *help, } } =20 - scrolled_window =3D gtk_scrolled_window_new(NULL, NULL); + scrolled_window =3D gtk_scrolled_window_new(); =20 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, @@ -665,15 +660,12 @@ int evlist__gtk_browse_hists(struct evlist *evlist, c= onst char *help, gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_la= bel); } =20 - gtk_widget_show_all(window); - perf_gtk__resize_window(window); - - gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); + gtk_widget_set_visible(window, TRUE); =20 ui_helpline__push(help); =20 - gtk_main(); + perf_gtk__run_main_loop(window); =20 perf_gtk__deactivate_context(&pgctx); =20 diff --git a/tools/perf/ui/gtk/progress.c b/tools/perf/ui/gtk/progress.c index eea6fcde518a..28a4b486360d 100644 --- a/tools/perf/ui/gtk/progress.c +++ b/tools/perf/ui/gtk/progress.c @@ -3,47 +3,62 @@ =20 #include "gtk.h" #include "../progress.h" +#include =20 static GtkWidget *dialog; static GtkWidget *progress; =20 +static void gtk_ui_progress__destroyed(GtkWidget *widget __maybe_unused, + gpointer data __maybe_unused) +{ + dialog =3D NULL; + progress =3D NULL; +} + static void gtk_ui_progress__update(struct ui_progress *p) { double fraction =3D p->total ? 1.0 * p->curr / p->total : 0.0; char buf[1024]; =20 if (dialog =3D=3D NULL) { - GtkWidget *vbox =3D gtk_vbox_new(TRUE, 5); + GtkWidget *vbox =3D gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); GtkWidget *label =3D gtk_label_new(p->title); =20 - dialog =3D gtk_window_new(GTK_WINDOW_TOPLEVEL); + dialog =3D gtk_window_new(); progress =3D gtk_progress_bar_new(); =20 - gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, FALSE, 3); - gtk_box_pack_start(GTK_BOX(vbox), progress, TRUE, TRUE, 3); + gtk_widget_set_vexpand(label, TRUE); + gtk_box_append(GTK_BOX(vbox), label); + gtk_widget_set_vexpand(progress, TRUE); + gtk_box_append(GTK_BOX(vbox), progress); =20 - gtk_container_add(GTK_CONTAINER(dialog), vbox); + gtk_window_set_child(GTK_WINDOW(dialog), vbox); + + g_signal_connect(dialog, "destroy", + G_CALLBACK(gtk_ui_progress__destroyed), NULL); =20 gtk_window_set_title(GTK_WINDOW(dialog), "perf"); - gtk_window_resize(GTK_WINDOW(dialog), 300, 80); - gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); + gtk_window_set_default_size(GTK_WINDOW(dialog), 300, 80); =20 - gtk_widget_show_all(dialog); + gtk_widget_set_visible(dialog, TRUE); } =20 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), fraction); snprintf(buf, sizeof(buf), "%"PRIu64" / %"PRIu64, p->curr, p->total); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), buf); =20 - /* we didn't call gtk_main yet, so do it manually */ - while (gtk_events_pending()) - gtk_main_iteration(); + /* we didn't start a main loop yet, so pump events manually */ + while (g_main_context_pending(NULL)) + g_main_context_iteration(NULL, FALSE); } =20 static void gtk_ui_progress__finish(void) { + if (dialog =3D=3D NULL) + return; + /* this will also destroy all of its children */ - gtk_widget_destroy(dialog); + gtk_window_destroy(GTK_WINDOW(dialog)); =20 dialog =3D NULL; } diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c index f5eee4d66873..9b44f3719747 100644 --- a/tools/perf/ui/gtk/setup.c +++ b/tools/perf/ui/gtk/setup.c @@ -12,7 +12,7 @@ int perf_gtk__init(void) gtk_ui_progress__init(); perf_gtk__init_hpp(); =20 - return gtk_init_check(NULL, NULL) ? 0 : -1; + return gtk_init_check() ? 0 : -1; } =20 void perf_gtk__exit(bool wait_for_ok __maybe_unused) @@ -20,5 +20,6 @@ void perf_gtk__exit(bool wait_for_ok __maybe_unused) if (!perf_gtk__is_active_context(pgctx)) return; perf_error__unregister(&perf_gtk_eops); - gtk_main_quit(); + perf_gtk__quit_error_dialog(); + perf_gtk__quit_main_loop(); } diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c index c47f5c387838..5096888b7c16 100644 --- a/tools/perf/ui/gtk/util.c +++ b/tools/perf/ui/gtk/util.c @@ -4,6 +4,7 @@ =20 #include #include +#include #include =20 struct perf_gtk_context *pgctx; @@ -28,27 +29,60 @@ int perf_gtk__deactivate_context(struct perf_gtk_contex= t **ctx) return 0; } =20 +static GMainLoop *perf_gtk__error_loop; + +void perf_gtk__quit_error_dialog(void) +{ + if (perf_gtk__error_loop) + g_main_loop_quit(perf_gtk__error_loop); +} + +static void perf_gtk__dialog_response(GtkDialog *dialog, + gint response_id __maybe_unused, + gpointer data __maybe_unused) +{ + gtk_window_destroy(GTK_WINDOW(dialog)); +} + static int perf_gtk__error(const char *format, va_list args) { char *msg; GtkWidget *dialog; + va_list args_copy; =20 + va_copy(args_copy, args); if (!perf_gtk__is_active_context(pgctx) || - vasprintf(&msg, format, args) < 0) { + vasprintf(&msg, format, args_copy) < 0) { + va_end(args_copy); fprintf(stderr, "Error:\n"); vfprintf(stderr, format, args); fprintf(stderr, "\n"); return -1; } + va_end(args_copy); =20 dialog =3D gtk_message_dialog_new_with_markup(GTK_WINDOW(pgctx->main_wind= ow), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Error\n\n%s", msg); - gtk_dialog_run(GTK_DIALOG(dialog)); =20 - gtk_widget_destroy(dialog); + /* + * "response" only fires when a button is clicked; DESTROY_WITH_PARENT + * destroys the dialog directly without it. Quit from "destroy" + * instead, which fires either way, so the nested loop below can't + * outlive the dialog and hang. + */ + perf_gtk__error_loop =3D g_main_loop_new(NULL, FALSE); + g_signal_connect(dialog, "response", + G_CALLBACK(perf_gtk__dialog_response), NULL); + g_signal_connect_swapped(dialog, "destroy", + G_CALLBACK(g_main_loop_quit), perf_gtk__error_loop); + + gtk_widget_set_visible(dialog, TRUE); + g_main_loop_run(perf_gtk__error_loop); + g_clear_pointer(&perf_gtk__error_loop, g_main_loop_unref); + free(msg); return 0; } @@ -57,14 +91,18 @@ static int perf_gtk__error(const char *format, va_list = args) static int perf_gtk__warning_info_bar(const char *format, va_list args) { char *msg; + va_list args_copy; =20 + va_copy(args_copy, args); if (!perf_gtk__is_active_context(pgctx) || - vasprintf(&msg, format, args) < 0) { + vasprintf(&msg, format, args_copy) < 0) { + va_end(args_copy); fprintf(stderr, "Warning:\n"); vfprintf(stderr, format, args); fprintf(stderr, "\n"); return -1; } + va_end(args_copy); =20 gtk_label_set_text(GTK_LABEL(pgctx->message_label), msg); gtk_info_bar_set_message_type(GTK_INFO_BAR(pgctx->info_bar), @@ -78,14 +116,18 @@ static int perf_gtk__warning_info_bar(const char *form= at, va_list args) static int perf_gtk__warning_statusbar(const char *format, va_list args) { char *msg, *p; + va_list args_copy; =20 + va_copy(args_copy, args); if (!perf_gtk__is_active_context(pgctx) || - vasprintf(&msg, format, args) < 0) { + vasprintf(&msg, format, args_copy) < 0) { + va_end(args_copy); fprintf(stderr, "Warning:\n"); vfprintf(stderr, format, args); fprintf(stderr, "\n"); return -1; } + va_end(args_copy); =20 gtk_statusbar_pop(GTK_STATUSBAR(pgctx->statbar), pgctx->statbar_ctx_id); diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index ff800047e697..d887346c7a63 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c @@ -14,7 +14,7 @@ int use_browser =3D -1; =20 #define PERF_GTK_DSO "libperf-gtk.so" =20 -#ifdef HAVE_GTK2_SUPPORT +#ifdef HAVE_GTK4_SUPPORT =20 static int setup_gtk_browser(void) { --=20 2.54.0 From nobody Sat Sep 26 01:41:49 2026 Received: from mail-yw1-f177.google.com (mail-yw1-f177.google.com [209.85.128.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B186736197A for ; Sun, 6 Sep 2026 15:03:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788707006; cv=none; b=YtfgB9Tc87pUmDdKqeZEMXfJGB7f45C6yWeZqcumSfZIiFvf6qGBmpw1hUp1xzvwtpXS/1NzUeqtCmao38Z7je+mirkW7zL5gwbW9QfR9DBiEpci0AKtl65c+cyYYy82z4a0FZqhMzACzC31HwPUEj6n39/FhWuBSrYYFVdTwqk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788707006; c=relaxed/simple; bh=AtjIi/QZTnf1hHLWLicIpAQjJaCCIdq8cq3hjX7SlN8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=B3q991dCBZSS+tq50C9Atb+sCzewtjRSBxHI7dZAT6SIt2bXQFqcQ6m8rKFeuEllqEkuZw0GBIZgRuys+OxiNVUJf++J7Gi8ql1zG4kiZyz3DvvfwjU8Y4x/vbSnQ+Iby5wYxiYs+l9EqxSyXji83D8cLJe9+3L2svMTcLxn9uI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Iwe5Uz5B; arc=none smtp.client-ip=209.85.128.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Iwe5Uz5B" Received: by mail-yw1-f177.google.com with SMTP id 00721157ae682-8565d77c277so32148217b3.0 for ; Sun, 06 Sep 2026 08:03:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788707003; x=1789311803; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=3GdZ76vBLFidffsN6N8xpDuSJHdSB1mCV3ORADvgs3Q=; b=Iwe5Uz5BM8fnFXLUMrNlO5ZZVf2SFdR/un78I0EVP8XERNlAWOES5fH/ibVMCagiLp kbXCw+YB/ezXEfIINNmsD9ticNc2MEMxQqw6DPQoZHTzXo/c3hZnYyNHvRbjRs5fPeOW iCxG2U1ymXRPTAXsBZ8PmzhQB2gC08vvFxjf4KBVEz0HcKcp7Q4avzO9D7GmSfqFbPTj YQW45PWKuwA0D/gKXzUO5X6ujb0KJhCzHffZ4lCuJqGWC7W5MWHz4aQvRQzC8PSrXRc9 r2LffQD1AfOTqdlJ2RVsdR0eK256ajFy2/i5HkQ396NVxx1aA7OFaxDA46u8IQjpl9xI iIug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788707003; x=1789311803; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=3GdZ76vBLFidffsN6N8xpDuSJHdSB1mCV3ORADvgs3Q=; b=tY7Q8AtNIh8sbdvyg8PQS7EwR0MsvyeaPEHgW0VnbYSUu9RgzBOGn1DIpgxhQveKvM sbLC26AUp4vBRI6YHL28UDBWjOkkp7Zgl94kG8iHayszSH99Z/QL7ZKSSHhgB+b4V6t7 lpDyCpgY4JXPaWSGgAGiyUmHJ8OfldBFRxIKzniaGxSPICtxBy9Z2K1uHl48I68Uy7Gv yVCS57hQQ1RnSKU7rxlc8pz7A64G0SeAsriOxMj0igve2uc6+woSDXVtclJqh6LVvXhm M2Px8JQIjBsiL7BM0upKzEdJZjp7Fo9xsHLPR1hyiw55gu/B2ee6zet0PN2CJuqD7FaY Hggw== X-Gm-Message-State: AFuF++m8yL/qAMKUPk7TMkSnGs53StPzMbBRLHhT2iyT+mvmgq1024gW DqArPqpR/pHkiprK3fNVmcRe3h4EbhW2ON4ihbmJI6mR5I38x1dB8WP5 X-Gm-Gg: AYBFou2UypxPcEPUjYO6FoDhATKJ3R20IzJInkdKTtMAnlb9F2Cj0jv96+fTlN9KMP9 r1PKUHIOs4PcC4t/cqpDLrSYoY7zvNEmlxAQyo7TJoXBr59C2ECufnhwioUGkmANc6ghkXish6B Jr4OlGMxeSVWlEK9W0stZNb8rpJDjhUAAukDhaDb8n42BxxqmZKBlYrfo4dohPe4EeM7OIJWVIg KZOPUd5gJ70hb+zFVpjatF+ufX4NQGeB6HcLNbdrw/HSV40C3cV3H1MzgEpegXA1WGL0e0VNJ5a 6GNJ2EMW/MLvvLs6H3hfUxa5z74nQ7l78FVcCi2cFMmLad+dM/lmHESYqK4vlNEdj4e9L4iWAc3 T1XNjDRnOu85dUnT2DAggH6uaTZFVEsrvKXGwK5YtqdWPCTj+tuxZbkMTfBFwzrirRgUxhBMrue S6M2ljADeE3F45qN/z338p9oEtyML/UfDUxGzA5CQz4WFhdJNGL4BW1zlGrZJV X-Received: by 2002:a05:690c:620f:b0:841:773e:8d86 with SMTP id 00721157ae682-871232363dfmr67600267b3.15.1788707002419; Sun, 06 Sep 2026 08:03:22 -0700 (PDT) Received: from localhost ([2600:1702:7a90:6f9f:8bc4:8aec:108d:7a04]) by smtp.gmail.com with ESMTPSA id 00721157ae682-871439c54e4sm56655697b3.6.2026.09.06.08.03.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 06 Sep 2026 08:03:21 -0700 (PDT) From: Matt Turner Date: Sun, 06 Sep 2026 11:03:16 -0400 Subject: [PATCH v2 2/2] perf tools: make the GTK4 report browser actually loadable at runtime Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260906-perf-gtk2-v2-2-3eccff053cd1@gmail.com> References: <20260906-perf-gtk2-v2-0-3eccff053cd1@gmail.com> In-Reply-To: <20260906-perf-gtk2-v2-0-3eccff053cd1@gmail.com> To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark Cc: linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, Matt Turner X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=4031; i=mattst88@gmail.com; h=from:subject:message-id; bh=AtjIi/QZTnf1hHLWLicIpAQjJaCCIdq8cq3hjX7SlN8=; b=owGbwMvMwCW25rVmCc8sv+mMp9WSGLLmNmwOeGalsTZw6SeVTV6JCdzx0v/atneFh1xkDZrvX 7pl16rdHR9ZGMS4GGaKKbLErVdkmdW2Y6nPaelfMHNYmUCGSIs0MAABCwNfbmJeqZGOkZ6ptqGe IZChYxQPkdNj0MgsLi5NLdJNKyhyyMsvSSzJzM8r1ssvSM0rSC/QS8tMK8nIyC8qTgUaoZeXWmL q6uhmZGhgYuloYeZk4Whq4uzsZOjk5ujo7OpkZGluYuBs6WjiamnOwMUpAHPNEnlGhtVv8w7acf JoTnd7JHAjk2Xtj2tPnDd8C5yk1Cr/5k8k7yeG/9FmTr5zrq9pyA8RzHMKW9Px+E3ZXMvj55/yJ 142PqYtxwkA X-Developer-Key: i=mattst88@gmail.com; a=openpgp; fpr=3BB639E56F861FA2E86505690FDD682D974CA72A perf report --gtk dlopen()s libperf-gtk.so and expects it to resolve symbols back against the running perf binary (callchain_param, symbol_conf, evsel__name, and friends all live in perf itself, not in the plugin). Two things stood in the way of that after the GTK 2 to GTK 4 port: perf never passed -rdynamic, so none of its own symbols were in its dynamic symbol table for a dlopen()ed plugin to find at all. Add -rdynamic to LDFLAGS when GTK4 support is enabled. annotated_source__hist_entry() was a static inline in annotate.h, so ui/gtk/annotate.c calling it pulled hashmap__find()'s expansion, hashmap_find(), directly into libperf-gtk.so as an undefined symbol. The only hashmap_find perf links against in the common case is libbpf's internal one (tools/lib/bpf/hashmap.c), which libbpf compiles with -fvisibility=3Dhidden; a hidden symbol can never be exported to a dlopen()ed plugin no matter what LDFLAGS perf itself gets. Move annotated_source__hist_entry() out of the header and into annotate.c, as an ordinary exported function, so the plugin depends on it the same way it already depends on evsel__group_desc() and friends, instead of reaching for hashmap_find directly. With both fixes, a default 'make GTK4=3D1' build (libbpf statically linked, as usual) can dlopen() libperf-gtk.so and open the report browser without needing NO_LIBBPF=3D1 or manual LDFLAGS. Verified with perf report --gtk against a real perf.data on an actual GTK4 desktop session. Signed-off-by: Matt Turner --- tools/perf/Makefile.config | 5 +++++ tools/perf/util/annotate.c | 11 +++++++++++ tools/perf/util/annotate.h | 12 ++---------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 3ac1826a0cbe..ef7419a5b013 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -789,6 +789,11 @@ ifdef GTK4 GTK_CFLAGS +=3D $(shell $(PKG_CONFIG) --cflags gtk4 2>/dev/null) GTK_LIBS :=3D $(shell $(PKG_CONFIG) --libs gtk4 2>/dev/null) EXTLIBS +=3D -ldl + # libperf-gtk.so is dlopen()ed at runtime and calls back into + # symbols defined in the perf binary itself (callchain_param, + # symbol_conf, evsel__name, ...): perf needs to export those + # dynamically for the plugin to resolve them. + LDFLAGS +=3D -rdynamic endif endif =20 diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index df70e95a8470..123b6d5fcea7 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -145,6 +145,17 @@ static int annotated_source__alloc_histograms(struct a= nnotated_source *src, return src->histograms ? 0 : -1; } =20 +struct sym_hist_entry * +annotated_source__hist_entry(struct annotated_source *src, const struct ev= sel *evsel, u64 offset) +{ + struct sym_hist_entry *entry; + long key =3D offset << 16 | evsel->core.idx; + + if (!hashmap__find(src->samples, key, &entry)) + return NULL; + return entry; +} + void symbol__annotate_zero_histograms(struct symbol *sym) { struct annotation *notes =3D symbol__annotation(sym); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index fa08d09b80f7..40038a3779d4 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -406,16 +406,8 @@ static inline struct sym_hist *annotation__histogram(s= truct annotation *notes, return annotated_source__histogram(notes->src, evsel); } =20 -static inline struct sym_hist_entry * -annotated_source__hist_entry(struct annotated_source *src, const struct ev= sel *evsel, u64 offset) -{ - struct sym_hist_entry *entry; - long key =3D offset << 16 | evsel->core.idx; - - if (!hashmap__find(src->samples, key, &entry)) - return NULL; - return entry; -} +struct sym_hist_entry * +annotated_source__hist_entry(struct annotated_source *src, const struct ev= sel *evsel, u64 offset); =20 static inline struct annotation *symbol__annotation(struct symbol *sym) { --=20 2.54.0