public inbox for linux-rt-users@vger.kernel.org
 help / color / mirror / Atom feed
From: Punit Agrawal <punitagrawal@gmail.com>
To: jkacur@redhat.com
Cc: Punit Agrawal <punit1.agrawal@toshiba.co.jp>,
	williams@redhat.com, linux-rt-users@vger.kernel.org
Subject: [RFC 7/7] rt-tests: cyclictest: Add support to report standard deviation
Date: Thu, 14 Oct 2021 16:12:47 +0900	[thread overview]
Message-ID: <20211014071247.4165329-8-punitagrawal@gmail.com> (raw)
In-Reply-To: <20211014071247.4165329-1-punitagrawal@gmail.com>

From: Punit Agrawal <punit1.agrawal@toshiba.co.jp>

For real time systems, the standard deviation is an important metric
to help qualify the suitability for low-latency workloads. Downstream
tools such as rteval calculate the value of the standard deviation
based on the latency histogram but this approach doesn't work in
situations when the max latency exceeds the range of the histogram.

The common formula to calculating standard deviation requires tracking
all samples which is not feasible. But an alternative approach is to
track the streaming standard deviation of the latency samples. With
this it is possible to update the standard deviation using -

         d = d' + (x - avg)(x - avg')

    stddev = sqrt (d / (n - 1))

where 'd' is similar to the variance, 'x' is the current latency
sample, 'n' is the number of samples and prime terms (') refer to the
previous values.

Implement the above algorithm to calculate the standard deviation and
update the reporting to also include standard deviation.

Signed-off-by: Punit Agrawal <punit1.agrawal@toshiba.co.jp>
---
 Makefile                    |  2 +-
 src/cyclictest/cyclictest.c | 43 +++++++++++++++++++++++++++++++------
 2 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/Makefile b/Makefile
index ec5d693436d0..3f08788c0208 100644
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,7 @@ sources = cyclictest.c \
 	  oslat.c
 
 TARGETS = $(sources:.c=)
-LIBS	= -lrt -lpthread
+LIBS	= -lrt -lpthread -lm
 RTTESTLIB = -lrttest -L$(OBJDIR)
 EXTRA_LIBS ?= -ldl	# for get_cpu
 RTTESTNUMA = -lrttestnuma -lnuma
diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c
index dde8b1625c62..2c18013a7643 100644
--- a/src/cyclictest/cyclictest.c
+++ b/src/cyclictest/cyclictest.c
@@ -23,6 +23,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <linux/unistd.h>
+#include <math.h>
 
 #include <sys/prctl.h>
 #include <sys/stat.h>
@@ -134,6 +135,7 @@ struct thread_stat {
 	long max;
 	long act;
 	double avg;
+	double var;
 	long *values;
 	long *smis;
 	long *hist_array;
@@ -358,6 +360,16 @@ try_again:
 	return err;
 }
 
+static double calc_stddev(struct thread_stat *stat)
+{
+	/* standard deviation of single samples is 0 */
+	if (stat->cycles <= 1)
+		return 0;
+
+	return sqrt(stat->var / (stat->cycles - 1));
+}
+
+
 #ifdef ARCH_HAS_SMI_COUNTER
 static int open_msr_file(int cpu)
 {
@@ -750,6 +762,17 @@ static void *timerthread(void *param)
 		prev_avg = stat->avg;
 		stat->avg = prev_avg + ((diff - prev_avg) / stat->cycles);
 
+		/*
+		 * Calculate a slight variation on variance - the
+		 * variance multiplied by (n - 1). This allows
+		 * updating the quantity as data becomes available
+		 * without keeping track of all past samples or averages.
+		 *
+		 * (n - 1) * var = var' + (x - avg) * (x - avg')
+		 *
+		 */
+		stat->var += (diff - stat->avg) * (diff - prev_avg);
+
 		next.tv_sec += interval.tv_sec;
 		next.tv_nsec += interval.tv_nsec;
 		if (par->mode == MODE_CYCLIC) {
@@ -1379,6 +1402,10 @@ static void print_hist(struct thread_param *par[], int nthreads)
 		fprintf(fd, " %05lu", par[j]->stats->cycles ?
 		       (long)(par[j]->stats->avg/par[j]->stats->cycles) : 0);
 	fprintf(fd, "\n");
+	fprintf(fd, "# StdDev Latencies:");
+	for (j = 0; j < nthreads; j++)
+		fprintf(fd, " %05lu", (long)calc_stddev(par[j]->stats));
+	fprintf(fd, "\n");
 	fprintf(fd, "# Max Latencies:");
 	maxmax = 0;
 	for (j = 0; j < nthreads; j++) {
@@ -1430,14 +1457,15 @@ static void print_stat(FILE *fp, struct thread_param *par, int index, int verbos
 			char *fmt;
 			if (use_nsecs)
 				fmt = "T:%2d (%5d) P:%2d I:%ld C:%7lu "
-				        "Min:%7ld Act:%8ld Avg:%8ld Max:%8ld";
+				        "Min:%7ld Act:%8ld Avg:%8ld StdDev:%8ld Max:%8ld";
 			else
 				fmt = "T:%2d (%5d) P:%2d I:%ld C:%7lu "
-				        "Min:%7ld Act:%5ld Avg:%5ld Max:%8ld";
+				        "Min:%7ld Act:%5ld Avg:%5ld StdDev:%5ld Max:%8ld";
 
 			fprintf(fp, fmt, index, stat->tid, par->prio,
 				par->interval, stat->cycles, stat->min,
-				stat->act, (long)stat->avg, stat->max);
+				stat->act, (long)stat->avg, (long)calc_stddev(stat),
+				stat->max);
 
 			if (smi)
 				fprintf(fp, " SMI:%8ld", stat->smi_count);
@@ -1485,14 +1513,15 @@ static void rstat_print_stat(struct thread_param *par, int index, int verbose, i
 			char *fmt;
 			if (use_nsecs)
 				fmt = "T:%2d (%5d) P:%2d I:%ld C:%7lu "
-				        "Min:%7ld Act:%8ld Avg:%8ld Max:%8ld";
+				        "Min:%7ld Act:%8ld Avg:%8ld StdDev:%8ld Max:%8ld";
 			else
 				fmt = "T:%2d (%5d) P:%2d I:%ld C:%7lu "
-				        "Min:%7ld Act:%5ld Avg:%5ld Max:%8ld";
+				        "Min:%7ld Act:%5ld Avg:%5ld StdDev:%5ld Max:%8ld";
 
 			dprintf(fd, fmt, index, stat->tid, par->prio,
 				par->interval, stat->cycles, stat->min,
-				stat->act, (long)stat->avg, stat->max);
+				stat->act, (long)stat->avg, (long)calc_stddev(stat),
+				stat->max);
 
 			if (smi)
 				dprintf(fd, " SMI:%8ld", stat->smi_count);
@@ -1781,6 +1810,7 @@ static void write_stats(FILE *f, void *data)
 		fprintf(f, "      \"min\": %ld,\n", s->min);
 		fprintf(f, "      \"max\": %ld,\n", s->max);
 		fprintf(f, "      \"avg\": %.2f,\n", s->avg);
+		fprintf(f, "      \"stddev\": %.2f,\n", calc_stddev(s));
 		fprintf(f, "      \"cpu\": %d,\n", par[i]->cpu);
 		fprintf(f, "      \"node\": %d\n", par[i]->node);
 		fprintf(f, "    }%s\n", i == num_threads - 1 ? "" : ",");
@@ -2091,6 +2121,7 @@ int main(int argc, char **argv)
 		stat->min = 1000000;
 		stat->max = 0;
 		stat->avg = 0.0;
+		stat->var = 0;
 		stat->threadstarted = 1;
 		stat->smi_count = 0;
 		status = pthread_create(&stat->thread, &attr, timerthread, par);
-- 
2.32.0


  parent reply	other threads:[~2021-10-14  7:13 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-14  7:12 [RFC 0/7] rt-tests: cyclictest: Add support to report standard deviation Punit Agrawal
2021-10-14  7:12 ` [RFC 1/7] rt-tests: cyclictest: Drop unused defines Punit Agrawal
2021-10-14 18:23   ` John Kacur
2021-11-11 20:28   ` John Kacur
2021-10-14  7:12 ` [RFC 2/7] rt-tests: cyclictest: Simplify duplicate initialization of "stop" Punit Agrawal
2021-10-14 18:29   ` John Kacur
2021-11-11 20:32   ` John Kacur
2021-10-14  7:12 ` [RFC 3/7] rt-tests: cyclictest: Drop unnecessary variable "stopped" Punit Agrawal
2021-10-14  7:12 ` [RFC 4/7] rt-tests: cyclictest: Drop unnecessary variable "bufsize" Punit Agrawal
2021-10-14 18:29   ` John Kacur
2021-10-15  8:05     ` Punit Agrawal
2021-10-15 13:07       ` John Kacur
2021-11-11 20:36   ` John Kacur
2021-10-14  7:12 ` [RFC 5/7] rt-tests: cyclictest: Move signal handler to avoid function declaration Punit Agrawal
2021-10-14 18:31   ` John Kacur
2021-10-15  8:21     ` Punit Agrawal
2021-10-14  7:12 ` [RFC 6/7] rt-tests: cyclictest: Use streaming algorithm to calculate averages Punit Agrawal
2021-10-14  7:12 ` Punit Agrawal [this message]
2021-10-14 11:50   ` [RFC 7/7] rt-tests: cyclictest: Add support to report standard deviation Daniel Wagner
2021-10-15  7:58     ` Punit Agrawal
2021-10-15  8:22       ` Daniel Wagner
2021-10-15 16:37 ` [RFC 0/7] " Joseph Salisbury
2021-10-18  0:28   ` Punit Agrawal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211014071247.4165329-8-punitagrawal@gmail.com \
    --to=punitagrawal@gmail.com \
    --cc=jkacur@redhat.com \
    --cc=linux-rt-users@vger.kernel.org \
    --cc=punit1.agrawal@toshiba.co.jp \
    --cc=williams@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox