From nobody Sat Feb 7 18:15:39 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.11]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C429E25742B for ; Mon, 12 May 2025 17:56:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747072567; cv=none; b=rsYc7KT1d+YzCfqVX5HZ9G5CEEJHwXk42m+VuTfL2dmkAqwW+mEqsAfjPwMsFPVsi0NPn5Cwn5zPFAp+NhoZdRxZxaKOQdC80QDnxIggRYhgesV/N51eeIT7+3msrKhR5R9PyDCXuf3yeWeoYM9XOBWkiN8JXOkMcOsDWRnWap4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1747072567; c=relaxed/simple; bh=+PM1XQX5taXMEXVfyMIOxtzRaXVApXcjBUSbRi9fomA=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=jdxqqFgLBM3ecAIHhCezg7vDl/3AKsBYukSlB+gVy6tKt5GqMDHKXPt/Oc7nZbu1zii0qdO82U3mjYyt0LEOMSPn5kXCn6/SAnj0HzREsdhH6uL5Q6DlnapwMJcQ6BJTCbY7nWVj+iizyxIRkGvoeOxWNyDbzHdm4cl0v9zVIjw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=none smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=FatTnEMw; arc=none smtp.client-ip=192.198.163.11 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="FatTnEMw" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1747072565; x=1778608565; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=+PM1XQX5taXMEXVfyMIOxtzRaXVApXcjBUSbRi9fomA=; b=FatTnEMwOb4VINczR7biZ1kwNJQVDa+qLCnF8HeXf5KP9KD6acxU6/YK k6JCAbaSZqbodCOfjHlZD6Z+LtzgYSzBzWC75f5tEz5mZkGPqe/bq51tn ACUVCaoOQsSoYrDW50iDIXMV/0JPmSLzdYh12PkymiopgqpFyh85CykGk 3xqdleEpUulB6HeOEcIXFyyAAcXY3uwIfwCJUcjrr65i5zQJeTvl/P69Y Zby19jbnqVfojmouCdTybeSccNho1VRofJggd1EJ4u/DTMT+7UEZbc8Jj 9qdxSVfyvQymWn9wbmjlnvdd/6TCf5azX7DP9cXnsqyG8bDGvTQhmGTPS A==; X-CSE-ConnectionGUID: 9gRZyJrWT8SCkLE32pYtLA== X-CSE-MsgGUID: tJLrVPFATyiddBLLzI64zg== X-IronPort-AV: E=McAfee;i="6700,10204,11431"; a="59520624" X-IronPort-AV: E=Sophos;i="6.15,282,1739865600"; d="scan'208";a="59520624" Received: from fmviesa010.fm.intel.com ([10.60.135.150]) by fmvoesa105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 12 May 2025 10:56:04 -0700 X-CSE-ConnectionGUID: mckp73vBSTeP8KmWKuZMJQ== X-CSE-MsgGUID: rIKCmK7zThq2uC4zZTUqlg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.15,282,1739865600"; d="scan'208";a="137909193" Received: from kanliang-dev.jf.intel.com ([10.165.154.102]) by fmviesa010.fm.intel.com with ESMTP; 12 May 2025 10:56:03 -0700 From: kan.liang@linux.intel.com To: peterz@infradead.org, mingo@redhat.com, acme@kernel.org, namhyung@kernel.org, irogers@google.com, linux-kernel@vger.kernel.org Cc: Kan Liang Subject: [RFC PATCH] perf/x86/intel: Add a check for dynamic constraints Date: Mon, 12 May 2025 10:55:42 -0700 Message-Id: <20250512175542.2000708-1-kan.liang@linux.intel.com> X-Mailer: git-send-email 2.38.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Kan Liang The current event scheduler has a limit. If the counter constraint of an event is not a subset of any other counter constraint with an equal or higher weight. The counters may not be fully utilized. To workaround it, the commit bc1738f6ee83 ("perf, x86: Fix event scheduler for constraints with overlapping counters") introduced an overlap flag, which is hardcoded to the event constraint that may trigger the limit. It only works for static constraints. Many features on and after Intel PMON v6 require dynamic constraints. An event constraint is decided by both static and dynamic constraints at runtime. See commit 4dfe3232cc04 ("perf/x86: Add dynamic constraint"). The dynamic constraints are from CPUID enumeration. It's impossible to hardcode it in advance. It's not practical to set the overlap flag to all events. It's harmful to the scheduler. For the existing Intel platforms, the dynamic constraints don't trigger the limit. A real fix is not required. However, for virtualization, VMM may give a weird CPUID enumeration to a guest. It's impossible to indicate what the weird enumeration is. A check is introduced, which can list the possible breaks if a weird enumeration is used. Check the dynamic constraints enumerated for normal, branch counters logging, and auto-counter reload. Check both PEBS and non-PEBS constratins. Closes: https://lore.kernel.org/lkml/20250416195610.GC38216@noisy.programmi= ng.kicks-ass.net/ Signed-off-by: Kan Liang --- arch/x86/events/intel/core.c | 156 +++++++++++++++++++++++++++++++++-- 1 file changed, 148 insertions(+), 8 deletions(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 3a319cf6d364..5928523dc96f 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -5257,6 +5257,151 @@ static void intel_pmu_check_event_constraints(struc= t event_constraint *event_con u64 fixed_cntr_mask, u64 intel_ctrl); =20 +enum dyn_constr_type { + DYN_CONSTR_NONE, + DYN_CONSTR_BR_CNTR, + DYN_CONSTR_ACR_CNTR, + DYN_CONSTR_ACR_CAUSE, + + DYN_CONSTR_MAX, +}; + +static const char * const dyn_constr_type_name[] =3D { + [DYN_CONSTR_NONE] =3D "a normal event", + [DYN_CONSTR_BR_CNTR] =3D "a branch counter logging event", + [DYN_CONSTR_ACR_CNTR] =3D "an auto-counter reload event", + [DYN_CONSTR_ACR_CAUSE] =3D "an auto-counter reload cause event", +}; + +static void __intel_pmu_check_dyn_constr(struct event_constraint *constr, + enum dyn_constr_type type, u64 mask) +{ + struct event_constraint *c1, *c2; + int new_weight, check_weight; + u64 new_mask, check_mask; + + for_each_event_constraint(c1, constr) { + new_mask =3D c1->idxmsk64 & mask; + new_weight =3D hweight64(new_mask); + + /* ignore topdown perf metrics event */ + if (c1->idxmsk64 & INTEL_PMC_MSK_TOPDOWN) + continue; + + if (!new_weight && fls64(c1->idxmsk64) < INTEL_PMC_IDX_FIXED) { + pr_info("The event 0x%llx is not supported as %s.\n", + c1->code, dyn_constr_type_name[type]); + } + + if (new_weight <=3D 1) + continue; + + for_each_event_constraint(c2, c1 + 1) { + bool check_fail =3D false; + + check_mask =3D c2->idxmsk64 & mask; + check_weight =3D hweight64(check_mask); + + if (c2->idxmsk64 & INTEL_PMC_MSK_TOPDOWN || + !check_weight) + continue; + + /* The same constraints or no overlap */ + if (new_mask =3D=3D check_mask || + (new_mask ^ check_mask) =3D=3D (new_mask | check_mask)) + continue; + + /* + * A scheduler issue may be triggered in the following cases. + * - Two overlap constraints have the same weight. + * E.g., A constraints: 0x3, B constraints: 0x6 + * event counter failure case + * B PMC[2:1] 1 + * A PMC[1:0] 0 + * A PMC[1:0] FAIL + * - Two overlap constraints have different weight. + * The constraint has a low weight, but has high last bit. + * E.g., A constraints: 0x7, B constraints: 0xC + * event counter failure case + * B PMC[3:2] 2 + * A PMC[2:0] 0 + * A PMC[2:0] 1 + * A PMC[2:0] FAIL + */ + if (new_weight =3D=3D check_weight) { + check_fail =3D true; + } else if (new_weight < check_weight) { + if ((new_mask | check_mask) !=3D check_mask && + fls64(new_mask) > fls64(check_mask)) + check_fail =3D true; + } else { + if ((new_mask | check_mask) !=3D new_mask && + fls64(new_mask) < fls64(check_mask)) + check_fail =3D true; + } + + if (check_fail) { + pr_info("The two events 0x%llx and 0x%llx may not be " + "fully scheduled under some circumstances as " + "%s.\n", + c1->code, c2->code, dyn_constr_type_name[type]); + } + } + } +} + +static void intel_pmu_check_dyn_constr(struct pmu *pmu, + struct event_constraint *constr, + u64 cntr_mask) +{ + enum dyn_constr_type i; + u64 mask; + + for (i =3D DYN_CONSTR_NONE; i < DYN_CONSTR_MAX; i++) { + mask =3D 0; + switch (i) { + case DYN_CONSTR_NONE: + mask =3D cntr_mask; + break; + case DYN_CONSTR_BR_CNTR: + if (x86_pmu.flags & PMU_FL_BR_CNTR) + mask =3D x86_pmu.lbr_counters; + break; + case DYN_CONSTR_ACR_CNTR: + mask =3D hybrid(pmu, acr_cntr_mask64) & GENMASK_ULL(INTEL_PMC_MAX_GENER= IC - 1, 0); + break; + case DYN_CONSTR_ACR_CAUSE: + if (hybrid(pmu, acr_cntr_mask64) =3D=3D hybrid(pmu, acr_cause_mask64)) + continue; + mask =3D hybrid(pmu, acr_cause_mask64) & GENMASK_ULL(INTEL_PMC_MAX_GENE= RIC - 1, 0); + break; + default: + pr_warn("Unsupported dynamic constraint type %d\n", i); + } + + if (mask) + __intel_pmu_check_dyn_constr(constr, i, mask); + } +} + +static void intel_pmu_check_event_constraints_all(struct pmu *pmu) +{ + struct event_constraint *event_constraints =3D hybrid(pmu, event_constrai= nts); + struct event_constraint *pebs_constraints =3D hybrid(pmu, pebs_constraint= s); + u64 cntr_mask =3D hybrid(pmu, cntr_mask64); + u64 fixed_cntr_mask =3D hybrid(pmu, fixed_cntr_mask64); + u64 intel_ctrl =3D hybrid(pmu, intel_ctrl); + + intel_pmu_check_event_constraints(event_constraints, cntr_mask, + fixed_cntr_mask, intel_ctrl); + + if (event_constraints) + intel_pmu_check_dyn_constr(pmu, event_constraints, cntr_mask); + + if (pebs_constraints) + intel_pmu_check_dyn_constr(pmu, pebs_constraints, cntr_mask); +} + static void intel_pmu_check_extra_regs(struct extra_reg *extra_regs); =20 static inline bool intel_pmu_broken_perf_cap(void) @@ -5319,10 +5464,7 @@ static void intel_pmu_check_hybrid_pmus(struct x86_h= ybrid_pmu *pmu) else pmu->intel_ctrl &=3D ~(1ULL << GLOBAL_CTRL_EN_PERF_METRICS); =20 - intel_pmu_check_event_constraints(pmu->event_constraints, - pmu->cntr_mask64, - pmu->fixed_cntr_mask64, - pmu->intel_ctrl); + intel_pmu_check_event_constraints_all(&pmu->pmu); =20 intel_pmu_check_extra_regs(pmu->extra_regs); } @@ -7734,10 +7876,8 @@ __init int intel_pmu_init(void) if (x86_pmu.intel_cap.anythread_deprecated) x86_pmu.format_attrs =3D intel_arch_formats_attr; =20 - intel_pmu_check_event_constraints(x86_pmu.event_constraints, - x86_pmu.cntr_mask64, - x86_pmu.fixed_cntr_mask64, - x86_pmu.intel_ctrl); + intel_pmu_check_event_constraints_all(NULL); + /* * Access LBR MSR may cause #GP under certain circumstances. * Check all LBR MSR here. --=20 2.38.1