diff mbox series

lib: Add Dhrystone benchmark test

Message ID 4d07ad990740a5f1e426ce4566fb514f60ec9bdd.1670509558.git.geert+renesas@glider.be
State Accepted
Commit d5528cc16893f1f64b07936b1e88aa023128debb
Headers show
Series lib: Add Dhrystone benchmark test | expand

Commit Message

Geert Uytterhoeven Dec. 8, 2022, 2:31 p.m. UTC
When working on SoC bring-up, (a full) userspace may not be available,
making it hard to benchmark the CPU performance of the system under
development.  Still, one may want to have a rough idea of the (relative)
performance of one or more CPU cores, especially when working on e.g.
the clock driver that controls the CPU core clock(s).

Hence make the classical Dhrystone 2.1 benchmark available as a Linux
kernel test module, based on[1].

When built-in, this benchmark can be run without any userspace present.

Parallel runs (run on multiple CPU cores) are supported, just kick the
"run" file multiple times.

Note that the actual figures depend on the configuration options that
control compiler optimization (e.g. CONFIG_CC_OPTIMIZE_FOR_SIZE vs.
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE), and on the compiler options used
when building the kernel in general.  Hence numbers may differ from
those obtained by running similar benchmarks in userspace.

[1] https://github.com/qris/dhrystone-deb.git

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
This has been used to validate secondary CPU bringup and cpufreq support
on the R-Car S4-8 and V4H SoCs.

Changes compared to the original Dhrystone 2.1 C version:
  - Remove trailing whitespace
  - Remove unused NOSTRUCTASSIGN
  - Remove unused NOENUM(S)
  - Remove unused REG
  - Use ktime for time measurements
  - Use kzalloc() for memory allocation
  - Remove definition and use of Null
  - Remove definitions of true and false
  - Use pr_info() for printing
  - Replace sscanf() use by parameter n
  - Replace userspace includes by kernel includes
  - Replace K&R by ANSI function declarations
  - Move/add external/forward declarations to dhry.h
  - Reshuffle functions to avoid forward declarations
  - Make local symbols static
  - Add kernel module wrapper
  - Let dhry() return the number of dhrystones
  - Add automatic iteration handling
  - Whitespace and indentation fixes
  - Fix braces and related indentation
  - Remove parentheses from return values
  - Reduce printed output
  - Use %px to print pointers
  - Verify results automatically
  - Make time measurement variables local
  - Add SPDX-License tags
  - Add Dhrystone benchmark test to config/build system

An unsquashed version can be found at
https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git/log/?h=topic/dhry-unsquashed
---
 lib/Kconfig.debug |  35 +++++
 lib/Makefile      |   2 +
 lib/dhry.h        | 358 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/dhry_1.c      | 283 ++++++++++++++++++++++++++++++++++++
 lib/dhry_2.c      | 175 ++++++++++++++++++++++
 lib/dhry_run.c    |  85 +++++++++++
 6 files changed, 938 insertions(+)
 create mode 100644 lib/dhry.h
 create mode 100644 lib/dhry_1.c
 create mode 100644 lib/dhry_2.c
 create mode 100644 lib/dhry_run.c

Comments

Andrew Morton Dec. 8, 2022, 10:57 p.m. UTC | #1
On Thu,  8 Dec 2022 15:31:28 +0100 Geert Uytterhoeven <geert+renesas@glider.be> wrote:

> Hence make the classical Dhrystone 2.1 benchmark available as a Linux
> kernel test module, based on[1].

I can take a look at this after the merge window.

I'm not able to figure out the licensing of this. 
https://netlib.org/benchmark/dhry-c appears to be silent on the topic?
Geert Uytterhoeven Dec. 9, 2022, 10:04 a.m. UTC | #2
Hi Andrew,

On Thu, Dec 8, 2022 at 11:57 PM Andrew Morton <akpm@linux-foundation.org> wrote:
> On Thu,  8 Dec 2022 15:31:28 +0100 Geert Uytterhoeven <geert+renesas@glider.be> wrote:
>
> > Hence make the classical Dhrystone 2.1 benchmark available as a Linux
> > kernel test module, based on[1].
>
> I can take a look at this after the merge window

Thanks!

> I'm not able to figure out the licensing of this.
> https://netlib.org/benchmark/dhry-c appears to be silent on the topic?

Searching the internet, people claim it's just public domain...

My topic/dhry-unsquashed branch has my rationale:

    FreeBSD uses BSD-2-Clause for this, which is probably the closest to the
    original intention of the authors.
    Augment with GPL-2.0-only, as this now calls into internal Linux APIs.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
diff mbox series

Patch

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index a1b56cde3f843fbc..9e834f8cd6d163db 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2036,6 +2036,41 @@  menuconfig RUNTIME_TESTING_MENU
 
 if RUNTIME_TESTING_MENU
 
+config TEST_DHRY
+	tristate "Dhrystone benchmark test"
+	help
+	  Enable this to include the Dhrystone 2.1 benchmark.  This test
+	  calculates the number of Dhrystones per second, and the number of
+	  DMIPS (Dhrystone MIPS) obtained when the Dhrystone score is divided
+	  by 1757 (the number of Dhrystones per second obtained on the VAX
+	  11/780, nominally a 1 MIPS machine).
+
+	  To run the benchmark, it needs to be enabled explicitly, either from
+	  the kernel command line (when built-in), or from userspace (when
+	  built-in or modular.
+
+	  Run once during kernel boot:
+
+	      test_dhry.run
+
+	  Set number of iterations from kernel command line:
+
+	      test_dhry.iterations=<n>
+
+	  Set number of iterations from userspace:
+
+	      echo <n> > /sys/module/test_dhry/parameters/iterations
+
+	  Trigger manual run from userspace:
+
+	      echo y > /sys/module/test_dhry/parameters/run
+
+	  If the number of iterations is <= 0, the test will devise a suitable
+	  number of iterations (test runs for at least 2s) automatically.
+	  This process takes ca. 4s.
+
+	  If unsure, say N.
+
 config LKDTM
 	tristate "Linux Kernel Dump Test Tool Module"
 	depends on DEBUG_FS
diff --git a/lib/Makefile b/lib/Makefile
index 59bd7c2f793a7e93..f78082e2f7591478 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -57,6 +57,8 @@  obj-$(CONFIG_TEST_HEXDUMP) += test_hexdump.o
 obj-y += kstrtox.o
 obj-$(CONFIG_FIND_BIT_BENCHMARK) += find_bit_benchmark.o
 obj-$(CONFIG_TEST_BPF) += test_bpf.o
+test_dhry-objs := dhry_1.o dhry_2.o dhry_run.o
+obj-$(CONFIG_TEST_DHRY) += test_dhry.o
 obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
 obj-$(CONFIG_TEST_BITOPS) += test_bitops.o
 CFLAGS_test_bitops.o += -Werror
diff --git a/lib/dhry.h b/lib/dhry.h
new file mode 100644
index 0000000000000000..e1a4db8e252c3342
--- /dev/null
+++ b/lib/dhry.h
@@ -0,0 +1,358 @@ 
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ ****************************************************************************
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *
+ *  Version:    C, Version 2.1
+ *
+ *  File:       dhry.h (part 1 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *                      Siemens AG, AUT E 51
+ *                      Postfach 3220
+ *                      8520 Erlangen
+ *                      Germany (West)
+ *                              Phone:  [+49]-9131-7-20330
+ *                                      (8-17 Central European Time)
+ *                              Usenet: ..!mcsun!unido!estevax!weicker
+ *
+ *              Original Version (in Ada) published in
+ *              "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
+ *              pp. 1013 - 1030, together with the statistics
+ *              on which the distribution of statements etc. is based.
+ *
+ *              In this C version, the following C library functions are used:
+ *              - strcpy, strcmp (inside the measurement loop)
+ *              - printf, scanf (outside the measurement loop)
+ *              In addition, Berkeley UNIX system calls "times ()" or "time ()"
+ *              are used for execution time measurement. For measurements
+ *              on other systems, these calls have to be changed.
+ *
+ *  Collection of Results:
+ *              Reinhold Weicker (address see above) and
+ *
+ *              Rick Richardson
+ *              PC Research. Inc.
+ *              94 Apple Orchard Drive
+ *              Tinton Falls, NJ 07724
+ *                      Phone:  (201) 389-8963 (9-17 EST)
+ *                      Usenet: ...!uunet!pcrat!rick
+ *
+ *      Please send results to Rick Richardson and/or Reinhold Weicker.
+ *      Complete information should be given on hardware and software used.
+ *      Hardware information includes: Machine type, CPU, type and size
+ *      of caches; for microprocessors: clock frequency, memory speed
+ *      (number of wait states).
+ *      Software information includes: Compiler (and runtime library)
+ *      manufacturer and version, compilation switches, OS version.
+ *      The Operating System version may give an indication about the
+ *      compiler; Dhrystone itself performs no OS calls in the measurement loop.
+ *
+ *      The complete output generated by the program should be mailed
+ *      such that at least some checks for correctness can be made.
+ *
+ ***************************************************************************
+ *
+ *  History:    This version C/2.1 has been made for two reasons:
+ *
+ *              1) There is an obvious need for a common C version of
+ *              Dhrystone, since C is at present the most popular system
+ *              programming language for the class of processors
+ *              (microcomputers, minicomputers) where Dhrystone is used most.
+ *              There should be, as far as possible, only one C version of
+ *              Dhrystone such that results can be compared without
+ *              restrictions. In the past, the C versions distributed
+ *              by Rick Richardson (Version 1.1) and by Reinhold Weicker
+ *              had small (though not significant) differences.
+ *
+ *              2) As far as it is possible without changes to the Dhrystone
+ *              statistics, optimizing compilers should be prevented from
+ *              removing significant statements.
+ *
+ *              This C version has been developed in cooperation with
+ *              Rick Richardson (Tinton Falls, NJ), it incorporates many
+ *              ideas from the "Version 1.1" distributed previously by
+ *              him over the UNIX network Usenet.
+ *              I also thank Chaim Benedelac (National Semiconductor),
+ *              David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
+ *              Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
+ *              for their help with comments on earlier versions of the
+ *              benchmark.
+ *
+ *  Changes:    In the initialization part, this version follows mostly
+ *              Rick Richardson's version distributed via Usenet, not the
+ *              version distributed earlier via floppy disk by Reinhold Weicker.
+ *              As a concession to older compilers, names have been made
+ *              unique within the first 8 characters.
+ *              Inside the measurement loop, this version follows the
+ *              version previously distributed by Reinhold Weicker.
+ *
+ *              At several places in the benchmark, code has been added,
+ *              but within the measurement loop only in branches that
+ *              are not executed. The intention is that optimizing compilers
+ *              should be prevented from moving code out of the measurement
+ *              loop, or from removing code altogether. Since the statements
+ *              that are executed within the measurement loop have NOT been
+ *              changed, the numbers defining the "Dhrystone distribution"
+ *              (distribution of statements, operand types and locality)
+ *              still hold. Except for sophisticated optimizing compilers,
+ *              execution times for this version should be the same as
+ *              for previous versions.
+ *
+ *              Since it has proven difficult to subtract the time for the
+ *              measurement loop overhead in a correct way, the loop check
+ *              has been made a part of the benchmark. This does have
+ *              an impact - though a very minor one - on the distribution
+ *              statistics which have been updated for this version.
+ *
+ *              All changes within the measurement loop are described
+ *              and discussed in the companion paper "Rationale for
+ *              Dhrystone version 2".
+ *
+ *              Because of the self-imposed limitation that the order and
+ *              distribution of the executed statements should not be
+ *              changed, there are still cases where optimizing compilers
+ *              may not generate code for some statements. To a certain
+ *              degree, this is unavoidable for small synthetic benchmarks.
+ *              Users of the benchmark are advised to check code listings
+ *              whether code is generated for all statements of Dhrystone.
+ *
+ *              Version 2.1 is identical to version 2.0 distributed via
+ *              the UNIX network Usenet in March 1988 except that it corrects
+ *              some minor deficiencies that were found by users of version 2.0.
+ *              The only change within the measurement loop is that a
+ *              non-executed "else" part was added to the "if" statement in
+ *              Func_3, and a non-executed "else" part removed from Proc_3.
+ *
+ ***************************************************************************
+ *
+ *  Compilation model and measurement (IMPORTANT):
+ *
+ *  This C version of Dhrystone consists of three files:
+ *  - dhry.h (this file, containing global definitions and comments)
+ *  - dhry_1.c (containing the code corresponding to Ada package Pack_1)
+ *  - dhry_2.c (containing the code corresponding to Ada package Pack_2)
+ *
+ *  The following "ground rules" apply for measurements:
+ *  - Separate compilation
+ *  - No procedure merging
+ *  - Otherwise, compiler optimizations are allowed but should be indicated
+ *  - Default results are those without register declarations
+ *  See the companion paper "Rationale for Dhrystone Version 2" for a more
+ *  detailed discussion of these ground rules.
+ *
+ *  For 16-Bit processors (e.g. 80186, 80286), times for all compilation
+ *  models ("small", "medium", "large" etc.) should be given if possible,
+ *  together with a definition of these models for the compiler system used.
+ *
+ **************************************************************************
+ *
+ *  Dhrystone (C version) statistics:
+ *
+ *  [Comment from the first distribution, updated for version 2.
+ *   Note that because of language differences, the numbers are slightly
+ *   different from the Ada version.]
+ *
+ *  The following program contains statements of a high level programming
+ *  language (here: C) in a distribution considered representative:
+ *
+ *    assignments                  52 (51.0 %)
+ *    control statements           33 (32.4 %)
+ *    procedure, function calls    17 (16.7 %)
+ *
+ *  103 statements are dynamically executed. The program is balanced with
+ *  respect to the three aspects:
+ *
+ *    - statement type
+ *    - operand type
+ *    - operand locality
+ *         operand global, local, parameter, or constant.
+ *
+ *  The combination of these three aspects is balanced only approximately.
+ *
+ *  1. Statement Type:
+ *  -----------------             number
+ *
+ *     V1 = V2                     9
+ *       (incl. V1 = F(..)
+ *     V = Constant               12
+ *     Assignment,                 7
+ *       with array element
+ *     Assignment,                 6
+ *       with record component
+ *                                --
+ *                                34       34
+ *
+ *     X = Y +|-|"&&"|"|" Z        5
+ *     X = Y +|-|"==" Constant     6
+ *     X = X +|- 1                 3
+ *     X = Y *|/ Z                 2
+ *     X = Expression,             1
+ *           two operators
+ *     X = Expression,             1
+ *           three operators
+ *                                --
+ *                                18       18
+ *
+ *     if ....                    14
+ *       with "else"      7
+ *       without "else"   7
+ *           executed        3
+ *           not executed    4
+ *     for ...                     7  |  counted every time
+ *     while ...                   4  |  the loop condition
+ *     do ... while                1  |  is evaluated
+ *     switch ...                  1
+ *     break                       1
+ *     declaration with            1
+ *       initialization
+ *                                --
+ *                                34       34
+ *
+ *     P (...)  procedure call    11
+ *       user procedure      10
+ *       library procedure    1
+ *     X = F (...)
+ *             function  call      6
+ *       user function        5
+ *       library function     1
+ *                                --
+ *                                17       17
+ *                                        ---
+ *                                        103
+ *
+ *    The average number of parameters in procedure or function calls
+ *    is 1.82 (not counting the function values as implicit parameters).
+ *
+ *
+ *  2. Operators
+ *  ------------
+ *                          number    approximate
+ *                                    percentage
+ *
+ *    Arithmetic             32          50.8
+ *
+ *       +                     21          33.3
+ *       -                      7          11.1
+ *       *                      3           4.8
+ *       / (int div)            1           1.6
+ *
+ *    Comparison             27           42.8
+ *
+ *       ==                     9           14.3
+ *       /=                     4            6.3
+ *       >                      1            1.6
+ *       <                      3            4.8
+ *       >=                     1            1.6
+ *       <=                     9           14.3
+ *
+ *    Logic                   4            6.3
+ *
+ *       && (AND-THEN)          1            1.6
+ *       |  (OR)                1            1.6
+ *       !  (NOT)               2            3.2
+ *
+ *                           --          -----
+ *                           63          100.1
+ *
+ *
+ *  3. Operand Type (counted once per operand reference):
+ *  ---------------
+ *                          number    approximate
+ *                                    percentage
+ *
+ *     Integer               175        72.3 %
+ *     Character              45        18.6 %
+ *     Pointer                12         5.0 %
+ *     String30                6         2.5 %
+ *     Array                   2         0.8 %
+ *     Record                  2         0.8 %
+ *                           ---       -------
+ *                           242       100.0 %
+ *
+ *  When there is an access path leading to the final operand (e.g. a record
+ *  component), only the final data type on the access path is counted.
+ *
+ *
+ *  4. Operand Locality:
+ *  -------------------
+ *                                number    approximate
+ *                                          percentage
+ *
+ *     local variable              114        47.1 %
+ *     global variable              22         9.1 %
+ *     parameter                    45        18.6 %
+ *        value                        23         9.5 %
+ *        reference                    22         9.1 %
+ *     function result               6         2.5 %
+ *     constant                     55        22.7 %
+ *                                 ---       -------
+ *                                 242       100.0 %
+ *
+ *
+ *  The program does not compute anything meaningful, but it is syntactically
+ *  and semantically correct. All variables have a value assigned to them
+ *  before they are used as a source operand.
+ *
+ *  There has been no explicit effort to account for the effects of a
+ *  cache, or to balance the use of long or short displacements for code or
+ *  data.
+ *
+ ***************************************************************************
+ */
+
+typedef enum {
+	Ident_1,
+	Ident_2,
+	Ident_3,
+	Ident_4,
+	Ident_5
+} Enumeration;	/* for boolean and enumeration types in Ada, Pascal */
+
+/* General definitions: */
+
+typedef int One_Thirty;
+typedef int One_Fifty;
+typedef char Capital_Letter;
+typedef int Boolean;
+typedef char Str_30[31];
+typedef int Arr_1_Dim[50];
+typedef int Arr_2_Dim[50][50];
+
+typedef struct record {
+	struct record *Ptr_Comp;
+	Enumeration    Discr;
+	union {
+		struct {
+			Enumeration Enum_Comp;
+			int Int_Comp;
+			char Str_Comp[31];
+		} var_1;
+		struct {
+			Enumeration E_Comp_2;
+			char Str_2_Comp[31];
+		} var_2;
+		struct {
+			char Ch_1_Comp;
+			char Ch_2_Comp;
+		} var_3;
+	} variant;
+} Rec_Type, *Rec_Pointer;
+
+
+extern int Int_Glob;
+extern char Ch_1_Glob;
+
+void Proc_6(Enumeration  Enum_Val_Par, Enumeration *Enum_Ref_Par);
+void Proc_7(One_Fifty Int_1_Par_Val, One_Fifty Int_2_Par_Val,
+	    One_Fifty *Int_Par_Ref);
+void Proc_8(Arr_1_Dim Arr_1_Par_Ref, Arr_2_Dim Arr_2_Par_Ref,
+	    int Int_1_Par_Val, int Int_2_Par_Val);
+Enumeration Func_1(Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val);
+Boolean Func_2(Str_30 Str_1_Par_Ref, Str_30 Str_2_Par_Ref);
+
+int dhry(int n);
diff --git a/lib/dhry_1.c b/lib/dhry_1.c
new file mode 100644
index 0000000000000000..83247106824cc7f4
--- /dev/null
+++ b/lib/dhry_1.c
@@ -0,0 +1,283 @@ 
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ ****************************************************************************
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *
+ *  Version:    C, Version 2.1
+ *
+ *  File:       dhry_1.c (part 2 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *
+ ****************************************************************************
+ */
+
+#include "dhry.h"
+
+#include <linux/ktime.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+/* Global Variables: */
+
+int Int_Glob;
+char Ch_1_Glob;
+
+static Rec_Pointer Ptr_Glob, Next_Ptr_Glob;
+static Boolean Bool_Glob;
+static char Ch_2_Glob;
+static int Arr_1_Glob[50];
+static int Arr_2_Glob[50][50];
+
+static void Proc_3(Rec_Pointer *Ptr_Ref_Par)
+/******************/
+/* executed once */
+/* Ptr_Ref_Par becomes Ptr_Glob */
+{
+	if (Ptr_Glob) {
+		/* then, executed */
+		*Ptr_Ref_Par = Ptr_Glob->Ptr_Comp;
+	}
+	Proc_7(10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp);
+} /* Proc_3 */
+
+
+static void Proc_1(Rec_Pointer Ptr_Val_Par)
+/******************/
+/* executed once */
+{
+	Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp;
+						/* == Ptr_Glob_Next */
+	/* Local variable, initialized with Ptr_Val_Par->Ptr_Comp,    */
+	/* corresponds to "rename" in Ada, "with" in Pascal           */
+
+	*Ptr_Val_Par->Ptr_Comp = *Ptr_Glob;
+	Ptr_Val_Par->variant.var_1.Int_Comp = 5;
+	Next_Record->variant.var_1.Int_Comp =
+		Ptr_Val_Par->variant.var_1.Int_Comp;
+	Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp;
+	Proc_3(&Next_Record->Ptr_Comp);
+	/* Ptr_Val_Par->Ptr_Comp->Ptr_Comp == Ptr_Glob->Ptr_Comp */
+	if (Next_Record->Discr == Ident_1) {
+		/* then, executed */
+		Next_Record->variant.var_1.Int_Comp = 6;
+		Proc_6(Ptr_Val_Par->variant.var_1.Enum_Comp,
+		       &Next_Record->variant.var_1.Enum_Comp);
+		Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp;
+		Proc_7(Next_Record->variant.var_1.Int_Comp, 10,
+		       &Next_Record->variant.var_1.Int_Comp);
+	} else {
+		/* not executed */
+		*Ptr_Val_Par = *Ptr_Val_Par->Ptr_Comp;
+	}
+} /* Proc_1 */
+
+
+static void Proc_2(One_Fifty *Int_Par_Ref)
+/******************/
+/* executed once */
+/* *Int_Par_Ref == 1, becomes 4 */
+{
+	One_Fifty  Int_Loc;
+	Enumeration   Enum_Loc;
+
+	Int_Loc = *Int_Par_Ref + 10;
+	do {
+		/* executed once */
+		if (Ch_1_Glob == 'A') {
+			/* then, executed */
+			Int_Loc -= 1;
+			*Int_Par_Ref = Int_Loc - Int_Glob;
+			Enum_Loc = Ident_1;
+		} /* if */
+	} while (Enum_Loc != Ident_1); /* true */
+} /* Proc_2 */
+
+
+static void Proc_4(void)
+/*******/
+/* executed once */
+{
+	Boolean Bool_Loc;
+
+	Bool_Loc = Ch_1_Glob == 'A';
+	Bool_Glob = Bool_Loc | Bool_Glob;
+	Ch_2_Glob = 'B';
+} /* Proc_4 */
+
+
+static void Proc_5(void)
+/*******/
+/* executed once */
+{
+	Ch_1_Glob = 'A';
+	Bool_Glob = false;
+} /* Proc_5 */
+
+
+int dhry(int n)
+/*****/
+
+  /* main program, corresponds to procedures        */
+  /* Main and Proc_0 in the Ada version             */
+{
+	One_Fifty Int_1_Loc;
+	One_Fifty Int_2_Loc;
+	One_Fifty Int_3_Loc;
+	char Ch_Index;
+	Enumeration Enum_Loc;
+	Str_30 Str_1_Loc;
+	Str_30 Str_2_Loc;
+	int Run_Index;
+	int Number_Of_Runs;
+	ktime_t Begin_Time, End_Time;
+	u32 User_Time;
+
+	/* Initializations */
+
+	Next_Ptr_Glob = (Rec_Pointer)kzalloc(sizeof(Rec_Type), GFP_KERNEL);
+	Ptr_Glob = (Rec_Pointer)kzalloc(sizeof(Rec_Type), GFP_KERNEL);
+
+	Ptr_Glob->Ptr_Comp = Next_Ptr_Glob;
+	Ptr_Glob->Discr = Ident_1;
+	Ptr_Glob->variant.var_1.Enum_Comp = Ident_3;
+	Ptr_Glob->variant.var_1.Int_Comp = 40;
+	strcpy(Ptr_Glob->variant.var_1.Str_Comp,
+	       "DHRYSTONE PROGRAM, SOME STRING");
+	strcpy(Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
+
+	Arr_2_Glob[8][7] = 10;
+	/* Was missing in published program. Without this statement,    */
+	/* Arr_2_Glob[8][7] would have an undefined value.             */
+	/* Warning: With 16-Bit processors and Number_Of_Runs > 32000,  */
+	/* overflow may occur for this array element.                   */
+
+	pr_debug("Dhrystone Benchmark, Version 2.1 (Language: C)\n");
+
+	Number_Of_Runs = n;
+
+	pr_debug("Execution starts, %d runs through Dhrystone\n",
+		 Number_Of_Runs);
+
+	/***************/
+	/* Start timer */
+	/***************/
+
+	Begin_Time = ktime_get();
+
+	for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index) {
+		Proc_5();
+		Proc_4();
+		/* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
+		Int_1_Loc = 2;
+		Int_2_Loc = 3;
+		strcpy(Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
+		Enum_Loc = Ident_2;
+		Bool_Glob = !Func_2(Str_1_Loc, Str_2_Loc);
+		/* Bool_Glob == 1 */
+		while (Int_1_Loc < Int_2_Loc) {
+			/* loop body executed once */
+			Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
+			/* Int_3_Loc == 7 */
+			Proc_7(Int_1_Loc, Int_2_Loc, &Int_3_Loc);
+			/* Int_3_Loc == 7 */
+			Int_1_Loc += 1;
+		} /* while */
+		/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+		Proc_8(Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
+		/* Int_Glob == 5 */
+		Proc_1(Ptr_Glob);
+		for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index) {
+			/* loop body executed twice */
+			if (Enum_Loc == Func_1(Ch_Index, 'C')) {
+				/* then, not executed */
+				Proc_6(Ident_1, &Enum_Loc);
+				strcpy(Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING");
+				Int_2_Loc = Run_Index;
+				Int_Glob = Run_Index;
+			}
+		}
+		/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+		Int_2_Loc = Int_2_Loc * Int_1_Loc;
+		Int_1_Loc = Int_2_Loc / Int_3_Loc;
+		Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
+		/* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
+		Proc_2(&Int_1_Loc);
+		/* Int_1_Loc == 5 */
+
+	} /* loop "for Run_Index" */
+
+	/**************/
+	/* Stop timer */
+	/**************/
+
+	End_Time = ktime_get();
+
+#define dhry_assert_int_eq(val, expected)				\
+	if (val != expected)						\
+		pr_err("%s: %d (FAIL, expected %d)\n", #val, val,	\
+		       expected);					\
+	else								\
+		pr_debug("%s: %d (OK)\n", #val, val)
+
+#define dhry_assert_char_eq(val, expected)				\
+	if (val != expected)						\
+		pr_err("%s: %c (FAIL, expected %c)\n", #val, val,	\
+		       expected);					\
+	else								\
+		pr_debug("%s: %c (OK)\n", #val, val)
+
+#define dhry_assert_string_eq(val, expected)				\
+	if (strcmp(val, expected))					\
+		pr_err("%s: %s (FAIL, expected %s)\n", #val, val,	\
+		       expected);					\
+	else								\
+		pr_debug("%s: %s (OK)\n", #val, val)
+
+	pr_debug("Execution ends\n");
+	pr_debug("Final values of the variables used in the benchmark:\n");
+	dhry_assert_int_eq(Int_Glob, 5);
+	dhry_assert_int_eq(Bool_Glob, 1);
+	dhry_assert_char_eq(Ch_1_Glob, 'A');
+	dhry_assert_char_eq(Ch_2_Glob, 'B');
+	dhry_assert_int_eq(Arr_1_Glob[8], 7);
+	dhry_assert_int_eq(Arr_2_Glob[8][7], Number_Of_Runs + 10);
+	pr_debug("Ptr_Comp: %px\n", Ptr_Glob->Ptr_Comp);
+	dhry_assert_int_eq(Ptr_Glob->Discr, 0);
+	dhry_assert_int_eq(Ptr_Glob->variant.var_1.Enum_Comp, 2);
+	dhry_assert_int_eq(Ptr_Glob->variant.var_1.Int_Comp, 17);
+	dhry_assert_string_eq(Ptr_Glob->variant.var_1.Str_Comp,
+			      "DHRYSTONE PROGRAM, SOME STRING");
+	if (Next_Ptr_Glob->Ptr_Comp != Ptr_Glob->Ptr_Comp)
+		pr_err("Next_Ptr_Glob->Ptr_Comp: %px (expected %px)\n",
+		       Next_Ptr_Glob->Ptr_Comp, Ptr_Glob->Ptr_Comp);
+	else
+		pr_debug("Next_Ptr_Glob->Ptr_Comp: %px\n",
+			 Next_Ptr_Glob->Ptr_Comp);
+	dhry_assert_int_eq(Next_Ptr_Glob->Discr, 0);
+	dhry_assert_int_eq(Next_Ptr_Glob->variant.var_1.Enum_Comp, 1);
+	dhry_assert_int_eq(Next_Ptr_Glob->variant.var_1.Int_Comp, 18);
+	dhry_assert_string_eq(Next_Ptr_Glob->variant.var_1.Str_Comp,
+			      "DHRYSTONE PROGRAM, SOME STRING");
+	dhry_assert_int_eq(Int_1_Loc, 5);
+	dhry_assert_int_eq(Int_2_Loc, 13);
+	dhry_assert_int_eq(Int_3_Loc, 7);
+	dhry_assert_int_eq(Enum_Loc, 1);
+	dhry_assert_string_eq(Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
+	dhry_assert_string_eq(Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
+
+	User_Time = ktime_to_ms(ktime_sub(End_Time, Begin_Time));
+
+	kfree(Ptr_Glob);
+	kfree(Next_Ptr_Glob);
+
+	/* Measurements should last at least 2 seconds */
+	if (User_Time < 2 * MSEC_PER_SEC)
+		return -EAGAIN;
+
+	return div_u64(mul_u32_u32(MSEC_PER_SEC, Number_Of_Runs), User_Time);
+}
diff --git a/lib/dhry_2.c b/lib/dhry_2.c
new file mode 100644
index 0000000000000000..c19e661f37d30a66
--- /dev/null
+++ b/lib/dhry_2.c
@@ -0,0 +1,175 @@ 
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ ****************************************************************************
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *
+ *  Version:    C, Version 2.1
+ *
+ *  File:       dhry_2.c (part 3 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *
+ ****************************************************************************
+ */
+
+#include "dhry.h"
+
+#include <linux/string.h>
+
+
+static Boolean Func_3(Enumeration Enum_Par_Val)
+/***************************/
+/* executed once        */
+/* Enum_Par_Val == Ident_3 */
+{
+	Enumeration Enum_Loc;
+
+	Enum_Loc = Enum_Par_Val;
+	if (Enum_Loc == Ident_3) {
+		/* then, executed */
+		return true;
+	} else {
+		/* not executed */
+		return false;
+	}
+} /* Func_3 */
+
+
+void Proc_6(Enumeration  Enum_Val_Par, Enumeration *Enum_Ref_Par)
+/*********************************/
+/* executed once */
+/* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */
+{
+	*Enum_Ref_Par = Enum_Val_Par;
+	if (!Func_3(Enum_Val_Par)) {
+		/* then, not executed */
+		*Enum_Ref_Par = Ident_4;
+	}
+	switch (Enum_Val_Par) {
+	case Ident_1:
+		*Enum_Ref_Par = Ident_1;
+		break;
+	case Ident_2:
+		if (Int_Glob > 100) {
+			/* then */
+			*Enum_Ref_Par = Ident_1;
+		} else {
+			*Enum_Ref_Par = Ident_4;
+		}
+		break;
+	case Ident_3: /* executed */
+		*Enum_Ref_Par = Ident_2;
+		break;
+	case Ident_4:
+		break;
+	case Ident_5:
+		*Enum_Ref_Par = Ident_3;
+		break;
+	} /* switch */
+} /* Proc_6 */
+
+
+void Proc_7(One_Fifty Int_1_Par_Val, One_Fifty Int_2_Par_Val, One_Fifty *Int_Par_Ref)
+/**********************************************/
+/* executed three times                                      */
+/* first call:      Int_1_Par_Val == 2, Int_2_Par_Val == 3,  */
+/*                  Int_Par_Ref becomes 7                    */
+/* second call:     Int_1_Par_Val == 10, Int_2_Par_Val == 5, */
+/*                  Int_Par_Ref becomes 17                   */
+/* third call:      Int_1_Par_Val == 6, Int_2_Par_Val == 10, */
+/*                  Int_Par_Ref becomes 18                   */
+{
+	One_Fifty Int_Loc;
+
+	Int_Loc = Int_1_Par_Val + 2;
+	*Int_Par_Ref = Int_2_Par_Val + Int_Loc;
+} /* Proc_7 */
+
+
+void Proc_8(Arr_1_Dim Arr_1_Par_Ref, Arr_2_Dim Arr_2_Par_Ref, int Int_1_Par_Val, int Int_2_Par_Val)
+/*********************************************************************/
+/* executed once      */
+/* Int_Par_Val_1 == 3 */
+/* Int_Par_Val_2 == 7 */
+{
+	One_Fifty Int_Index;
+	One_Fifty Int_Loc;
+
+	Int_Loc = Int_1_Par_Val + 5;
+	Arr_1_Par_Ref[Int_Loc] = Int_2_Par_Val;
+	Arr_1_Par_Ref[Int_Loc+1] = Arr_1_Par_Ref[Int_Loc];
+	Arr_1_Par_Ref[Int_Loc+30] = Int_Loc;
+	for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index)
+		Arr_2_Par_Ref[Int_Loc][Int_Index] = Int_Loc;
+	Arr_2_Par_Ref[Int_Loc][Int_Loc-1] += 1;
+	Arr_2_Par_Ref[Int_Loc+20][Int_Loc] = Arr_1_Par_Ref[Int_Loc];
+	Int_Glob = 5;
+} /* Proc_8 */
+
+
+Enumeration Func_1(Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val)
+/*************************************************/
+/* executed three times                                         */
+/* first call:      Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R'    */
+/* second call:     Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C'    */
+/* third call:      Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C'    */
+{
+	Capital_Letter Ch_1_Loc;
+	Capital_Letter Ch_2_Loc;
+
+	Ch_1_Loc = Ch_1_Par_Val;
+	Ch_2_Loc = Ch_1_Loc;
+	if (Ch_2_Loc != Ch_2_Par_Val) {
+		/* then, executed */
+		return Ident_1;
+	} else {
+		/* not executed */
+		Ch_1_Glob = Ch_1_Loc;
+		return Ident_2;
+	}
+} /* Func_1 */
+
+
+Boolean Func_2(Str_30 Str_1_Par_Ref, Str_30 Str_2_Par_Ref)
+/*************************************************/
+/* executed once */
+/* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */
+/* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */
+{
+	One_Thirty Int_Loc;
+	Capital_Letter Ch_Loc;
+
+	Int_Loc = 2;
+	while (Int_Loc <= 2) {
+		/* loop body executed once */
+		if (Func_1(Str_1_Par_Ref[Int_Loc],
+			   Str_2_Par_Ref[Int_Loc+1]) == Ident_1) {
+			/* then, executed */
+			Ch_Loc = 'A';
+			Int_Loc += 1;
+		}
+	} /* if, while */
+	if (Ch_Loc >= 'W' && Ch_Loc < 'Z') {
+		/* then, not executed */
+		Int_Loc = 7;
+	}
+	if (Ch_Loc == 'R') {
+		/* then, not executed */
+		return true;
+	} else {
+		/* executed */
+		if (strcmp(Str_1_Par_Ref, Str_2_Par_Ref) > 0) {
+			/* then, not executed */
+			Int_Loc += 7;
+			Int_Glob = Int_Loc;
+			return true;
+		} else {
+			/* executed */
+			return false;
+		}
+	} /* if Ch_Loc */
+} /* Func_2 */
diff --git a/lib/dhry_run.c b/lib/dhry_run.c
new file mode 100644
index 0000000000000000..31a1d442e4a0fc19
--- /dev/null
+++ b/lib/dhry_run.c
@@ -0,0 +1,85 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Dhrystone benchmark test module
+ *
+ * Copyright (C) 2022 Glider bv
+ */
+
+#include "dhry.h"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/smp.h>
+
+#define DHRY_VAX	1757
+
+static int dhry_run_set(const char *val, const struct kernel_param *kp);
+static const struct kernel_param_ops run_ops = {
+	.flags = KERNEL_PARAM_OPS_FL_NOARG,
+	.set = dhry_run_set,
+};
+static bool dhry_run;
+module_param_cb(run, &run_ops, &dhry_run, 0200);
+MODULE_PARM_DESC(run, "Run the test (default: false)");
+
+static int iterations = -1;
+module_param(iterations, int, 0644);
+MODULE_PARM_DESC(iterations,
+		"Number of iterations through the benchmark (default: auto)");
+
+static void dhry_benchmark(void)
+{
+	int i, n;
+
+	if (iterations > 0) {
+		n = dhry(iterations);
+		goto report;
+	}
+
+	for (i = DHRY_VAX; i > 0; i <<= 1) {
+		n = dhry(i);
+		if (n != -EAGAIN)
+			break;
+	}
+
+report:
+	if (n >= 0)
+		pr_info("CPU%u: Dhrystones per Second: %d (%d DMIPS)\n",
+			smp_processor_id(), n, n / DHRY_VAX);
+	else if (n == -EAGAIN)
+		pr_err("Please increase the number of iterations\n");
+	else
+		pr_err("Dhrystone benchmark failed error %pe\n", ERR_PTR(n));
+}
+
+static int dhry_run_set(const char *val, const struct kernel_param *kp)
+{
+	int ret;
+
+	if (val) {
+		ret = param_set_bool(val, kp);
+		if (ret)
+			return ret;
+	} else {
+		dhry_run = true;
+	}
+
+	if (dhry_run && system_state == SYSTEM_RUNNING)
+		dhry_benchmark();
+
+	return ret;
+}
+
+static int __init dhry_init(void)
+{
+	if (dhry_run)
+		dhry_benchmark();
+
+	return 0;
+}
+module_init(dhry_init);
+
+MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
+MODULE_LICENSE("GPL");