Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | /* pi.c - pi computation portion of FPU sharing test */
/*
* Copyright (c) 2011-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
DESCRIPTION
This module is used for the microkernel version of the FPU sharing test,
and supplements the basic load/store test by incorporating two additional
threads that utilize the floating point unit.
Testing utilizes a pair of tasks that independently compute pi. The lower
priority task is regularly preempted by the higher priority task, thereby
testing whether floating point context information is properly preserved.
The following formula is used to compute pi:
pi = 4 * (1 - 1/3 + 1/5 - 1/7 + 1/9 - ... )
This series converges to pi very slowly. For example, performing 50,000
iterations results in an accuracy of 3 decimal places.
A reference value of pi is computed once at the start of the test. All
subsequent computations must produce the same value, otherwise an error
has occurred.
*/
#include <zephyr.h>
#include <stdio.h>
#include <tc_util.h>
#include <float_context.h>
/*
* PI_NUM_ITERATIONS: This macro is defined in the project's Makefile and
* is configurable from the command line.
*/
static double reference_pi = 0.0f;
/*
* Test counters are "volatile" because GCC wasn't properly updating
* calc_pi_low_count properly when calculate_pi_low() contained a "return"
* in its error handling logic -- the value was incremented in a register,
* but never written back to memory. (Seems to be a compiler bug!)
*/
static volatile unsigned int calc_pi_low_count = 0;
static volatile unsigned int calc_pi_high_count = 0;
/**
*
* @brief Entry point for the low priority pi compute task
*
* @return N/A
*/
void calculate_pi_low(void)
{
volatile double pi; /* volatile to avoid optimizing out of loop */
double divisor = 3.0;
double sign = -1.0;
unsigned int ix;
/* loop forever, unless an error is detected */
while (1) {
sign = -1.0;
pi = 1.0;
divisor = 3.0;
for (ix = 0; ix < PI_NUM_ITERATIONS; ix++) {
pi += sign / divisor;
divisor += 2.0;
sign *= -1.0;
}
pi *= 4;
if (reference_pi == 0.0f) {
reference_pi = pi;
} else if (reference_pi != pi) {
TC_ERROR("Computed pi %1.6f, reference pi %1.6f\n",
pi, reference_pi);
fpu_sharing_error = 1;
return;
}
++calc_pi_low_count;
}
}
/**
*
* @brief Entry point for the high priority pi compute task
*
* @return N/A
*/
void calculate_pi_high(void)
{
volatile double pi; /* volatile to avoid optimizing out of loop */
double divisor = 3.0;
double sign = -1.0;
unsigned int ix;
/* loop forever, unless an error is detected */
while (1) {
sign = -1.0;
pi = 1.0;
divisor = 3.0;
for (ix = 0; ix < PI_NUM_ITERATIONS; ix++) {
pi += sign / divisor;
divisor += 2.0;
sign *= -1.0;
}
/*
* Relinquish the processor for the remainder of the current
* system clock tick, so that lower priority threads get a
* chance to run.
*
* This exercises the ability of the nanokernel to restore the
* FPU state of a low priority thread _and_ the ability of the
* nanokernel to provide a "clean" FPU state to this thread
* once the sleep ends.
*/
task_sleep(1);
pi *= 4;
if (reference_pi == 0.0f) {
reference_pi = pi;
} else if (reference_pi != pi) {
TC_ERROR("Computed pi %1.6f, reference pi %1.6f\n",
pi, reference_pi);
fpu_sharing_error = 1;
return;
}
/* periodically issue progress report */
if ((++calc_pi_high_count % 100) == 50) {
printf("Pi calculation OK after %u (high) + %u (low) tests (computed %1.6f)\n",
calc_pi_high_count, calc_pi_low_count, pi);
}
}
}
|