From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pg1-f198.google.com (mail-pg1-f198.google.com [209.85.215.198]) (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 1E7EE5013D6 for ; Wed, 16 Sep 2026 23:47:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.198 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789602444; cv=none; b=gcG75aQowtSQB/V10Wr/DayUbIIFRVIYZSHENAcEKbToX/c3VeMRY3HIR9z6c9iCuW74WwXxsvqdTaDthhbJE5AymTvycVpRZk8NkZ3lbjHLVgPrInXei3iDnEtkKFY8j4nRljmDKbPs9QqgCVMzw/SrWbDfZ3d842mTWW9usJk= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789602444; c=relaxed/simple; bh=8PnJhMbJfPW2TG6Tymzwhur83WhT4MYpBVhb6jWo10Q=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Q0R04IC1d0a5kOmhZB0J5Kw/0yQowh/S7DxPtDgl2aH0wYvZTyknhr3LQuU8TNJgog3qmBFLbU4MJP+sER8PSH3TGesM7Xjl1nolF/PJWQm6ELzMI8C/vGSVE3GtYOr6ZkcaYI95Sl1qhxpy5z7cnWVu+VhR83+4JuwQjZQnVXM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=tOU3atJo; arc=none smtp.client-ip=209.85.215.198 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="tOU3atJo" Received: by mail-pg1-f198.google.com with SMTP id 41be03b00d2f7-cc435388657so306102a12.3 for ; Wed, 16 Sep 2026 16:47:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1789602441; x=1790207241; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=6D1ESuvEsdtOmtDCzS/PXitfXFcHsOG4PWfs9i8aKQc=; b=tOU3atJolsH/t4FEilxyA5FN0M1sMLrgmLNZQoEJ1jII3khYcTnxuKDEGKLZknwpMB v8Xn7uZHYFIdblTTVy1agScs7bzirT2eHImZj+utWEW/medEJv5kFD4YFYWjTp42hp4F e46orUi8VtXmUK7qlFmE9DvT6kZpP4HhDtN8ryThRfILCQZomUxZCLPIe3xecVKou2uD +G4a+9XbjJ4Z+1S8PrjrvA0/w/Tmbfoc7O1j0vpXRM1fLQX2NmlmddORRkqRDCa2af5+ xrgTH+OAkVmDBkzP9sfJYv6Gr0KxoOaRhoYKZfriCenCzXd7WAanhQy2fUyYaqod4ohA z2cA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789602441; x=1790207241; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=6D1ESuvEsdtOmtDCzS/PXitfXFcHsOG4PWfs9i8aKQc=; b=je+JS9k2hNtIjSSyLUgFQJ5+SFp+/fAiA7BYy3WeZJjfm3IhVvDZMJ8QF9xdRwsGQ3 24hWse9uYSoHxNvYafnG/d6YzKmuxlFUyDSu2zb8+hl+TtCB17TuCkIxLk7bgCbidhue yngx3dmQcLoP66t8HEMvGQYAQWYavYXhdGIaoZ767SN8QJvFxA+7k5gi8WKn2Etmq/S0 jRNydLL6yGlfkw4FfkJmkV8LzllPWvB1NXu7FBS32LM7hMxNilJAtxq5o74LnWcuB7Mq mt+ot9hOgRoLDHet+n5bRHus96RJI8NoMxPEaFoNNPoRcUbccL2O6hIgO/Qwf/qgn4H4 BQQA== X-Forwarded-Encrypted: i=1; AKwUvBwKeyxsg+eI6tchqIwwAZUHmyKTZi0N8aMsr/Tzo6cHq2uHwJlP3nwnQLzxMvaziLUK1FqqBz7DH8EwYoeeUChE@vger.kernel.org X-Gm-Message-State: AFuF++mVCCUi7wT8jebTvkNx6AkAtpqkajd03NqAjwsJDHNyWNFCz8LC A7Lt4pe+dRZImTQ/h6l558QaUqr5O91G37KEK+k72opN8XmVp34pH4KWV/RiCNkNjNY3t2YeCTF A6H4239offg== X-Received: from dlbrn14.prod.google.com ([2002:a05:7022:150e:b0:143:8ccf:e704]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a21:700e:b0:3db:4e0a:df51 with SMTP id adf61e73a8af0-3dd5f738a75mr10901269637.22.1789602441164; Wed, 16 Sep 2026 16:47:21 -0700 (PDT) Date: Wed, 16 Sep 2026 16:46:51 -0700 In-Reply-To: <20260916234652.439778-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-perf-users@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260916065248.3153556-1-irogers@google.com> <20260916234652.439778-1-irogers@google.com> X-Mailer: git-send-email 2.55.0.1082.g2b9226bbc0-goog Message-ID: <20260916234652.439778-9-irogers@google.com> Subject: [PATCH v3 8/9] perf test: Expand tests for --hybrid-merge From: Ian Rogers To: irogers@google.com, acme@kernel.org, namhyung@kernel.org Cc: ak@kernel.org, ak@linux.intel.com, andi@firstfloor.org, linux-perf-users@vger.kernel.org Content-Type: text/plain; charset="UTF-8" Add a "Hybrid event merging" test that checks evlist__can_merge_hybrid() and evlist__merge_hybrid() directly, covering the events a wildcard expanded to over two core PMUs, the same over three, and events that must not be merged. Add a report_hybrid_merge.sh shell test that records and then reports with --hybrid-merge, and extend top.sh to cover perf top with it. Signed-off-by: Ian Rogers Assisted-by: Antigravity:gemini-3.1-pro --- tools/perf/tests/Build | 1 + tools/perf/tests/builtin-test.c | 1 + tools/perf/tests/hybrid-merge.c | 206 ++++++++++++++++++ tools/perf/tests/shell/report_hybrid_merge.sh | 121 ++++++++++ tools/perf/tests/shell/top.sh | 73 ++++++- tools/perf/tests/tests.h | 1 + 6 files changed, 392 insertions(+), 11 deletions(-) create mode 100644 tools/perf/tests/hybrid-merge.c create mode 100755 tools/perf/tests/shell/report_hybrid_merge.sh diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 66944a4f4968..406e48eed1c8 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -65,6 +65,7 @@ perf-test-y += perf-time-to-tsc.o perf-test-y += dlfilter-test.o perf-test-y += sigtrap.o perf-test-y += event_groups.o +perf-test-y += hybrid-merge.o perf-test-y += symbols.o perf-test-y += util.o perf-test-y += hwmon_pmu.o diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 4d0784b16723..6293b37266cf 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -149,6 +149,7 @@ static struct test_suite *generic_tests[] = { &suite__dlfilter, &suite__sigtrap, &suite__event_groups, + &suite__hybrid_merge, &suite__symbols, &suite__util, &suite__subcmd_help, diff --git a/tools/perf/tests/hybrid-merge.c b/tools/perf/tests/hybrid-merge.c new file mode 100644 index 000000000000..426b1d09618e --- /dev/null +++ b/tools/perf/tests/hybrid-merge.c @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include "debug.h" +#include "env.h" +#include "evlist.h" +#include "evsel.h" +#include "tests.h" + +/* A hybrid machine with 2 core PMUs, as read from a perf.data file. */ +static struct hybrid_node two_core_pmus[] = { + { .pmu_name = (char *)"cpu_atom", .cpus = (char *)"0-3", }, + { .pmu_name = (char *)"cpu_core", .cpus = (char *)"4-7", }, +}; + +/* A machine with more than 2 kinds of core, like some Arm big.LITTLE. */ +static struct hybrid_node three_core_pmus[] = { + { .pmu_name = (char *)"cpu_atom", .cpus = (char *)"0-3", }, + { .pmu_name = (char *)"cpu_core", .cpus = (char *)"4-7", }, + { .pmu_name = (char *)"cpu_lowpower", .cpus = (char *)"8", }, +}; + +static struct evsel *test_evsel__new(struct evlist *evlist, const char *name) +{ + struct perf_event_attr attr = { + .type = PERF_TYPE_RAW, + .size = sizeof(attr), + .config = 0x3c, + }; + struct evsel *evsel = evsel__new(&attr); + + if (!evsel) + return NULL; + + evsel->name = strdup(name); + if (!evsel->name) { + evsel__put(evsel); + return NULL; + } + evlist__add(evlist, evsel); + return evsel; +} + +/* + * The assertions are in helpers taking an already allocated evlist, so that the + * caller can release the evlist however an assertion fails. + */ +static int check_merge_events(struct evlist *evlist, struct perf_env *env) +{ + struct evsel *atom_cycles, *core_cycles, *atom_insns, *core_insns, *pos; + + /* As if "perf record -e cycles,instructions" ran on a hybrid machine. */ + atom_cycles = test_evsel__new(evlist, "cpu_atom/cycles/"); + core_cycles = test_evsel__new(evlist, "cpu_core/cycles/"); + atom_insns = test_evsel__new(evlist, "cpu_atom/instructions/"); + core_insns = test_evsel__new(evlist, "cpu_core/instructions/"); + TEST_ASSERT_VAL("failed to allocate evsels", + atom_cycles && core_cycles && atom_insns && core_insns); + + TEST_ASSERT_VAL("events should be mergeable", + evlist__can_merge_hybrid(evlist, env)); + + /* Testing for merging must not alter the evlist. */ + evlist__for_each_entry(evlist, pos) { + TEST_ASSERT_VAL("evlist modified by evlist__can_merge_hybrid", + !pos->first_wildcard_match); + } + + evlist__merge_hybrid(evlist, env); + + TEST_ASSERT_VAL("cycles not merged", + core_cycles->first_wildcard_match == atom_cycles); + /* All the events must be merged, not just the first pair found. */ + TEST_ASSERT_VAL("instructions not merged", + core_insns->first_wildcard_match == atom_insns); + TEST_ASSERT_VAL("wrong cycles leader", + evsel__leader(core_cycles) == atom_cycles); + TEST_ASSERT_VAL("wrong instructions leader", + evsel__leader(core_insns) == atom_insns); + TEST_ASSERT_VAL("wrong cycles group size", atom_cycles->core.nr_members == 2); + TEST_ASSERT_VAL("wrong instructions group size", atom_insns->core.nr_members == 2); + + return TEST_OK; +} + +static int test__hybrid_merge_events(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + struct perf_env env = { + .nr_hybrid_nodes = ARRAY_SIZE(two_core_pmus), + .hybrid_nodes = two_core_pmus, + }; + struct evlist *evlist = evlist__new(); + int ret; + + TEST_ASSERT_VAL("failed to allocate evlist", evlist); + + ret = check_merge_events(evlist, &env); + evlist__put(evlist); + return ret; +} + +static int check_merge_3_core_pmus(struct evlist *evlist, struct perf_env *env) +{ + struct evsel *atom_cycles, *core_cycles, *lowpower_cycles; + + atom_cycles = test_evsel__new(evlist, "cpu_atom/cycles/"); + core_cycles = test_evsel__new(evlist, "cpu_core/cycles/"); + lowpower_cycles = test_evsel__new(evlist, "cpu_lowpower/cycles/"); + TEST_ASSERT_VAL("failed to allocate evsels", + atom_cycles && core_cycles && lowpower_cycles); + + evlist__merge_hybrid(evlist, env); + + TEST_ASSERT_VAL("second core PMU not merged", + core_cycles->first_wildcard_match == atom_cycles); + TEST_ASSERT_VAL("third core PMU not merged", + lowpower_cycles->first_wildcard_match == atom_cycles); + TEST_ASSERT_VAL("wrong group size", atom_cycles->core.nr_members == 3); + + return TEST_OK; +} + +static int test__hybrid_merge_3_core_pmus(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + struct perf_env env = { + .nr_hybrid_nodes = ARRAY_SIZE(three_core_pmus), + .hybrid_nodes = three_core_pmus, + }; + struct evlist *evlist = evlist__new(); + int ret; + + TEST_ASSERT_VAL("failed to allocate evlist", evlist); + + ret = check_merge_3_core_pmus(evlist, &env); + evlist__put(evlist); + return ret; +} + +static int check_unmergeable_core_events(struct evlist *evlist, struct perf_env *env) +{ + /* A single event has nothing to merge with. */ + TEST_ASSERT_VAL("failed to allocate evsel", + test_evsel__new(evlist, "cpu_core/cycles/")); + TEST_ASSERT_VAL("a single event shouldn't merge", + !evlist__can_merge_hybrid(evlist, env)); + + /* Events of different names shouldn't merge. */ + TEST_ASSERT_VAL("failed to allocate evsel", + test_evsel__new(evlist, "cpu_atom/instructions/")); + TEST_ASSERT_VAL("events with different names shouldn't merge", + !evlist__can_merge_hybrid(evlist, env)); + + return TEST_OK; +} + +static int check_unmergeable_uncore_events(struct evlist *evlist, struct perf_env *env) +{ + /* Matching events on non-core PMUs shouldn't merge. */ + TEST_ASSERT_VAL("failed to allocate evsels", + test_evsel__new(evlist, "uncore_imc_0/clockticks/") && + test_evsel__new(evlist, "uncore_imc_1/clockticks/")); + TEST_ASSERT_VAL("uncore events shouldn't merge", + !evlist__can_merge_hybrid(evlist, env)); + + return TEST_OK; +} + +static int test__hybrid_merge_unmergeable(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + struct perf_env env = { + .nr_hybrid_nodes = ARRAY_SIZE(two_core_pmus), + .hybrid_nodes = two_core_pmus, + }; + struct evlist *evlist = evlist__new(); + int ret; + + TEST_ASSERT_VAL("failed to allocate evlist", evlist); + + ret = check_unmergeable_core_events(evlist, &env); + evlist__put(evlist); + if (ret != TEST_OK) + return ret; + + evlist = evlist__new(); + TEST_ASSERT_VAL("failed to allocate evlist", evlist); + + ret = check_unmergeable_uncore_events(evlist, &env); + evlist__put(evlist); + return ret; +} + +static struct test_case tests__hybrid_merge[] = { + TEST_CASE("Merge events of 2 core PMUs", hybrid_merge_events), + TEST_CASE("Merge events of 3 core PMUs", hybrid_merge_3_core_pmus), + TEST_CASE("Events that shouldn't merge", hybrid_merge_unmergeable), + { .name = NULL, } +}; + +struct test_suite suite__hybrid_merge = { + .desc = "Hybrid event merging", + .test_cases = tests__hybrid_merge, +}; diff --git a/tools/perf/tests/shell/report_hybrid_merge.sh b/tools/perf/tests/shell/report_hybrid_merge.sh new file mode 100755 index 000000000000..aca5d16c6c9d --- /dev/null +++ b/tools/perf/tests/shell/report_hybrid_merge.sh @@ -0,0 +1,121 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# perf report hybrid merge tests + +set -e + +err=0 +log_dir=$(mktemp -d /tmp/__perf_test.report_hybrid_merge.XXXXXX) +perf_data="${log_dir}/perf.data" +perf_out="${log_dir}/perf.out" +perf_config="${log_dir}/perfconfig" + +cleanup() { + rm -rf "${log_dir}" + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +# Record 2 events so that all the events of a hybrid machine must be merged, +# not just the first pair found. +events="" +record_events() { + for try in "cycles,instructions" "cpu-clock,task-clock"; do + if perf record -o "${perf_data}" -e "${try}" -- \ + perf test -w thloop 1 >/dev/null 2>&1; then + events="${try//,/ }" + return 0 + fi + done + return 1 +} + +test_hybrid_merge_report() { + echo "Perf report hybrid merge test" + + # Test with multiple fields to ensure formatting alignment doesn't hide members + if ! perf report -i "${perf_data}" --hybrid-merge \ + -F comm,overhead --stdio > "${perf_out}" 2>&1; then + echo "Perf report hybrid merge test [Failed: run err]" + err=1 + return + fi + + # Check if the output actually contains the 'comm' and 'overhead' headers correctly + if ! grep -qi "Overhead" "${perf_out}"; then + echo "Perf report hybrid merge test [Failed: missing overhead header]" + err=1 + return + fi + + if ! grep -qi "Command" "${perf_out}"; then + echo "Perf report hybrid merge test [Failed: missing comm header]" + err=1 + return + fi + + # Every recorded event must be displayed, merged into a group on a + # hybrid machine and separately elsewhere. + if ! perf report -i "${perf_data}" --hybrid-merge --stdio \ + > "${perf_out}" 2>&1; then + echo "Perf report hybrid merge test [Failed: run err]" + err=1 + return + fi + for event in ${events}; do + if ! grep -q -- "${event}" "${perf_out}"; then + echo "Perf report hybrid merge test [Failed: missing event ${event}]" + cat "${perf_out}" + err=1 + return + fi + done + + echo "Perf report hybrid merge test [Success]" +} + +test_hybrid_merge_config() { + echo "Perf report hybrid merge config test" + + cat < "${perf_config}" +[core] + hybrid-merge = true +EOF + + # Merging from the config file is a default, it must give way to an + # explicitly requested --hierarchy rather than failing. + if ! PERF_CONFIG="${perf_config}" perf report -i "${perf_data}" \ + --hierarchy --stdio > "${perf_out}" 2>&1; then + echo "Perf report hybrid merge config test [Failed: --hierarchy]" + cat "${perf_out}" + err=1 + return + fi + + # Asking for both on the command line remains an error. + if PERF_CONFIG="${perf_config}" perf report -i "${perf_data}" \ + --hierarchy --hybrid-merge --stdio > "${perf_out}" 2>&1; then + echo "Perf report hybrid merge config test [Failed: no error for both]" + err=1 + return + fi + + echo "Perf report hybrid merge config test [Success]" +} + +if ! record_events; then + echo "Perf report hybrid merge test [Skipped: perf record failed]" + cleanup + exit 2 +fi + +test_hybrid_merge_report +test_hybrid_merge_config +cleanup +exit $err diff --git a/tools/perf/tests/shell/top.sh b/tools/perf/tests/shell/top.sh index ad7fccd09025..3d52677ccb5f 100755 --- a/tools/perf/tests/shell/top.sh +++ b/tools/perf/tests/shell/top.sh @@ -35,21 +35,22 @@ test_basic_perf_top() { # Use -d 1 to avoid flooding output # Use -e cpu-clock to ensure we get samples # Use sleep to keep stdin open but silent, preventing EOF loop or interactive spam - if ! sleep 10 | timeout 5s perf top --stdio -d 1 -e cpu-clock -p $PID > "${log_file}" 2>&1; then - retval=$? - if [ $retval -ne 124 ] && [ $retval -ne 0 ]; then - echo "Basic perf top test [Failed: perf top failed to start or run (ret=$retval)]" - head -n 50 "${log_file}" - kill $PID - wait $PID 2>/dev/null || true - err=1 - return - fi + retval=0 + sleep 10 | timeout 5s perf top --stdio -d 1 -e cpu-clock \ + -p $PID > "${log_file}" 2>&1 || retval=$? + if [ "${retval:-0}" -ne 124 ] && [ "${retval:-0}" -ne 0 ]; then + echo "Basic perf top test [Failed: perf top failed to start or run (ret=$retval)]" + head -n 50 "${log_file}" + kill $PID 2>/dev/null || true + wait $PID 2>/dev/null || true + err=1 + return fi - kill $PID + kill $PID 2>/dev/null || true wait $PID 2>/dev/null || true + # Check for some sample data (percentage) if ! grep -E -q "[0-9]+\.[0-9]+%" "${log_file}"; then echo "Basic perf top test [Failed: no sample percentage found]" @@ -69,6 +70,56 @@ test_basic_perf_top() { echo "Basic perf top test [Success]" } +test_hybrid_merge_perf_top() { + echo "Perf top hybrid merge test" + + perf test -w thloop 20 & + PID=$! + + # Allow it to start + sleep 0.1 + + # Run without explicitly requesting -e cycles so heavily virtualized + # environments can seamlessly fall back to cpu-clock while real + # hybrid hardware will naturally cover the merge logic. + retval=0 + sleep 10 | timeout 5s perf top \ + --stdio --hybrid-merge -d 1 -p $PID > "${log_file}" 2>&1 || retval=$? + if [ "${retval:-0}" -ne 124 ] && [ "${retval:-0}" -ne 0 ]; then + echo "Perf top hybrid merge test [Failed: run err=$retval]" + head -n 50 "${log_file}" + kill $PID 2>/dev/null || true + wait $PID 2>/dev/null || true + err=1 + return + fi + + kill $PID 2>/dev/null || true + wait $PID 2>/dev/null || true + + # Wait a tiny bit for the file system to catch up on the logs + sleep 0.1 + + # Check for some sample data (percentage) + if ! grep -E -q "[0-9]+\.[0-9]+%" "${log_file}"; then + echo "Perf top hybrid merge test [Failed: no sample percentage found]" + head -n 50 "${log_file}" + err=1 + return + fi + + # Check for the test loop symbol to ensure attribution worked + if ! grep -q "test_loop" "${log_file}"; then + echo "Perf top hybrid merge test [Failed: test_loop symbol not found]" + head -n 50 "${log_file}" + err=1 + return + fi + + echo "Perf top hybrid merge test [Success]" +} + test_basic_perf_top +test_hybrid_merge_perf_top cleanup exit $err diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index cee9e6b62dcc..9c96f33483d1 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -177,6 +177,7 @@ DECLARE_SUITE(perf_time_to_tsc); DECLARE_SUITE(dlfilter); DECLARE_SUITE(sigtrap); DECLARE_SUITE(event_groups); +DECLARE_SUITE(hybrid_merge); DECLARE_SUITE(symbols); DECLARE_SUITE(util); DECLARE_SUITE(uncore_event_sorting); -- 2.55.0.1082.g2b9226bbc0-goog