@@ -1219,13 +1219,16 @@ int parse_events_add_numeric(struct parse_events_state *parse_state,
1219
1219
1220
1220
int parse_events_add_pmu (struct parse_events_state * parse_state ,
1221
1221
struct list_head * list , char * name ,
1222
- struct list_head * head_config , bool auto_merge_stats )
1222
+ struct list_head * head_config ,
1223
+ bool auto_merge_stats ,
1224
+ bool use_alias )
1223
1225
{
1224
1226
struct perf_event_attr attr ;
1225
1227
struct perf_pmu_info info ;
1226
1228
struct perf_pmu * pmu ;
1227
1229
struct perf_evsel * evsel ;
1228
1230
struct parse_events_error * err = parse_state -> error ;
1231
+ bool use_uncore_alias ;
1229
1232
LIST_HEAD (config_terms );
1230
1233
1231
1234
pmu = perf_pmu__find (name );
@@ -1244,11 +1247,14 @@ int parse_events_add_pmu(struct parse_events_state *parse_state,
1244
1247
memset (& attr , 0 , sizeof (attr ));
1245
1248
}
1246
1249
1250
+ use_uncore_alias = (pmu -> is_uncore && use_alias );
1251
+
1247
1252
if (!head_config ) {
1248
1253
attr .type = pmu -> type ;
1249
1254
evsel = __add_event (list , & parse_state -> idx , & attr , NULL , pmu , NULL , auto_merge_stats );
1250
1255
if (evsel ) {
1251
1256
evsel -> pmu_name = name ;
1257
+ evsel -> use_uncore_alias = use_uncore_alias ;
1252
1258
return 0 ;
1253
1259
} else {
1254
1260
return - ENOMEM ;
@@ -1282,6 +1288,7 @@ int parse_events_add_pmu(struct parse_events_state *parse_state,
1282
1288
evsel -> metric_expr = info .metric_expr ;
1283
1289
evsel -> metric_name = info .metric_name ;
1284
1290
evsel -> pmu_name = name ;
1291
+ evsel -> use_uncore_alias = use_uncore_alias ;
1285
1292
}
1286
1293
1287
1294
return evsel ? 0 : - ENOMEM ;
@@ -1317,7 +1324,8 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
1317
1324
list_add_tail (& term -> list , head );
1318
1325
1319
1326
if (!parse_events_add_pmu (parse_state , list ,
1320
- pmu -> name , head , true)) {
1327
+ pmu -> name , head ,
1328
+ true, true)) {
1321
1329
pr_debug ("%s -> %s/%s/\n" , str ,
1322
1330
pmu -> name , alias -> str );
1323
1331
ok ++ ;
@@ -1339,7 +1347,120 @@ int parse_events__modifier_group(struct list_head *list,
1339
1347
return parse_events__modifier_event (list , event_mod , true);
1340
1348
}
1341
1349
1342
- void parse_events__set_leader (char * name , struct list_head * list )
1350
+ /*
1351
+ * Check if the two uncore PMUs are from the same uncore block
1352
+ * The format of the uncore PMU name is uncore_#blockname_#pmuidx
1353
+ */
1354
+ static bool is_same_uncore_block (const char * pmu_name_a , const char * pmu_name_b )
1355
+ {
1356
+ char * end_a , * end_b ;
1357
+
1358
+ end_a = strrchr (pmu_name_a , '_' );
1359
+ end_b = strrchr (pmu_name_b , '_' );
1360
+
1361
+ if (!end_a || !end_b )
1362
+ return false;
1363
+
1364
+ if ((end_a - pmu_name_a ) != (end_b - pmu_name_b ))
1365
+ return false;
1366
+
1367
+ return (strncmp (pmu_name_a , pmu_name_b , end_a - pmu_name_a ) == 0 );
1368
+ }
1369
+
1370
+ static int
1371
+ parse_events__set_leader_for_uncore_aliase (char * name , struct list_head * list ,
1372
+ struct parse_events_state * parse_state )
1373
+ {
1374
+ struct perf_evsel * evsel , * leader ;
1375
+ uintptr_t * leaders ;
1376
+ bool is_leader = true;
1377
+ int i , nr_pmu = 0 , total_members , ret = 0 ;
1378
+
1379
+ leader = list_first_entry (list , struct perf_evsel , node );
1380
+ evsel = list_last_entry (list , struct perf_evsel , node );
1381
+ total_members = evsel -> idx - leader -> idx + 1 ;
1382
+
1383
+ leaders = calloc (total_members , sizeof (uintptr_t ));
1384
+ if (WARN_ON (!leaders ))
1385
+ return 0 ;
1386
+
1387
+ /*
1388
+ * Going through the whole group and doing sanity check.
1389
+ * All members must use alias, and be from the same uncore block.
1390
+ * Also, storing the leader events in an array.
1391
+ */
1392
+ __evlist__for_each_entry (list , evsel ) {
1393
+
1394
+ /* Only split the uncore group which members use alias */
1395
+ if (!evsel -> use_uncore_alias )
1396
+ goto out ;
1397
+
1398
+ /* The events must be from the same uncore block */
1399
+ if (!is_same_uncore_block (leader -> pmu_name , evsel -> pmu_name ))
1400
+ goto out ;
1401
+
1402
+ if (!is_leader )
1403
+ continue ;
1404
+ /*
1405
+ * If the event's PMU name starts to repeat, it must be a new
1406
+ * event. That can be used to distinguish the leader from
1407
+ * other members, even they have the same event name.
1408
+ */
1409
+ if ((leader != evsel ) && (leader -> pmu_name == evsel -> pmu_name )) {
1410
+ is_leader = false;
1411
+ continue ;
1412
+ }
1413
+ /* The name is always alias name */
1414
+ WARN_ON (strcmp (leader -> name , evsel -> name ));
1415
+
1416
+ /* Store the leader event for each PMU */
1417
+ leaders [nr_pmu ++ ] = (uintptr_t ) evsel ;
1418
+ }
1419
+
1420
+ /* only one event alias */
1421
+ if (nr_pmu == total_members ) {
1422
+ parse_state -> nr_groups -- ;
1423
+ goto handled ;
1424
+ }
1425
+
1426
+ /*
1427
+ * An uncore event alias is a joint name which means the same event
1428
+ * runs on all PMUs of a block.
1429
+ * Perf doesn't support mixed events from different PMUs in the same
1430
+ * group. The big group has to be split into multiple small groups
1431
+ * which only include the events from the same PMU.
1432
+ *
1433
+ * Here the uncore event aliases must be from the same uncore block.
1434
+ * The number of PMUs must be same for each alias. The number of new
1435
+ * small groups equals to the number of PMUs.
1436
+ * Setting the leader event for corresponding members in each group.
1437
+ */
1438
+ i = 0 ;
1439
+ __evlist__for_each_entry (list , evsel ) {
1440
+ if (i >= nr_pmu )
1441
+ i = 0 ;
1442
+ evsel -> leader = (struct perf_evsel * ) leaders [i ++ ];
1443
+ }
1444
+
1445
+ /* The number of members and group name are same for each group */
1446
+ for (i = 0 ; i < nr_pmu ; i ++ ) {
1447
+ evsel = (struct perf_evsel * ) leaders [i ];
1448
+ evsel -> nr_members = total_members / nr_pmu ;
1449
+ evsel -> group_name = name ? strdup (name ) : NULL ;
1450
+ }
1451
+
1452
+ /* Take the new small groups into account */
1453
+ parse_state -> nr_groups += nr_pmu - 1 ;
1454
+
1455
+ handled :
1456
+ ret = 1 ;
1457
+ out :
1458
+ free (leaders );
1459
+ return ret ;
1460
+ }
1461
+
1462
+ void parse_events__set_leader (char * name , struct list_head * list ,
1463
+ struct parse_events_state * parse_state )
1343
1464
{
1344
1465
struct perf_evsel * leader ;
1345
1466
@@ -1348,6 +1469,9 @@ void parse_events__set_leader(char *name, struct list_head *list)
1348
1469
return ;
1349
1470
}
1350
1471
1472
+ if (parse_events__set_leader_for_uncore_aliase (name , list , parse_state ))
1473
+ return ;
1474
+
1351
1475
__perf_evlist__set_leader (list );
1352
1476
leader = list_entry (list -> next , struct perf_evsel , node );
1353
1477
leader -> group_name = name ? strdup (name ) : NULL ;
0 commit comments