Skip to content

Commit 3cbec9d

Browse files
valschneiderrostedt
authored andcommitted
tracing/filters: Enable filtering a scalar field by a cpumask
Several events use a scalar field to denote a CPU: o sched_wakeup.target_cpu o sched_migrate_task.orig_cpu,dest_cpu o sched_move_numa.src_cpu,dst_cpu o ipi_send_cpu.cpu o ... Filtering these currently requires using arithmetic comparison functions, which can be tedious when dealing with interleaved SMT or NUMA CPU ids. Allow these to be filtered by a user-provided cpumask, which enables e.g.: $ trace-cmd record -e 'sched_wakeup' -f 'target_cpu & CPUS{2,4,6,8-32}' Link: https://lkml.kernel.org/r/[email protected] Cc: Masami Hiramatsu <[email protected]> Cc: Jonathan Corbet <[email protected]> Cc: Juri Lelli <[email protected]> Cc: Daniel Bristot de Oliveira <[email protected]> Cc: Marcelo Tosatti <[email protected]> Cc: Leonardo Bras <[email protected]> Cc: Frederic Weisbecker <[email protected]> Signed-off-by: Valentin Schneider <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 39f7c41 commit 3cbec9d

File tree

1 file changed

+81
-11
lines changed

1 file changed

+81
-11
lines changed

kernel/trace/trace_events_filter.c

Lines changed: 81 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,19 @@ static const char * ops[] = { OPS };
4646
enum filter_pred_fn {
4747
FILTER_PRED_FN_NOP,
4848
FILTER_PRED_FN_64,
49+
FILTER_PRED_FN_64_CPUMASK,
4950
FILTER_PRED_FN_S64,
5051
FILTER_PRED_FN_U64,
5152
FILTER_PRED_FN_32,
53+
FILTER_PRED_FN_32_CPUMASK,
5254
FILTER_PRED_FN_S32,
5355
FILTER_PRED_FN_U32,
5456
FILTER_PRED_FN_16,
57+
FILTER_PRED_FN_16_CPUMASK,
5558
FILTER_PRED_FN_S16,
5659
FILTER_PRED_FN_U16,
5760
FILTER_PRED_FN_8,
61+
FILTER_PRED_FN_8_CPUMASK,
5862
FILTER_PRED_FN_S8,
5963
FILTER_PRED_FN_U8,
6064
FILTER_PRED_FN_COMM,
@@ -643,6 +647,39 @@ predicate_parse(const char *str, int nr_parens, int nr_preds,
643647
return ERR_PTR(ret);
644648
}
645649

650+
static inline int
651+
do_filter_cpumask(int op, const struct cpumask *mask, const struct cpumask *cmp)
652+
{
653+
switch (op) {
654+
case OP_EQ:
655+
return cpumask_equal(mask, cmp);
656+
case OP_NE:
657+
return !cpumask_equal(mask, cmp);
658+
case OP_BAND:
659+
return cpumask_intersects(mask, cmp);
660+
default:
661+
return 0;
662+
}
663+
}
664+
665+
/* Optimisation of do_filter_cpumask() for scalar fields */
666+
static inline int
667+
do_filter_scalar_cpumask(int op, unsigned int cpu, const struct cpumask *mask)
668+
{
669+
switch (op) {
670+
case OP_EQ:
671+
return cpumask_test_cpu(cpu, mask) &&
672+
cpumask_nth(1, mask) >= nr_cpu_ids;
673+
case OP_NE:
674+
return !cpumask_test_cpu(cpu, mask) ||
675+
cpumask_nth(1, mask) < nr_cpu_ids;
676+
case OP_BAND:
677+
return cpumask_test_cpu(cpu, mask);
678+
default:
679+
return 0;
680+
}
681+
}
682+
646683
enum pred_cmp_types {
647684
PRED_CMP_TYPE_NOP,
648685
PRED_CMP_TYPE_LT,
@@ -686,6 +723,18 @@ static int filter_pred_##type(struct filter_pred *pred, void *event) \
686723
} \
687724
}
688725

726+
#define DEFINE_CPUMASK_COMPARISON_PRED(size) \
727+
static int filter_pred_##size##_cpumask(struct filter_pred *pred, void *event) \
728+
{ \
729+
u##size *addr = (u##size *)(event + pred->offset); \
730+
unsigned int cpu = *addr; \
731+
\
732+
if (cpu >= nr_cpu_ids) \
733+
return 0; \
734+
\
735+
return do_filter_scalar_cpumask(pred->op, cpu, pred->mask); \
736+
}
737+
689738
#define DEFINE_EQUALITY_PRED(size) \
690739
static int filter_pred_##size(struct filter_pred *pred, void *event) \
691740
{ \
@@ -707,6 +756,11 @@ DEFINE_COMPARISON_PRED(u16);
707756
DEFINE_COMPARISON_PRED(s8);
708757
DEFINE_COMPARISON_PRED(u8);
709758

759+
DEFINE_CPUMASK_COMPARISON_PRED(64);
760+
DEFINE_CPUMASK_COMPARISON_PRED(32);
761+
DEFINE_CPUMASK_COMPARISON_PRED(16);
762+
DEFINE_CPUMASK_COMPARISON_PRED(8);
763+
710764
DEFINE_EQUALITY_PRED(64);
711765
DEFINE_EQUALITY_PRED(32);
712766
DEFINE_EQUALITY_PRED(16);
@@ -891,16 +945,7 @@ static int filter_pred_cpumask(struct filter_pred *pred, void *event)
891945
const struct cpumask *mask = (event + loc);
892946
const struct cpumask *cmp = pred->mask;
893947

894-
switch (pred->op) {
895-
case OP_EQ:
896-
return cpumask_equal(mask, cmp);
897-
case OP_NE:
898-
return !cpumask_equal(mask, cmp);
899-
case OP_BAND:
900-
return cpumask_intersects(mask, cmp);
901-
default:
902-
return 0;
903-
}
948+
return do_filter_cpumask(pred->op, mask, cmp);
904949
}
905950

906951
/* Filter predicate for COMM. */
@@ -1351,24 +1396,32 @@ static int filter_pred_fn_call(struct filter_pred *pred, void *event)
13511396
switch (pred->fn_num) {
13521397
case FILTER_PRED_FN_64:
13531398
return filter_pred_64(pred, event);
1399+
case FILTER_PRED_FN_64_CPUMASK:
1400+
return filter_pred_64_cpumask(pred, event);
13541401
case FILTER_PRED_FN_S64:
13551402
return filter_pred_s64(pred, event);
13561403
case FILTER_PRED_FN_U64:
13571404
return filter_pred_u64(pred, event);
13581405
case FILTER_PRED_FN_32:
13591406
return filter_pred_32(pred, event);
1407+
case FILTER_PRED_FN_32_CPUMASK:
1408+
return filter_pred_32_cpumask(pred, event);
13601409
case FILTER_PRED_FN_S32:
13611410
return filter_pred_s32(pred, event);
13621411
case FILTER_PRED_FN_U32:
13631412
return filter_pred_u32(pred, event);
13641413
case FILTER_PRED_FN_16:
13651414
return filter_pred_16(pred, event);
1415+
case FILTER_PRED_FN_16_CPUMASK:
1416+
return filter_pred_16_cpumask(pred, event);
13661417
case FILTER_PRED_FN_S16:
13671418
return filter_pred_s16(pred, event);
13681419
case FILTER_PRED_FN_U16:
13691420
return filter_pred_u16(pred, event);
13701421
case FILTER_PRED_FN_8:
13711422
return filter_pred_8(pred, event);
1423+
case FILTER_PRED_FN_8_CPUMASK:
1424+
return filter_pred_8_cpumask(pred, event);
13721425
case FILTER_PRED_FN_S8:
13731426
return filter_pred_s8(pred, event);
13741427
case FILTER_PRED_FN_U8:
@@ -1606,6 +1659,7 @@ static int parse_pred(const char *str, void *data,
16061659

16071660
switch (field->filter_type) {
16081661
case FILTER_CPUMASK:
1662+
case FILTER_OTHER:
16091663
break;
16101664
default:
16111665
parse_error(pe, FILT_ERR_ILLEGAL_FIELD_OP, pos + i);
@@ -1658,8 +1712,24 @@ static int parse_pred(const char *str, void *data,
16581712

16591713
/* Move along */
16601714
i++;
1661-
if (field->filter_type == FILTER_CPUMASK)
1715+
if (field->filter_type == FILTER_CPUMASK) {
16621716
pred->fn_num = FILTER_PRED_FN_CPUMASK;
1717+
} else {
1718+
switch (field->size) {
1719+
case 8:
1720+
pred->fn_num = FILTER_PRED_FN_64_CPUMASK;
1721+
break;
1722+
case 4:
1723+
pred->fn_num = FILTER_PRED_FN_32_CPUMASK;
1724+
break;
1725+
case 2:
1726+
pred->fn_num = FILTER_PRED_FN_16_CPUMASK;
1727+
break;
1728+
case 1:
1729+
pred->fn_num = FILTER_PRED_FN_8_CPUMASK;
1730+
break;
1731+
}
1732+
}
16631733

16641734
/* This is either a string, or an integer */
16651735
} else if (str[i] == '\'' || str[i] == '"') {

0 commit comments

Comments
 (0)