diff mbox series

[v2,15/17] libtraceeval histogram: Add traceeval_iterator_sort_custom()

Message ID 20230811053940.1408424-16-rostedt@goodmis.org (mailing list archive)
State Superseded
Headers show
Series libtraceeval histogram: Updates | expand

Commit Message

Steven Rostedt Aug. 11, 2023, 5:39 a.m. UTC
From: "Steven Rostedt (Google)" <rostedt@goodmis.org>

Add an iterator where the application can supply the sort algorithm where
it gets the teval descriptor along with the keys and values of both of the
entries to compare against. Also, allow it to submit its own data to the
compare function:

int traceeval_iterator_sort_custom(struct traceeval_iterator *iter,
				   traceeval_cmp_fn sort_fn, void *data);

with

typedef int (*traceeval_cmp_fn)(struct traceeval *teval,
				const union traceeval_data *Akeys,
				const union traceeval_data *Avals,
				const union traceeval_data *Bkeys,
				const union traceeval_data *Bvals,
				void *data);

Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
 include/traceeval-hist.h |  9 +++++++++
 src/histograms.c         | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+)

Comments

Ross Zwisler Aug. 16, 2023, 10:57 p.m. UTC | #1
On Fri, Aug 11, 2023 at 01:39:38AM -0400, Steven Rostedt wrote:
> From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
> 
> Add an iterator where the application can supply the sort algorithm where
> it gets the teval descriptor along with the keys and values of both of the
> entries to compare against. Also, allow it to submit its own data to the
> compare function:
> 
> int traceeval_iterator_sort_custom(struct traceeval_iterator *iter,
> 				   traceeval_cmp_fn sort_fn, void *data);
> 
> with
> 
> typedef int (*traceeval_cmp_fn)(struct traceeval *teval,
> 				const union traceeval_data *Akeys,
> 				const union traceeval_data *Avals,
> 				const union traceeval_data *Bkeys,
> 				const union traceeval_data *Bvals,
> 				void *data);
> 
> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
> ---
>  include/traceeval-hist.h |  9 +++++++++
>  src/histograms.c         | 34 ++++++++++++++++++++++++++++++++++
>  2 files changed, 43 insertions(+)
> 
> diff --git a/include/traceeval-hist.h b/include/traceeval-hist.h
> index 1a24d6117b93..839f63630897 100644
> --- a/include/traceeval-hist.h
> +++ b/include/traceeval-hist.h
> @@ -86,6 +86,13 @@ typedef int (*traceeval_data_copy_fn)(const struct traceeval_type *type,
>  				      union traceeval_data *copy,
>  				      const union traceeval_data *origin);
>  
> +typedef int (*traceeval_cmp_fn)(struct traceeval *teval,
> +				const union traceeval_data *Akeys,
> +				const union traceeval_data *Avals,
> +				const union traceeval_data *Bkeys,
> +				const union traceeval_data *Bvals,
> +				void *data);
> +
>  /*
>   * struct traceeval_type - Describes the type of a traceevent_data instance
>   * @type: The enum type that describes the traceeval_data
> @@ -172,6 +179,8 @@ struct traceeval_iterator *traceeval_iterator_get(struct traceeval *teval);
>  void traceeval_iterator_put(struct traceeval_iterator *iter);
>  int traceeval_iterator_sort(struct traceeval_iterator *iter, const char *sort_field,
>  			    int level, bool ascending);
> +int traceeval_iterator_sort_custom(struct traceeval_iterator *iter,
> +				   traceeval_cmp_fn sort_fn, void *data);
>  int traceeval_iterator_next(struct traceeval_iterator *iter,
>  			    const union traceeval_data **keys);
>  
> diff --git a/src/histograms.c b/src/histograms.c
> index 643a550422f6..33c87644d468 100644
> --- a/src/histograms.c
> +++ b/src/histograms.c
> @@ -1153,6 +1153,40 @@ static int sort_iter(struct traceeval_iterator *iter)
>  	return 0;
>  }
>  
> +struct iter_custom_data {
> +	struct traceeval_iterator *iter;
> +	traceeval_cmp_fn sort_fn;
> +	void *data;
> +};
> +
> +static int iter_custom_cmp(const void *A, const void *B, void *data)
> +{
> +	struct iter_custom_data *cust_data = data;
> +	struct traceeval_iterator *iter = cust_data->iter;
> +	struct traceeval *teval = iter->teval;
> +	const struct entry *a = *((const struct entry **)A);
> +	const struct entry *b = *((const struct entry **)B);
> +
> +	return cust_data->sort_fn(teval, a->keys, a->vals, b->keys, b->vals,
> +				  cust_data->data);
> +}
> +
> +int traceeval_iterator_sort_custom(struct traceeval_iterator *iter,
> +				   traceeval_cmp_fn sort_fn, void *data)
> +{
> +	struct iter_custom_data cust_data = {
> +		.iter = iter,
> +		.sort_fn = sort_fn,
> +		.data = data
> +	};
> +
> +	qsort_r(iter->entries, iter->nr_entries, sizeof(*iter->entries),
> +		iter_custom_cmp, &cust_data);

I guess I don't yet see what this gives us over the existing sorting and
iterators?  Does this do the same thing, we just pass in the sort function
instead of calling traceeval_iterator_sort() one or more times?

> +
> +	iter->needs_sort = false;

Also probably need to set
  iter->next = 0;

> +	return 0;
> +}
> +
>  /**
>   * traceeval_iterator_next - retrieve the next entry from an iterator
>   * @iter: The iterator to retrieve the next entry from
> -- 
> 2.40.1
>
Steven Rostedt Aug. 16, 2023, 11:22 p.m. UTC | #2
On Wed, 16 Aug 2023 16:57:16 -0600
Ross Zwisler <zwisler@google.com> wrote:

> > +static int iter_custom_cmp(const void *A, const void *B, void *data)
> > +{
> > +	struct iter_custom_data *cust_data = data;
> > +	struct traceeval_iterator *iter = cust_data->iter;
> > +	struct traceeval *teval = iter->teval;
> > +	const struct entry *a = *((const struct entry **)A);
> > +	const struct entry *b = *((const struct entry **)B);
> > +
> > +	return cust_data->sort_fn(teval, a->keys, a->vals, b->keys, b->vals,
> > +				  cust_data->data);
> > +}
> > +
> > +int traceeval_iterator_sort_custom(struct traceeval_iterator *iter,
> > +				   traceeval_cmp_fn sort_fn, void *data)
> > +{
> > +	struct iter_custom_data cust_data = {
> > +		.iter = iter,
> > +		.sort_fn = sort_fn,
> > +		.data = data
> > +	};
> > +
> > +	qsort_r(iter->entries, iter->nr_entries, sizeof(*iter->entries),
> > +		iter_custom_cmp, &cust_data);  
> 
> I guess I don't yet see what this gives us over the existing sorting and
> iterators?  Does this do the same thing, we just pass in the sort function
> instead of calling traceeval_iterator_sort() one or more times?

This should be used in replace of the other sorting. It allows the user to
make a complex sort. If you look at the last patch, the sample uses this:

+/*
+ * Sort all the processes by the RUNNING state.
+ *  If A and B have the same COMM, then sort by state.
+ *  else
+ *    Find the RUNNNIG state for A and B
+ *    If the RUNNING state does not exist, it's considered -1
+ *  If RUNNING is equal, then sort by COMM.
+ */
+static int compare_pdata(struct traceeval *teval_data,
+				const union traceeval_data *Akeys,
+				const union traceeval_data *Avals,
+				const union traceeval_data *Bkeys,
+				const union traceeval_data *Bvals,
+				void *data)
+{
+	struct traceeval *teval = data; /* The deltas are here */
+	union traceeval_data keysA[] = {
+		{ .cstring = Akeys[0].cstring }, { .number = RUNNING } };
+	union traceeval_data keysB[] = {
+		{ .cstring = Bkeys[0].cstring }, { .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) {
+		/* Sort decending */
+		if (Bkeys[1].number > Akeys[1].number)
+			return -1;
+		return Bkeys[1].number != Akeys[1].number;
+	}
+
+	/* Get the RUNNING values for both processes */
+	statA = traceeval_stat(teval, keysA, &delta_vals[0]);
+	if (statA)
+		totalA = traceeval_stat_total(statA);
+
+	statB = traceeval_stat(teval, keysB, &delta_vals[0]);
+	if (statB)
+		totalB = traceeval_stat_total(statB);
+
+	if (totalB < totalA)
+		return -1;
+	if (totalB > totalA)
+		return 1;
+
+	return strcmp(Bkeys[0].cstring, Akeys[0].cstring);
+}


> 
> > +
> > +	iter->needs_sort = false;  
> 
> Also probably need to set
>   iter->next = 0;

So much for redundancy!

Thanks,

-- Steve

> 
> > +	return 0;
> > +}
> > +
diff mbox series

Patch

diff --git a/include/traceeval-hist.h b/include/traceeval-hist.h
index 1a24d6117b93..839f63630897 100644
--- a/include/traceeval-hist.h
+++ b/include/traceeval-hist.h
@@ -86,6 +86,13 @@  typedef int (*traceeval_data_copy_fn)(const struct traceeval_type *type,
 				      union traceeval_data *copy,
 				      const union traceeval_data *origin);
 
+typedef int (*traceeval_cmp_fn)(struct traceeval *teval,
+				const union traceeval_data *Akeys,
+				const union traceeval_data *Avals,
+				const union traceeval_data *Bkeys,
+				const union traceeval_data *Bvals,
+				void *data);
+
 /*
  * struct traceeval_type - Describes the type of a traceevent_data instance
  * @type: The enum type that describes the traceeval_data
@@ -172,6 +179,8 @@  struct traceeval_iterator *traceeval_iterator_get(struct traceeval *teval);
 void traceeval_iterator_put(struct traceeval_iterator *iter);
 int traceeval_iterator_sort(struct traceeval_iterator *iter, const char *sort_field,
 			    int level, bool ascending);
+int traceeval_iterator_sort_custom(struct traceeval_iterator *iter,
+				   traceeval_cmp_fn sort_fn, void *data);
 int traceeval_iterator_next(struct traceeval_iterator *iter,
 			    const union traceeval_data **keys);
 
diff --git a/src/histograms.c b/src/histograms.c
index 643a550422f6..33c87644d468 100644
--- a/src/histograms.c
+++ b/src/histograms.c
@@ -1153,6 +1153,40 @@  static int sort_iter(struct traceeval_iterator *iter)
 	return 0;
 }
 
+struct iter_custom_data {
+	struct traceeval_iterator *iter;
+	traceeval_cmp_fn sort_fn;
+	void *data;
+};
+
+static int iter_custom_cmp(const void *A, const void *B, void *data)
+{
+	struct iter_custom_data *cust_data = data;
+	struct traceeval_iterator *iter = cust_data->iter;
+	struct traceeval *teval = iter->teval;
+	const struct entry *a = *((const struct entry **)A);
+	const struct entry *b = *((const struct entry **)B);
+
+	return cust_data->sort_fn(teval, a->keys, a->vals, b->keys, b->vals,
+				  cust_data->data);
+}
+
+int traceeval_iterator_sort_custom(struct traceeval_iterator *iter,
+				   traceeval_cmp_fn sort_fn, void *data)
+{
+	struct iter_custom_data cust_data = {
+		.iter = iter,
+		.sort_fn = sort_fn,
+		.data = data
+	};
+
+	qsort_r(iter->entries, iter->nr_entries, sizeof(*iter->entries),
+		iter_custom_cmp, &cust_data);
+
+	iter->needs_sort = false;
+	return 0;
+}
+
 /**
  * traceeval_iterator_next - retrieve the next entry from an iterator
  * @iter: The iterator to retrieve the next entry from