[][kernel][mt7988][backport dhrystone from kernel 6.4]
[Description]
Add backport dhrystone from kernel 6.4 to backport-5.4.
[Release-log]
N/A
Change-Id: I0cf90c7bc11002da820e7c2aa6a261df2dfb0747
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7672020
diff --git a/target/linux/generic/backport-5.4/999-1900-lib-add-Dhrystone-benchmark-test.patch b/target/linux/generic/backport-5.4/999-1900-lib-add-Dhrystone-benchmark-test.patch
new file mode 100644
index 0000000..a299b20
--- /dev/null
+++ b/target/linux/generic/backport-5.4/999-1900-lib-add-Dhrystone-benchmark-test.patch
@@ -0,0 +1,1036 @@
+From d5528cc16893f1f64b07936b1e88aa023128debb Mon Sep 17 00:00:00 2001
+From: Geert Uytterhoeven <geert+renesas@glider.be>
+Date: Thu, 8 Dec 2022 15:31:28 +0100
+Subject: [PATCH] lib: add Dhrystone benchmark test
+
+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>
+Link: https://lkml.kernel.org/r/4d07ad990740a5f1e426ce4566fb514f60ec9bdd.1670509558.git.geert+renesas@glider.be
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Brendan Higgins <brendanhiggins@google.com>
+Cc: David Gow <davidgow@google.com>
+[geert+renesas@glider.be: fix uninitialized use of ret]
+ Link: https://lkml.kernel.org/r/alpine.DEB.2.22.394.2212190857310.137329@ramsan.of.borg
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+---
+ 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
+
+diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
+index 881c3f84e88a..918bda4ee120 100644
+--- a/lib/Kconfig.debug
++++ b/lib/Kconfig.debug
+@@ -2079,6 +2079,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 4d9461bfea42..06b9dcd80cda 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 000000000000..e1a4db8e252c
+--- /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 000000000000..83247106824c
+--- /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 000000000000..c19e661f37d3
+--- /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 000000000000..f9d33efa6d09
+--- /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 0;
++}
++
++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");
+--
+2.18.0
+