diff options
author | Steven Rostedt (Google) <rostedt@goodmis.org> | 2022-02-01 17:32:25 -0500 |
---|---|---|
committer | Steven Rostedt (Google) <rostedt@goodmis.org> | 2022-02-01 17:32:25 -0500 |
commit | 88fd2a659f8d9e19280f8e9d8333e8a797f6f7bd (patch) | |
tree | 535a7fcc178522989063fad44908c1155b1c4861 | |
parent | f9b6e031d0ab384786d3e58067544142e3ed618f (diff) | |
download | ktrace-88fd2a659f8d9e19280f8e9d8333e8a797f6f7bd.tar.gz |
ktrace: Have synthetic event creation do deltas
Allow the create synthetic event allow fields to compare the start and end
events.
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-rw-r--r-- | src/create.c | 296 |
1 files changed, 229 insertions, 67 deletions
diff --git a/src/create.c b/src/create.c index bd851d8..6e6d9d2 100644 --- a/src/create.c +++ b/src/create.c @@ -271,22 +271,44 @@ static int usage_synthetic(struct ccli *ccli) "# match system/event2 fields. Then add the fields of the synthetic event\n" "# on how they will map to the other fields.\n#\n" "# A synthetic event field may also equal timestamps:\n" - "# start=system/event.TIMESTAMP\n#\n" + "# start=system/event.TIMESTAMP\n" + "# start=system/event.TIMESTAMP_USECS\n#\n" "# Or even a delta:\n" "# delta=system/event.TIMESTAMP-system2/event2.TIMESTAMP\n" ); return 0; } +static char *check_ts(char *val) +{ + if (strcmp(val, "TIMESTAMP") == 0) + val = TRACEFS_HIST_TIMESTAMP; + else if ((strcmp(val, "TIMESTAMP_USECS") == 0) || + strcmp(val, "TIMESTAMP_USEC") == 0) + val = TRACEFS_HIST_TIMESTAMP_USECS; + return val; +} + int add_synth_field(struct ccli *ccli, struct tracefs_synth *synth, char *start_system, char *start_event, char *end_system, char *end_event, char *field) { char *system; + char *system2; char *event; + char *event2; + bool start1; + bool start2; char *name; char *val; + char *val2; char *sav; + char *p; + int ret; + + p = strchr(field, '-'); + if (p) + *p = '\0'; name = strtok_r(field, "=", &sav); system = strtok_r(NULL, "/", &sav); @@ -301,25 +323,84 @@ int add_synth_field(struct ccli *ccli, struct tracefs_synth *synth, return -1; } + val = strtok_r(NULL, ".", &sav); - if (!system) { + if (!val) { ccli_printf(ccli, "# Missing .field in '%s' \n", event); return -1; } + val = check_ts(val); + if ((strcmp(system, start_system) == 0) && (strcmp(event, start_event) == 0)) { - return tracefs_synth_add_start_field(synth, val, name); - } + start1 = true; - if ((strcmp(system, end_system) == 0) && - (strcmp(event, end_event) == 0)) { - return tracefs_synth_add_end_field(synth, val, name); + } else if ((strcmp(system, end_system) == 0) && + (strcmp(event, end_event) == 0)) { + start1 = false; + } else { + ccli_printf(ccli, "# %s/%s does not match either start or end events\n", + system, event); + return -1; } - ccli_printf(ccli, "# %s/%s does not match either start or end events\n", - system, event); - return -1; + if (p) { + p++; + system2 = strtok_r(p, "/", &sav); + if (!system2) { + ccli_printf(ccli, "# Missing '/' in '%s'\n", p); + return -1; + } + + event2 = strtok_r(NULL, ".", &sav); + if (!event) { + ccli_printf(ccli, "# Missing /event.field in '%s'\n", system2); + return -1; + } + + val2 = strtok_r(NULL, ".", &sav); + if (!val2) { + ccli_printf(ccli, "# Missing .field in '%s' \n", event2); + return -1; + } + + val2 = check_ts(val2); + + if ((strcmp(system2, start_system) == 0) && + (strcmp(event2, start_event) == 0)) { + start2 = true; + + } else if ((strcmp(system2, end_system) == 0) && + (strcmp(event2, end_event) == 0)) { + start2 = false; + } else { + ccli_printf(ccli, "# %s/%s does not match either start or end events\n", + system2, event2); + return -1; + } + + if (start1 == start2) { + ccli_printf(ccli, "# Can not compare with the same event\n"); + return -1; + } + + if (start2) { + p = val; + val = val2; + val2 = p; + } + printf("val=%s val2=%s name=%s\n", val, val2, name); + ret = tracefs_synth_add_compare_field(synth, val, val2, + TRACEFS_SYNTH_DELTA_END, name); + if (ret < 0) + perror("add_compare_field"); + return ret; + } + if (start1) + return tracefs_synth_add_start_field(synth, val, name); + else + return tracefs_synth_add_end_field(synth, val, name); } static int create_synthetic(struct ccli *ccli, void *data, @@ -692,6 +773,7 @@ static int event_completion(struct ccli *ccli, struct tep_handle *tep, systems = tracefs_event_systems(NULL); if (!systems) return 0; + for (i = 0; ret >= 0 && systems[i]; i++) ret = ccli_list_add(ccli, list, &cnt, systems[i]); @@ -836,31 +918,19 @@ static int append_event_field(struct ccli *ccli, struct tep_handle *tep, char ** return field_completion(ccli, event, list, ename, &cnt); } -static int append_field_ts(struct ccli *ccli, struct tep_handle *tep, char ***list, - char *ename) +static int append_field_completion(struct ccli *ccli, char ***list, int *cnt, + struct tep_handle *tep, char *p, char *str, + char *ename, char *match) { struct tep_event *event; - int cnt = 0; - char *e; - char *p; int ret; + int i, r; - /* Find start of the event */ - e = strchr(ename, '='); - if (!e) // should not happen - return 0; - e++; - - /* Find the end of the event */ - for (p = e; *p && *p != '.'; p++) - ; - if (!*p) // Should not happen! - return 0; *p = '\0'; - event = find_event(tep, e); + event = find_event(tep, ename); if (!event) { - ccli_printf(ccli, "\n# Event %s not found\n", e); + ccli_printf(ccli, "\n# Event %s not found\n", ename); ccli_line_refresh(ccli); return 0; } @@ -868,23 +938,137 @@ static int append_field_ts(struct ccli *ccli, struct tep_handle *tep, char ***li *p = '.'; p[1] = '\0'; - ret = field_completion(ccli, event, list, ename, &cnt); + ret = field_completion(ccli, event, list, str, cnt); if (ret > 0) { - ret = ccli_list_add_printf(ccli, list, &cnt, - "%sTIMESTAMP", ename); + ret = ccli_list_add_printf(ccli, list, cnt, + "%sTIMESTAMP", str); + ret = ccli_list_add_printf(ccli, list, cnt, + "%sTIMESTAMP_USECS", str); if (ret < 0) - ccli_list_free(ccli, list, cnt); + ccli_list_free(ccli, list, *cnt); } + if (ret > 0) { + /* If there's any matches, add the "subtraction" */ + for (i = 0, r = ret; ret > 0 && i < r; i++) { + if (strcmp((*list)[i], match) == 0) { + ret = ccli_list_add_printf(ccli, list, cnt, + "%s-", match); + break; + } + } + } + if (ret < 0) + ccli_list_free(ccli, list, *cnt); + + match[strlen(match)] = CCLI_NOSPACE; return ret; } +static int synth_event_match(struct ccli *ccli, char ***list, int *cnt, + struct tep_handle *tep, char *prefix, + char *ename1, char *ename2) +{ + struct tep_event *event1; + struct tep_event *event2; + char *p; + + /* Can only be one of the previous events */ + p = strchr(ename1, '.'); + if (!p) { + ccli_printf(ccli, "# %s needs a field\n", ename1); + ccli_line_refresh(ccli); + return 0; + } + *p = '\0'; + event1 = find_event(tep, ename1); + if (!event1) { + ccli_printf(ccli, "\n# Event %s not found\n", ename1); + ccli_line_refresh(ccli); + return 0; + } + p = strchr(ename2, '.'); + if (!p) { + ccli_printf(ccli, "\n# %s needs a field\n", ename2); + ccli_line_refresh(ccli); + return 0; + } + *p = '\0'; + event2 = find_event(tep, ename2); + if (!event2) { + ccli_printf(ccli, "\n# Event %s not found\n", ename2); + ccli_line_refresh(ccli); + return 0; + } + + ccli_list_add_printf(ccli, list, cnt, "%s%s/%s", + prefix, event1->system, event1->name); + return ccli_list_add_printf(ccli, list, cnt, "%s%s/%s", + prefix, event2->system, event2->name); +} + +static int append_field_cal(struct ccli *ccli, struct tep_handle *tep, char ***list, + char *ename1, char *ename2, + char *str, char *match) +{ + char *prefix; + int cnt = 0; + char *e; + char *p; + int ret; + + /* Find start of the event */ + e = strchr(str, '-'); + if (!e) // should not happen + return 0; + + *e = 0; + ret = asprintf(&prefix, "%s-", str); + if (ret < 0) + return 0; + *e = '-'; + e++; + p = strchr(e, '.'); + if (!p) { + ret = synth_event_match(ccli, list, &cnt, + tep, prefix, ename1, ename2); + free(prefix); + match[strlen(match)] = '.'; + return ret; + } + free(prefix); + + return append_field_completion(ccli, list, &cnt, tep, p, str, e, match); +} + +static int append_field_ts(struct ccli *ccli, struct tep_handle *tep, char ***list, + char *str, char *match) +{ + int cnt = 0; + char *e; + char *p; + + /* Find start of the event */ + e = strchr(str, '='); + if (!e) // should not happen + return 0; + e++; + + /* Find the end of the event */ + for (p = e; *p && *p != '.'; p++) + ; + if (!*p) // Should not happen! + return 0; + + return append_field_completion(ccli, list, &cnt, tep, p, str, e, match); +} + static int synthetic_completion(struct ccli *ccli, void *data, int argc, char **argv, char ***list, int word, char *match) { struct tep_handle *tep = data; - struct tep_event *event1, *event2; + char *prefix; char *p; int cnt = 0; int len; @@ -915,45 +1099,23 @@ static int synthetic_completion(struct ccli *ccli, void *data, ccli_line_refresh(ccli); return 0; } + if (strchr(p, '-')) + return append_field_cal(ccli, tep, list, + argv[1], argv[2], argv[word], match); + if (strchr(p, '.')) - return append_field_ts(ccli, tep, list, argv[word]); + return append_field_ts(ccli, tep, list, argv[word], match); - argv[word][p - match] = '\0'; + len = p - match; + prefix = argv[word]; + prefix[len + 1] = '\0'; + prefix[len] = '='; - /* Can only be one of the previous events */ - p = strchr(argv[1], '.'); - if (!p) { - ccli_printf(ccli, "# %s needs a field\n", argv[1]); - ccli_line_refresh(ccli); - return 0; - } - *p = '\0'; - event1 = find_event(tep, argv[1]); - if (!event1) { - ccli_printf(ccli, "\n# Event %s not found\n", argv[1]); - ccli_line_refresh(ccli); - return 0; - } - p = strchr(argv[2], '.'); - if (!p) { - ccli_printf(ccli, "\n# %s needs a field\n", argv[2]); - ccli_line_refresh(ccli); - return 0; - } - *p = '\0'; - event2 = find_event(tep, argv[2]); - if (!event2) { - ccli_printf(ccli, "\n# Event %s not found\n", argv[2]); - ccli_line_refresh(ccli); - return 0; - } - - ccli_list_add_printf(ccli, list, &cnt, "%s=%s/%s", argv[word], - event1->system, event1->name); - ret = ccli_list_add_printf(ccli, list, &cnt, "%s=%s/%s", - argv[word], event2->system, event2->name); + ret = synth_event_match(ccli, list, &cnt, tep, prefix, argv[1], argv[2]); match[strlen(match)] = '.'; + if (ret < 0) + ccli_list_free(ccli, list, cnt); return ret; } printf("\neprobe word=%d match=%s\n", word, match); |