public inbox for linux-rt-users@vger.kernel.org
 help / color / mirror / Atom feed
From: Costa Shulyupin <costa.shul@redhat.com>
To: linux-rt-users <linux-rt-users@vger.kernel.org>,
	John Kacur <jkacur@redhat.com>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
	Tomas Glozar <tglozar@redhat.com>,
	Crystal Wood <crwood@redhat.com>,
	Costa Shulyupin <costa.shul@redhat.com>
Subject: [PATCH v1] cyclictest: Generate optstring dynamically from long_options
Date: Sat, 10 Jan 2026 13:37:38 +0200	[thread overview]
Message-ID: <20260110113738.2376456-1-costa.shul@redhat.com> (raw)

The hard-coded optstring in cyclictest has become bloated and
error-prone, even resulting in a duplicate 'D:' entry.

Modify the long_options array to use the 'val' member of struct option
to store the corresponding short-option character. Add getopt_auto() to
automatically construct the optstring from this array at runtime.

This eliminates the need to manually maintain a redundant optstring and
prevents synchronization errors when adding or modifying command-line
options.

Signed-off-by: Costa Shulyupin <costa.shul@redhat.com>
---
 Makefile                    |   3 +-
 src/cyclictest/cyclictest.c | 147 +++++++++++++++---------------------
 src/include/opt.h           |  11 +++
 src/lib/opt.c               |  29 +++++++
 4 files changed, 101 insertions(+), 89 deletions(-)
 create mode 100644 src/include/opt.h
 create mode 100644 src/lib/opt.c

diff --git a/Makefile b/Makefile
index e3d02cd25924..12bd42850bb1 100644
--- a/Makefile
+++ b/Makefile
@@ -194,7 +194,8 @@ oslat: $(OBJDIR)/oslat.o $(OBJDIR)/librttest.a $(OBJDIR)/librttestnuma.a
 	bzip2 -c $< > $@
 
 LIBOBJS =$(addprefix $(OBJDIR)/,rt-error.o rt-get_cpu.o rt-sched.o rt-utils.o \
-	histogram.o)
+	histogram.o opt.o)
+
 $(OBJDIR)/librttest.a: $(LIBOBJS)
 	$(AR) rcs $@ $^
 
diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c
index b4bce8915b43..a1566159d398 100644
--- a/src/cyclictest/cyclictest.c
+++ b/src/cyclictest/cyclictest.c
@@ -17,7 +17,6 @@
 #include <stdarg.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <getopt.h>
 #include <pthread.h>
 #include <signal.h>
 #include <sched.h>
@@ -39,6 +38,7 @@
 #include "rt-numa.h"
 #include "rt-error.h"
 #include "histogram.h"
+#include "opt.h"
 
 #include <bionic.h>
 
@@ -1078,17 +1078,10 @@ static char *policyname(int policy)
 
 
 enum option_values {
-	OPT_AFFINITY=1, OPT_BREAKTRACE, OPT_CLOCK,
-	OPT_DEFAULT_SYSTEM, OPT_DISTANCE, OPT_DURATION, OPT_LATENCY,
-	OPT_FIFO, OPT_HISTOGRAM, OPT_HISTOFALL, OPT_HISTFILE,
-	OPT_INTERVAL, OPT_JSON, OPT_MAINAFFINITY, OPT_LOOPS, OPT_MLOCKALL,
-	OPT_REFRESH, OPT_NANOSLEEP, OPT_NSECS, OPT_OSCOPE, OPT_PRIORITY,
-	OPT_QUIET, OPT_PRIOSPREAD, OPT_RELATIVE, OPT_RESOLUTION,
-	OPT_SYSTEM, OPT_SMP, OPT_THREADS, OPT_TRIGGER,
-	OPT_TRIGGER_NODES, OPT_UNBUFFERED, OPT_NUMA, OPT_VERBOSE,
-	OPT_DBGCYCLIC, OPT_POLICY, OPT_HELP, OPT_NUMOPTS,
-	OPT_ALIGNED, OPT_SECALIGNED, OPT_LAPTOP, OPT_SMI,
-	OPT_TRACEMARK, OPT_POSIX_TIMERS, OPT_DEEPEST_IDLE_STATE,
+	OPT_DEFAULT_SYSTEM, OPT_LATENCY, OPT_HISTFILE, OPT_JSON,
+	OPT_MAINAFFINITY, OPT_PRIOSPREAD, OPT_SECALIGNED, OPT_SMI,
+	OPT_TRIGGER, OPT_TRIGGER_NODES, OPT_TRACEMARK, OPT_DBGCYCLIC,
+	OPT_POLICY, OPT_HELP, OPT_LAPTOP, OPT_DEEPEST_IDLE_STATE,
 };
 
 /* Process commandline options */
@@ -1097,63 +1090,63 @@ static void process_options(int argc, char *argv[], int max_cpus)
 	int error = 0;
 	int option_affinity = 0;
 
+	/*
+	 * Options for getopt
+	 * Ordered alphabetically by single letter name
+	 */
+	static struct option long_options[] = {
+		{"affinity",         optional_argument, NULL, 'a'},
+		{"aligned",          optional_argument, NULL, 'A'},
+		{"breaktrace",       required_argument, NULL, 'b'},
+		{"clock",            required_argument, NULL, 'c'},
+		{"default-system",   no_argument,       NULL, OPT_DEFAULT_SYSTEM },
+		{"distance",         required_argument, NULL, 'd'},
+		{"duration",         required_argument, NULL, 'D'},
+		{"latency",          required_argument, NULL, OPT_LATENCY },
+		{"fifo",             required_argument, NULL, 'F'},
+		{"histogram",        required_argument, NULL, 'h'},
+		{"histofall",        required_argument, NULL, 'H'},
+		{"histfile",	     required_argument, NULL, OPT_HISTFILE },
+		{"interval",         required_argument, NULL, 'i'},
+		{"json",             required_argument, NULL, OPT_JSON },
+		{"laptop",	     no_argument,	NULL, OPT_LAPTOP },
+		{"loops",            required_argument, NULL, 'l'},
+		{"mainaffinity",     required_argument, NULL, OPT_MAINAFFINITY},
+		{"mlockall",         no_argument,       NULL, 'm'},
+		{"refresh_on_max",   no_argument,       NULL, 'M'},
+		{"nsecs",            no_argument,       NULL, 'N'},
+		{"oscope",           required_argument, NULL, 'o'},
+		{"priority",         required_argument, NULL, 'p'},
+		{"quiet",            no_argument,       NULL, 'q'},
+		{"priospread",       no_argument,       NULL, OPT_PRIOSPREAD },
+		{"relative",         no_argument,       NULL, 'r'},
+		{"resolution",       no_argument,       NULL, 'R'},
+		{"secaligned",       optional_argument, NULL, OPT_SECALIGNED },
+		{"system",           no_argument,       NULL, 's'},
+		{"smi",              no_argument,       NULL, OPT_SMI },
+		{"smp",              no_argument,       NULL, 'S'},
+		{"spike",	     required_argument, NULL, OPT_TRIGGER },
+		{"spike-nodes",	     required_argument, NULL, OPT_TRIGGER_NODES },
+		{"threads",          optional_argument, NULL, 't'},
+		{"tracemark",	     no_argument,	NULL, OPT_TRACEMARK },
+		{"unbuffered",       no_argument,       NULL, 'u'},
+		{"verbose",          no_argument,       NULL, 'v'},
+		{"dbg_cyclictest",   no_argument,       NULL, OPT_DBGCYCLIC },
+		{"policy",           required_argument, NULL, OPT_POLICY },
+		{"help",             no_argument,       NULL, OPT_HELP },
+		{"posix_timers",     no_argument,	NULL, 'x'},
+		{"deepest-idle-state", required_argument,	NULL, OPT_DEEPEST_IDLE_STATE },
+		{NULL, 0, NULL, 0 },
+	};
+	char *opts = build_optstring(long_options);
+
 	for (;;) {
-		int option_index = 0;
-		/*
-		 * Options for getopt
-		 * Ordered alphabetically by single letter name
-		 */
-		static struct option long_options[] = {
-			{"affinity",         optional_argument, NULL, OPT_AFFINITY},
-			{"aligned",          optional_argument, NULL, OPT_ALIGNED },
-			{"breaktrace",       required_argument, NULL, OPT_BREAKTRACE },
-			{"clock",            required_argument, NULL, OPT_CLOCK },
-			{"default-system",   no_argument,       NULL, OPT_DEFAULT_SYSTEM },
-			{"distance",         required_argument, NULL, OPT_DISTANCE },
-			{"duration",         required_argument, NULL, OPT_DURATION },
-			{"latency",          required_argument, NULL, OPT_LATENCY },
-			{"fifo",             required_argument, NULL, OPT_FIFO },
-			{"histogram",        required_argument, NULL, OPT_HISTOGRAM },
-			{"histofall",        required_argument, NULL, OPT_HISTOFALL },
-			{"histfile",	     required_argument, NULL, OPT_HISTFILE },
-			{"interval",         required_argument, NULL, OPT_INTERVAL },
-			{"json",             required_argument, NULL, OPT_JSON },
-			{"laptop",	     no_argument,	NULL, OPT_LAPTOP },
-			{"loops",            required_argument, NULL, OPT_LOOPS },
-			{"mainaffinity",     required_argument, NULL, OPT_MAINAFFINITY},
-			{"mlockall",         no_argument,       NULL, OPT_MLOCKALL },
-			{"refresh_on_max",   no_argument,       NULL, OPT_REFRESH },
-			{"nsecs",            no_argument,       NULL, OPT_NSECS },
-			{"oscope",           required_argument, NULL, OPT_OSCOPE },
-			{"priority",         required_argument, NULL, OPT_PRIORITY },
-			{"quiet",            no_argument,       NULL, OPT_QUIET },
-			{"priospread",       no_argument,       NULL, OPT_PRIOSPREAD },
-			{"relative",         no_argument,       NULL, OPT_RELATIVE },
-			{"resolution",       no_argument,       NULL, OPT_RESOLUTION },
-			{"secaligned",       optional_argument, NULL, OPT_SECALIGNED },
-			{"system",           no_argument,       NULL, OPT_SYSTEM },
-			{"smi",              no_argument,       NULL, OPT_SMI },
-			{"smp",              no_argument,       NULL, OPT_SMP },
-			{"spike",	     required_argument, NULL, OPT_TRIGGER },
-			{"spike-nodes",	     required_argument, NULL, OPT_TRIGGER_NODES },
-			{"threads",          optional_argument, NULL, OPT_THREADS },
-			{"tracemark",	     no_argument,	NULL, OPT_TRACEMARK },
-			{"unbuffered",       no_argument,       NULL, OPT_UNBUFFERED },
-			{"verbose",          no_argument,       NULL, OPT_VERBOSE },
-			{"dbg_cyclictest",   no_argument,       NULL, OPT_DBGCYCLIC },
-			{"policy",           required_argument, NULL, OPT_POLICY },
-			{"help",             no_argument,       NULL, OPT_HELP },
-			{"posix_timers",     no_argument,	NULL, OPT_POSIX_TIMERS },
-			{"deepest-idle-state", required_argument,	NULL, OPT_DEEPEST_IDLE_STATE },
-			{NULL, 0, NULL, 0 },
-		};
-		int c = getopt_long(argc, argv, "a::A::b:c:d:D:F:h:H:i:l:MNo:p:mqrRsSt::uvD:x",
-				    long_options, &option_index);
+		int c = getopt_long(argc, argv, opts, long_options, NULL);
+
 		if (c == -1)
 			break;
 		switch (c) {
 		case 'a':
-		case OPT_AFFINITY:
 			option_affinity = 1;
 			/* smp sets AFFINITY_USEALL in OPT_SMP */
 			if (smp)
@@ -1181,7 +1174,6 @@ static void process_options(int argc, char *argv[], int max_cpus)
 					numa_bitmask_weight(affinity_mask));
 			break;
 		case 'A':
-		case OPT_ALIGNED:
 			aligned = 1;
 			if (optarg != NULL)
 				offset = atoi(optarg) * 1000;
@@ -1191,29 +1183,22 @@ static void process_options(int argc, char *argv[], int max_cpus)
 				offset = 0;
 			break;
 		case 'b':
-		case OPT_BREAKTRACE:
 			tracelimit = atoi(optarg); break;
 		case 'c':
-		case OPT_CLOCK:
 			clocksel = atoi(optarg); break;
 		case OPT_DEFAULT_SYSTEM:
 			power_management = 1; break;
 		case 'd':
-		case OPT_DISTANCE:
 			distance = atoi(optarg); break;
 		case 'D':
-		case OPT_DURATION:
 			duration = parse_time_string(optarg); break;
 		case 'F':
-		case OPT_FIFO:
 			use_fifo = 1;
 			strncpy(fifopath, optarg, strnlen(optarg, MAX_PATH-1));
 			break;
 		case 'H':
-		case OPT_HISTOFALL:
 			histofall = 1; /* fall through */
 		case 'h':
-		case OPT_HISTOGRAM:
 			histogram = atoi(optarg);
 			if (!histogram)
 				display_help(1);
@@ -1223,13 +1208,11 @@ static void process_options(int argc, char *argv[], int max_cpus)
 			strncpy(histfile, optarg, strnlen(optarg, MAX_PATH-1));
 			break;
 		case 'i':
-		case OPT_INTERVAL:
 			interval = atoi(optarg); break;
 		case OPT_JSON:
 			strncpy(jsonfile, optarg, strnlen(optarg, MAX_PATH-1));
 			break;
 		case 'l':
-		case OPT_LOOPS:
 			max_cycles = atoi(optarg); break;
 		case OPT_MAINAFFINITY:
 			if (optarg) {
@@ -1242,31 +1225,23 @@ static void process_options(int argc, char *argv[], int max_cpus)
 			}
 			break;
 		case 'm':
-		case OPT_MLOCKALL:
 			lockall = 1; break;
 		case 'M':
-		case OPT_REFRESH:
 			refresh_on_max = 1; break;
 		case 'N':
-		case OPT_NSECS:
 			use_nsecs = 1; break;
 		case 'o':
-		case OPT_OSCOPE:
 			oscope_reduction = atoi(optarg); break;
 		case 'p':
-		case OPT_PRIORITY:
 			priority = atoi(optarg);
 			if (policy != SCHED_FIFO && policy != SCHED_RR)
 				policy = SCHED_FIFO;
 			break;
 		case 'q':
-		case OPT_QUIET:
 			quiet = 1; break;
 		case 'r':
-		case OPT_RELATIVE:
 			timermode = TIMER_RELTIME; break;
 		case 'R':
-		case OPT_RESOLUTION:
 			check_clock_resolution = 1; break;
 		case OPT_SECALIGNED:
 			secaligned = 1;
@@ -1278,10 +1253,8 @@ static void process_options(int argc, char *argv[], int max_cpus)
 				offset = 0;
 			break;
 		case 's':
-		case OPT_SYSTEM:
 			use_system = MODE_SYS_OFFSET; break;
 		case 'S':
-		case OPT_SMP: /* SMP testing */
 			if (numa)
 				fatal("numa and smp options are mutually exclusive\n");
 			smp = 1;
@@ -1289,7 +1262,6 @@ static void process_options(int argc, char *argv[], int max_cpus)
 			setaffinity = AFFINITY_USEALL;
 			break;
 		case 't':
-		case OPT_THREADS:
 			if (smp) {
 				warn("-t ignored due to smp mode\n");
 				break;
@@ -1309,12 +1281,10 @@ static void process_options(int argc, char *argv[], int max_cpus)
 				trigger_list_size = atoi(optarg);
 			break;
 		case 'u':
-		case OPT_UNBUFFERED:
 			setvbuf(stdout, NULL, _IONBF, 0); break;
 		case 'v':
-		case OPT_VERBOSE: verbose = 1; break;
+			verbose = 1; break;
 		case 'x':
-		case OPT_POSIX_TIMERS:
 			use_nanosleep = MODE_CYCLIC; break;
 		case '?':
 		case OPT_HELP:
@@ -1437,6 +1407,7 @@ static void process_options(int argc, char *argv[], int max_cpus)
 			rt_bitmask_free(affinity_mask);
 		display_help(1);
 	}
+	free(opts);
 }
 
 static int check_timer(void)
diff --git a/src/include/opt.h b/src/include/opt.h
new file mode 100644
index 000000000000..4d01917be024
--- /dev/null
+++ b/src/include/opt.h
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+#include <getopt.h>
+
+/*
+ * build_optstring - allocate and build optstring from long_options
+ *
+ * Free resulted optstring aftre use.
+ */
+char *build_optstring(const struct option *long_opts);
diff --git a/src/lib/opt.c b/src/lib/opt.c
new file mode 100644
index 000000000000..d235788001d9
--- /dev/null
+++ b/src/lib/opt.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <stdlib.h>
+
+#include "opt.h"
+
+char *build_optstring(const struct option *long_opts)
+{
+	char *opts = NULL;
+	int n = 0;
+
+	for (int i = 0; long_opts[i].name; i++) {
+		opts = realloc(opts, n + 4);
+
+		if (long_opts[i].flag || long_opts[i].val < 32 || long_opts[i].val > 127)
+			continue;
+
+		opts[n++] = long_opts[i].val;
+
+		if (long_opts[i].has_arg == required_argument)
+			opts[n++] = ':';
+		else if (long_opts[i].has_arg == optional_argument) {
+			opts[n++] = ':';
+			opts[n++] = ':';
+		}
+	}
+	opts[n] = '\0';
+
+	return opts;
+}
-- 
2.52.0


             reply	other threads:[~2026-01-10 11:37 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-10 11:37 Costa Shulyupin [this message]
2026-01-12 21:13 ` [PATCH v1] cyclictest: Generate optstring dynamically from long_options Crystal Wood
2026-01-13  8:13   ` Sebastian Andrzej Siewior
2026-01-13 10:00     ` Costa Shulyupin
2026-01-13 11:14       ` Sebastian Andrzej Siewior
2026-01-13 23:41         ` Crystal Wood
2026-01-13 23:34     ` Crystal Wood
2026-01-13 12:45   ` Costa Shulyupin

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=20260110113738.2376456-1-costa.shul@redhat.com \
    --to=costa.shul@redhat.com \
    --cc=bigeasy@linutronix.de \
    --cc=crwood@redhat.com \
    --cc=jkacur@redhat.com \
    --cc=linux-rt-users@vger.kernel.org \
    --cc=tglozar@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