Commit 1458c4f0 authored by James Morse's avatar James Morse
Browse files

arm_mpam: resctrl: Add support for csu counters



resctrl exposes a counter via a file named llc_occupancy. This isn't really
a counter as its value goes up and down, this is a snapshot of the cache
storage usage monitor.

Add some picking code which will only find an L3. The resctrl counter
file is called llc_occupancy but we don't check it is the last one as
it is already identified as L3.

Tested-by: default avatarShaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Tested-by: default avatarZeng Heng <zengheng4@huawei.com>
Tested-by: default avatarPunit Agrawal <punit.agrawal@oss.qualcomm.com>
Tested-by: default avatarGavin Shan <gshan@redhat.com>
Tested-by: default avatarJesse Chick <jessechick@os.amperecomputing.com>
Reviewed-by: default avatarZeng Heng <zengheng4@huawei.com>
Reviewed-by: default avatarShaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Reviewed-by: default avatarJonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: default avatarGavin Shan <gshan@redhat.com>
Co-developed-by: default avatarDave Martin <dave.martin@arm.com>
Signed-off-by: default avatarDave Martin <dave.martin@arm.com>
Co-developed-by: default avatarBen Horgan <ben.horgan@arm.com>
Signed-off-by: default avatarBen Horgan <ben.horgan@arm.com>
Signed-off-by: default avatarJames Morse <james.morse@arm.com>
parent 264c2859
Loading
Loading
Loading
Loading
+83 −0
Original line number Diff line number Diff line
@@ -311,6 +311,28 @@ static bool class_has_usable_mba(struct mpam_props *cprops)
	return mba_class_use_mbw_max(cprops);
}

static bool cache_has_usable_csu(struct mpam_class *class)
{
	struct mpam_props *cprops;

	if (!class)
		return false;

	cprops = &class->props;

	if (!mpam_has_feature(mpam_feat_msmon_csu, cprops))
		return false;

	/*
	 * CSU counters settle on the value, so we can get away with
	 * having only one.
	 */
	if (!cprops->num_csu_mon)
		return false;

	return true;
}

/*
 * Calculate the worst-case percentage change from each implemented step
 * in the control.
@@ -630,6 +652,64 @@ static void mpam_resctrl_pick_mba(void)
	}
}

static void counter_update_class(enum resctrl_event_id evt_id,
				 struct mpam_class *class)
{
	struct mpam_class *existing_class = mpam_resctrl_counters[evt_id].class;

	if (existing_class) {
		if (class->level == 3) {
			pr_debug("Existing class is L3 - L3 wins\n");
			return;
		}

		if (existing_class->level < class->level) {
			pr_debug("Existing class is closer to L3, %u versus %u - closer is better\n",
				 existing_class->level, class->level);
			return;
		}
	}

	mpam_resctrl_counters[evt_id].class = class;
}

static void mpam_resctrl_pick_counters(void)
{
	struct mpam_class *class;

	lockdep_assert_cpus_held();

	guard(srcu)(&mpam_srcu);
	list_for_each_entry_srcu(class, &mpam_classes, classes_list,
				 srcu_read_lock_held(&mpam_srcu)) {
		/* The name of the resource is L3... */
		if (class->type == MPAM_CLASS_CACHE && class->level != 3) {
			pr_debug("class %u is a cache but not the L3", class->level);
			continue;
		}

		if (!cpumask_equal(&class->affinity, cpu_possible_mask)) {
			pr_debug("class %u does not cover all CPUs",
				 class->level);
			continue;
		}

		if (cache_has_usable_csu(class)) {
			pr_debug("class %u has usable CSU",
				 class->level);

			/* CSU counters only make sense on a cache. */
			switch (class->type) {
			case MPAM_CLASS_CACHE:
				counter_update_class(QOS_L3_OCCUP_EVENT_ID, class);
				break;
			default:
				break;
			}
		}
	}
}

static int mpam_resctrl_control_init(struct mpam_resctrl_res *res)
{
	struct mpam_class *class = res->class;
@@ -1264,6 +1344,9 @@ int mpam_resctrl_setup(void)
		}
	}

	/* Find some classes to use for monitors */
	mpam_resctrl_pick_counters();

	for_each_mpam_resctrl_mon(mon, eventid) {
		if (!mon->class)
			continue;	// dummy resource