Skip to content

Commit 0007f39

Browse files
Kan LiangPeter Zijlstra
authored andcommitted
perf/x86/uncore: Save the unit control address of all units
The unit control address of some CXL units may be wrongly calculated under some configuration on a EMR machine. The current implementation only saves the unit control address of the units from the first die, and the first unit of the rest of dies. Perf assumed that the units from the other dies have the same offset as the first die. So the unit control address of the rest of the units can be calculated. However, the assumption is wrong, especially for the CXL units. Introduce an RB tree for each uncore type to save the unit control address and three kinds of ID information (unit ID, PMU ID, and die ID) for all units. The unit ID is a physical ID of a unit. The PMU ID is a logical ID assigned to a unit. The logical IDs start from 0 and must be contiguous. The physical ID and the logical ID are 1:1 mapping. The units with the same physical ID in different dies share the same PMU. The die ID indicates which die a unit belongs to. The RB tree can be searched by two different keys (unit ID or PMU ID + die ID). During the RB tree setup, the unit ID is used as a key to look up the RB tree. The perf can create/assign a proper PMU ID to the unit. Later, after the RB tree is setup, PMU ID + die ID is used as a key to look up the RB tree to fill the cpumask of a PMU. It's used more frequently, so PMU ID + die ID is compared in the unit_less(). The uncore_find_unit() has to be O(N). But the RB tree setup only occurs once during the driver load time. It should be acceptable. Compared with the current implementation, more space is required to save the information of all units. The extra size should be acceptable. For example, on EMR, there are 221 units at most. For a 2-socket machine, the extra space is ~6KB at most. Signed-off-by: Kan Liang <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent cd84351 commit 0007f39

File tree

2 files changed

+87
-2
lines changed

2 files changed

+87
-2
lines changed

arch/x86/events/intel/uncore_discovery.c

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ add_uncore_discovery_type(struct uncore_unit_discovery *unit)
9393
if (!type->box_ctrl_die)
9494
goto free_type;
9595

96+
type->units = RB_ROOT;
97+
9698
type->access_type = unit->access_type;
9799
num_discovered_types[type->access_type]++;
98100
type->type = unit->box_type;
@@ -120,10 +122,59 @@ get_uncore_discovery_type(struct uncore_unit_discovery *unit)
120122
return add_uncore_discovery_type(unit);
121123
}
122124

125+
static inline bool unit_less(struct rb_node *a, const struct rb_node *b)
126+
{
127+
struct intel_uncore_discovery_unit *a_node, *b_node;
128+
129+
a_node = rb_entry(a, struct intel_uncore_discovery_unit, node);
130+
b_node = rb_entry(b, struct intel_uncore_discovery_unit, node);
131+
132+
if (a_node->pmu_idx < b_node->pmu_idx)
133+
return true;
134+
if (a_node->pmu_idx > b_node->pmu_idx)
135+
return false;
136+
137+
if (a_node->die < b_node->die)
138+
return true;
139+
if (a_node->die > b_node->die)
140+
return false;
141+
142+
return 0;
143+
}
144+
145+
static inline struct intel_uncore_discovery_unit *
146+
uncore_find_unit(struct rb_root *root, unsigned int id)
147+
{
148+
struct intel_uncore_discovery_unit *unit;
149+
struct rb_node *node;
150+
151+
for (node = rb_first(root); node; node = rb_next(node)) {
152+
unit = rb_entry(node, struct intel_uncore_discovery_unit, node);
153+
if (unit->id == id)
154+
return unit;
155+
}
156+
157+
return NULL;
158+
}
159+
160+
static void uncore_find_add_unit(struct intel_uncore_discovery_unit *node,
161+
struct rb_root *root, u16 *num_units)
162+
{
163+
struct intel_uncore_discovery_unit *unit = uncore_find_unit(root, node->id);
164+
165+
if (unit)
166+
node->pmu_idx = unit->pmu_idx;
167+
else if (num_units)
168+
node->pmu_idx = (*num_units)++;
169+
170+
rb_add(&node->node, root, unit_less);
171+
}
172+
123173
static void
124174
uncore_insert_box_info(struct uncore_unit_discovery *unit,
125175
int die, bool parsed)
126176
{
177+
struct intel_uncore_discovery_unit *node;
127178
struct intel_uncore_discovery_type *type;
128179
unsigned int *ids;
129180
u64 *box_offset;
@@ -136,14 +187,26 @@ uncore_insert_box_info(struct uncore_unit_discovery *unit,
136187
return;
137188
}
138189

190+
node = kzalloc(sizeof(*node), GFP_KERNEL);
191+
if (!node)
192+
return;
193+
194+
node->die = die;
195+
node->id = unit->box_id;
196+
node->addr = unit->ctl;
197+
139198
if (parsed) {
140199
type = search_uncore_discovery_type(unit->box_type);
141200
if (!type) {
142201
pr_info("A spurious uncore type %d is detected, "
143202
"Disable the uncore type.\n",
144203
unit->box_type);
204+
kfree(node);
145205
return;
146206
}
207+
208+
uncore_find_add_unit(node, &type->units, &type->num_units);
209+
147210
/* Store the first box of each die */
148211
if (!type->box_ctrl_die[die])
149212
type->box_ctrl_die[die] = unit->ctl;
@@ -152,16 +215,18 @@ uncore_insert_box_info(struct uncore_unit_discovery *unit,
152215

153216
type = get_uncore_discovery_type(unit);
154217
if (!type)
155-
return;
218+
goto free_node;
156219

157220
box_offset = kcalloc(type->num_boxes + 1, sizeof(u64), GFP_KERNEL);
158221
if (!box_offset)
159-
return;
222+
goto free_node;
160223

161224
ids = kcalloc(type->num_boxes + 1, sizeof(unsigned int), GFP_KERNEL);
162225
if (!ids)
163226
goto free_box_offset;
164227

228+
uncore_find_add_unit(node, &type->units, &type->num_units);
229+
165230
/* Store generic information for the first box */
166231
if (!type->num_boxes) {
167232
type->box_ctrl = unit->ctl;
@@ -201,6 +266,8 @@ uncore_insert_box_info(struct uncore_unit_discovery *unit,
201266
free_box_offset:
202267
kfree(box_offset);
203268

269+
free_node:
270+
kfree(node);
204271
}
205272

206273
static bool
@@ -339,8 +406,16 @@ bool intel_uncore_has_discovery_tables(int *ignore)
339406
void intel_uncore_clear_discovery_tables(void)
340407
{
341408
struct intel_uncore_discovery_type *type, *next;
409+
struct intel_uncore_discovery_unit *pos;
410+
struct rb_node *node;
342411

343412
rbtree_postorder_for_each_entry_safe(type, next, &discovery_tables, node) {
413+
while (!RB_EMPTY_ROOT(&type->units)) {
414+
node = rb_first(&type->units);
415+
pos = rb_entry(node, struct intel_uncore_discovery_unit, node);
416+
rb_erase(node, &type->units);
417+
kfree(pos);
418+
}
344419
kfree(type->box_ctrl_die);
345420
kfree(type);
346421
}

arch/x86/events/intel/uncore_discovery.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,17 +113,27 @@ struct uncore_unit_discovery {
113113
};
114114
};
115115

116+
struct intel_uncore_discovery_unit {
117+
struct rb_node node;
118+
unsigned int pmu_idx; /* The idx of the corresponding PMU */
119+
unsigned int id; /* Unit ID */
120+
unsigned int die; /* Die ID */
121+
u64 addr; /* Unit Control Address */
122+
};
123+
116124
struct intel_uncore_discovery_type {
117125
struct rb_node node;
118126
enum uncore_access_type access_type;
119127
u64 box_ctrl; /* Unit ctrl addr of the first box */
120128
u64 *box_ctrl_die; /* Unit ctrl addr of the first box of each die */
129+
struct rb_root units; /* Unit ctrl addr for all units */
121130
u16 type; /* Type ID of the uncore block */
122131
u8 num_counters;
123132
u8 counter_width;
124133
u8 ctl_offset; /* Counter Control 0 offset */
125134
u8 ctr_offset; /* Counter 0 offset */
126135
u16 num_boxes; /* number of boxes for the uncore block */
136+
u16 num_units; /* number of units */
127137
unsigned int *ids; /* Box IDs */
128138
u64 *box_offset; /* Box offset */
129139
};

0 commit comments

Comments
 (0)