@@ -4,10 +4,10 @@ message(STATUS "dataload")
add_executable(dload dataload.c)
target_link_libraries(dload kshark)
-# message(STATUS "datafilter")
-# add_executable(dfilter datafilter.c)
-# target_link_libraries(dfilter kshark)
-#
+message(STATUS "datafilter")
+add_executable(dfilter datafilter.c)
+target_link_libraries(dfilter kshark)
+
# message(STATUS "datahisto")
# add_executable(dhisto datahisto.c)
# target_link_libraries(dhisto kshark)
@@ -7,22 +7,22 @@
// C
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
// KernelShark
#include "libkshark.h"
+#include "libkshark-tepdata.h"
const char *default_file = "trace.dat";
int main(int argc, char **argv)
{
- ssize_t i, n_rows, n_tasks, n_evts, count;
+ size_t i, sd, n_rows, n_tasks, n_evts, count;
struct kshark_context *kshark_ctx;
+ struct kshark_data_stream *stream;
struct kshark_entry **data = NULL;
- struct tep_event_filter *adv_filter;
- struct tep_event *event;
+ int *pids, *evt_ids;
char *entry_str;
- bool status;
- int *pids;
/* Create a new kshark session. */
kshark_ctx = NULL;
@@ -31,32 +31,30 @@ int main(int argc, char **argv)
/* Open a trace data file produced by trace-cmd. */
if (argc > 1)
- status = kshark_open(kshark_ctx, argv[1]);
+ sd = kshark_open(kshark_ctx, argv[1]);
else
- status = kshark_open(kshark_ctx, default_file);
+ sd = kshark_open(kshark_ctx, default_file);
- if (!status) {
+ if (sd < 0) {
kshark_free(kshark_ctx);
return 1;
}
/* Load the content of the file into an array of entries. */
- n_rows = kshark_load_data_entries(kshark_ctx, &data);
- if (n_rows < 1) {
- kshark_free(kshark_ctx);
- return 1;
- }
+ n_rows = kshark_load_entries(kshark_ctx, sd, &data);
/* Filter the trace data coming from trace-cmd. */
- n_tasks = kshark_get_task_pids(kshark_ctx, &pids);
+ n_tasks = kshark_get_task_pids(kshark_ctx, sd, &pids);
+ stream = kshark_get_data_stream(kshark_ctx, sd);
for (i = 0; i < n_tasks; ++i) {
- const char *task_str =
- tep_data_comm_from_pid(kshark_ctx->pevent,
- pids[i]);
+ char *task_str =
+ kshark_comm_from_pid(sd, pids[i]);
if (strcmp(task_str, "trace-cmd") == 0)
- kshark_filter_add_id(kshark_ctx, KS_HIDE_TASK_FILTER,
- pids[i]);
+ kshark_filter_add_id(kshark_ctx, sd,
+ KS_HIDE_TASK_FILTER,
+ pids[i]);
+ free(task_str);
}
free(pids);
@@ -66,7 +64,8 @@ int main(int argc, char **argv)
* filterd entris in text format.
*/
kshark_ctx->filter_mask = KS_TEXT_VIEW_FILTER_MASK;
- kshark_filter_entries(kshark_ctx, data, n_rows);
+ kshark_ctx->filter_mask |= KS_EVENT_VIEW_FILTER_MASK;
+ kshark_filter_stream_entries(kshark_ctx, sd, data, n_rows);
/* Print to the screen the first 10 visible entries. */
count = 0;
@@ -87,15 +86,19 @@ int main(int argc, char **argv)
puts("\n\n");
/* Show only "sched" events. */
- n_evts = tep_get_events_count(kshark_ctx->pevent);
+ n_evts = stream->n_events;
+ evt_ids = kshark_get_all_event_ids(kshark_ctx->stream[sd]);
for (i = 0; i < n_evts; ++i) {
- event = tep_get_event(kshark_ctx->pevent, i);
- if (strcmp(event->system, "sched") == 0)
- kshark_filter_add_id(kshark_ctx, KS_SHOW_EVENT_FILTER,
- event->id);
+ char *event_str =
+ kshark_event_from_id(sd, evt_ids[i]);
+ if (strstr(event_str, "sched/"))
+ kshark_filter_add_id(kshark_ctx, sd,
+ KS_SHOW_EVENT_FILTER,
+ evt_ids[i]);
+ free(event_str);
}
- kshark_filter_entries(kshark_ctx, data, n_rows);
+ kshark_filter_stream_entries(kshark_ctx, sd, data, n_rows);
/* Print to the screen the first 10 visible entries. */
count = 0;
@@ -116,19 +119,17 @@ int main(int argc, char **argv)
puts("\n\n");
/* Clear all filters. */
- kshark_filter_clear(kshark_ctx, KS_HIDE_TASK_FILTER);
- kshark_filter_clear(kshark_ctx, KS_SHOW_EVENT_FILTER);
+ kshark_filter_clear(kshark_ctx, sd, KS_HIDE_TASK_FILTER);
+ kshark_filter_clear(kshark_ctx, sd, KS_SHOW_EVENT_FILTER);
/* Use the Advanced filter to do event content based filtering. */
- adv_filter = kshark_ctx->advanced_event_filter;
- tep_filter_add_filter_str(adv_filter,
- "sched/sched_wakeup:target_cpu==1");
+ kshark_tep_add_filter_str(stream, "sched/sched_wakeup:target_cpu>1");
/* The Advanced filter requires reloading the data. */
for (i = 0; i < n_rows; ++i)
free(data[i]);
- n_rows = kshark_load_data_entries(kshark_ctx, &data);
+ n_rows = kshark_load_entries(kshark_ctx, sd, &data);
count = 0;
for (i = 0; i < n_rows; ++i) {
@@ -149,7 +150,7 @@ int main(int argc, char **argv)
free(data);
/* Close the file. */
- kshark_close(kshark_ctx);
+ kshark_close(kshark_ctx, sd);
/* Close the session. */
kshark_free(kshark_ctx);
@@ -34,6 +34,7 @@ install(TARGETS kshark
install(FILES "${KS_DIR}/src/libkshark.h"
"${KS_DIR}/src/libkshark-model.h"
"${KS_DIR}/src/libkshark-plugin.h"
+ "${KS_DIR}/src/libkshark-tepdata.h"
DESTINATION ${KS_INCLUDS_DESTINATION}
COMPONENT libkshark-devel)
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: LGPL-2.1
/*
- * Copyright (C) 2018 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ * Copyright (C) 2018 VMware Inc, Yordan Karadzhov (VMware) <y.karadz@gmail.com>
*/
/**
@@ -11,9 +11,11 @@
// C
#include <stdbool.h>
+#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
+#include <stdio.h>
// KernelShark
#include "libkshark.h"
@@ -74,7 +76,9 @@ kshark_data_collection_alloc(struct kshark_context *kshark_ctx,
ssize_t first,
size_t n_rows,
matching_condition_func cond,
- int val,
+ int sd,
+ int *values,
+ int n_val,
size_t margin)
{
struct kshark_entry_collection *col_ptr = NULL;
@@ -117,7 +121,7 @@ kshark_data_collection_alloc(struct kshark_context *kshark_ctx,
}
for (i = first + margin; i < end; ++i) {
- if (!cond(kshark_ctx, data[i], val)) {
+ if (!cond(kshark_ctx, data[i], sd, values)) {
/*
* The entry is irrelevant for this collection.
* Do nothing.
@@ -147,7 +151,7 @@ kshark_data_collection_alloc(struct kshark_context *kshark_ctx,
}
} else if (good_data &&
data[i]->next &&
- !cond(kshark_ctx, data[i]->next, val)) {
+ !cond(kshark_ctx, data[i]->next, sd, values)) {
/*
* Break the collection here. Add some margin data
* after the data of interest.
@@ -168,7 +172,7 @@ kshark_data_collection_alloc(struct kshark_context *kshark_ctx,
*/
if (i + margin >= j) {
for (;j < i + margin; ++j) {
- if (cond(kshark_ctx, data[j], val)) {
+ if (cond(kshark_ctx, data[j], sd, values)) {
/*
* Good data has been found.
* Continue extending the
@@ -228,9 +232,15 @@ kshark_data_collection_alloc(struct kshark_context *kshark_ctx,
}
col_ptr->cond = cond;
- col_ptr->val = val;
+ col_ptr->n_val = n_val;
+ col_ptr->stream_id = sd;
+ col_ptr->values = malloc(n_val * sizeof(*col_ptr->values));
+ memcpy(col_ptr->values, values, n_val * sizeof(*col_ptr->values));
col_ptr->size = resume_count;
+ if (!col_ptr->size)
+ free(col_list);
+
for (i = 0; i < col_ptr->size; ++i) {
assert(col_list->type == COLLECTION_RESUME);
col_ptr->resume_points[i] = col_list->index;
@@ -316,8 +326,8 @@ map_collection_request_init(const struct kshark_entry_collection *col,
size_t req_end;
if (req->next || col->size == 0) {
- fprintf(stderr, "Unexpected input in ");
- fprintf(stderr, "map_collection_request_init()\n");
+ fprintf(stderr,
+ "Unexpected input in map_collection_request_init()\n");
goto do_nothing;
}
@@ -477,7 +487,8 @@ map_collection_back_request(const struct kshark_entry_collection *col,
kshark_entry_request_alloc(req_first,
0,
req->cond,
- req->val,
+ req->sd,
+ req->values,
req->vis_only,
req->vis_mask);
@@ -561,7 +572,8 @@ map_collection_front_request(const struct kshark_entry_collection *col,
kshark_entry_request_alloc(req_first,
0,
req->cond,
- req->val,
+ req->sd,
+ req->values,
req->vis_only,
req->vis_mask);
@@ -702,25 +714,41 @@ kshark_get_collection_entry_back(struct kshark_entry_request *req,
return entry;
}
+static bool val_compare(int *val_a, int *val_b, size_t n_val)
+{
+ size_t i;
+
+ for (i = 0; i < n_val; ++i)
+ if (val_a[i] != val_b[i])
+ return false;
+
+ return true;
+}
+
/**
* @brief Search the list of Data collections and find the collection defined
* with a given Matching condition function and value.
*
* @param col: Input location for the Data collection list.
* @param cond: Matching condition function.
- * @param val: Matching condition value, used by the Matching condition
- * function.
+ * @param sd: Data stream identifier.
+ * @param values: Array of matching condition value, used by the Matching
+ * condition function.
+ * @param n_val: The size of the array of Matching values.
*
* @returns Pointer to a Data collections on success, or NULL on failure.
*/
struct kshark_entry_collection *
kshark_find_data_collection(struct kshark_entry_collection *col,
matching_condition_func cond,
- int val)
+ int sd, int *values, size_t n_val)
{
while (col) {
- if (col->cond == cond && col->val == val)
- return col;
+ if (col->cond == cond &&
+ col->stream_id == sd &&
+ col->n_val == n_val &&
+ val_compare(col->values, values, n_val))
+ return col;
col = col->next;
}
@@ -748,6 +776,7 @@ static void kshark_free_data_collection(struct kshark_entry_collection *col)
{
free(col->resume_points);
free(col->break_points);
+ free(col->values);
free(col);
}
@@ -761,7 +790,10 @@ static void kshark_free_data_collection(struct kshark_entry_collection *col)
* @param n_rows: The size of the inputted data.
* @param cond: Matching condition function for the collection to be
* registered.
- * @param val: Matching condition value of for collection to be registered.
+ * @param sd: Data stream identifier.
+ * @param values: Array of matching condition value, used by the Matching
+ * condition function.
+ * @param n_val: The size of the array of Matching values.
* @param margin: The size of the additional (margin) data which do not
* satisfy the matching condition, but is added at the
* beginning and at the end of each interval of the collection
@@ -776,7 +808,8 @@ kshark_register_data_collection(struct kshark_context *kshark_ctx,
struct kshark_entry **data,
size_t n_rows,
matching_condition_func cond,
- int val,
+ int sd,
+ int *values, size_t n_val,
size_t margin)
{
struct kshark_entry_collection *col;
@@ -784,7 +817,7 @@ kshark_register_data_collection(struct kshark_context *kshark_ctx,
col = kshark_add_collection_to_list(kshark_ctx,
&kshark_ctx->collections,
data, n_rows,
- cond, val,
+ cond, sd, values, n_val,
margin);
return col;
@@ -801,7 +834,10 @@ kshark_register_data_collection(struct kshark_context *kshark_ctx,
* @param n_rows: The size of the inputted data.
* @param cond: Matching condition function for the collection to be
* registered.
- * @param val: Matching condition value of for collection to be registered.
+ * @param sd: Data stream identifier.
+ * @param values: Array of matching condition value, used by the Matching
+ * condition function.
+ * @param n_val: The size of the array of Matching values.
* @param margin: The size of the additional (margin) data which do not
* satisfy the matching condition, but is added at the
* beginning and at the end of each interval of the collection
@@ -817,14 +853,18 @@ kshark_add_collection_to_list(struct kshark_context *kshark_ctx,
struct kshark_entry **data,
size_t n_rows,
matching_condition_func cond,
- int val,
+ int sd, int *values, size_t n_val,
size_t margin)
{
struct kshark_entry_collection *col;
+ if (!data || n_rows == 0)
+ return NULL;
+
col = kshark_data_collection_alloc(kshark_ctx, data,
0, n_rows,
- cond, val,
+ cond, sd,
+ values, n_val,
margin);
if (col) {
@@ -844,18 +884,23 @@ kshark_add_collection_to_list(struct kshark_context *kshark_ctx,
* @param col: Input location for the Data collection list.
* @param cond: Matching condition function of the collection to be
* unregistered.
- *
- * @param val: Matching condition value of the collection to be unregistered.
+ * @param sd: Data stream identifier.
+ * @param values: Array of matching condition value, used by the Matching
+ * condition function.
+ * @param n_val: The size of the array of Matching values.
*/
void kshark_unregister_data_collection(struct kshark_entry_collection **col,
matching_condition_func cond,
- int val)
+ int sd, int *values, size_t n_val)
{
struct kshark_entry_collection **last = col;
struct kshark_entry_collection *list;
for (list = *col; list; list = list->next) {
- if (list->cond == cond && list->val == val) {
+ if (list->cond == cond &&
+ list->stream_id == sd &&
+ list->n_val == n_val &&
+ val_compare(list->values, values, n_val)) {
*last = list->next;
kshark_free_data_collection(list);
return;
@@ -865,6 +910,32 @@ void kshark_unregister_data_collection(struct kshark_entry_collection **col,
}
}
+/**
+ * @brief Unregister all Data collections associated with a given Data stream.
+ *
+ * @param col: Input location for the Data collection list.
+ * @param sd: Data stream identifier.
+ */
+void kshark_unregister_stream_collections(struct kshark_entry_collection **col,
+ int sd)
+{
+ struct kshark_entry_collection **last = col;
+ struct kshark_entry_collection *list;
+
+ list = *col;
+ while (list) {
+ if (list->stream_id == sd) {
+ *last = list->next;
+ kshark_free_data_collection(list);
+ list = *last;
+ continue;
+ }
+
+ last = &list->next;
+ list = list->next;
+ }
+}
+
/**
* @brief Free all Data collections in a given list.
*
@@ -362,6 +362,9 @@ static ssize_t get_records(struct kshark_context *kshark_ctx,
pid = entry->pid;
+ /* Apply Id filtering. */
+ kshark_apply_filters(kshark_ctx, stream, entry);
+
/* Apply advanced event filtering. */
if (adv_filter && adv_filter->filters &&
tep_filter_match(adv_filter, rec) != FILTER_MATCH)
@@ -1235,6 +1238,44 @@ out:
return peer_handle;
}
+/** A list of built in default plugins for FTRACE (trace-cmd) data. */
+const char *tep_plugin_names[] = {
+ "sched_events",
+ "missed_events",
+ "kvm_combo",
+};
+
+/**
+ * Register to the data stream all default plugins for FTRACE (trace-cmd) data.
+ */
+int kshark_tep_handle_plugins(struct kshark_context *kshark_ctx, int sd)
+{
+ struct kshark_plugin_list *plugin;
+ struct kshark_data_stream *stream;
+ int i, n_tep_plugins;
+
+ n_tep_plugins = (sizeof(tep_plugin_names) / sizeof((tep_plugin_names)[0]));
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!stream)
+ return -EEXIST;
+
+ for (i = 0; i < n_tep_plugins; ++i) {
+ plugin = kshark_find_plugin_by_name(kshark_ctx->plugins,
+ tep_plugin_names[i]);
+
+ if (plugin && plugin->process_interface) {
+ kshark_register_plugin_to_stream(stream,
+ plugin->process_interface,
+ true);
+ } else {
+ fprintf(stderr, "Plugin \"%s\" not found.\n",
+ tep_plugin_names[i]);
+ }
+ }
+
+ return kshark_handle_all_dpis(stream, KSHARK_PLUGIN_INIT);
+}
+
/** The Process Id of the Idle tasks is zero. */
#define LINUX_IDLE_TASK_PID 0
@@ -1299,6 +1340,210 @@ static inline char *set_tep_format(struct kshark_data_stream *stream)
TEP_DATA_FORMAT_IDENTIFIER);
}
+static struct tracecmd_input *get_top_input(struct kshark_context *kshark_ctx,
+ int sd)
+{
+ struct kshark_data_stream *top_stream;
+
+ top_stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!top_stream)
+ return NULL;
+
+ return kshark_get_tep_input(top_stream);
+}
+
+/**
+ * @brief Get an array containing the names of all buffers in FTRACE data
+ * file.
+ *
+ * @param kshark_ctx: Input location for context pointer.
+ * @param sd: Data stream identifier of the top buffers in the FTRACE data
+ * file.
+ * @param n_buffers: Output location for the size of the outputted array,
+ * or a negative error code on failure.
+ *
+ * @returns Array of strings on success, or NULL on failure. The user is
+ * responsible for freeing the elements of the outputted array.
+ */
+char **kshark_tep_get_buffer_names(struct kshark_context *kshark_ctx, int sd,
+ int *n_buffers)
+{
+ struct tracecmd_input *top_input;
+ char **buffer_names;
+ int i, n;
+
+ top_input = get_top_input(kshark_ctx, sd);
+ if (!top_input) {
+ *n_buffers = -EFAULT;
+ return NULL;
+ }
+
+ n = tracecmd_buffer_instances(top_input);
+ buffer_names = calloc(n, sizeof(char *));
+ if (!buffer_names) {
+ *n_buffers = -ENOMEM;
+ return NULL;
+ }
+
+ for (i = 0; i < n; ++i) {
+ buffer_names[i] =
+ strdup(tracecmd_buffer_instance_name(top_input, i));
+ if (!buffer_names[i])
+ goto free_all;
+ }
+
+ *n_buffers = n;
+ return buffer_names;
+
+ free_all:
+ for (i = 0; i < n; ++i)
+ free(buffer_names[i]);
+ free(buffer_names);
+
+ *n_buffers = -ENOMEM;
+ return NULL;
+}
+
+static void set_stream_fields(struct tracecmd_input *top_input, int i,
+ const char *file,
+ const char *name,
+ struct kshark_data_stream *buffer_stream,
+ struct tracecmd_input **buffer_input)
+{
+ *buffer_input = tracecmd_buffer_instance_handle(top_input, i);
+
+ buffer_stream->name = strdup(name);
+ buffer_stream->file = strdup(file);
+ set_tep_format(buffer_stream);
+}
+
+/**
+ * @brief Open a given buffers in FTRACE (trace-cmd) data file.
+ *
+ * @param kshark_ctx: Input location for context pointer.
+ * @param sd: Data stream identifier of the top buffers in the FTRACE data
+ * file.
+ * @param buffer_name: The name of the buffer to open.
+ *
+ * @returns Data stream identifier of the buffer on success. Otherwise a
+ * negative error code.
+ */
+int kshark_tep_open_buffer(struct kshark_context *kshark_ctx, int sd,
+ const char *buffer_name)
+{
+ struct kshark_data_stream *top_stream, *buffer_stream;
+ struct tracecmd_input *top_input, *buffer_input;
+ int i, sd_buffer, n_buffers, ret = -ENODATA;
+ char **names;
+
+ top_stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!top_stream)
+ return -EFAULT;
+
+ top_input = kshark_get_tep_input(top_stream);
+ if (!top_input)
+ return -EFAULT;
+
+ names = kshark_tep_get_buffer_names(kshark_ctx, sd, &n_buffers);
+ if (!names)
+ return n_buffers;
+
+ sd_buffer = kshark_add_stream(kshark_ctx);
+ buffer_stream = kshark_get_data_stream(kshark_ctx, sd_buffer);
+ if (!buffer_stream)
+ return -EFAULT;
+
+ for (i = 0; i < n_buffers; ++i) {
+ if (strcmp(buffer_name, names[i]) == 0) {
+ set_stream_fields(top_input, i,
+ top_stream->file,
+ buffer_name,
+ buffer_stream,
+ &buffer_input);
+
+ if (!buffer_stream->name || !buffer_stream->file) {
+ free(buffer_stream->name);
+ free(buffer_stream->file);
+
+ ret = -ENOMEM;
+ break;
+ }
+
+ ret = kshark_tep_stream_init(buffer_stream,
+ buffer_input);
+ break;
+ }
+ }
+
+ for (i = 0; i < n_buffers; ++i)
+ free(names[i]);
+ free(names);
+
+ return (ret < 0)? ret : buffer_stream->stream_id;
+}
+
+/**
+ * @brief Initialize data streams for all buffers in a FTRACE (trace-cmd) data
+ * file.
+ *
+ * @param kshark_ctx: Input location for context pointer.
+ * @param sd: Data stream identifier of the top buffers in the FTRACE data
+ * file.
+ *
+ * @returns The total number of data streams initialized on success. Otherwise
+ * a negative error code.
+ */
+int kshark_tep_init_all_buffers(struct kshark_context *kshark_ctx,
+ int sd)
+{
+ struct kshark_data_stream *top_stream, *buffer_stream;
+ struct tracecmd_input *buffer_input;
+ struct tracecmd_input *top_input;
+ int i, n_buffers, sd_buffer, ret;
+
+ top_stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!top_stream)
+ return -EFAULT;
+
+ top_input = kshark_get_tep_input(top_stream);
+ if (!top_input)
+ return -EFAULT;
+
+ n_buffers = tracecmd_buffer_instances(top_input);
+ for (i = 0; i < n_buffers; ++i) {
+ sd_buffer = kshark_add_stream(kshark_ctx);
+ if (sd_buffer < 0)
+ return -EFAULT;
+
+ buffer_stream = kshark_ctx->stream[sd_buffer];
+
+ set_stream_fields(top_input, i,
+ top_stream->file,
+ tracecmd_buffer_instance_name(top_input, i),
+ buffer_stream,
+ &buffer_input);
+
+ if (!buffer_stream->name || !buffer_stream->file) {
+ free(buffer_stream->name);
+ free(buffer_stream->file);
+ ret = -ENOMEM;
+ break;
+ }
+
+ ret = kshark_tep_stream_init(buffer_stream, buffer_input);
+ if (ret != 0)
+ return -EFAULT;
+ }
+
+ return n_buffers;
+}
+
+/** Is this a stream corresponding to the "top" buffer in the file. */
+bool kshark_tep_is_top_stream(struct kshark_data_stream *stream)
+{
+ return strcmp(stream->name, KS_UNNAMED) == 0;
+}
+
/** Check is the file contains TEP tracing data. */
bool kshark_tep_check_data(const char *file_name)
{
@@ -1510,3 +1755,149 @@ char **kshark_tracecmd_local_tracers()
{
return tracefs_tracers(tracefs_tracing_dir());
}
+
+/**
+ * @brief Free an array, allocated by kshark_tracecmd_get_hostguest_mapping() API
+ *
+ *
+ * @param map: Array, allocated by kshark_tracecmd_get_hostguest_mapping() API
+ * @param count: Number of entries in the array
+ *
+ */
+void kshark_tracecmd_free_hostguest_map(struct kshark_host_guest_map *map, int count)
+{
+ int i;
+
+ if (!map)
+ return;
+ for (i = 0; i < count; i++) {
+ free(map[i].guest_name);
+ free(map[i].cpu_pid);
+ memset(&map[i], 0, sizeof(*map));
+ }
+ free(map);
+}
+
+/**
+ * @brief Get mapping of guest VCPU to host task, running that VCPU.
+ * Array of mappings for each guest is allocated and returned
+ * in map input parameter.
+ *
+ *
+ * @param map: Returns allocated array of kshark_host_guest_map structures, each
+ * one describing VCPUs mapping of one guest.
+ *
+ * @return The number of entries in the *map array, or a negative error code on
+ * failure.
+ */
+int kshark_tracecmd_get_hostguest_mapping(struct kshark_host_guest_map **map)
+{
+ struct kshark_host_guest_map *gmap = NULL;
+ struct tracecmd_input *peer_handle = NULL;
+ struct kshark_data_stream *peer_stream;
+ struct tracecmd_input *guest_handle = NULL;
+ struct kshark_data_stream *guest_stream;
+ struct kshark_context *kshark_ctx = NULL;
+ unsigned long long trace_id;
+ const char *name;
+ int vcpu_count;
+ const int *cpu_pid;
+ int *stream_ids;
+ int i, j, k;
+ int count = 0;
+ int ret;
+
+ if (!map || !kshark_instance(&kshark_ctx))
+ return -EFAULT;
+ if (*map)
+ return -EEXIST;
+
+ stream_ids = kshark_all_streams(kshark_ctx);
+ for (i = 0; i < kshark_ctx->n_streams; i++) {
+ guest_stream = kshark_get_data_stream(kshark_ctx, stream_ids[i]);
+ if (!guest_stream || !kshark_is_tep(guest_stream))
+ continue;
+ guest_handle = kshark_get_tep_input(guest_stream);
+ if (!guest_handle)
+ continue;
+ trace_id = tracecmd_get_traceid(guest_handle);
+ if (!trace_id)
+ continue;
+ for (j = 0; j < kshark_ctx->n_streams; j++) {
+ if (stream_ids[i] == stream_ids[j])
+ continue;
+ peer_stream = kshark_get_data_stream(kshark_ctx, stream_ids[j]);
+ if (!peer_stream || !kshark_is_tep(guest_stream))
+ continue;
+ peer_handle = kshark_get_tep_input(peer_stream);
+ if (!peer_handle)
+ continue;
+ ret = tracecmd_get_guest_cpumap(peer_handle, trace_id,
+ &name, &vcpu_count, &cpu_pid);
+ if (!ret && vcpu_count) {
+ gmap = realloc(*map,
+ (count + 1) * sizeof(struct kshark_host_guest_map));
+ if (!gmap)
+ goto mem_error;
+ *map = gmap;
+ memset(&gmap[count], 0, sizeof(struct kshark_host_guest_map));
+ count++;
+ gmap[count - 1].guest_id = stream_ids[i];
+ gmap[count - 1].host_id = stream_ids[j];
+ gmap[count - 1].guest_name = strdup(name);
+ if (!gmap[count - 1].guest_name)
+ goto mem_error;
+ gmap[count - 1].vcpu_count = vcpu_count;
+ gmap[count - 1].cpu_pid = malloc(sizeof(int) * vcpu_count);
+ if (!gmap[count - 1].cpu_pid)
+ goto mem_error;
+ for (k = 0; k < vcpu_count; k++)
+ gmap[count - 1].cpu_pid[k] = cpu_pid[k];
+ break;
+ }
+ }
+ }
+
+ free(stream_ids);
+ return count;
+
+mem_error:
+ free(stream_ids);
+ if (*map) {
+ kshark_tracecmd_free_hostguest_map(*map, count);
+ *map = NULL;
+ }
+
+ return -ENOMEM;
+}
+
+/**
+ * @brief Find the data stream corresponding the top buffer of a FTRACE
+ * (trace-cmd) data file.
+ *
+ * @param kshark_ctx: Input location for context pointer.
+ * @param file: The name of the file.
+ *
+ * @returns Data stream identifier of the top buffers in the FTRACE data
+ * fileon success. Otherwise a negative error code.
+ */
+int kshark_tep_find_top_stream(struct kshark_context *kshark_ctx,
+ const char *file)
+{
+ struct kshark_data_stream *top_stream = NULL, *stream;
+ int i, *stream_ids = kshark_all_streams(kshark_ctx);
+
+ for (i = 0; i < kshark_ctx->n_streams; ++i) {
+ stream = kshark_ctx->stream[stream_ids[i]];
+ if (strcmp(stream->file, file) == 0 &&
+ kshark_tep_is_top_stream(stream))
+ top_stream = stream;
+ }
+
+ free(stream_ids);
+
+ if (!top_stream)
+ return -EEXIST;
+
+ return top_stream->stream_id;
+}
@@ -51,11 +51,60 @@ void kshark_tep_filter_reset(struct kshark_data_stream *stream);
char **kshark_tracecmd_local_tracers();
+struct tep_handle;
+
+struct tep_handle *kshark_get_tep(struct kshark_data_stream *stream);
+
+struct tracecmd_input;
+
+struct tracecmd_input *kshark_get_tep_input(struct kshark_data_stream *stream);
+
struct tep_record;
ssize_t kshark_load_tep_records(struct kshark_context *kshark_ctx, int sd,
struct tep_record ***data_rows);
+/**
+ * Structure representing the mapping between the virtual CPUs and their
+ * corresponding processes in the host.
+ */
+struct kshark_host_guest_map {
+ /** ID of guest stream */
+ int guest_id;
+
+ /** ID of host stream */
+ int host_id;
+
+ /** Guest name */
+ char *guest_name;
+
+ /** Number of guest's CPUs in *cpu_pid array */
+ int vcpu_count;
+
+ /** Array of host task PIDs, index is the VCPU id */
+ int *cpu_pid;
+};
+
+void kshark_tracecmd_free_hostguest_map(struct kshark_host_guest_map *map,
+ int count);
+
+int kshark_tracecmd_get_hostguest_mapping(struct kshark_host_guest_map **map);
+
+char **kshark_tep_get_buffer_names(struct kshark_context *kshark_ctx, int sd,
+ int *n_buffers);
+
+int kshark_tep_open_buffer(struct kshark_context *kshark_ctx, int sd,
+ const char *buffer_name);
+
+int kshark_tep_init_all_buffers(struct kshark_context *kshark_ctx, int sd);
+
+int kshark_tep_handle_plugins(struct kshark_context *kshark_ctx, int sd);
+
+int kshark_tep_find_top_stream(struct kshark_context *kshark_ctx,
+ const char *file);
+
+bool kshark_tep_is_top_stream(struct kshark_data_stream *stream);
+
#ifdef __cplusplus
}
#endif
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: LGPL-2.1
/*
- * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov (VMware) <y.karadz@gmail.com>
*/
/**
@@ -9,8 +9,10 @@
* @brief API for processing of tracing data.
*/
+#ifndef _GNU_SOURCE
/** Use GNU C Library. */
-#define _GNU_SOURCE 1
+#define _GNU_SOURCE
+#endif // _GNU_SOURCE
// C
#include <stdlib.h>
@@ -37,23 +39,6 @@ static bool kshark_default_context(struct kshark_context **context)
kshark_ctx->stream_info.array_size = KS_DEFAULT_NUM_STREAMS;
kshark_ctx->stream_info.max_stream_id = -1;
- kshark_ctx->collections = NULL;
- kshark_ctx->plugins = NULL;
-
- kshark_ctx->show_task_filter = tracecmd_filter_id_hash_alloc();
- kshark_ctx->hide_task_filter = tracecmd_filter_id_hash_alloc();
-
- kshark_ctx->show_event_filter = tracecmd_filter_id_hash_alloc();
- kshark_ctx->hide_event_filter = tracecmd_filter_id_hash_alloc();
-
- kshark_ctx->show_cpu_filter = tracecmd_filter_id_hash_alloc();
- kshark_ctx->hide_cpu_filter = tracecmd_filter_id_hash_alloc();
-
- kshark_ctx->filter_mask = 0x0;
-
- kshark_ctx->stream_info.array_size = KS_DEFAULT_NUM_STREAMS;
- kshark_ctx->stream_info.max_stream_id = -1;
-
/* Will free kshark_context_handler. */
kshark_free(NULL);
@@ -468,6 +453,12 @@ int kshark_close(struct kshark_context *kshark_ctx, int sd)
if (!stream)
return -EFAULT;
+ /*
+ * All data collections are file specific. Make sure that collections
+ * from this file are not going to be used with another file.
+ */
+ kshark_unregister_stream_collections(&kshark_ctx->collections, sd);
+
/* Close all active plugins for this stream. */
if (stream->plugins) {
kshark_handle_all_dpis(stream, KSHARK_PLUGIN_CLOSE);
@@ -1042,103 +1033,134 @@ ssize_t kshark_get_task_pids(struct kshark_context *kshark_ctx, int sd,
return stream->tasks->count;
}
-static bool filter_find(struct tracecmd_filter_id *filter, int pid,
+static bool filter_find(struct kshark_hash_id *filter, int pid,
bool test)
{
return !filter || !filter->count ||
- !!(unsigned long)tracecmd_filter_id_find(filter, pid) == test;
+ kshark_hash_id_find(filter, pid) == test;
+}
+
+static bool kshark_show_task(struct kshark_data_stream *stream, int pid)
+{
+ return filter_find(stream->show_task_filter, pid, true) &&
+ filter_find(stream->hide_task_filter, pid, false);
+}
+
+static bool kshark_show_event(struct kshark_data_stream *stream, int pid)
+{
+ return filter_find(stream->show_event_filter, pid, true) &&
+ filter_find(stream->hide_event_filter, pid, false);
}
-static bool kshark_show_task(struct kshark_context *kshark_ctx, int pid)
+static bool kshark_show_cpu(struct kshark_data_stream *stream, int cpu)
{
- return filter_find(kshark_ctx->show_task_filter, pid, true) &&
- filter_find(kshark_ctx->hide_task_filter, pid, false);
+ return filter_find(stream->show_cpu_filter, cpu, true) &&
+ filter_find(stream->hide_cpu_filter, cpu, false);
}
-static bool kshark_show_event(struct kshark_context *kshark_ctx, int pid)
+static struct kshark_hash_id *get_filter(struct kshark_context *kshark_ctx,
+ int sd,
+ enum kshark_filter_type filter_id)
{
- return filter_find(kshark_ctx->show_event_filter, pid, true) &&
- filter_find(kshark_ctx->hide_event_filter, pid, false);
+ struct kshark_data_stream *stream;
+
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!stream)
+ return NULL;
+
+ return kshark_get_filter(stream, filter_id);
}
-static bool kshark_show_cpu(struct kshark_context *kshark_ctx, int cpu)
+/**
+ * @brief Get an Id Filter.
+ *
+ * @param stream: Input location for a Trace data stream pointer.
+ * @param filter_id: Identifier of the filter.
+ */
+struct kshark_hash_id *
+kshark_get_filter(struct kshark_data_stream *stream,
+ enum kshark_filter_type filter_id)
{
- return filter_find(kshark_ctx->show_cpu_filter, cpu, true) &&
- filter_find(kshark_ctx->hide_cpu_filter, cpu, false);
+ switch (filter_id) {
+ case KS_SHOW_CPU_FILTER:
+ return stream->show_cpu_filter;
+ case KS_HIDE_CPU_FILTER:
+ return stream->hide_cpu_filter;
+ case KS_SHOW_EVENT_FILTER:
+ return stream->show_event_filter;
+ case KS_HIDE_EVENT_FILTER:
+ return stream->hide_event_filter;
+ case KS_SHOW_TASK_FILTER:
+ return stream->show_task_filter;
+ case KS_HIDE_TASK_FILTER:
+ return stream->hide_task_filter;
+ default:
+ return NULL;
+ }
}
/**
- * @brief Add an Id value to the filster specified by "filter_id".
+ * @brief Add an Id value to the filter specified by "filter_id".
*
* @param kshark_ctx: Input location for the session context pointer.
+ * @param sd: Data stream identifier.
* @param filter_id: Identifier of the filter.
* @param id: Id value to be added to the filter.
*/
-void kshark_filter_add_id(struct kshark_context *kshark_ctx,
+void kshark_filter_add_id(struct kshark_context *kshark_ctx, int sd,
int filter_id, int id)
{
- struct tracecmd_filter_id *filter;
+ struct kshark_hash_id *filter;
- switch (filter_id) {
- case KS_SHOW_CPU_FILTER:
- filter = kshark_ctx->show_cpu_filter;
- break;
- case KS_HIDE_CPU_FILTER:
- filter = kshark_ctx->hide_cpu_filter;
- break;
- case KS_SHOW_EVENT_FILTER:
- filter = kshark_ctx->show_event_filter;
- break;
- case KS_HIDE_EVENT_FILTER:
- filter = kshark_ctx->hide_event_filter;
- break;
- case KS_SHOW_TASK_FILTER:
- filter = kshark_ctx->show_task_filter;
- break;
- case KS_HIDE_TASK_FILTER:
- filter = kshark_ctx->hide_task_filter;
- break;
- default:
- return;
+ filter = get_filter(kshark_ctx, sd, filter_id);
+ if (filter)
+ kshark_hash_id_add(filter, id);
+}
+
+/**
+ * @brief Get an array containing all Ids associated with a given Id Filter.
+ *
+ * @param kshark_ctx: Input location for context pointer.
+ * @param sd: Data stream identifier.
+ * @param filter_id: Identifier of the filter.
+ * @param n: Output location for the size of the returned array.
+ *
+ * @return The user is responsible for freeing the array.
+ */
+int *kshark_get_filter_ids(struct kshark_context *kshark_ctx, int sd,
+ int filter_id, int *n)
+{
+ struct kshark_hash_id *filter;
+
+ filter = get_filter(kshark_ctx, sd, filter_id);
+ if (filter) {
+ if (n)
+ *n = filter->count;
+
+ return kshark_hash_ids(filter);
}
- tracecmd_filter_id_add(filter, id);
+ if (n)
+ *n = 0;
+
+ return NULL;
}
/**
- * @brief Clear (reset) the filster specified by "filter_id".
+ * @brief Clear (reset) the filter specified by "filter_id".
*
* @param kshark_ctx: Input location for the session context pointer.
+ * @param sd: Data stream identifier.
* @param filter_id: Identifier of the filter.
*/
-void kshark_filter_clear(struct kshark_context *kshark_ctx, int filter_id)
+void kshark_filter_clear(struct kshark_context *kshark_ctx, int sd,
+ int filter_id)
{
- struct tracecmd_filter_id *filter;
-
- switch (filter_id) {
- case KS_SHOW_CPU_FILTER:
- filter = kshark_ctx->show_cpu_filter;
- break;
- case KS_HIDE_CPU_FILTER:
- filter = kshark_ctx->hide_cpu_filter;
- break;
- case KS_SHOW_EVENT_FILTER:
- filter = kshark_ctx->show_event_filter;
- break;
- case KS_HIDE_EVENT_FILTER:
- filter = kshark_ctx->hide_event_filter;
- break;
- case KS_SHOW_TASK_FILTER:
- filter = kshark_ctx->show_task_filter;
- break;
- case KS_HIDE_TASK_FILTER:
- filter = kshark_ctx->hide_task_filter;
- break;
- default:
- return;
- }
+ struct kshark_hash_id *filter;
- tracecmd_filter_id_clear(filter);
+ filter = get_filter(kshark_ctx, sd, filter_id);
+ if (filter)
+ kshark_hash_id_clear(filter);
}
/**
@@ -1148,7 +1170,7 @@ void kshark_filter_clear(struct kshark_context *kshark_ctx, int filter_id)
*
* @returns True if the Id filter is set, otherwise False.
*/
-bool kshark_this_filter_is_set(struct tracecmd_filter_id *filter)
+bool kshark_this_filter_is_set(struct kshark_hash_id *filter)
{
return filter && filter->count;
}
@@ -1157,17 +1179,49 @@ bool kshark_this_filter_is_set(struct tracecmd_filter_id *filter)
* @brief Check if an Id filter is set.
*
* @param kshark_ctx: Input location for the session context pointer.
+ * @param sd: Data stream identifier.
*
- * @returns True if at least one Id filter is set, otherwise False.
+ * @returns True if at least one Id filter of the stream is set, otherwise
+ * False.
*/
-bool kshark_filter_is_set(struct kshark_context *kshark_ctx)
+bool kshark_filter_is_set(struct kshark_context *kshark_ctx, int sd)
{
- return kshark_this_filter_is_set(kshark_ctx->show_task_filter) ||
-- kshark_this_filter_is_set(kshark_ctx->hide_task_filter) ||
-- kshark_this_filter_is_set(kshark_ctx->show_cpu_filter) ||
-- kshark_this_filter_is_set(kshark_ctx->hide_cpu_filter) ||
-- kshark_this_filter_is_set(kshark_ctx->show_event_filter) ||
-- kshark_this_filter_is_set(kshark_ctx->hide_event_filter);
+ struct kshark_data_stream *stream;
+
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!stream)
+ return false;
+
+ return kshark_this_filter_is_set(stream->show_task_filter) ||
+ kshark_this_filter_is_set(stream->hide_task_filter) ||
+ kshark_this_filter_is_set(stream->show_cpu_filter) ||
+ kshark_this_filter_is_set(stream->hide_cpu_filter) ||
+ kshark_this_filter_is_set(stream->show_event_filter) ||
+ kshark_this_filter_is_set(stream->hide_event_filter);
+}
+
+/**
+ * @brief Apply filters to a given entry.
+ *
+ * @param kshark_ctx: Input location for the session context pointer.
+ * @param stream: Input location for a Trace data stream pointer.
+ * @param entry: Input location for entry.
+ */
+void kshark_apply_filters(struct kshark_context *kshark_ctx,
+ struct kshark_data_stream *stream,
+ struct kshark_entry *entry)
+{
+ /* Apply event filtering. */
+ if (!kshark_show_event(stream, entry->event_id))
+ unset_event_filter_flag(kshark_ctx, entry);
+
+ /* Apply CPU filtering. */
+ if (!kshark_show_cpu(stream, entry->cpu))
+ entry->visible &= ~kshark_ctx->filter_mask;
+
+ /* Apply task filtering. */
+ if (!kshark_show_task(stream, entry->pid))
+ entry->visible &= ~kshark_ctx->filter_mask;
}
static void set_all_visible(uint16_t *v) {
@@ -1175,56 +1229,100 @@ static void set_all_visible(uint16_t *v) {
*v |= 0xFF & ~KS_PLUGIN_UNTOUCHED_MASK;
}
+static void filter_entries(struct kshark_context *kshark_ctx, int sd,
+ struct kshark_entry **data, size_t n_entries)
+{
+ struct kshark_data_stream *stream = NULL;
+ size_t i;
+
+ /* Sanity checks before starting. */
+ if (sd >= 0) {
+ /* We will filter particular Data stream. */
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!stream)
+ return;
+
+ if (kshark_is_tep(stream) &&
+ kshark_tep_filter_is_set(stream)) {
+ /* The advanced filter is set. */
+ fprintf(stderr,
+ "Failed to filter (sd = %i)!\n", sd);
+ fprintf(stderr,
+ "Reset the Advanced filter or reload the data.\n");
+
+ return;
+ }
+
+ if (!kshark_filter_is_set(kshark_ctx, sd))
+ return;
+ }
+
+ /* Apply only the Id filters. */
+ for (i = 0; i < n_entries; ++i) {
+ if (sd >= 0) {
+ /*
+ * We only filter particular stream. Chack is the entry
+ * belongs to this stream.
+ */
+ if (data[i]->stream_id != sd)
+ continue;
+ } else {
+ /* We filter all streams. */
+ stream = kshark_ctx->stream[data[i]->stream_id];
+ }
+
+ /* Start with and entry which is visible everywhere. */
+ set_all_visible(&data[i]->visible);
+
+ /* Apply Id filtering. */
+ kshark_apply_filters(kshark_ctx, stream, data[i]);
+ }
+}
+
/**
* @brief This function loops over the array of entries specified by "data"
- * and "n_entries" and sets the "visible" fields of each entry
- * according to the criteria provided by the filters of the session's
- * context. The field "filter_mask" of the session's context is used to
- * control the level of visibility/invisibility of the entries which
- * are filtered-out.
+ * and "n_entries" and sets the "visible" fields of each entry from a
+ * given Data stream according to the criteria provided by the filters
+ * of the session's context. The field "filter_mask" of the session's
+ * context is used to control the level of visibility/invisibility of
+ * the entries which are filtered-out.
* WARNING: Do not use this function if the advanced filter is set.
* Applying the advanced filter requires access to prevent_record,
* hence the data has to be reloaded using kshark_load_entries().
*
* @param kshark_ctx: Input location for the session context pointer.
+ * @param sd: Data stream identifier.
* @param data: Input location for the trace data to be filtered.
* @param n_entries: The size of the inputted data.
*/
-void kshark_filter_entries(struct kshark_context *kshark_ctx,
- struct kshark_entry **data,
- size_t n_entries)
+void kshark_filter_stream_entries(struct kshark_context *kshark_ctx,
+ int sd,
+ struct kshark_entry **data,
+ size_t n_entries)
{
- int i;
-
- if (kshark_ctx->advanced_event_filter->filters) {
- /* The advanced filter is set. */
- fprintf(stderr,
- "Failed to filter!\n");
- fprintf(stderr,
- "Reset the Advanced filter or reload the data.\n");
- return;
- }
-
- if (!kshark_filter_is_set(kshark_ctx))
- return;
-
- /* Apply only the Id filters. */
- for (i = 0; i < n_entries; ++i) {
- /* Start with and entry which is visible everywhere. */
- set_all_visible(&data[i]->visible);
-
- /* Apply event filtering. */
- if (!kshark_show_event(kshark_ctx, data[i]->event_id))
- unset_event_filter_flag(kshark_ctx, data[i]);
-
- /* Apply CPU filtering. */
- if (!kshark_show_cpu(kshark_ctx, data[i]->cpu))
- data[i]->visible &= ~kshark_ctx->filter_mask;
+ if (sd >= 0)
+ filter_entries(kshark_ctx, sd, data, n_entries);
+}
- /* Apply task filtering. */
- if (!kshark_show_task(kshark_ctx, data[i]->pid))
- data[i]->visible &= ~kshark_ctx->filter_mask;
- }
+/**
+ * @brief This function loops over the array of entries specified by "data"
+ * and "n_entries" and sets the "visible" fields of each entry from
+ * all Data stream according to the criteria provided by the filters
+ * of the session's context. The field "filter_mask" of the session's
+ * context is used to control the level of visibility/invisibility of
+ * the entries which are filtered-out.
+ * WARNING: Do not use this function if the advanced filter is set.
+ * Applying the advanced filter requires access to prevent_record,
+ * hence the data has to be reloaded using kshark_load_data_entries().
+ *
+ * @param kshark_ctx: Input location for the session context pointer.
+ * @param data: Input location for the trace data to be filtered.
+ * @param n_entries: The size of the inputted data.
+ */
+void kshark_filter_all_entries(struct kshark_context *kshark_ctx,
+ struct kshark_entry **data, size_t n_entries)
+{
+ filter_entries(kshark_ctx, -1, data, n_entries);
}
/**
@@ -1241,6 +1339,7 @@ void kshark_clear_all_filters(struct kshark_context *kshark_ctx,
size_t n_entries)
{
int i;
+
for (i = 0; i < n_entries; ++i)
set_all_visible(&data[i]->visible);
}
@@ -1364,15 +1463,15 @@ void kshark_convert_nano(uint64_t time, uint64_t *sec, uint64_t *usec)
* @param h: Array index specifying the upper edge of the range to search in.
*
* @returns On success, the first kshark_entry inside the range, having a
- timestamp equal or bigger than "time".
- If all entries inside the range have timestamps greater than "time"
- the function returns BSEARCH_ALL_GREATER (negative value).
- If all entries inside the range have timestamps smaller than "time"
- the function returns BSEARCH_ALL_SMALLER (negative value).
+ * timestamp equal or bigger than "time".
+ * If all entries inside the range have timestamps greater than "time"
+ * the function returns BSEARCH_ALL_GREATER (negative value).
+ * If all entries inside the range have timestamps smaller than "time"
+ * the function returns BSEARCH_ALL_SMALLER (negative value).
*/
-ssize_t kshark_find_entry_by_time(uint64_t time,
- struct kshark_entry **data,
- size_t l, size_t h)
+ssize_t kshark_find_entry_by_time(int64_t time,
+ struct kshark_entry **data,
+ size_t l, size_t h)
{
size_t mid;
@@ -1396,15 +1495,16 @@ ssize_t kshark_find_entry_by_time(uint64_t time,
*
* @param kshark_ctx: Input location for the session context pointer.
* @param e: kshark_entry to be checked.
+ * @param sd: Data stream identifier.
* @param pid: Matching condition value.
*
* @returns True if the Pid of the entry matches the value of "pid".
* Else false.
*/
bool kshark_match_pid(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int pid)
+ struct kshark_entry *e, int sd, int *pid)
{
- if (e->pid == pid)
+ if (e->stream_id == sd && e->pid == *pid)
return true;
return false;
@@ -1415,20 +1515,80 @@ bool kshark_match_pid(struct kshark_context *kshark_ctx,
*
* @param kshark_ctx: Input location for the session context pointer.
* @param e: kshark_entry to be checked.
+ * @param sd: Data stream identifier.
* @param cpu: Matching condition value.
*
* @returns True if the Cpu of the entry matches the value of "cpu".
* Else false.
*/
bool kshark_match_cpu(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int cpu)
+ struct kshark_entry *e, int sd, int *cpu)
{
- if (e->cpu == cpu)
+ if (e->stream_id == sd && e->cpu == *cpu)
return true;
return false;
}
+/**
+ * @brief Simple event Id matching function to be user for data requests.
+ *
+ * @param kshark_ctx: Input location for the session context pointer.
+ * @param e: kshark_entry to be checked.
+ * @param sd: Data stream identifier.
+ * @param event_id: Matching condition value.
+ *
+ * @returns True if the event Id of the entry matches the value of "event_id".
+ * Else false.
+ */
+bool kshark_match_event_id(struct kshark_context *kshark_ctx,
+ struct kshark_entry *e, int sd, int *event_id)
+{
+ return e->stream_id == sd && e->event_id == *event_id;
+}
+
+/**
+ * @brief Simple Event Id and PID matching function to be user for data requests.
+ *
+ * @param kshark_ctx: Input location for the session context pointer.
+ * @param e: kshark_entry to be checked.
+ * @param sd: Data stream identifier.
+ * @param values: An array of matching condition value.
+ * values[0] is the matches PID and values[1] is the matches event Id.
+ *
+ * @returns True if the event Id of the entry matches the values.
+ * Else false.
+ */
+bool kshark_match_event_and_pid(struct kshark_context *kshark_ctx,
+ struct kshark_entry *e,
+ int sd, int *values)
+{
+ return e->stream_id == sd &&
+ e->event_id == values[0] &&
+ e->pid == values[1];
+}
+
+/**
+ * @brief Simple Event Id and CPU matching function to be user for data requests.
+ *
+ * @param kshark_ctx: Input location for the session context pointer.
+ * @param e: kshark_entry to be checked.
+ * @param sd: Data stream identifier.
+ * @param values: An array of matching condition value.
+ * values[0] is the matches PID and values[1] is the matches event Id.
+ *
+ * @returns True if the event Id of the entry matches the values.
+ * Else false.
+ */
+bool kshark_match_event_and_cpu(struct kshark_context *kshark_ctx,
+ struct kshark_entry *e,
+ int sd, int *values)
+{
+ return e->stream_id == sd &&
+ e->event_id == values[0] &&
+ e->cpu == values[1];
+}
+
/**
* @brief Create Data request. The request defines the properties of the
* requested kshark_entry.
@@ -1437,8 +1597,9 @@ bool kshark_match_cpu(struct kshark_context *kshark_ctx,
* where the search starts.
* @param n: Number of array elements to search in.
* @param cond: Matching condition function.
- * @param val: Matching condition value, used by the Matching condition
- * function.
+ * @param sd: Data stream identifier.
+ * @param values: Matching condition values, used by the Matching condition
+ * function.
* @param vis_only: If true, a visible entry is requested.
* @param vis_mask: If "vis_only" is true, use this mask to specify the level
* of visibility of the requested entry.
@@ -1449,7 +1610,7 @@ bool kshark_match_cpu(struct kshark_context *kshark_ctx,
*/
struct kshark_entry_request *
kshark_entry_request_alloc(size_t first, size_t n,
- matching_condition_func cond, int val,
+ matching_condition_func cond, int sd, int *values,
bool vis_only, int vis_mask)
{
struct kshark_entry_request *req = malloc(sizeof(*req));
@@ -1464,7 +1625,8 @@ kshark_entry_request_alloc(size_t first, size_t n,
req->first = first;
req->n = n;
req->cond = cond;
- req->val = val;
+ req->sd = sd;
+ req->values = values;
req->vis_only = vis_only;
req->vis_mask = vis_mask;
@@ -1518,7 +1680,7 @@ get_entry(const struct kshark_entry_request *req,
*/
assert((inc > 0 && start < end) || (inc < 0 && start > end));
for (i = start; i != end; i += inc) {
- if (req->cond(kshark_ctx, data[i], req->val)) {
+ if (req->cond(kshark_ctx, data[i], req->sd, req->values)) {
/*
* Data satisfying the condition has been found.
*/
@@ -14,6 +14,7 @@
// C
#include <stdint.h>
+#include <string.h>
#include <pthread.h>
#include <errno.h>
@@ -24,10 +25,6 @@
extern "C" {
#endif
-// trace-cmd
-#include "trace-cmd/trace-cmd.h"
-#include "trace-filter-hash.h"
-
// KernelShark
#include "libkshark-plugin.h"
@@ -378,27 +375,6 @@ struct kshark_context {
/** Parameters of the stream descriptor array. */
struct kshark_stream_array_descriptor stream_info;
- /** A mutex, used to protect the access to the input file. */
- pthread_mutex_t input_mutex;
-
- /** Hash of tasks to filter on. */
- struct tracecmd_filter_id *show_task_filter;
-
- /** Hash of tasks to not display. */
- struct tracecmd_filter_id *hide_task_filter;
-
- /** Hash of events to filter on. */
- struct tracecmd_filter_id *show_event_filter;
-
- /** Hash of events to not display. */
- struct tracecmd_filter_id *hide_event_filter;
-
- /** Hash of CPUs to filter on. */
- struct tracecmd_filter_id *show_cpu_filter;
-
- /** Hash of CPUs to not display. */
- struct tracecmd_filter_id *hide_cpu_filter;
-
/**
* Bit mask, controlling the visibility of the entries after filtering.
* If given bit is set here, all entries which are filtered-out will
@@ -406,12 +382,6 @@ struct kshark_context {
*/
uint8_t filter_mask;
- /**
- * Filter allowing sophisticated filtering based on the content of
- * the event.
- */
- struct tep_event_filter *advanced_event_filter;
-
/** List of Data collections. */
struct kshark_entry_collection *collections;
@@ -570,14 +540,22 @@ enum kshark_filter_type {
KS_HIDE_CPU_FILTER,
};
-void kshark_filter_add_id(struct kshark_context *kshark_ctx,
+struct kshark_hash_id *
+kshark_get_filter(struct kshark_data_stream *stream,
+ enum kshark_filter_type filter_id);
+
+void kshark_filter_add_id(struct kshark_context *kshark_ctx, int sd,
int filter_id, int id);
-void kshark_filter_clear(struct kshark_context *kshark_ctx, int filter_id);
+int *kshark_get_filter_ids(struct kshark_context *kshark_ctx, int sd,
+ int filter_id, int *n);
+
+void kshark_filter_clear(struct kshark_context *kshark_ctx, int sd,
+ int filter_id);
-bool kshark_this_filter_is_set(struct tracecmd_filter_id *filter);
+bool kshark_this_filter_is_set(struct kshark_hash_id *filter);
-bool kshark_filter_is_set(struct kshark_context *kshark_ctx);
+bool kshark_filter_is_set(struct kshark_context *kshark_ctx, int sd);
static inline void unset_event_filter_flag(struct kshark_context *kshark_ctx,
struct kshark_entry *e)
@@ -594,9 +572,16 @@ static inline void unset_event_filter_flag(struct kshark_context *kshark_ctx,
e->visible &= ~event_mask;
}
-void kshark_filter_entries(struct kshark_context *kshark_ctx,
- struct kshark_entry **data,
- size_t n_entries);
+void kshark_apply_filters(struct kshark_context *kshark_ctx,
+ struct kshark_data_stream *stream,
+ struct kshark_entry *entry);
+
+void kshark_filter_stream_entries(struct kshark_context *kshark_ctx, int sd,
+ struct kshark_entry **data,
+ size_t n_entries);
+
+void kshark_filter_all_entries(struct kshark_context *kshark_ctx,
+ struct kshark_entry **data, size_t n_entries);
void kshark_clear_all_filters(struct kshark_context *kshark_ctx,
struct kshark_entry **data,
@@ -607,10 +592,10 @@ void kshark_plugin_actions(struct kshark_data_stream *stream,
/** Search failed identifiers. */
enum kshark_search_failed {
- /** All entries have timestamps greater timestamps. */
+ /** All entries have greater timestamps. */
BSEARCH_ALL_GREATER = -1,
- /** All entries have timestamps smaller timestamps. */
+ /** All entries have smaller timestamps. */
BSEARCH_ALL_SMALLER = -2,
};
@@ -626,15 +611,26 @@ enum kshark_search_failed {
} \
})
-ssize_t kshark_find_entry_by_time(uint64_t time,
+ssize_t kshark_find_entry_by_time(int64_t time,
struct kshark_entry **data_rows,
size_t l, size_t h);
bool kshark_match_pid(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int pid);
+ struct kshark_entry *e, int sd, int *pid);
bool kshark_match_cpu(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int cpu);
+ struct kshark_entry *e, int sd, int *cpu);
+
+bool kshark_match_event_id(struct kshark_context *kshark_ctx,
+ struct kshark_entry *e, int sd, int *event_id);
+
+bool kshark_match_event_and_pid(struct kshark_context *kshark_ctx,
+ struct kshark_entry *e,
+ int sd, int *values);
+
+bool kshark_match_event_and_cpu(struct kshark_context *kshark_ctx,
+ struct kshark_entry *e,
+ int sd, int *values);
/**
* Empty bin identifier.
@@ -652,7 +648,7 @@ bool kshark_match_cpu(struct kshark_context *kshark_ctx,
/** Matching condition function type. To be user for data requests */
typedef bool (matching_condition_func)(struct kshark_context*,
struct kshark_entry*,
- int);
+ int, int*);
/**
* Data request structure, defining the properties of the required
@@ -674,10 +670,13 @@ struct kshark_entry_request {
/** Matching condition function. */
matching_condition_func *cond;
+ /** Data stream identifier. */
+ int sd;
+
/**
* Matching condition value, used by the Matching condition function.
*/
- int val;
+ int *values;
/** If true, a visible entry is requested. */
bool vis_only;
@@ -691,7 +690,7 @@ struct kshark_entry_request {
struct kshark_entry_request *
kshark_entry_request_alloc(size_t first, size_t n,
- matching_condition_func cond, int val,
+ matching_condition_func cond, int sd, int *values,
bool vis_only, int vis_mask);
void kshark_free_entry_request(struct kshark_entry_request *req);
@@ -708,8 +707,8 @@ kshark_get_entry_back(const struct kshark_entry_request *req,
/**
* Data collections are used to optimize the search for an entry having an
- * abstract property, defined by a Matching condition function and a value.
- * When a collection is processed, the data which is relevant for the
+ * abstract property, defined by a Matching condition function and an array of
+ * values. When a collection is processed, the data which is relevant for the
* collection is enclosed in "Data intervals", defined by pairs of "Resume" and
* "Break" points. It is guaranteed that the data outside of the intervals
* contains no entries satisfying the abstract matching condition. However, the
@@ -726,11 +725,17 @@ struct kshark_entry_collection {
/** Matching condition function, used to define the collections. */
matching_condition_func *cond;
+ /** Data stream identifier. */
+ int stream_id;
+
/**
- * Matching condition value, used by the Matching condition finction
- * to define the collections.
+ * Array of matching condition values, used by the Matching condition
+ * finction to define the collection.
*/
- int val;
+ int *values;
+
+ /** The suze of the array of matching condition values. */
+ int n_val;
/**
* Array of indexes defining the beginning of each individual data
@@ -753,26 +758,30 @@ kshark_add_collection_to_list(struct kshark_context *kshark_ctx,
struct kshark_entry **data,
size_t n_rows,
matching_condition_func cond,
- int val,
+ int sd, int *values, size_t n_val,
size_t margin);
struct kshark_entry_collection *
kshark_register_data_collection(struct kshark_context *kshark_ctx,
struct kshark_entry **data, size_t n_rows,
- matching_condition_func cond, int val,
+ matching_condition_func cond,
+ int sd, int *values, size_t n_val,
size_t margin);
void kshark_unregister_data_collection(struct kshark_entry_collection **col,
matching_condition_func cond,
- int val);
+ int sd, int *values, size_t n_val);
struct kshark_entry_collection *
kshark_find_data_collection(struct kshark_entry_collection *col,
matching_condition_func cond,
- int val);
+ int sd, int *values, size_t n_val);
void kshark_reset_data_collection(struct kshark_entry_collection *col);
+void kshark_unregister_stream_collections(struct kshark_entry_collection **col,
+ int sd);
+
void kshark_free_collection_list(struct kshark_entry_collection *col);
const struct kshark_entry *
@@ -914,17 +923,27 @@ bool kshark_export_adv_filters(struct kshark_context *kshark_ctx,
bool kshark_import_adv_filters(struct kshark_context *kshark_ctx,
struct kshark_config_doc *conf);
+bool kshark_export_event_filter(struct kshark_data_stream *stream,
+ enum kshark_filter_type filter_type,
+ const char *filter_name,
+ struct kshark_config_doc *conf);
+
+int kshark_import_event_filter(struct kshark_data_stream *stream,
+ enum kshark_filter_type filter_type,
+ const char *filter_name,
+ struct kshark_config_doc *conf);
+
bool kshark_export_user_mask(struct kshark_context *kshark_ctx,
struct kshark_config_doc **conf);
bool kshark_import_user_mask(struct kshark_context *kshark_ctx,
struct kshark_config_doc *conf);
-bool kshark_export_filter_array(struct tracecmd_filter_id *filter,
+bool kshark_export_filter_array(struct kshark_hash_id *filter,
const char *filter_name,
struct kshark_config_doc *conf);
-bool kshark_import_filter_array(struct tracecmd_filter_id *filter,
+bool kshark_import_filter_array(struct kshark_hash_id *filter,
const char *filter_name,
struct kshark_config_doc *conf);
deleted file mode 100644
@@ -1,64 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1 */
-/*
- * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
- * Copyright (C) 2018 VMware Inc, Steven Rostedt <rostedt@goodmis.org>
- *
- */
-#ifndef _TRACE_FILTER_HASH_H
-#define _TRACE_FILTER_HASH_H
-
-#include <stdint.h>
-
-struct tracecmd_filter_id_item {
- struct tracecmd_filter_id_item *next;
- int id;
-};
-
-struct tracecmd_filter_id {
- struct tracecmd_filter_id_item **hash;
- int count;
-};
-
-/**
- * tracecmd_quick_hash - A quick (non secured) hash alogirthm
- * @val: The value to perform the hash on
- * @bits: The size in bits you need to return
- *
- * This is a quick hashing function adapted from Donald E. Knuth's 32
- * bit multiplicative hash. See The Art of Computer Programming (TAOCP).
- * Multiplication by the Prime number, closest to the golden ratio of
- * 2^32.
- *
- * @bits is used to max the result for use cases that require
- * a power of 2 return value that is less than 32 bits. Any value
- * of @bits greater than 31 (or zero), will simply return the full hash on @val.
- */
-static inline uint32_t tracecmd_quick_hash(uint32_t val, unsigned int bits)
-{
- val *= UINT32_C(2654435761);
-
- if (!bits || bits > 31)
- return val;
-
- return val & ((1 << bits) - 1);
-}
-
-struct tracecmd_filter_id_item *
- tracecmd_filter_id_find(struct tracecmd_filter_id *hash, int id);
-void tracecmd_filter_id_add(struct tracecmd_filter_id *hash, int id);
-void tracecmd_filter_id_remove(struct tracecmd_filter_id *hash, int id);
-void tracecmd_filter_id_clear(struct tracecmd_filter_id *hash);
-struct tracecmd_filter_id *tracecmd_filter_id_hash_alloc(void);
-void tracecmd_filter_id_hash_free(struct tracecmd_filter_id *hash);
-struct tracecmd_filter_id *
- tracecmd_filter_id_hash_copy(struct tracecmd_filter_id *hash);
-int *tracecmd_filter_ids(struct tracecmd_filter_id *hash);
-int tracecmd_filter_id_compare(struct tracecmd_filter_id *hash1,
- struct tracecmd_filter_id *hash2);
-
-static inline int tracecmd_filter_task_count(struct tracecmd_filter_id *hash)
-{
- return hash->count;
-}
-
-#endif /* _TRACE_FILTER_HASH_H */
The patch contains a number various relatively small modifications needed in order to finalize the integration. Unfortunately those changes are hard to disentangle so we will do everything in a single patch. Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com> --- examples/CMakeLists.txt | 8 +- examples/datafilter.c | 67 +++--- src/CMakeLists.txt | 1 + src/libkshark-collection.c | 121 ++++++++-- src/libkshark-tepdata.c | 391 ++++++++++++++++++++++++++++++++ src/libkshark-tepdata.h | 49 ++++ src/libkshark.c | 454 +++++++++++++++++++++++++------------ src/libkshark.h | 133 ++++++----- src/trace-filter-hash.h | 64 ------ 9 files changed, 959 insertions(+), 329 deletions(-) delete mode 100644 src/trace-filter-hash.h