diff options
-rw-r--r-- | Documentation/trace-cmd-report.1.txt | 8 | ||||
-rw-r--r-- | parse-filter.c | 75 |
2 files changed, 65 insertions, 18 deletions
diff --git a/Documentation/trace-cmd-report.1.txt b/Documentation/trace-cmd-report.1.txt index fbab3f4..86169f2 100644 --- a/Documentation/trace-cmd-report.1.txt +++ b/Documentation/trace-cmd-report.1.txt | |||
@@ -98,6 +98,14 @@ OPTIONS | |||
98 | 98 | ||
99 | Although the output displays 'R', having 'prev_stat=="R"' will not work. | 99 | Although the output displays 'R', having 'prev_stat=="R"' will not work. |
100 | 100 | ||
101 | Note: You can also specify 'COMM' as an EVENT_FIELD. This will use the | ||
102 | task name (or comm) of the record to compare. For example, to filter out | ||
103 | all of the "trace-cmd" tasks: | ||
104 | |||
105 | ------------------------------------------ | ||
106 | -F '.*:COMM != "trace-cmd"' | ||
107 | ------------------------------------------ | ||
108 | |||
101 | *-v*:: | 109 | *-v*:: |
102 | This causes the following filters of *-F* to filter out the matching | 110 | This causes the following filters of *-F* to filter out the matching |
103 | events. | 111 | events. |
diff --git a/parse-filter.c b/parse-filter.c index 75512e3..eb2ef6d 100644 --- a/parse-filter.c +++ b/parse-filter.c | |||
@@ -28,6 +28,12 @@ | |||
28 | #include "parse-events.h" | 28 | #include "parse-events.h" |
29 | #include "util.h" | 29 | #include "util.h" |
30 | 30 | ||
31 | #define COMM "COMM" | ||
32 | |||
33 | static struct format_field comm = { | ||
34 | .name = "COMM", | ||
35 | }; | ||
36 | |||
31 | struct event_list { | 37 | struct event_list { |
32 | struct event_list *next; | 38 | struct event_list *next; |
33 | struct event_format *event; | 39 | struct event_format *event; |
@@ -539,13 +545,18 @@ process_value_token(struct event_format *event, struct filter_arg **parg, | |||
539 | } | 545 | } |
540 | /* Consider this a field */ | 546 | /* Consider this a field */ |
541 | field = pevent_find_any_field(event, token); | 547 | field = pevent_find_any_field(event, token); |
542 | free_token(token); | ||
543 | if (!field) { | 548 | if (!field) { |
544 | /* not a field, so NULL it up */ | 549 | if (strcmp(token, COMM) != 0) { |
545 | free_arg(arg); | 550 | /* not a field, so NULL it up */ |
546 | arg = NULL; | 551 | free_token(token); |
547 | break; | 552 | free_arg(arg); |
553 | arg = NULL; | ||
554 | break; | ||
555 | } | ||
556 | /* If token is 'COMM' then it is special */ | ||
557 | field = &comm; | ||
548 | } | 558 | } |
559 | free_token(token); | ||
549 | 560 | ||
550 | arg->type = FILTER_ARG_FIELD; | 561 | arg->type = FILTER_ARG_FIELD; |
551 | arg->field.field = field; | 562 | arg->field.field = field; |
@@ -1414,11 +1425,31 @@ int pevent_filter_event_has_trivial(struct event_filter *filter, | |||
1414 | static int test_filter(struct event_format *event, | 1425 | static int test_filter(struct event_format *event, |
1415 | struct filter_arg *arg, struct record *record); | 1426 | struct filter_arg *arg, struct record *record); |
1416 | 1427 | ||
1428 | static const char * | ||
1429 | get_comm(struct event_format *event, struct record *record) | ||
1430 | { | ||
1431 | const char *comm; | ||
1432 | int pid; | ||
1433 | |||
1434 | pid = pevent_data_pid(event->pevent, record); | ||
1435 | comm = pevent_data_comm_from_pid(event->pevent, pid); | ||
1436 | return comm; | ||
1437 | } | ||
1438 | |||
1417 | static unsigned long long | 1439 | static unsigned long long |
1418 | get_value(struct format_field *field, struct record *record) | 1440 | get_value(struct event_format *event, |
1441 | struct format_field *field, struct record *record) | ||
1419 | { | 1442 | { |
1420 | unsigned long long val; | 1443 | unsigned long long val; |
1421 | 1444 | ||
1445 | /* Handle our dummy "comm" field */ | ||
1446 | if (field == &comm) { | ||
1447 | const char *name; | ||
1448 | |||
1449 | name = get_comm(event, record); | ||
1450 | return (unsigned long long)name; | ||
1451 | } | ||
1452 | |||
1422 | pevent_read_number_field(field, record->data, &val); | 1453 | pevent_read_number_field(field, record->data, &val); |
1423 | 1454 | ||
1424 | if (!(field->flags & FIELD_IS_SIGNED)) | 1455 | if (!(field->flags & FIELD_IS_SIGNED)) |
@@ -1491,7 +1522,7 @@ get_arg_value(struct event_format *event, struct filter_arg *arg, struct record | |||
1491 | { | 1522 | { |
1492 | switch (arg->type) { | 1523 | switch (arg->type) { |
1493 | case FILTER_ARG_FIELD: | 1524 | case FILTER_ARG_FIELD: |
1494 | return get_value(arg->field.field, record); | 1525 | return get_value(event, arg->field.field, record); |
1495 | 1526 | ||
1496 | case FILTER_ARG_VALUE: | 1527 | case FILTER_ARG_VALUE: |
1497 | if (arg->value.type != FILTER_NUMBER) | 1528 | if (arg->value.type != FILTER_NUMBER) |
@@ -1540,11 +1571,9 @@ static int test_num(struct event_format *event, | |||
1540 | } | 1571 | } |
1541 | } | 1572 | } |
1542 | 1573 | ||
1543 | static int test_str(struct event_format *event, | 1574 | static const char *get_field_str(struct filter_arg *arg, struct record *record) |
1544 | struct filter_arg *arg, struct record *record) | ||
1545 | { | 1575 | { |
1546 | const char *val = record->data + arg->str.field->offset; | 1576 | const char *val = record->data + arg->str.field->offset; |
1547 | const char *buffer; | ||
1548 | 1577 | ||
1549 | /* | 1578 | /* |
1550 | * We need to copy the data since we can't be sure the field | 1579 | * We need to copy the data since we can't be sure the field |
@@ -1554,24 +1583,34 @@ static int test_str(struct event_format *event, | |||
1554 | /* copy it */ | 1583 | /* copy it */ |
1555 | memcpy(arg->str.buffer, val, arg->str.field->size); | 1584 | memcpy(arg->str.buffer, val, arg->str.field->size); |
1556 | /* the buffer is already NULL terminated */ | 1585 | /* the buffer is already NULL terminated */ |
1557 | buffer = arg->str.buffer; | 1586 | val = arg->str.buffer; |
1558 | } else | 1587 | } |
1559 | /* OK, it's NULL terminated */ | 1588 | return val; |
1560 | buffer = val; | 1589 | } |
1590 | |||
1591 | static int test_str(struct event_format *event, | ||
1592 | struct filter_arg *arg, struct record *record) | ||
1593 | { | ||
1594 | const char *val; | ||
1595 | |||
1596 | if (arg->str.field == &comm) | ||
1597 | val = get_comm(event, record); | ||
1598 | else | ||
1599 | val = get_field_str(arg, record); | ||
1561 | 1600 | ||
1562 | switch (arg->str.type) { | 1601 | switch (arg->str.type) { |
1563 | case FILTER_CMP_MATCH: | 1602 | case FILTER_CMP_MATCH: |
1564 | return strcmp(buffer, arg->str.val) == 0; | 1603 | return strcmp(val, arg->str.val) == 0; |
1565 | 1604 | ||
1566 | case FILTER_CMP_NOT_MATCH: | 1605 | case FILTER_CMP_NOT_MATCH: |
1567 | return strcmp(buffer, arg->str.val) != 0; | 1606 | return strcmp(val, arg->str.val) != 0; |
1568 | 1607 | ||
1569 | case FILTER_CMP_REGEX: | 1608 | case FILTER_CMP_REGEX: |
1570 | /* Returns zero on match */ | 1609 | /* Returns zero on match */ |
1571 | return !regexec(&arg->str.reg, buffer, 0, NULL, 0); | 1610 | return !regexec(&arg->str.reg, val, 0, NULL, 0); |
1572 | 1611 | ||
1573 | case FILTER_CMP_NOT_REGEX: | 1612 | case FILTER_CMP_NOT_REGEX: |
1574 | return regexec(&arg->str.reg, buffer, 0, NULL, 0); | 1613 | return regexec(&arg->str.reg, val, 0, NULL, 0); |
1575 | 1614 | ||
1576 | default: | 1615 | default: |
1577 | /* ?? */ | 1616 | /* ?? */ |