summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Google) <rostedt@goodmis.org>2022-02-01 17:32:25 -0500
committerSteven Rostedt (Google) <rostedt@goodmis.org>2022-02-01 17:32:25 -0500
commit88fd2a659f8d9e19280f8e9d8333e8a797f6f7bd (patch)
tree535a7fcc178522989063fad44908c1155b1c4861
parentf9b6e031d0ab384786d3e58067544142e3ed618f (diff)
downloadktrace-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.c296
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);