From patchwork Fri Oct 25 07:40:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 13850154 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3E62B15B13D for ; Fri, 25 Oct 2024 07:42:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729842127; cv=none; b=nJvjoUt3PN51NJsFSQqjZNS9JXm8ospiQCY9HW8F9FJy4TQ5fiuCnEeX6grRo4JxEx04wyM4ZJoejBvCTTAUmd0dMI4ZG3fOMn4vGB5+f7RLzdtrKnxZFIgFlP5saZxvrQqDZJpgTzbIQ5zx4735fPmTeF4Y+CIqovUMf1LIzEw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729842127; c=relaxed/simple; bh=gqvqTnn5bpS+zGyakPzTPbVBJLTBuLNBlc+n0Jg1g3Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MlYumykU6WAP5M4ycX8viMDmbxEieRcD43+VW1Q4BO8eMK3CgwQdfgcZwBUa+A7v/Cq7EugAaVitfypnt9gHge8Yg5Njjf7aNYtMKBHhURkETrTVUHMQ0GEfKtS9q+i/WsMZA30vMpNvH70x8Ia7BK1GLpMorskj0cvDXsXLfY0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 17DE9C4CEC3; Fri, 25 Oct 2024 07:42:07 +0000 (UTC) Received: from rostedt by gandalf with local (Exim 4.98) (envelope-from ) id 1t4Ey8-00000004r2h-46t6; Fri, 25 Oct 2024 03:42:48 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: "Steven Rostedt (Google)" Subject: [PATCH 1/4] libtraceeval task-eval: Add wake up latency Date: Fri, 25 Oct 2024 03:40:44 -0400 Message-ID: <20241025074247.1157166-2-rostedt@goodmis.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241025074247.1157166-1-rostedt@goodmis.org> References: <20241025074247.1157166-1-rostedt@goodmis.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: "Steven Rostedt (Google)" Add logic to keep track of the wake up latency if the sched_waking event is recorded. Signed-off-by: Steven Rostedt (Google) --- samples/task-eval.c | 238 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 222 insertions(+), 16 deletions(-) diff --git a/samples/task-eval.c b/samples/task-eval.c index 178936dec686..7b709f715332 100644 --- a/samples/task-eval.c +++ b/samples/task-eval.c @@ -92,7 +92,8 @@ enum sched_state { IDLE, ZOMBIE, EXITED, - OTHER + OTHER, + WAKEUP, }; /* @@ -222,6 +223,68 @@ static void insert_cpu_data(struct traceeval *teval, int cpu, int state, traceeval_insert(teval, keys, vals); } +/* + * When tracking tasks and threads wake up timings. + */ +static struct traceeval_type wakeup_delta_keys[] = { + { + .type = TRACEEVAL_TYPE_NUMBER, + .name = "PID", + }, +}; + +/* + * When finishing the timings of the task being woken up. + */ +static struct traceeval_type wakeup_delta_vals[] = { + { + .type = TRACEEVAL_TYPE_STRING, + .name = "COMM", + }, + { + .type = TRACEEVAL_TYPE_NUMBER, + .name = "Prio", + }, +}; + +static void start_wakeup_data(struct traceeval *teval, int pid, + const char *comm, int prio, unsigned long long ts) +{ + struct traceeval_data keys[1]; + struct traceeval_data vals[2]; + + TRACEEVAL_SET_NUMBER(keys[0], pid); + + TRACEEVAL_SET_CSTRING(vals[0], comm); + TRACEEVAL_SET_NUMBER(vals[1], prio); + + traceeval_delta_start(teval, keys, vals, ts); +} + +static int stop_wakeup_data(struct traceeval *teval, int pid, + const char **comm, int *prio, unsigned long long ts, + unsigned long long *delta) +{ + const struct traceeval_data *results; + struct traceeval_data keys[1]; + int ret; + + TRACEEVAL_SET_NUMBER(keys[0], pid); + + ret = traceeval_delta_stop(teval, keys, &results, ts, delta, NULL); + if (ret < 1) + return ret; + + if (comm) + *comm = results[0].string; + + if (prio) + *prio = results[1].number; + + traceeval_results_release(teval, results); + return 1; +} + /* * When tracking tasks and threads, remember the task id (PID) * when scheduling out (for sleep state) or in (for running state). @@ -405,11 +468,11 @@ static struct traceeval_type thread_keys[] = { }, { .type = TRACEEVAL_TYPE_NUMBER, - .name = "Schedule state", + .name = "Prio", }, { .type = TRACEEVAL_TYPE_NUMBER, - .name = "Prio", + .name = "Schedule state", }, }; @@ -432,8 +495,64 @@ static void insert_thread_data(struct traceeval *teval, struct traceeval_data vals[1]; TRACEEVAL_SET_NUMBER(keys[0], tid); - TRACEEVAL_SET_NUMBER(keys[1], state); - TRACEEVAL_SET_NUMBER(keys[2], prio); + TRACEEVAL_SET_NUMBER(keys[1], prio); + TRACEEVAL_SET_NUMBER(keys[2], state); + + TRACEEVAL_SET_DELTA(vals[0], delta, timestamp); + + traceeval_insert(teval, keys, vals); +} + +static struct traceeval_type wakeup_task_keys[] = { + { + .type = TRACEEVAL_TYPE_STRING, + .name = "COMM" + }, +}; + +static struct traceeval_type wakeup_thread_keys[] = { + { + .type = TRACEEVAL_TYPE_NUMBER, + .name = "PID" + }, + { + .type = TRACEEVAL_TYPE_NUMBER, + .name = "Prio" + }, +}; + +static struct traceeval_type wakeup_vals[] = { + { + .type = TRACEEVAL_TYPE_DELTA, + .name = DELTA_NAME, + }, +}; + +static void insert_wakeup_task_data(struct traceeval *teval, + const char *comm, + unsigned long long delta, + unsigned long long timestamp) +{ + struct traceeval_data keys[1]; + struct traceeval_data vals[1]; + + TRACEEVAL_SET_CSTRING(keys[0], comm); + + TRACEEVAL_SET_DELTA(vals[0], delta, timestamp); + + traceeval_insert(teval, keys, vals); +} + +static void insert_wakeup_thread_data(struct traceeval *teval, + int tid, int prio, + unsigned long long delta, + unsigned long long timestamp) +{ + struct traceeval_data keys[2]; + struct traceeval_data vals[1]; + + TRACEEVAL_SET_NUMBER(keys[0], tid); + TRACEEVAL_SET_NUMBER(keys[1], prio); TRACEEVAL_SET_DELTA(vals[0], delta, timestamp); @@ -443,11 +562,13 @@ static void insert_thread_data(struct traceeval *teval, struct process_data { struct traceeval *teval_cpus; struct traceeval *teval_threads; + struct traceeval *teval_wakeup; }; struct task_data { struct traceeval *teval_cpus; struct traceeval *teval_tasks; + struct traceeval *teval_wakeup; unsigned long long last_ts; char *comm; }; @@ -468,6 +589,7 @@ static void release_data(const struct traceeval_type *type, pdata = data->pointer; traceeval_release(pdata->teval_cpus); traceeval_release(pdata->teval_threads); + traceeval_release(pdata->teval_wakeup); free(pdata); data->pointer = NULL; } @@ -481,6 +603,10 @@ static void init_process_data(struct process_data *pdata) pdata->teval_threads = traceeval_init(thread_keys, thread_vals); if (!pdata->teval_threads) pdie("Creating trace eval threads"); + + pdata->teval_wakeup = traceeval_init(wakeup_thread_keys, wakeup_vals); + if (!pdata->teval_wakeup) + pdie("Creating trace eval wakeup"); } void set_process_data(struct task_data *tdata, const char *comm, void *data) @@ -576,6 +702,7 @@ static void update_thread(struct task_data *tdata, int pid, const char *comm, unsigned long long ts) { struct process_data *pdata; + int ret; pdata = get_process_data(tdata, comm); @@ -583,6 +710,12 @@ static void update_thread(struct task_data *tdata, int pid, const char *comm, /* Also update the process */ insert_task_data(tdata->teval_tasks, comm, state, pdata, delta, ts); + + ret = stop_wakeup_data(tdata->teval_wakeup, pid, &comm, &prio, ts, &delta); + if (ret < 1) + return; + insert_wakeup_task_data(tdata->teval_wakeup, comm, delta, ts); + insert_wakeup_thread_data(pdata->teval_wakeup, pid, prio, delta, ts); } static void start_running_thread(struct task_data *tdata, @@ -660,6 +793,12 @@ static void sched_out(struct task_data *tdata, const char *comm, /* Start timing the task while it's off the CPU */ start_task_data(tdata->teval_tasks, pid, state, comm, prio, record->ts); + /* + * If a wakeup happened when the task was running, do not record + * the wakeup latency. + */ + stop_wakeup_data(tdata->teval_wakeup, pid, NULL, NULL, record->ts, NULL); + if (ret <= 0) return; @@ -759,6 +898,43 @@ static int switch_func(struct tracecmd_input *handle, struct tep_event *event, return 0; } +static int wakeup_func(struct tracecmd_input *handle, struct tep_event *event, + struct tep_record *record, int cpu, void *data) +{ + static struct tep_format_field *comm_field; + static struct tep_format_field *pid_field; + static struct tep_format_field *prio_field; + struct task_data *tdata = data; + unsigned long long val; + const char *comm; + int prio; + int pid; + int ret; + + if (!comm_field) { + comm_field = get_field(event, "comm"); + pid_field = get_field(event, "pid"); + prio_field = get_field(event, "prio"); + } + + comm = record->data + comm_field->offset; + if (tdata->comm && strcmp(comm, tdata->comm) != 0) + return 0; + + ret = tep_read_number_field(pid_field, record->data, &val); + if (ret < 0) + die("Could not read sched_switch pid for record"); + pid = val; + + ret = tep_read_number_field(prio_field, record->data, &val); + if (ret < 0) + die("Could not read sched_switch prio for record"); + prio = val; + + start_wakeup_data(tdata->teval_wakeup, pid, comm, prio, record->ts); + return 0; +} + static void print_microseconds(int idx, unsigned long long nsecs) { unsigned long long usecs; @@ -947,10 +1123,15 @@ static void display_state_times(int state, struct traceeval_stat *stat) case SLEEP: printf(" Total sleep time (us):"); print_stats(12, stat); + break; + case WAKEUP: + printf(" Total wakeup time (us):"); + print_stats(11, stat); + break; } } -static void display_threads(struct traceeval *teval) +static void display_threads(struct traceeval *teval, struct traceeval *wake_teval) { struct traceeval_iterator *iter = traceeval_iterator_get(teval); const struct traceeval_data *keys; @@ -962,15 +1143,15 @@ static void display_threads(struct traceeval *teval) traceeval_iterator_sort(iter, thread_keys[0].name, 0, true); /* PRIO */ - traceeval_iterator_sort(iter, thread_keys[2].name, 1, true); + traceeval_iterator_sort(iter, thread_keys[1].name, 1, true); /* STATE */ - traceeval_iterator_sort(iter, thread_keys[1].name, 2, true); + traceeval_iterator_sort(iter, thread_keys[2].name, 2, true); while (traceeval_iterator_next(iter, &keys) > 0) { int tid = keys[0].number; - int state = keys[1].number; - int prio = keys[2].number; + int prio = keys[1].number; + int state = keys[2].number; stat = traceeval_iterator_stat(iter, DELTA_NAME); if (!stat) @@ -987,6 +1168,14 @@ static void display_threads(struct traceeval *teval) last_prio = prio; display_state_times(state, stat); + + if (state != RUNNING) + continue; + + stat = traceeval_stat_size(wake_teval, keys, 2, DELTA_NAME); + if (!stat) + continue; + display_state_times(WAKEUP, stat); } traceeval_iterator_put(iter); @@ -997,12 +1186,12 @@ static void display_threads(struct traceeval *teval) static void display_process(struct process_data *pdata) { - display_threads(pdata->teval_threads); + display_threads(pdata->teval_threads, pdata->teval_wakeup); display_cpus(pdata->teval_cpus); printf("\n"); } -static void display_process_stats(struct traceeval *teval, +static void display_process_stats(struct traceeval *teval, struct traceeval *wake_teval, struct process_data *pdata, const char *comm) { struct traceeval_stat *stat; @@ -1016,10 +1205,18 @@ static void display_process_stats(struct traceeval *teval, stat = traceeval_stat(teval, keys, DELTA_NAME); display_state_times(i, stat); + + if (i != RUNNING) + continue; + + stat = traceeval_stat_size(wake_teval, keys, 1, DELTA_NAME); + if (!stat) + continue; + display_state_times(WAKEUP, stat); } } -static void display_processes(struct traceeval *teval) +static void display_processes(struct traceeval *teval, struct traceeval *wake_teval) { struct traceeval_iterator *iter = traceeval_iterator_get(teval); const struct traceeval_data *keys; @@ -1049,7 +1246,7 @@ static void display_processes(struct traceeval *teval) printf("Task: %s\n", comm); - display_process_stats(teval, pdata, comm); + display_process_stats(teval, wake_teval, pdata, comm); if (pdata) display_process(pdata); } @@ -1066,7 +1263,7 @@ static void display(struct task_data *tdata) unsigned long long idle_time = 0; if (tdata->comm) { - return display_processes(tdata->teval_tasks); + return display_processes(tdata->teval_tasks, tdata->teval_wakeup); } iter = traceeval_iterator_get(teval); @@ -1105,7 +1302,7 @@ static void display(struct task_data *tdata) display_cpus(tdata->teval_cpus); printf("\n"); - display_processes(tdata->teval_tasks); + display_processes(tdata->teval_tasks, tdata->teval_wakeup); } static void free_tdata(struct task_data *tdata) @@ -1115,6 +1312,7 @@ static void free_tdata(struct task_data *tdata) traceeval_release(tdata->teval_cpus); traceeval_release(tdata->teval_tasks); + traceeval_release(tdata->teval_wakeup); } /* @@ -1237,7 +1435,15 @@ int main (int argc, char **argv) if (traceeval_delta_create(data.teval_cpus, cpu_delta_keys, cpu_delta_vals) < 0) pdie("Creating trace delta cpus"); + data.teval_wakeup = traceeval_init(wakeup_task_keys, wakeup_vals); + if (!data.teval_wakeup) + pdie("Creating trace eval wakeup"); + + if (traceeval_delta_create(data.teval_wakeup, wakeup_delta_keys, wakeup_delta_vals) < 0) + pdie("Creating trace delta wakeup"); + tracecmd_follow_event(handle, "sched", "sched_switch", switch_func, &data); + tracecmd_follow_event(handle, "sched", "sched_waking", wakeup_func, &data); tracecmd_iterate_events(handle, NULL, 0, event_callback, &data); From patchwork Fri Oct 25 07:40:45 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 13850156 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 64DFC1B393B for ; Fri, 25 Oct 2024 07:42:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729842127; cv=none; b=BcUjqx7XmdjIbKAb5pp4NWwdavzjPr7gcUic3YIiIslVIm7GSh8gNsIuwiA5rG7Ar1XV6u9sZr+aBYXGHSte0iBv1B8M8TACx0Kpkz7BHEIrs9ZdEF3rVKIFz3pYOkufkysX1aF076LTDh7FnDtNz/di/9nF5gryyZiIjVHpfFE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729842127; c=relaxed/simple; bh=/cNBE4kKCXd0IMrlmibZR3WdRLKURjZ435iI2NvnmSw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ph3qCPamhT5yuFsPKKnxEOIhM6tq0LjanD3qxLNcT3GP+AwkCZZ3rljgRPPnLJKVUpZqR+zw4/TGXhBMLQYc0kDUfDt57O9YKDW52L/ilqogwrTeyeji7FpWSIzQINEgZbRc2OrMN6UesLZzMBDuAxk45U8ZglUcnvCG+av9kGM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 18058C4AF09; Fri, 25 Oct 2024 07:42:07 +0000 (UTC) Received: from rostedt by gandalf with local (Exim 4.98) (envelope-from ) id 1t4Ey9-00000004r2k-02aD; Fri, 25 Oct 2024 03:42:49 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: "Steven Rostedt (Google)" Subject: [PATCH 2/4] libtraceeval samples: Add PARKED and DEAD fields Date: Fri, 25 Oct 2024 03:40:45 -0400 Message-ID: <20241025074247.1157166-3-rostedt@goodmis.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241025074247.1157166-1-rostedt@goodmis.org> References: <20241025074247.1157166-1-rostedt@goodmis.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: "Steven Rostedt (Google)" get_stop_state() was returning PREEMPT when a task was really in the PARKED or DEAD state. Check those as well. Signed-off-by: Steven Rostedt (Google) --- samples/task-eval.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/samples/task-eval.c b/samples/task-eval.c index 7b709f715332..47ccce8e4737 100644 --- a/samples/task-eval.c +++ b/samples/task-eval.c @@ -91,7 +91,9 @@ enum sched_state { SLEEP, IDLE, ZOMBIE, + PARKED, EXITED, + DEAD, OTHER, WAKEUP, }; @@ -749,6 +751,10 @@ static int get_stop_state(unsigned long long val) return ZOMBIE; if (val & 0x20) return EXITED; + if (val & 0x40) + return PARKED; + if (val & 0x80) + return DEAD; return PREEMPT; } From patchwork Fri Oct 25 07:40:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 13850157 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 80EDD1B85CA for ; Fri, 25 Oct 2024 07:42:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729842127; cv=none; b=P0Ip5xH/cyxZxyGOug0dcyWVJsku07/EjStLqhQThauN5mE4f/drroz/9ywghH6HbhKVThLn6SIlqozmwu3ihSRdoNJDZldr0UffCBYUSOx694I+yBb4Ri5kp2a0sfid8RO8Xw9Ag22lFPQajz+bvoapTni4xpSPxUKYXMbul/A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729842127; c=relaxed/simple; bh=7hJbs6cyNzYdec/zkTGHOgKRvygqUOuj49be/cfq8vk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HSI9MRSlQzqLt3XSsI3hhaPt8LZvNTp4yQx0BsVBuzIQVCXO78G22gba6x5hUqbjI+ejFYEVPGLKTRMahQF7SuGIinQKXsZICL7z+0ti6b4K5wx9NjCg0jNXpMSNoTdYQ2oZikk2cdRe6uLPmanHOMIrCBljatwFICsqF0mYZNs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 291AAC4CEE4; Fri, 25 Oct 2024 07:42:07 +0000 (UTC) Received: from rostedt by gandalf with local (Exim 4.98) (envelope-from ) id 1t4Ey9-00000004r2n-0AEr; Fri, 25 Oct 2024 03:42:49 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: "Steven Rostedt (Google)" Subject: [PATCH 3/4] libtraceevent: Add DECLARE_TRACEEVAL_ Date: Fri, 25 Oct 2024 03:40:46 -0400 Message-ID: <20241025074247.1157166-4-rostedt@goodmis.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241025074247.1157166-1-rostedt@goodmis.org> References: <20241025074247.1157166-1-rostedt@goodmis.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: "Steven Rostedt (Google)" Using the format of: { .type = TRACEEVAL_TYPE_NUMBER, .name = "Schedule state" }, { .type = TRACEEVAL_TYPE_STRING, .name = "COMM", }, { .type = TRACEEVAL_TYPE_NUMBER, .name = "Prio", }, Is cumbersome, instead add macros that make it easier to assign these values: DECLARE_TRACEEVAL_NUMBER("Schedule state"), DECLARE_TRACEEVAL_STRING("COMM"), DECLARE_TRACEEVAL_NUMBER("Prio"), Signed-off-by: Steven Rostedt (Google) --- include/traceeval.h | 19 +++++++ samples/task-eval.c | 122 +++++++++----------------------------------- 2 files changed, 43 insertions(+), 98 deletions(-) diff --git a/include/traceeval.h b/include/traceeval.h index f02ecdd58ffb..7de59a302445 100644 --- a/include/traceeval.h +++ b/include/traceeval.h @@ -97,6 +97,24 @@ struct traceeval_data { }; }; +#define __TRACEEVAL_DECLARE(data_type, data_name) \ + { .type = TRACEEVAL_TYPE_##data_type, .name = (data_name) } + +#define DECLARE_TRACEEVAL_NUMBER(data) __TRACEEVAL_DECLARE(NUMBER, data) +#define DECLARE_TRACEEVAL_NUMBER_8(data) __TRACEEVAL_DECLARE(NUMBER_8, data) +#define DECLARE_TRACEEVAL_NUMBER_16(data) __TRACEEVAL_DECLARE(NUMBER_16, data) +#define DECLARE_TRACEEVAL_NUMBER_32(data) __TRACEEVAL_DECLARE(NUMBER_32, data) +#define DECLARE_TRACEEVAL_NUMBER_64(data) __TRACEEVAL_DECLARE(NUMBER_64, data) +#define DECLARE_TRACEEVAL_STRING(data) __TRACEEVAL_DECLARE(STRING, data) +#define DECLARE_TRACEEVAL_CSTRING(data) __TRACEEVAL_DECLARE(STRING, data) +#define DECLARE_TRACEEVAL_DELTA(data) __TRACEEVAL_DECLARE(DELTA, data) +#define DECLARE_TRACEEVAL_POINTER(data_name, data_release, data_copy) \ + { \ + .type = TRACEEVAL_TYPE_POINTER, \ + .name = (data_name), \ + .release = data_release, .copy = data_copy, \ + } + #define __TRACEEVAL_DATA(data_type, member, data) \ { .type = TRACEEVAL_TYPE_##data_type, .member = (data) } @@ -362,6 +380,7 @@ int traceeval_iterator_query(struct traceeval_iterator *iter, const struct traceeval_data **results); void traceeval_iterator_results_release(struct traceeval_iterator *iter, const struct traceeval_data *results); +int traceeval_iterator_reset(struct traceeval_iterator *iter); struct traceeval_stat *traceeval_iterator_stat(struct traceeval_iterator *iter, const char *val_name); int traceeval_iterator_delta_stop(struct traceeval_iterator *iter, diff --git a/samples/task-eval.c b/samples/task-eval.c index 47ccce8e4737..26197385c91d 100644 --- a/samples/task-eval.c +++ b/samples/task-eval.c @@ -104,10 +104,7 @@ enum sched_state { * sched_switch event. */ static struct traceeval_type cpu_delta_keys[] = { - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "CPU", - }, + DECLARE_TRACEEVAL_NUMBER("CPU"), }; /* @@ -117,10 +114,7 @@ static struct traceeval_type cpu_delta_keys[] = { * as RUNNING. */ static struct traceeval_type cpu_delta_vals[] = { - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "Schedule state", - }, + DECLARE_TRACEEVAL_NUMBER("Schedule state"), }; static void start_cpu_data(struct traceeval *teval, int cpu, int state, @@ -190,14 +184,8 @@ int cpu_last_state(struct traceeval *teval, int cpu, int *state) * The output will show all the CPUs and their IDLE vs RUNNING states. */ static struct traceeval_type cpu_keys[] = { - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "CPU", - }, - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "Schedule state", - }, + DECLARE_TRACEEVAL_NUMBER("CPU"), + DECLARE_TRACEEVAL_NUMBER("Schedule state"), }; /* @@ -205,10 +193,7 @@ static struct traceeval_type cpu_keys[] = { * CPU was in that state. */ static struct traceeval_type cpu_vals[] = { - { - .type = TRACEEVAL_TYPE_DELTA, - .name = DELTA_NAME, - }, + DECLARE_TRACEEVAL_DELTA(DELTA_NAME), }; static void insert_cpu_data(struct traceeval *teval, int cpu, int state, @@ -229,24 +214,15 @@ static void insert_cpu_data(struct traceeval *teval, int cpu, int state, * When tracking tasks and threads wake up timings. */ static struct traceeval_type wakeup_delta_keys[] = { - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "PID", - }, + DECLARE_TRACEEVAL_NUMBER("PID"), }; /* * When finishing the timings of the task being woken up. */ static struct traceeval_type wakeup_delta_vals[] = { - { - .type = TRACEEVAL_TYPE_STRING, - .name = "COMM", - }, - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "Prio", - }, + DECLARE_TRACEEVAL_STRING("COMM"), + DECLARE_TRACEEVAL_NUMBER("Prio"), }; static void start_wakeup_data(struct traceeval *teval, int pid, @@ -292,10 +268,7 @@ static int stop_wakeup_data(struct traceeval *teval, int pid, * when scheduling out (for sleep state) or in (for running state). */ static struct traceeval_type task_delta_keys[] = { - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "PID", - }, + DECLARE_TRACEEVAL_NUMBER("PID"), }; /* @@ -304,18 +277,9 @@ static struct traceeval_type task_delta_keys[] = { * and the priority it had. This will be saved for the output. */ static struct traceeval_type task_delta_vals[] = { - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "Schedule state" - }, - { - .type = TRACEEVAL_TYPE_STRING, - .name = "COMM", - }, - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "Prio", - }, + DECLARE_TRACEEVAL_NUMBER("Schedule state"), + DECLARE_TRACEEVAL_STRING("COMM"), + DECLARE_TRACEEVAL_NUMBER("Prio"), }; static void start_task_data(struct traceeval *teval, int pid, int state, @@ -367,14 +331,8 @@ static int stop_task_data(struct traceeval *teval, int pid, int *state, * they were in: RUNNING, BLOCKED, PREEMPTED, SLEEPING. */ static struct traceeval_type task_keys[] = { - { - .type = TRACEEVAL_TYPE_STRING, - .name = "COMM" - }, - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "Schedule state" - }, + DECLARE_TRACEEVAL_STRING("COMM"), + DECLARE_TRACEEVAL_NUMBER("Schedule state"), }; static void release_data(const struct traceeval_type *type, @@ -400,16 +358,8 @@ static int copy_data(const struct traceeval_type *type, * that will be saved in the "data" field. */ static struct traceeval_type task_vals[] = { - { - .type = TRACEEVAL_TYPE_POINTER, - .name = "data", - .release = release_data, - .copy = copy_data, - }, - { - .type = TRACEEVAL_TYPE_DELTA, - .name = DELTA_NAME, - }, + DECLARE_TRACEEVAL_POINTER("data", release_data, copy_data), + DECLARE_TRACEEVAL_DELTA(DELTA_NAME), }; static int insert_task_data(struct traceeval *teval, const char *comm, @@ -464,28 +414,16 @@ static bool task_data_exists(struct traceeval *teval, const char *comm, void **d * and their priority. */ static struct traceeval_type thread_keys[] = { - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "TID", - }, - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "Prio", - }, - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "Schedule state", - }, + DECLARE_TRACEEVAL_NUMBER("TID"), + DECLARE_TRACEEVAL_NUMBER("Prio"), + DECLARE_TRACEEVAL_NUMBER("Schedule state"), }; /* * Save the timings of the thread/state/prio keys. */ static struct traceeval_type thread_vals[] = { - { - .type = TRACEEVAL_TYPE_DELTA, - .name = DELTA_NAME, - }, + DECLARE_TRACEEVAL_DELTA(DELTA_NAME), }; static void insert_thread_data(struct traceeval *teval, @@ -506,28 +444,16 @@ static void insert_thread_data(struct traceeval *teval, } static struct traceeval_type wakeup_task_keys[] = { - { - .type = TRACEEVAL_TYPE_STRING, - .name = "COMM" - }, + DECLARE_TRACEEVAL_STRING("COMM"), }; static struct traceeval_type wakeup_thread_keys[] = { - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "PID" - }, - { - .type = TRACEEVAL_TYPE_NUMBER, - .name = "Prio" - }, + DECLARE_TRACEEVAL_NUMBER("PID"), + DECLARE_TRACEEVAL_NUMBER("Prio"), }; static struct traceeval_type wakeup_vals[] = { - { - .type = TRACEEVAL_TYPE_DELTA, - .name = DELTA_NAME, - }, + DECLARE_TRACEEVAL_DELTA(DELTA_NAME), }; static void insert_wakeup_task_data(struct traceeval *teval, From patchwork Fri Oct 25 07:40:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 13850158 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 80E831B81C1 for ; Fri, 25 Oct 2024 07:42:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729842127; cv=none; b=ktOftu7QiyVrvVEcGm6/bd8YbSDT+8qXP/M69bdbDE8IxbcqDHiF29/8nvZ7F3P2sfkLybQxd3wqKuFZAvmE416mRpQRwTFBAyU2NaG4EV97OvDgnOCIJlLNEJGORH+UIRaS73Pd6Fv+G18XMToZ12+xZVPBHAb3Q3i/Vw9ImTM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729842127; c=relaxed/simple; bh=3XKlpAbA05O6qjGiS+uCYQcKd9TZx30qszisJXTiOCg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DjXyA5rGBbvYRG2UeXqE7ru0EPoWm/m6U7fNOg+RBXUtVEUMUI9DFMo0Ik1BK3tI/ku9xJXpTe/6zEfDvWPOCkrKsoFMhA5cyzk5wJ1CuL7ayw5ARBWmrPGJXHEfLgzL3km7LbE+jFv05WayXJF76nxWxbMgxC57l1lqvMSn6Dc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 280DCC4CEE5; Fri, 25 Oct 2024 07:42:07 +0000 (UTC) Received: from rostedt by gandalf with local (Exim 4.98) (envelope-from ) id 1t4Ey9-00000004r2t-0JGK; Fri, 25 Oct 2024 03:42:49 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: "Steven Rostedt (Google)" , Ross Zwisler Subject: [PATCH v2 4/4] libtraceeval: Add traceeval_type_index() API Date: Fri, 25 Oct 2024 03:40:47 -0400 Message-ID: <20241025074247.1157166-5-rostedt@goodmis.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241025074247.1157166-1-rostedt@goodmis.org> References: <20241025074247.1157166-1-rostedt@goodmis.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: "Steven Rostedt (Google)" Add a way to get the index of a traceeval_type from its name. This makes indexing the elements more robust and less error prone. By adding a way to index the names via variables, keys can be added and rearranged without worrying about the other accesses in the program being affected. The new functions are: traceeval_type_index() traceeval_type_index_size() The use case can by: static struct traceeval_type keys[] = { { .type = TRACEEVAL_TYPE_NUMBER, .name = "PID" } }; static ssize_t MY_KEY; static void init_keys(void) { MY_KEY = traceeval_type_index("PID", keys); } static void insert_data(struct traceeval *teval, int data) { struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(keys)]; TRACEEVAL_SET_NUMBER(keys[MY_KEY], data); traceeval_insert(teval, keys, NULL); } Using this method keeps from having to constantly tinker with hardcoded index numbers when adding or rearranging keys and values. Cc: Ross Zwisler Signed-off-by: Steven Rostedt (Google) --- Changes since v1: https://lore.kernel.org/linux-trace-devel/20231019113008.4699da30@gandalf.local.home - Rebased on latest work Documentation/libtraceeval-init.txt | 52 ++++-- Documentation/libtraceeval.txt | 4 + include/traceeval.h | 15 ++ samples/task-eval.c | 241 ++++++++++++++++++---------- 4 files changed, 217 insertions(+), 95 deletions(-) diff --git a/Documentation/libtraceeval-init.txt b/Documentation/libtraceeval-init.txt index 1c09cee319c8..10a2729372bb 100644 --- a/Documentation/libtraceeval-init.txt +++ b/Documentation/libtraceeval-init.txt @@ -3,7 +3,8 @@ libtraceeval(3) NAME ---- -traceeval_init, traceeval_init_size, traceeval_release - Create a trace evaluation helper mechanism. +traceeval_init, traceeval_init_size, traceeval_release, traceeval_type_index, traceeval_type_index_size +- Create a trace evaluation helper mechanism. SYNOPSIS -------- @@ -15,6 +16,8 @@ struct traceeval pass:[*]*traceeval_init*(struct traceeval_type pass:[*]_keys_, struct traceeval pass:[*]*traceeval_init_size*(struct traceeval_type pass:[*]_keys_, struct traceeval_type pass:[*]_vals_, int _nr_keys_, int _nr_vals_); void *traceeval_release*(struct traceeval pass:[*]_teval_); +ssize_t *traceeval_type_index*(const char pass:[*]_name_, struct traceeval_type pass:*]_type_); +ssize_t *traceeval_type_index_size*(const char pass:[*]_name_, struct traceeval_type pass:*]_type_, size_t nr_types); -- DESCRIPTION @@ -164,11 +167,22 @@ requires static size arrays is because it is really just a macro that calles The *traceeval_release()* function releases and frees all the resources of a traceeval returned by *traceeval_init()* and *traceeval_init_size()*. +The *traceeval_type_index()* is a helper function that is used to find the +index of a traceeval_type _type_ by its given _name_. If the name is not found, it returns +-1. This is handy to not have to remember which index belongs to which field. +By creating variables to hold the indexes, the variables can be used instead. +The *traceeval_type_index()* requires that _type_ is a static array. If a dynamic +array is required, then *traceeval_type_index_size()* can be used where _nr_types_ +is the size of the _type_ array. + RETURN VALUE ------------ The *traceeval_init()* and *traceeval_init_size()* both return a descriptor to the traceeval or NULL on error. +The *traceeval_type_index()* and *traceeval_type_index_size()* return the index +of the given _name_ in _type_ or -1 if not found. + EXAMPLE ------- [source,c] @@ -202,13 +216,29 @@ struct traceeval_type sched_keys[] = { }, }; +static ssize_t SCHED_COMM; +static ssize_t SCHED_PID; +static ssize_t SCHED_STATE; + +static void init_indexes(void) +{ + SCHED_COMM = traceeval_type_index("COMM", sched_keys); + SCHED_PID = traceeval_type_index("PID", sched_keys); + SCHED_STATE = traceeval_type_index("State", sched_keys); + + if (SCHED_COMM < 0 || SCHED_PID < 0 || SCHED_STATE < 0) { + printf("Had a typo in assiging indexes\n"); + exit(-1); + } +} + static int sched_callback(struct tep_event *event, struct tep_record *record, int cpu, void *data) { static struct tep_format_field *pid_field; static struct tep_format_field *comm_field; static struct tep_format_field *state_field; - struct traceeval_data keys[3]; + struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(sched_keys)]; struct traceeval *teval = data; unsigned long long val; char *comm; @@ -232,9 +262,9 @@ static int sched_callback(struct tep_event *event, struct tep_record *record, comm = record->data + comm_field->offset; - TRACEEVAL_SET_STRING(keys[0], comm); - TRACEEVAL_SET_NUMBER(keys[1], pid); - TRACEEVAL_SET_NUMBER(keys[2], state); + TRACEEVAL_SET_STRING(keys[SCHED_COMM], comm); + TRACEEVAL_SET_NUMBER(keys[SCHED_PID], pid); + TRACEEVAL_SET_NUMBER(keys[SCHED_STATE], state); traceeval_insert(teval, keys, NULL); @@ -243,7 +273,7 @@ static int sched_callback(struct tep_event *event, struct tep_record *record, static char *get_state(int state) { - switch (state & 7) { + switch (state & 0x1ff) { case 0: return "R"; case 1: @@ -260,17 +290,17 @@ static void display_teval(struct traceeval *teval) const struct traceeval_data *keys; /* Sort comms first. */ - traceeval_iterator_sort(iter, sched_keys[0].name, 0, true); + traceeval_iterator_sort(iter, sched_keys[SCHED_COMM].name, 0, true); /* Sort pids next */ - traceeval_iterator_sort(iter, sched_keys[1].name, 1, true); + traceeval_iterator_sort(iter, sched_keys[SCHED_PID].name, 1, true); /* Sort state last */ - traceeval_iterator_sort(iter, sched_keys[2].name, 2, true); + traceeval_iterator_sort(iter, sched_keys[SCHED_STATE].name, 2, true); while (traceeval_iterator_next(iter, &keys) > 0) { ssize_t hits = traceeval_hitcount_size(teval, keys, TRACEEVAL_ARRAY_SIZE(sched_keys)); printf("%s [%ld] %s: %zd\n", - keys[0].string, keys[1].number, get_state(keys[2].number), hits); + keys[SCHED_COMM].string, keys[SCHED_PID].number, get_state(keys[SCHED_STATE].number), hits); } traceeval_iterator_put(iter); } @@ -289,6 +319,8 @@ int main (int argc, char **argv) bool finished = false; int ret; + init_indexes(); + teval = traceeval_init(sched_keys, NULL); if (!teval) pdie("Creating traceeval"); diff --git a/Documentation/libtraceeval.txt b/Documentation/libtraceeval.txt index a8644b3b3c74..0c25ff7b1fa2 100644 --- a/Documentation/libtraceeval.txt +++ b/Documentation/libtraceeval.txt @@ -17,6 +17,10 @@ Creating and releasing the traceeval resources: int _nr_keys_, int _nr_vals_); void *traceeval_release*(struct traceeval pass:[*]_teval_); +Helper functions for indexing the traceeval_type and traceveal_data elements: + ssize_t *traceeval_type_index*(const char pass:[*]_name_, struct traceeval_type pass:*]_type_); + ssize_t *traceeval_type_index_size*(const char pass:[*]_name_, struct traceeval_type pass:*]_type_, size_t nr_types); + Inserting and removing elements from the traceeval: int *traceeval_insert*(struct traceeval pass:[*]_teval_, const struct traceeval_data pass:[*]_keys_, diff --git a/include/traceeval.h b/include/traceeval.h index 7de59a302445..a1079c3dba98 100644 --- a/include/traceeval.h +++ b/include/traceeval.h @@ -11,6 +11,7 @@ #include #include #include +#include #include /* Data definition interfaces */ @@ -242,6 +243,20 @@ struct traceeval_type { traceeval_data_hash_fn hash; }; +#define traceeval_type_index(name, type) \ + traceeval_type_index_size(name, type, TRACEEVAL_ARRAY_SIZE(type)) + +static inline ssize_t traceeval_type_index_size(const char *name, + struct traceeval_type *type, + size_t size) +{ + for (size_t i = 0; i < size; i++) { + if (strcmp(type[i].name, name) == 0) + return i; + } + return -1; +} + /* Statistics about a given entry element */ struct traceeval_stat; diff --git a/samples/task-eval.c b/samples/task-eval.c index 26197385c91d..406ca9af4537 100644 --- a/samples/task-eval.c +++ b/samples/task-eval.c @@ -117,14 +117,17 @@ static struct traceeval_type cpu_delta_vals[] = { DECLARE_TRACEEVAL_NUMBER("Schedule state"), }; +static ssize_t CPU_DELTA_KEY; +static ssize_t CPU_DELTA_STATE; + static void start_cpu_data(struct traceeval *teval, int cpu, int state, unsigned long long ts) { - struct traceeval_data keys[1]; - struct traceeval_data vals[1]; + struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(cpu_delta_keys)]; + struct traceeval_data vals[TRACEEVAL_ARRAY_SIZE(cpu_delta_vals)]; - TRACEEVAL_SET_NUMBER(keys[0], cpu); - TRACEEVAL_SET_NUMBER(vals[0], state); + TRACEEVAL_SET_NUMBER(keys[CPU_DELTA_KEY], cpu); + TRACEEVAL_SET_NUMBER(vals[CPU_DELTA_STATE], state); traceeval_delta_start(teval, keys, vals, ts); } @@ -132,11 +135,11 @@ static void start_cpu_data(struct traceeval *teval, int cpu, int state, static void continue_cpu_data(struct traceeval *teval, int cpu, int state, unsigned long long ts) { - struct traceeval_data keys[1]; - struct traceeval_data vals[1]; + struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(cpu_delta_keys)]; + struct traceeval_data vals[TRACEEVAL_ARRAY_SIZE(cpu_delta_vals)]; - TRACEEVAL_SET_NUMBER(keys[0], cpu); - TRACEEVAL_SET_NUMBER(vals[0], state); + TRACEEVAL_SET_NUMBER(keys[CPU_DELTA_KEY], cpu); + TRACEEVAL_SET_NUMBER(vals[CPU_DELTA_STATE], state); traceeval_delta_continue(teval, keys, vals, ts); } @@ -145,18 +148,18 @@ static int stop_cpu_data(struct traceeval *teval, int cpu, int *state, unsigned long long ts, unsigned long long *delta) { + struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(cpu_delta_keys)]; const struct traceeval_data *results; - struct traceeval_data keys[1]; int ret; - TRACEEVAL_SET_NUMBER(keys[0], cpu); + TRACEEVAL_SET_NUMBER(keys[CPU_DELTA_KEY], cpu); ret = traceeval_delta_stop(teval, keys, &results, ts, delta, NULL); if (ret < 1) return ret; if (state) - *state = results[0].number; + *state = results[CPU_DELTA_STATE].number; traceeval_results_release(teval, results); return 1; @@ -164,17 +167,17 @@ static int stop_cpu_data(struct traceeval *teval, int cpu, int *state, int cpu_last_state(struct traceeval *teval, int cpu, int *state) { + struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(cpu_delta_keys)]; const struct traceeval_data *results; - struct traceeval_data keys[1]; int ret; - TRACEEVAL_SET_NUMBER(keys[0], cpu); + TRACEEVAL_SET_NUMBER(keys[CPU_DELTA_KEY], cpu); ret = traceeval_delta_query(teval, keys, &results, NULL); if (ret < 1) return ret; - *state = results[0].number; + *state = results[CPU_DELTA_STATE].number; traceeval_results_release(teval, results); return 1; @@ -196,16 +199,20 @@ static struct traceeval_type cpu_vals[] = { DECLARE_TRACEEVAL_DELTA(DELTA_NAME), }; +static ssize_t CPU_KEY; +static ssize_t CPU_STATE; +static ssize_t CPU_DELTA; + static void insert_cpu_data(struct traceeval *teval, int cpu, int state, unsigned long long delta, unsigned long long ts) { - struct traceeval_data keys[2]; - struct traceeval_data vals[1]; + struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(cpu_keys)]; + struct traceeval_data vals[TRACEEVAL_ARRAY_SIZE(cpu_vals)]; - TRACEEVAL_SET_NUMBER(keys[0], cpu); - TRACEEVAL_SET_NUMBER(keys[1], state); + TRACEEVAL_SET_NUMBER(keys[CPU_KEY], cpu); + TRACEEVAL_SET_NUMBER(keys[CPU_STATE], state); - TRACEEVAL_SET_DELTA(vals[0], delta, ts); + TRACEEVAL_SET_DELTA(vals[CPU_DELTA], delta, ts); traceeval_insert(teval, keys, vals); } @@ -225,16 +232,20 @@ static struct traceeval_type wakeup_delta_vals[] = { DECLARE_TRACEEVAL_NUMBER("Prio"), }; +static ssize_t WAKEUP_DELTA_PID; +static ssize_t WAKEUP_DELTA_COMM; +static ssize_t WAKEUP_DELTA_PRIO; + static void start_wakeup_data(struct traceeval *teval, int pid, const char *comm, int prio, unsigned long long ts) { - struct traceeval_data keys[1]; - struct traceeval_data vals[2]; + struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(wakeup_delta_keys)]; + struct traceeval_data vals[TRACEEVAL_ARRAY_SIZE(wakeup_delta_vals)]; - TRACEEVAL_SET_NUMBER(keys[0], pid); + TRACEEVAL_SET_NUMBER(keys[WAKEUP_DELTA_PID], pid); - TRACEEVAL_SET_CSTRING(vals[0], comm); - TRACEEVAL_SET_NUMBER(vals[1], prio); + TRACEEVAL_SET_CSTRING(vals[WAKEUP_DELTA_COMM], comm); + TRACEEVAL_SET_NUMBER(vals[WAKEUP_DELTA_PRIO], prio); traceeval_delta_start(teval, keys, vals, ts); } @@ -243,21 +254,21 @@ static int stop_wakeup_data(struct traceeval *teval, int pid, const char **comm, int *prio, unsigned long long ts, unsigned long long *delta) { + struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(wakeup_delta_keys)]; const struct traceeval_data *results; - struct traceeval_data keys[1]; int ret; - TRACEEVAL_SET_NUMBER(keys[0], pid); + TRACEEVAL_SET_NUMBER(keys[WAKEUP_DELTA_PID], pid); ret = traceeval_delta_stop(teval, keys, &results, ts, delta, NULL); if (ret < 1) return ret; if (comm) - *comm = results[0].string; + *comm = results[WAKEUP_DELTA_COMM].string; if (prio) - *prio = results[1].number; + *prio = results[WAKEUP_DELTA_PRIO].number; traceeval_results_release(teval, results); return 1; @@ -282,17 +293,22 @@ static struct traceeval_type task_delta_vals[] = { DECLARE_TRACEEVAL_NUMBER("Prio"), }; +static ssize_t TASK_DELTA_PID; +static ssize_t TASK_DELTA_STATE; +static ssize_t TASK_DELTA_COMM; +static ssize_t TASK_DELTA_PRIO; + static void start_task_data(struct traceeval *teval, int pid, int state, const char *comm, int prio, unsigned long long ts) { - struct traceeval_data keys[1]; - struct traceeval_data vals[3]; + struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(task_delta_keys)]; + struct traceeval_data vals[TRACEEVAL_ARRAY_SIZE(task_delta_vals)]; - TRACEEVAL_SET_NUMBER(keys[0], pid); + TRACEEVAL_SET_NUMBER(keys[TASK_DELTA_PID], pid); - TRACEEVAL_SET_NUMBER(vals[0], state); - TRACEEVAL_SET_CSTRING(vals[1], comm); - TRACEEVAL_SET_NUMBER(vals[2], prio); + TRACEEVAL_SET_NUMBER(vals[TASK_DELTA_STATE], state); + TRACEEVAL_SET_CSTRING(vals[TASK_DELTA_COMM], comm); + TRACEEVAL_SET_NUMBER(vals[TASK_DELTA_PRIO], prio); traceeval_delta_start(teval, keys, vals, ts); } @@ -301,24 +317,24 @@ static int stop_task_data(struct traceeval *teval, int pid, int *state, const char **comm, int *prio, unsigned long long ts, unsigned long long *delta, unsigned long long *save_ts) { + struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(task_delta_keys)]; const struct traceeval_data *results; - struct traceeval_data keys[1]; int ret; - TRACEEVAL_SET_NUMBER(keys[0], pid); + TRACEEVAL_SET_NUMBER(keys[TASK_DELTA_PID], pid); ret = traceeval_delta_stop(teval, keys, &results, ts, delta, save_ts); if (ret < 1) return ret; if (state) - *state = results[0].number; + *state = results[TASK_DELTA_STATE].number; if (comm) - *comm = results[1].string; + *comm = results[TASK_DELTA_COMM].string; if (prio) - *prio = results[2].number; + *prio = results[TASK_DELTA_PRIO].number; traceeval_results_release(teval, results); return 1; @@ -362,15 +378,20 @@ static struct traceeval_type task_vals[] = { DECLARE_TRACEEVAL_DELTA(DELTA_NAME), }; +static ssize_t TASK_COMM; +static ssize_t TASK_STATE; +static ssize_t TASK_DATA; +static ssize_t TASK_DELTA; + static int insert_task_data(struct traceeval *teval, const char *comm, int state, void *data, unsigned long long delta, unsigned long long timestamp) { - struct traceeval_data keys[2]; - struct traceeval_data vals[2]; + struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(task_keys)]; + struct traceeval_data vals[TRACEEVAL_ARRAY_SIZE(task_vals)]; - TRACEEVAL_SET_CSTRING(keys[0], comm); - TRACEEVAL_SET_NUMBER(keys[1], state); + TRACEEVAL_SET_CSTRING(keys[TASK_COMM], comm); + TRACEEVAL_SET_NUMBER(keys[TASK_STATE], state); /* * Can not have data stored more than once, only save it for @@ -379,8 +400,8 @@ static int insert_task_data(struct traceeval *teval, const char *comm, if (state != RUNNING) data = NULL; - TRACEEVAL_SET_POINTER(vals[0], data); - TRACEEVAL_SET_DELTA(vals[1], delta, timestamp); + TRACEEVAL_SET_POINTER(vals[TASK_DATA], data); + TRACEEVAL_SET_DELTA(vals[TASK_DELTA], delta, timestamp); return traceeval_insert(teval, keys, vals); } @@ -426,19 +447,24 @@ static struct traceeval_type thread_vals[] = { DECLARE_TRACEEVAL_DELTA(DELTA_NAME), }; +static ssize_t THREAD_TID; +static ssize_t THREAD_PRIO; +static ssize_t THREAD_STATE; +static ssize_t THREAD_DELTA; + static void insert_thread_data(struct traceeval *teval, int tid, int state, int prio, unsigned long long delta, unsigned long long timestamp) { - struct traceeval_data keys[3]; - struct traceeval_data vals[1]; + struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(thread_keys)]; + struct traceeval_data vals[TRACEEVAL_ARRAY_SIZE(thread_vals)]; - TRACEEVAL_SET_NUMBER(keys[0], tid); - TRACEEVAL_SET_NUMBER(keys[1], prio); - TRACEEVAL_SET_NUMBER(keys[2], state); + TRACEEVAL_SET_NUMBER(keys[THREAD_TID], tid); + TRACEEVAL_SET_NUMBER(keys[THREAD_PRIO], prio); + TRACEEVAL_SET_NUMBER(keys[THREAD_STATE], state); - TRACEEVAL_SET_DELTA(vals[0], delta, timestamp); + TRACEEVAL_SET_DELTA(vals[THREAD_DELTA], delta, timestamp); traceeval_insert(teval, keys, vals); } @@ -456,17 +482,60 @@ static struct traceeval_type wakeup_vals[] = { DECLARE_TRACEEVAL_DELTA(DELTA_NAME), }; +static ssize_t WAKEUP_TASK_COMM; +static ssize_t WAKEUP_THREAD_PID; +static ssize_t WAKEUP_THREAD_PRIO; +static ssize_t WAKEUP_DELTA; + +#define assign_type(type, name, array) \ + if ((type = traceeval_type_index(name, array)) < 0) \ + die("Invalid index %s for %s", name, #type); + +static void init_indexes(void) +{ + assign_type(CPU_DELTA_KEY, "CPU", cpu_delta_keys); + assign_type(CPU_DELTA_STATE, "Schedule state", cpu_delta_vals); + + assign_type(CPU_KEY, "CPU", cpu_keys); + assign_type(CPU_STATE, "Schedule state", cpu_keys); + assign_type(CPU_DELTA, DELTA_NAME, cpu_vals); + + assign_type(WAKEUP_DELTA_PID, "PID", wakeup_delta_keys); + assign_type(WAKEUP_DELTA_COMM, "COMM", wakeup_delta_vals); + assign_type(WAKEUP_DELTA_PRIO, "Prio", wakeup_delta_vals); + + assign_type(TASK_DELTA_PID, "PID", task_delta_keys); + assign_type(TASK_DELTA_STATE, "Schedule state", task_delta_vals); + assign_type(TASK_DELTA_COMM, "COMM", task_delta_vals); + assign_type(TASK_DELTA_PRIO, "Prio", task_delta_vals); + + assign_type(TASK_COMM, "COMM", task_keys); + assign_type(TASK_STATE, "Schedule state", task_keys); + assign_type(TASK_DATA, "data", task_vals); + assign_type(TASK_DELTA, DELTA_NAME, task_vals); + + assign_type(THREAD_TID, "TID", thread_keys); + assign_type(THREAD_PRIO, "Prio", thread_keys); + assign_type(THREAD_STATE, "Schedule state", thread_keys); + assign_type(THREAD_DELTA, DELTA_NAME, thread_vals); + + assign_type(WAKEUP_TASK_COMM, "COMM", wakeup_task_keys); + assign_type(WAKEUP_THREAD_PID, "PID", wakeup_thread_keys); + assign_type(WAKEUP_THREAD_PRIO, "Prio", wakeup_thread_keys); + assign_type(WAKEUP_DELTA, DELTA_NAME, wakeup_vals) +} + static void insert_wakeup_task_data(struct traceeval *teval, const char *comm, unsigned long long delta, unsigned long long timestamp) { - struct traceeval_data keys[1]; - struct traceeval_data vals[1]; + struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(wakeup_task_keys)]; + struct traceeval_data vals[TRACEEVAL_ARRAY_SIZE(wakeup_vals)]; - TRACEEVAL_SET_CSTRING(keys[0], comm); + TRACEEVAL_SET_CSTRING(keys[WAKEUP_TASK_COMM], comm); - TRACEEVAL_SET_DELTA(vals[0], delta, timestamp); + TRACEEVAL_SET_DELTA(vals[WAKEUP_DELTA], delta, timestamp); traceeval_insert(teval, keys, vals); } @@ -476,13 +545,13 @@ static void insert_wakeup_thread_data(struct traceeval *teval, unsigned long long delta, unsigned long long timestamp) { - struct traceeval_data keys[2]; - struct traceeval_data vals[1]; + struct traceeval_data keys[TRACEEVAL_ARRAY_SIZE(wakeup_thread_keys)]; + struct traceeval_data vals[TRACEEVAL_ARRAY_SIZE(wakeup_vals)]; - TRACEEVAL_SET_NUMBER(keys[0], tid); - TRACEEVAL_SET_NUMBER(keys[1], prio); + TRACEEVAL_SET_NUMBER(keys[WAKEUP_THREAD_PID], tid); + TRACEEVAL_SET_NUMBER(keys[WAKEUP_THREAD_PRIO], prio); - TRACEEVAL_SET_DELTA(vals[0], delta, timestamp); + TRACEEVAL_SET_DELTA(vals[WAKEUP_DELTA], delta, timestamp); traceeval_insert(teval, keys, vals); } @@ -900,22 +969,22 @@ static int compare_pdata(struct traceeval *teval, void *data) { struct traceeval_data keysA[] = { - DEFINE_TRACEEVAL_CSTRING( Akeys[0].cstring ), - DEFINE_TRACEEVAL_NUMBER( RUNNING ), }; + DEFINE_TRACEEVAL_CSTRING( Akeys[TASK_COMM].cstring ), + DEFINE_TRACEEVAL_NUMBER( RUNNING ), }; struct traceeval_data keysB[] = { - DEFINE_TRACEEVAL_CSTRING( Bkeys[0].cstring ), - DEFINE_TRACEEVAL_NUMBER( RUNNING ), }; + DEFINE_TRACEEVAL_CSTRING( Bkeys[TASK_COMM].cstring ), + DEFINE_TRACEEVAL_NUMBER( RUNNING ), }; struct traceeval_stat *statA; struct traceeval_stat *statB; unsigned long long totalA = -1; unsigned long long totalB = -1; /* First check if we are on the same task */ - if (strcmp(Akeys[0].cstring, Bkeys[0].cstring) == 0) { + if (strcmp(Akeys[TASK_COMM].cstring, Bkeys[TASK_COMM].cstring) == 0) { /* Sort decending */ - if (Bkeys[1].number > Akeys[1].number) + if (Bkeys[TASK_STATE].number > Akeys[TASK_STATE].number) return -1; - return Bkeys[1].number != Akeys[1].number; + return Bkeys[TASK_STATE].number != Akeys[TASK_STATE].number; } /* Get the RUNNING values for both processes */ @@ -932,7 +1001,7 @@ static int compare_pdata(struct traceeval *teval, if (totalB > totalA) return 1; - return strcmp(Bkeys[0].cstring, Akeys[0].cstring); + return strcmp(Bkeys[TASK_COMM].cstring, Akeys[TASK_COMM].cstring); } static void display_cpus(struct traceeval *teval) @@ -948,12 +1017,12 @@ static void display_cpus(struct traceeval *teval) printf("\n"); - traceeval_iterator_sort(iter, cpu_keys[0].name, 0, true); - traceeval_iterator_sort(iter, cpu_keys[1].name, 1, true); + traceeval_iterator_sort(iter, cpu_keys[CPU_KEY].name, 0, true); + traceeval_iterator_sort(iter, cpu_keys[CPU_STATE].name, 1, true); while (traceeval_iterator_next(iter, &keys) > 0) { - int state = keys[1].number; - int cpu = keys[0].number; + int state = keys[CPU_STATE].number; + int cpu = keys[CPU_KEY].number; stat = traceeval_iterator_stat(iter, DELTA_NAME); if (!stat) @@ -1072,18 +1141,18 @@ static void display_threads(struct traceeval *teval, struct traceeval *wake_teva int last_prio = -1; /* PID */ - traceeval_iterator_sort(iter, thread_keys[0].name, 0, true); + traceeval_iterator_sort(iter, thread_keys[THREAD_TID].name, 0, true); /* PRIO */ - traceeval_iterator_sort(iter, thread_keys[1].name, 1, true); + traceeval_iterator_sort(iter, thread_keys[THREAD_PRIO].name, 1, true); /* STATE */ - traceeval_iterator_sort(iter, thread_keys[2].name, 2, true); + traceeval_iterator_sort(iter, thread_keys[THREAD_STATE].name, 2, true); while (traceeval_iterator_next(iter, &keys) > 0) { - int tid = keys[0].number; - int prio = keys[1].number; - int state = keys[2].number; + int tid = keys[THREAD_TID].number; + int prio = keys[THREAD_PRIO].number; + int state = keys[THREAD_STATE].number; stat = traceeval_iterator_stat(iter, DELTA_NAME); if (!stat) @@ -1160,7 +1229,7 @@ static void display_processes(struct traceeval *teval, struct traceeval *wake_te while (traceeval_iterator_next(iter, &keys) > 0) { const struct traceeval_data *results; struct process_data *pdata = NULL; - const char *comm = keys[0].cstring; + const char *comm = keys[TASK_COMM].cstring; if (strcmp(comm, last_comm) == 0) continue; @@ -1173,7 +1242,7 @@ static void display_processes(struct traceeval *teval, struct traceeval *wake_te if (ret < 1) continue; /* ?? */ - pdata = results[0].pointer; + pdata = results[TASK_DATA].pointer; traceeval_results_release(teval, results); printf("Task: %s\n", comm); @@ -1206,7 +1275,7 @@ static void display(struct task_data *tdata) pdie("No cpus?"); while (traceeval_iterator_next(iter, &keys) > 0) { - int state = keys[1].number; + int state = keys[CPU_STATE].number; stat = traceeval_iterator_stat(iter, DELTA_NAME); if (!stat) @@ -1268,11 +1337,11 @@ static void finish_leftovers(struct task_data *data) traceeval_iterator_delta_stop(iter, &results, data->last_ts, &delta, NULL); - pid = keys[0].number; + pid = keys[TASK_DELTA_PID].number; - state = results[0].number; - comm = results[1].cstring; - prio = results[2].number; + state = results[TASK_DELTA_STATE].number; + comm = results[TASK_DELTA_COMM].cstring; + prio = results[TASK_DELTA_PRIO].number; update_thread(data, pid, comm, state, prio, delta, data->last_ts); } @@ -1330,6 +1399,8 @@ int main (int argc, char **argv) if (argc < 1) usage(); + init_indexes(); + handle = tracecmd_open(argv[0], TRACECMD_FL_LOAD_NO_PLUGINS); if (!handle) pdie("Error opening %s", argv[0]);