OPT_x = (1 << 3),
/* Insert new options above this line. */
/* Non-compat options: */
- OPT_p = (1 << 4),
- OPT_l = (1 << 5) * ENABLE_FEATURE_NTPD_SERVER,
+ OPT_w = (1 << 4),
+ OPT_p = (1 << 5),
+ OPT_l = (1 << 6) * ENABLE_FEATURE_NTPD_SERVER,
};
struct globals {
return a;
return b;
}
-#define SQRT(x) (sqrt(x))
+static NOINLINE double my_SQRT(double X)
+{
+ union {
+ float f;
+ int32_t i;
+ } v;
+ double invsqrt;
+ double Xhalf = X * 0.5;
+
+ /* Fast and good approximation to 1/sqrt(X), black magic */
+ v.f = X;
+ /*v.i = 0x5f3759df - (v.i >> 1);*/
+ v.i = 0x5f375a86 - (v.i >> 1); /* - this constant is slightly better */
+ invsqrt = v.f; /* better than 0.2% accuracy */
+
+ /* Refining it using Newton's method: x1 = x0 - f(x0)/f'(x0)
+ * f(x) = 1/(x*x) - X (f==0 when x = 1/sqrt(X))
+ * f'(x) = -2/(x*x*x)
+ * f(x)/f'(x) = (X - 1/(x*x)) / (2/(x*x*x)) = X*x*x*x/2 - x/2
+ * x1 = x0 - (X*x0*x0*x0/2 - x0/2) = 1.5*x0 - X*x0*x0*x0/2 = x0*(1.5 - (X/2)*x0*x0)
+ */
+ invsqrt = invsqrt * (1.5 - Xhalf * invsqrt * invsqrt); /* ~0.05% accuracy */
+ /* invsqrt = invsqrt * (1.5 - Xhalf * invsqrt * invsqrt); 2nd iter: ~0.0001% accuracy */
+ /* With 4 iterations, more than half results will be exact,
+ * at 6th iterations result stabilizes with about 72% results exact.
+ * We are well satisfied with 0.05% accuracy.
+ */
+
+ return X * invsqrt; /* X * 1/sqrt(X) ~= sqrt(X) */
+}
+static ALWAYS_INLINE double SQRT(double X)
+{
+ /* If this arch doesn't use IEEE 754 floats, fall back to using libm */
+ if (sizeof(float) != 4)
+ return sqrt(X);
+
+ /* This avoids needing libm, saves about 0.5k on x86-32 */
+ return my_SQRT(X);
+}
static double
gettime1900d(void)
double min_jitter = min_jitter;
if (num_survivors <= MIN_CLUSTERED) {
- bb_error_msg("num_survivors %d <= %d, not discarding more",
+ VERB3 bb_error_msg("num_survivors %d <= %d, not discarding more",
num_survivors, MIN_CLUSTERED);
break;
}
|| errno == EAGAIN
) {
//TODO: always do this?
- set_next(p, retry_interval());
- goto close_sock;
+ interval = retry_interval();
+ goto set_next_and_close_sock;
}
xfunc_die();
}
// "RATE" - peer is overloaded, reduce polling freq
interval = poll_interval(0);
bb_error_msg("reply from %s: not synced, next query in %us", p->p_dotted, interval);
- goto close_sock;
+ goto set_next_and_close_sock;
}
// /* Verify valid root distance */
}
p->reachable_bits |= 1;
- VERB1 {
- bb_error_msg("reply from %s: reach 0x%02x offset %f delay %f",
+ if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) {
+ bb_error_msg("reply from %s: reach 0x%02x offset %f delay %f status 0x%02x strat %d refid 0x%08x rootdelay %f",
p->p_dotted,
p->reachable_bits,
- datapoint->d_offset, p->lastpkt_delay);
+ datapoint->d_offset,
+ p->lastpkt_delay,
+ p->lastpkt_status,
+ p->lastpkt_stratum,
+ p->lastpkt_refid,
+ p->lastpkt_rootdelay
+ /* not shown: m_ppoll, m_precision_exp, m_rootdisp,
+ * m_reftime, m_orgtime, m_rectime, m_xmttime
+ */
+ );
}
/* Muck with statictics and update the clock */
filter_datapoints(p);
q = select_and_cluster();
rc = -1;
- if (q)
- rc = update_local_clock(q);
+ if (q) {
+ rc = 0;
+ if (!(option_mask32 & OPT_w))
+ rc = update_local_clock(q);
+ }
if (rc != 0) {
/* Adjust the poll interval by comparing the current offset
/* Decide when to send new query for this peer */
interval = poll_interval(0);
- set_next(p, interval);
- close_sock:
+ set_next_and_close_sock:
+ set_next(p, interval);
/* We do not expect any more packets from this peer for now.
* Closing the socket informs kernel about it.
* We open a new socket when we send a new query.
/* Parse options */
peers = NULL;
- opt_complementary = "dd:p::"; /* d: counter, p: list */
+ opt_complementary = "dd:p::wn"; /* d: counter; p: list; -w implies -n */
opts = getopt32(argv,
"nqNx" /* compat */
- "p:"IF_FEATURE_NTPD_SERVER("l") /* NOT compat */
+ "wp:"IF_FEATURE_NTPD_SERVER("l") /* NOT compat */
"d" /* compat */
"46aAbgL", /* compat, ignored */
&peers, &G.verbose);