From nobody@FreeBSD.org  Wed Sep 17 14:58:11 2008
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id A2DBE106564A
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 17 Sep 2008 14:58:11 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 9001F8FC17
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 17 Sep 2008 14:58:11 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.2/8.14.2) with ESMTP id m8HEwBVf038920
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 17 Sep 2008 14:58:11 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.2/8.14.1/Submit) id m8HEwAWB038918;
	Wed, 17 Sep 2008 14:58:10 GMT
	(envelope-from nobody)
Message-Id: <200809171458.m8HEwAWB038918@www.freebsd.org>
Date: Wed, 17 Sep 2008 14:58:10 GMT
From: Henri Hennebert <hlh@restart.be>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Dtrace timestamp variable is wrapping as if define as uint32_t
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         127441
>Category:       kern
>Synopsis:       [dtrace] Dtrace timestamp variable is wrapping as if define as uint32_t
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Sep 17 15:00:12 UTC 2008
>Closed-Date:    Tue Mar 01 04:41:49 UTC 2011
>Last-Modified:  Tue Mar 01 04:41:49 UTC 2011
>Originator:     Henri Hennebert
>Release:        7.1-PRERELEASE
>Organization:
>Environment:
FreeBSD morzine.restart.bel 7.1-PRERELEASE FreeBSD 7.1-PRERELEASE #0: Sun Sep 14 17:24:37 CEST 2008 root@morzine.restart.bel:/usr/obj/usr/src/sys/MORZINE i386
>Description:
I am reading the 'Solaris Dynamic tracing guide' and using FreeBSD for the practical test.

In this D program:

dtrace:::BEGIN
{
        i = 10;
}

profile:::tick-1sec
/i > 0/
{
 	printf("[%d] value is %d\n", timestamp, i--);
}

profile:::tick-1sec
/i <= 0/
{
 	printf("[%d]  B O U M !\n", timestamp);
	exit(0);
}

the value of timestamp has never more than 10 decimal digits.

By the way is it the right place to describe dtrace problems or is there a wiki or something.

Thanks
Henri
>How-To-Repeat:
Run previous program.
>Fix:


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->jb 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Wed Sep 17 15:13:01 UTC 2008 
Responsible-Changed-Why:  
Over to maintainer. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=127441 

From: Andriy Gapon <avg@freebsd.org>
To: bug-followup@freebsd.org, Henri Hennebert <hlh@restart.be>
Cc:  
Subject: Re: kern/127441: [dtrace] Dtrace timestamp variable is wrapping as
 if define as uint32_t
Date: Wed, 24 Jun 2009 19:16:27 +0300

 I think that the following is relevant to this PR.
 
 -------- Original Message --------
 Subject: Re: DTrace "timestamp" wraps at about 2^33 (64-bit value)?
 Date: Mon, 22 Jun 2009 14:07:43 +0300
 From: Andriy Gapon <avg@icyb.net.ua>
 To: Thomas Backman <serenity@exscape.org>
 CC: FreeBSD current <freebsd-current@freebsd.org>,  John Birrell <jb@FreeBSD.org>
 References: <668B820A-AAA7-4A40-8CF5-7DDCFDCD95FC@exscape.org>
 
 on 20/06/2009 19:29 Thomas Backman said the following:
 > It appears the DTrace "timestamp" variable is wrapping around way, way
 > too quickly - it only goes to somewhere slightly above 2^33 (in
 > practice, at least), and since it's in nanoseconds, that's not a lot.
 > (2^33 ns is less than 10 seconds, actually. 2^64 is 584.55 years, however!)
 [snip]
 > uint64_t
 > dtrace_gethrtime()
 > {
 >     return ((rdtsc() + tsc_skew[curcpu]) * (int64_t) 1000000000 / tsc_freq);
 
 It appears that (rdtsc() + X) * 10^9 overflows 64-bit value for sufficiently small
 values of rdtsc.
 BTW, I think it would have been better/clearer to use uint64_t in the cast.
 
 I think that to minimize overflow and sufficiently accurate result a formula like
 the following could be used:
 
 x = rdtsc() + tsc_skew[curcpu];
 sec = x / tsc_freq;
 r = x % tsc_freq;
 res = sec * 10^9 + (r * 10^9 / tsc_freq);
 
 I have not tested the formula.
 I have suspicions about its accuracy in the edge cases,
 esp. if tsc_freq > (2^64 - 1) / 10^9 (not sure if have that in reality).
 
 -- 
 Andriy Gapon
 
 
 -- 
 Andriy Gapon

From: Andriy Gapon <avg@freebsd.org>
To: bug-followup@freebsd.org, Henri Hennebert <hlh@restart.be>,
        Thomas Backman <serenity@exscape.org>, John Birrell <jb@freebsd.org>
Cc: John Baldwin <jhb@freebsd.org>
Subject: Re: kern/127441: [dtrace] Dtrace timestamp variable is wrapping as
 if define as uint32_t
Date: Fri, 26 Jun 2009 14:19:01 +0300

 What do you think about the following patch?
 I am testing it here now and it looks OK so far.
 
 --- a/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 +++ b/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 @@ -439,7 +439,16 @@
  uint64_t
  dtrace_gethrtime()
  {
 -	return ((rdtsc() + tsc_skew[curcpu]) * (int64_t) 1000000000 / tsc_freq);
 +	static const uint64_t NSEC_FACTOR = 1000000000;
 +	uint64_t t;
 +	uint64_t s;
 +	uint64_t r;
 +
 +	t = rdtsc() + tsc_skew[curcpu];
 +	s = t / tsc_freq;
 +	r = t % tsc_freq;
 +
 +	return (s * NSEC_FACTOR + (r * NSEC_FACTOR) / tsc_freq);
  }
 
  uint64_t
 
 -- 
 Andriy Gapon

From: Thomas Backman <serenity@exscape.org>
To: Andriy Gapon <avg@FreeBSD.org>
Cc: bug-followup@freebsd.org,
 Henri Hennebert <hlh@restart.be>,
 John Birrell <jb@freebsd.org>,
 John Baldwin <jhb@freebsd.org>
Subject: Re: kern/127441: [dtrace] Dtrace timestamp variable is wrapping as if define as uint32_t
Date: Fri, 26 Jun 2009 13:52:53 +0200

 On Jun 26, 2009, at 01:19 PM, Andriy Gapon wrote:
 
 >
 > What do you think about the following patch?
 > I am testing it here now and it looks OK so far.
 >
 > --- a/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 > +++ b/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 > @@ -439,7 +439,16 @@
 > uint64_t
 > dtrace_gethrtime()
 > {
 > -	return ((rdtsc() + tsc_skew[curcpu]) * (int64_t) 1000000000 /  
 > tsc_freq);
 > +	static const uint64_t NSEC_FACTOR = 1000000000;
 > +	uint64_t t;
 > +	uint64_t s;
 > +	uint64_t r;
 > +
 > +	t = rdtsc() + tsc_skew[curcpu];
 > +	s = t / tsc_freq;
 > +	r = t % tsc_freq;
 > +
 > +	return (s * NSEC_FACTOR + (r * NSEC_FACTOR) / tsc_freq);
 > }
 >
 > uint64_t
 >
 > -- 
 > Andriy Gapon
 As for me, I have *no* clue how it works in theory, so to speak, but  
 it appears to work in practice (I hope the script is correct enough):
 
 # dtrace -n 'int ts; BEGIN { ts = timestamp; } tick-1sec { self->now =  
 timestamp; trace(self->now-ts); ts = self->now; }'
 dtrace: description 'int ts' matched 2 probes
 CPU     ID                    FUNCTION:NAME
    0  40948                       :tick-1sec         996771003
    0  40948                       :tick-1sec         998992677
    0  40948                       :tick-1sec         999992457
    0  40948                       :tick-1sec         999991835
    0  40948                       :tick-1sec         999992589
    0  40948                       :tick-1sec         999992174
    0  40948                       :tick-1sec         999992451
    0  40948                       :tick-1sec         999992589
    0  40948                       :tick-1sec         999992155
    0  40948                       :tick-1sec         999992338
    0  40948                       :tick-1sec         999992257
    0  40948                       :tick-1sec         999992470
    0  40948                       :tick-1sec         999992801
    0  40948                       :tick-1sec         999991784
    0  40948                       :tick-1sec         999993064
 
 The precision appears about the same as the old code, except that the  
 results aren't screwed up ;)
 
 OLD CODE:
 # dtrace -n 'int ts; BEGIN { ts = timestamp; } tick-1sec { self->now =  
 timestamp; trace(self->now-ts); ts = self->now; }'
 dtrace: description 'int ts' matched 2 probes
 CPU     ID                    FUNCTION:NAME
    0  40948                       :tick-1sec       -8184680854
    0  40948                       :tick-1sec         999991815
    0  40948                       :tick-1sec         999991798
    0  40948                       :tick-1sec         999991793
    0  40948                       :tick-1sec         999991675
    0  40948                       :tick-1sec         999991893
    0  40948                       :tick-1sec         999991459
    0  40948                       :tick-1sec         999991931
    0  40948                       :tick-1sec         999991728
    0  40948                       :tick-1sec         999992183
    0  40948                       :tick-1sec       -8180830112
    0  40948                       :tick-1sec         999991328
    0  40948                       :tick-1sec         999989548
 
 Regards,
 Thomas

From: Andriy Gapon <avg@freebsd.org>
To: bug-followup@freebsd.org, Henri Hennebert <hlh@restart.be>,
        Thomas Backman <serenity@exscape.org>, John Birrell <jb@freebsd.org>
Cc: John Baldwin <jhb@freebsd.org>
Subject: Re: kern/127441: [dtrace] Dtrace timestamp variable is wrapping as
 if define as uint32_t
Date: Fri, 26 Jun 2009 16:22:05 +0300

 on 26/06/2009 14:19 Andriy Gapon said the following:
 > What do you think about the following patch?
 > I am testing it here now and it looks OK so far.
 > 
 > --- a/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 > +++ b/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 > @@ -439,7 +439,16 @@
 >  uint64_t
 >  dtrace_gethrtime()
 >  {
 > -	return ((rdtsc() + tsc_skew[curcpu]) * (int64_t) 1000000000 / tsc_freq);
 > +	static const uint64_t NSEC_FACTOR = 1000000000;
 > +	uint64_t t;
 > +	uint64_t s;
 > +	uint64_t r;
 > +
 > +	t = rdtsc() + tsc_skew[curcpu];
 > +	s = t / tsc_freq;
 > +	r = t % tsc_freq;
 > +
 > +	return (s * NSEC_FACTOR + (r * NSEC_FACTOR) / tsc_freq);
 >  }
 > 
 >  uint64_t
 
 But I've just found a problem that this patch brings to the light.
 I have a machine with invariant_tsc=0 and powerd running (est cpufreq driver), as
 a result tsc_freq changes wildly (by an order of magnitude).
 
 As a result dtrace_gethrtime returns very inconsistent results.
 E.g.: X/Y vs (X+1)/(Y*10), where X is rdtsc return value and Y is some value of
 tsc_freq.
 
 
 -- 
 Andriy Gapon

From: Andriy Gapon <avg@freebsd.org>
To: bug-followup@freebsd.org, Henri Hennebert <hlh@restart.be>,
        Thomas Backman <serenity@exscape.org>, John Birrell <jb@freebsd.org>
Cc: John Baldwin <jhb@freebsd.org>
Subject: Re: kern/127441: [dtrace] Dtrace timestamp variable is wrapping as
 if define as uint32_t
Date: Fri, 26 Jun 2009 17:55:19 +0300

 on 26/06/2009 16:22 Andriy Gapon said the following:
 > But I've just found a problem that this patch brings to the light.
 > I have a machine with invariant_tsc=0 and powerd running (est cpufreq driver), as
 > a result tsc_freq changes wildly (by an order of magnitude).
 > 
 > As a result dtrace_gethrtime returns very inconsistent results.
 > E.g.: X/Y vs (X+1)/(Y*10), where X is rdtsc return value and Y is some value of
 > tsc_freq.
 
 Hmm, actually that system was stable/7 and it looks like the code is not smart
 enough to recognize that my CPU has invariant TSC.
 Something like 185460 needs to be MFC-ed.
 
 But that's beside the point. Using rdtsc/tsc_freq on systems with non-invariant
 TSC in such a straighfoward fashion is  incorrect in my opinion.
 
 Ideas for a better approach? Maybe just use rdtsc as is (and document timestamp to
 be that) or something?
 
 -- 
 Andriy Gapon

From: John Baldwin <jhb@freebsd.org>
To: Andriy Gapon <avg@freebsd.org>
Cc: bug-followup@freebsd.org,
 Henri Hennebert <hlh@restart.be>,
 Thomas Backman <serenity@exscape.org>,
 John Birrell <jb@freebsd.org>,
 "George Neville-Neil" <gnn@freebsd.org>
Subject: Re: kern/127441: [dtrace] Dtrace timestamp variable is wrapping as if define as uint32_t
Date: Fri, 26 Jun 2009 11:06:55 -0400

 On Friday 26 June 2009 10:55:19 am Andriy Gapon wrote:
 > on 26/06/2009 16:22 Andriy Gapon said the following:
 > > But I've just found a problem that this patch brings to the light.
 > > I have a machine with invariant_tsc=0 and powerd running (est cpufreq 
 driver), as
 > > a result tsc_freq changes wildly (by an order of magnitude).
 > > 
 > > As a result dtrace_gethrtime returns very inconsistent results.
 > > E.g.: X/Y vs (X+1)/(Y*10), where X is rdtsc return value and Y is some 
 value of
 > > tsc_freq.
 > 
 > Hmm, actually that system was stable/7 and it looks like the code is not 
 smart
 > enough to recognize that my CPU has invariant TSC.
 > Something like 185460 needs to be MFC-ed.
 > 
 > But that's beside the point. Using rdtsc/tsc_freq on systems with 
 non-invariant
 > TSC in such a straighfoward fashion is  incorrect in my opinion.
 > 
 > Ideas for a better approach? Maybe just use rdtsc as is (and document 
 timestamp to
 > be that) or something?
 
 If possible I would use rdtsc() and let users know the caveat that with
 non-invariant TSC's and cpufreq it will not be very reliable.  All the other
 alternatives for the non-invariant TSC case would be relatively expensive.
 
 -- 
 John Baldwin

From: Henri Hennebert <hlh@restart.be>
To: Andriy Gapon <avg@freebsd.org>
Cc: bug-followup@freebsd.org, Thomas Backman <serenity@exscape.org>,
        John Birrell <jb@freebsd.org>, John Baldwin <jhb@freebsd.org>
Subject: Re: kern/127441: [dtrace] Dtrace timestamp variable is wrapping as
 if define as uint32_t
Date: Sat, 27 Jun 2009 13:52:33 +0200

 Andriy Gapon wrote:
 > What do you think about the following patch?
 > I am testing it here now and it looks OK so far.
 > 
 > --- a/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 > +++ b/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 > @@ -439,7 +439,16 @@
 >  uint64_t
 >  dtrace_gethrtime()
 >  {
 > -	return ((rdtsc() + tsc_skew[curcpu]) * (int64_t) 1000000000 / tsc_freq);
 > +	static const uint64_t NSEC_FACTOR = 1000000000;
 > +	uint64_t t;
 > +	uint64_t s;
 > +	uint64_t r;
 > +
 > +	t = rdtsc() + tsc_skew[curcpu];
 > +	s = t / tsc_freq;
 > +	r = t % tsc_freq;
 > +
 > +	return (s * NSEC_FACTOR + (r * NSEC_FACTOR) / tsc_freq);
 >  }
 > 
 >  uint64_t
 > 
 This patch work also for i386 (7.2_STABLE) and correct the problem.
 
 Thanks
 Henri

From: Thomas Backman <serenity@exscape.org>
To: bug-followup@FreeBSD.org
Cc: FreeBSD current <freebsd-current@freebsd.org>,
 re@freebsd.org
Subject: Re: kern/127441: [dtrace] Dtrace timestamp variable is wrapping as if define as uint32_t
Date: Sun, 5 Jul 2009 10:16:54 +0200

 Could we have this patch merged in time for 8.0? I don't know if the  
 problems in the PR followups are big enough, but considering that the  
 current implementation is horribly broken for everyone, and the patch  
 fixes it for a large number of people, I don't really see the downside  
 in merging it for the time being.
 
 Regards,
 Thomas

From: Andriy Gapon <avg@freebsd.org>
To: bug-followup@freebsd.org
Cc: John Baldwin <jhb@freebsd.org>, Henri Hennebert <hlh@restart.be>,
        Thomas Backman <serenity@exscape.org>, John Birrell <jb@freebsd.org>,
        George Neville-Neil <gnn@freebsd.org>, Bruce Evans <bde@zeta.org.au>
Subject: Re: kern/127441: [dtrace] Dtrace timestamp variable is wrapping as
 if define as uint32_t
Date: Mon, 13 Jul 2009 18:26:19 +0300

 What about something like the following?
 The patch introduces the following benefits comparing to current code and the
 previous patch:
 
 1) no "premature" overflow
 2) quite fast computation om amd64, faster than the remainder approach, only
    slightly slower than the original x*y/z code
 3) very fast on i386, faster than the original x*y/z code
 4) supports any tsc frequency between 62.5MHz and 1 THz with very good precision
 5) uses constant TSC factor, thus producing correct timestamps when TSC is
   	   invariant and producing "scaled TSC values" when TSC is not invariant; this is
    not perfect, but should be sufficiently good for such circumstances.
 
 I put some comments describing the computations.
 The idea is borrowed from OpenSolaris code, no copy-pasting, but no assurance that
 the idea/algorithm is not patented either.
 
 Going forward we could track cpufreq events and re-calculate the factor for
 non-invariant TSC case, but I am not sure how much merit would that have.
 
 If there are no objections (technical and legal), I would like to propose the code
 (along with i386 twin) for 8.0.
 
 diff --git a/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 b/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 index 260b99b..82f1967 100644
 --- a/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 +++ b/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 @@ -366,6 +366,10 @@ dtrace_safe_defer_signal(void)
  static int64_t	tgt_cpu_tsc;
  static int64_t	hst_cpu_tsc;
  static int64_t	tsc_skew[MAXCPU];
 +static uint64_t	nsec_scale;
 +
 +/* See below for the explanation of ths macro. */
 +#define SCALE_SHIFT	28
 
  static void
  dtrace_gethrtime_init_sync(void *arg)
 @@ -401,9 +405,33 @@ dtrace_gethrtime_init_cpu(void *arg)
  static void
  dtrace_gethrtime_init(void *arg)
  {
 +	struct pcpu *cp;
 +	uint64_t tsc_f;
  	cpumask_t map;
  	int i;
 -	struct pcpu *cp;
 +
 +	/* Get TSC frequency known at this moment.
 +	 * This should be constant if TSC is invariant.
 +	 * Otherwise tick->time conversion will be inaccurate, but
 +	 * will preserve monotonic property of TSC.
 +	 */
 +	tsc_f = tsc_freq;
 +
 +	/* The following line checks that nsec_scale calculated below
 +	 * doesn't overflow 32-bit unsigned integer.
 +	 * Minimum supported TSC frequency is 62.5MHz.
 +	 */
 +	KASSERT(f > (NANOSEC >> (32 - SCALE_SHIFT)), "TSC frequency is too low");
 +
 +	/* We scale up NANOSEC/tsc_f ratio to preserve as much precision
 +	 * as possible.
 +	 * 2^28 factor was chosen quite arbitrarily from practical
 +	 * considerations:
 +	 * - it supports TSC frequencies as low as 62.5MHz (see above);
 +	 * - it provides quite good precision (e < 0.01%) up to THz
 +	 *   (terahertz) values;
 +	 */
 +	nsec_scale = ((uint64_t)NANOSEC << SCALE_SHIFT) / tsc_f;
 
  	/* The current CPU is the reference one. */
  	tsc_skew[curcpu] = 0;
 @@ -439,7 +467,20 @@ SYSINIT(dtrace_gethrtime_init, SI_SUB_SMP, SI_ORDER_ANY,
 dtrace_gethrtime_init,
  uint64_t
  dtrace_gethrtime()
  {
 -	return ((rdtsc() + tsc_skew[curcpu]) * (int64_t) 1000000000 / tsc_freq);
 +	uint64_t tsc;
 +	uint32_t lo;
 +	uint32_t hi;
 +
 +	/* We split TSC value into lower and higher 32-bit halves and separately
 +	 * scale them with nsec_scale, then we scale them down by 2^28
 +	 * (see nsec_scale calculations) taking into account 32-bit shift of
 +	 * the higher half and finally add.
 +	 */
 +	tsc = rdtsc() + tsc_skew[curcpu];
 +	lo = tsc;
 +	hi = tsc >> 32;
 +	return (((lo * nsec_scale) >> SCALE_SHIFT) +
 +	    ((hi * nsec_scale) << (32 - SCALE_SHIFT)));
  }
 
  uint64_t
 
 -- 
 Andriy Gapon

From: Thomas Backman <serenity@exscape.org>
To: bug-followup@freebsd.org
Cc: Andriy Gapon <avg@FreeBSD.org>
Subject: Re: kern/127441: [dtrace] Dtrace timestamp variable is wrapping as if define as uint32_t
Date: Mon, 13 Jul 2009 19:06:29 +0200

 On Jul 13, 2009, at 17:26, Andriy Gapon wrote:
 >
 > What about something like the following?
 > The patch introduces the following benefits comparing to current  
 > code and the
 > previous patch:
 >
 > 1) no "premature" overflow
 > 2) quite fast computation om amd64, faster than the remainder  
 > approach, only
 >   slightly slower than the original x*y/z code
 > 3) very fast on i386, faster than the original x*y/z code
 > 4) supports any tsc frequency between 62.5MHz and 1 THz with very  
 > good precision
 > 5) uses constant TSC factor, thus producing correct timestamps when  
 > TSC is
 >  	   invariant and producing "scaled TSC values" when TSC is not  
 > invariant; this is
 >   not perfect, but should be sufficiently good for such circumstances.
 >
 > I put some comments describing the computations.
 > The idea is borrowed from OpenSolaris code, no copy-pasting, but no  
 > assurance that
 > the idea/algorithm is not patented either.
 >
 > Going forward we could track cpufreq events and re-calculate the  
 > factor for
 > non-invariant TSC case, but I am not sure how much merit would that  
 > have.
 >
 > If there are no objections (technical and legal), I would like to  
 > propose the code
 > (along with i386 twin) for 8.0.
 >
 > diff --git a/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 > b/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 > [...]
 
 Doesn't the CDDL license automatically make it permitted to literally  
 copy/paste the code (as is actually done with a lot of the DTrace/ZFS  
 code)?
 Anyhow, I tried the patch on amd64 (Athlon 64 3200+, singlecore) and  
 it seems to work just the same as the previous one, in other words,  
 "works for me". :)
 
 Regards,
 Thomas

From: Andriy Gapon <avg@freebsd.org>
To: Thomas Backman <serenity@exscape.org>
Cc: bug-followup@freebsd.org
Subject: Re: kern/127441: [dtrace] Dtrace timestamp variable is wrapping as
 if define as uint32_t
Date: Tue, 14 Jul 2009 11:05:42 +0300

 on 13/07/2009 20:06 Thomas Backman said the following:
 > Doesn't the CDDL license automatically make it permitted to literally
 > copy/paste the code (as is actually done with a lot of the DTrace/ZFS
 > code)?
 
 At the very least it has an explicit patent clause.
 That and the fact that Bruce Evans suggested a very similar technique when I
 asked him for an advise.
 
 > Anyhow, I tried the patch on amd64 (Athlon 64 3200+, singlecore) and it
 > seems to work just the same as the previous one, in other words, "works
 > for me". :)
 
 Thank you very much for testing again!
 
 -- 
 Andriy Gapon

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/127441: commit references a PR
Date: Wed, 15 Jul 2009 17:07:51 +0000 (UTC)

 Author: avg
 Date: Wed Jul 15 17:07:39 2009
 New Revision: 195710
 URL: http://svn.freebsd.org/changeset/base/195710
 
 Log:
   dtrace_gethrtime: improve scaling of TSC ticks to nanoseconds
   
   Currently dtrace_gethrtime uses formula similar to the following for
   converting TSC ticks to nanoseconds:
   rdtsc() * 10^9 / tsc_freq
   The dividend overflows 64-bit type and wraps-around every 2^64/10^9 =
   18446744073 ticks which is just a few seconds on modern machines.
   
   Now we instead use precalculated scaling factor of
   10^9*2^N/tsc_freq < 2^32 and perform TSC value multiplication separately
   for each 32-bit half.  This allows to avoid overflow of the dividend
   described above.
   The idea is taken from OpenSolaris.
   This has an added feature of always scaling TSC with invariant value
   regardless of TSC frequency changes. Thus the timestamps will not be
   accurate if TSC actually changes, but they are always proportional to
   TSC ticks and thus monotonic. This should be much better than current
   formula which produces wildly different non-monotonic results on when
   tsc_freq changes.
   
   Also drop write-only 'cp' variable from amd64 dtrace_gethrtime_init()
   to make it identical to the i386 twin.
   
   PR:		kern/127441
   Tested by:	Thomas Backman <serenity@exscape.org>
   Reviewed by:	jhb
   Discussed with:	current@, bde, gnn
   Silence from:	jb
   Approved by:	re (gnn)
   MFC after:	1 week
 
 Modified:
   head/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
   head/sys/cddl/dev/dtrace/i386/dtrace_subr.c
 
 Modified: head/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 ==============================================================================
 --- head/sys/cddl/dev/dtrace/amd64/dtrace_subr.c	Wed Jul 15 13:50:06 2009	(r195709)
 +++ head/sys/cddl/dev/dtrace/amd64/dtrace_subr.c	Wed Jul 15 17:07:39 2009	(r195710)
 @@ -366,6 +366,10 @@ dtrace_safe_defer_signal(void)
  static int64_t	tgt_cpu_tsc;
  static int64_t	hst_cpu_tsc;
  static int64_t	tsc_skew[MAXCPU];
 +static uint64_t	nsec_scale;
 +
 +/* See below for the explanation of this macro. */
 +#define SCALE_SHIFT	28
  
  static void
  dtrace_gethrtime_init_sync(void *arg)
 @@ -401,9 +405,36 @@ dtrace_gethrtime_init_cpu(void *arg)
  static void
  dtrace_gethrtime_init(void *arg)
  {
 +	uint64_t tsc_f;
  	cpumask_t map;
  	int i;
 -	struct pcpu *cp;
 +
 +	/*
 +	 * Get TSC frequency known at this moment.
 +	 * This should be constant if TSC is invariant.
 +	 * Otherwise tick->time conversion will be inaccurate, but
 +	 * will preserve monotonic property of TSC.
 +	 */
 +	tsc_f = tsc_freq;
 +
 +	/*
 +	 * The following line checks that nsec_scale calculated below
 +	 * doesn't overflow 32-bit unsigned integer, so that it can multiply
 +	 * another 32-bit integer without overflowing 64-bit.
 +	 * Thus minimum supported TSC frequency is 62.5MHz.
 +	 */
 +	KASSERT(tsc_f > (NANOSEC >> (32 - SCALE_SHIFT)), ("TSC frequency is too low"));
 +
 +	/*
 +	 * We scale up NANOSEC/tsc_f ratio to preserve as much precision
 +	 * as possible.
 +	 * 2^28 factor was chosen quite arbitrarily from practical
 +	 * considerations:
 +	 * - it supports TSC frequencies as low as 62.5MHz (see above);
 +	 * - it provides quite good precision (e < 0.01%) up to THz
 +	 *   (terahertz) values;
 +	 */
 +	nsec_scale = ((uint64_t)NANOSEC << SCALE_SHIFT) / tsc_f;
  
  	/* The current CPU is the reference one. */
  	tsc_skew[curcpu] = 0;
 @@ -412,7 +443,7 @@ dtrace_gethrtime_init(void *arg)
  		if (i == curcpu)
  			continue;
  
 -		if ((cp = pcpu_find(i)) == NULL)
 +		if (pcpu_find(i) == NULL)
  			continue;
  
  		map = 0;
 @@ -439,7 +470,21 @@ SYSINIT(dtrace_gethrtime_init, SI_SUB_SM
  uint64_t
  dtrace_gethrtime()
  {
 -	return ((rdtsc() + tsc_skew[curcpu]) * (int64_t) 1000000000 / tsc_freq);
 +	uint64_t tsc;
 +	uint32_t lo;
 +	uint32_t hi;
 +
 +	/*
 +	 * We split TSC value into lower and higher 32-bit halves and separately
 +	 * scale them with nsec_scale, then we scale them down by 2^28
 +	 * (see nsec_scale calculations) taking into account 32-bit shift of
 +	 * the higher half and finally add.
 +	 */
 +	tsc = rdtsc() + tsc_skew[curcpu];
 +	lo = tsc;
 +	hi = tsc >> 32;
 +	return (((lo * nsec_scale) >> SCALE_SHIFT) +
 +	    ((hi * nsec_scale) << (32 - SCALE_SHIFT)));
  }
  
  uint64_t
 
 Modified: head/sys/cddl/dev/dtrace/i386/dtrace_subr.c
 ==============================================================================
 --- head/sys/cddl/dev/dtrace/i386/dtrace_subr.c	Wed Jul 15 13:50:06 2009	(r195709)
 +++ head/sys/cddl/dev/dtrace/i386/dtrace_subr.c	Wed Jul 15 17:07:39 2009	(r195710)
 @@ -366,6 +366,10 @@ dtrace_safe_defer_signal(void)
  static int64_t	tgt_cpu_tsc;
  static int64_t	hst_cpu_tsc;
  static int64_t	tsc_skew[MAXCPU];
 +static uint64_t	nsec_scale;
 +
 +/* See below for the explanation of this macro. */
 +#define SCALE_SHIFT	28
  
  static void
  dtrace_gethrtime_init_sync(void *arg)
 @@ -401,9 +405,37 @@ dtrace_gethrtime_init_cpu(void *arg)
  static void
  dtrace_gethrtime_init(void *arg)
  {
 +	uint64_t tsc_f;
  	cpumask_t map;
  	int i;
  
 +	/*
 +	 * Get TSC frequency known at this moment.
 +	 * This should be constant if TSC is invariant.
 +	 * Otherwise tick->time conversion will be inaccurate, but
 +	 * will preserve monotonic property of TSC.
 +	 */
 +	tsc_f = tsc_freq;
 +
 +	/*
 +	 * The following line checks that nsec_scale calculated below
 +	 * doesn't overflow 32-bit unsigned integer, so that it can multiply
 +	 * another 32-bit integer without overflowing 64-bit.
 +	 * Thus minimum supported TSC frequency is 62.5MHz.
 +	 */
 +	KASSERT(tsc_f > (NANOSEC >> (32 - SCALE_SHIFT)), ("TSC frequency is too low"));
 +
 +	/*
 +	 * We scale up NANOSEC/tsc_f ratio to preserve as much precision
 +	 * as possible.
 +	 * 2^28 factor was chosen quite arbitrarily from practical
 +	 * considerations:
 +	 * - it supports TSC frequencies as low as 62.5MHz (see above);
 +	 * - it provides quite good precision (e < 0.01%) up to THz
 +	 *   (terahertz) values;
 +	 */
 +	nsec_scale = ((uint64_t)NANOSEC << SCALE_SHIFT) / tsc_f;
 +
  	/* The current CPU is the reference one. */
  	tsc_skew[curcpu] = 0;
  
 @@ -438,7 +470,21 @@ SYSINIT(dtrace_gethrtime_init, SI_SUB_SM
  uint64_t
  dtrace_gethrtime()
  {
 -	return ((rdtsc() + tsc_skew[curcpu]) * (int64_t) 1000000000 / tsc_freq);
 +	uint64_t tsc;
 +	uint32_t lo;
 +	uint32_t hi;
 +
 +	/*
 +	 * We split TSC value into lower and higher 32-bit halves and separately
 +	 * scale them with nsec_scale, then we scale them down by 2^28
 +	 * (see nsec_scale calculations) taking into account 32-bit shift of
 +	 * the higher half and finally add.
 +	 */
 +	tsc = rdtsc() + tsc_skew[curcpu];
 +	lo = tsc;
 +	hi = tsc >> 32;
 +	return (((lo * nsec_scale) >> SCALE_SHIFT) +
 +	    ((hi * nsec_scale) << (32 - SCALE_SHIFT)));
  }
  
  uint64_t
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/127441: commit references a PR
Date: Wed, 22 Jul 2009 15:41:52 +0000 (UTC)

 Author: avg
 Date: Wed Jul 22 15:41:37 2009
 New Revision: 195824
 URL: http://svn.freebsd.org/changeset/base/195824
 
 Log:
   MFC 195710: dtrace_gethrtime: improve scaling of TSC ticks to
   nanoseconds
   
   PR:		kern/127441
 
 Modified:
   stable/7/sys/   (props changed)
   stable/7/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
   stable/7/sys/cddl/dev/dtrace/i386/dtrace_subr.c
   stable/7/sys/contrib/pf/   (props changed)
 
 Modified: stable/7/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
 ==============================================================================
 --- stable/7/sys/cddl/dev/dtrace/amd64/dtrace_subr.c	Wed Jul 22 15:26:19 2009	(r195823)
 +++ stable/7/sys/cddl/dev/dtrace/amd64/dtrace_subr.c	Wed Jul 22 15:41:37 2009	(r195824)
 @@ -366,6 +366,10 @@ dtrace_safe_defer_signal(void)
  static int64_t	tgt_cpu_tsc;
  static int64_t	hst_cpu_tsc;
  static int64_t	tsc_skew[MAXCPU];
 +static uint64_t	nsec_scale;
 +
 +/* See below for the explanation of this macro. */
 +#define SCALE_SHIFT	28
  
  static void
  dtrace_gethrtime_init_sync(void *arg)
 @@ -401,9 +405,36 @@ dtrace_gethrtime_init_cpu(void *arg)
  static void
  dtrace_gethrtime_init(void *arg)
  {
 +	uint64_t tsc_f;
  	cpumask_t map;
  	int i;
 -	struct pcpu *cp;
 +
 +	/*
 +	 * Get TSC frequency known at this moment.
 +	 * This should be constant if TSC is invariant.
 +	 * Otherwise tick->time conversion will be inaccurate, but
 +	 * will preserve monotonic property of TSC.
 +	 */
 +	tsc_f = tsc_freq;
 +
 +	/*
 +	 * The following line checks that nsec_scale calculated below
 +	 * doesn't overflow 32-bit unsigned integer, so that it can multiply
 +	 * another 32-bit integer without overflowing 64-bit.
 +	 * Thus minimum supported TSC frequency is 62.5MHz.
 +	 */
 +	KASSERT(tsc_f > (NANOSEC >> (32 - SCALE_SHIFT)), ("TSC frequency is too low"));
 +
 +	/*
 +	 * We scale up NANOSEC/tsc_f ratio to preserve as much precision
 +	 * as possible.
 +	 * 2^28 factor was chosen quite arbitrarily from practical
 +	 * considerations:
 +	 * - it supports TSC frequencies as low as 62.5MHz (see above);
 +	 * - it provides quite good precision (e < 0.01%) up to THz
 +	 *   (terahertz) values;
 +	 */
 +	nsec_scale = ((uint64_t)NANOSEC << SCALE_SHIFT) / tsc_f;
  
  	/* The current CPU is the reference one. */
  	tsc_skew[curcpu] = 0;
 @@ -412,7 +443,7 @@ dtrace_gethrtime_init(void *arg)
  		if (i == curcpu)
  			continue;
  
 -		if ((cp = pcpu_find(i)) == NULL)
 +		if (pcpu_find(i) == NULL)
  			continue;
  
  		map = 0;
 @@ -439,7 +470,21 @@ SYSINIT(dtrace_gethrtime_init, SI_SUB_SM
  uint64_t
  dtrace_gethrtime()
  {
 -	return ((rdtsc() + tsc_skew[curcpu]) * (int64_t) 1000000000 / tsc_freq);
 +	uint64_t tsc;
 +	uint32_t lo;
 +	uint32_t hi;
 +
 +	/*
 +	 * We split TSC value into lower and higher 32-bit halves and separately
 +	 * scale them with nsec_scale, then we scale them down by 2^28
 +	 * (see nsec_scale calculations) taking into account 32-bit shift of
 +	 * the higher half and finally add.
 +	 */
 +	tsc = rdtsc() + tsc_skew[curcpu];
 +	lo = tsc;
 +	hi = tsc >> 32;
 +	return (((lo * nsec_scale) >> SCALE_SHIFT) +
 +	    ((hi * nsec_scale) << (32 - SCALE_SHIFT)));
  }
  
  uint64_t
 
 Modified: stable/7/sys/cddl/dev/dtrace/i386/dtrace_subr.c
 ==============================================================================
 --- stable/7/sys/cddl/dev/dtrace/i386/dtrace_subr.c	Wed Jul 22 15:26:19 2009	(r195823)
 +++ stable/7/sys/cddl/dev/dtrace/i386/dtrace_subr.c	Wed Jul 22 15:41:37 2009	(r195824)
 @@ -366,6 +366,10 @@ dtrace_safe_defer_signal(void)
  static int64_t	tgt_cpu_tsc;
  static int64_t	hst_cpu_tsc;
  static int64_t	tsc_skew[MAXCPU];
 +static uint64_t	nsec_scale;
 +
 +/* See below for the explanation of this macro. */
 +#define SCALE_SHIFT	28
  
  static void
  dtrace_gethrtime_init_sync(void *arg)
 @@ -401,10 +405,38 @@ dtrace_gethrtime_init_cpu(void *arg)
  static void
  dtrace_gethrtime_init(void *arg)
  {
 +	uint64_t tsc_f;
  	cpumask_t map;
  	int i;
  	struct pcpu *cp;
  
 +	/*
 +	 * Get TSC frequency known at this moment.
 +	 * This should be constant if TSC is invariant.
 +	 * Otherwise tick->time conversion will be inaccurate, but
 +	 * will preserve monotonic property of TSC.
 +	 */
 +	tsc_f = tsc_freq;
 +
 +	/*
 +	 * The following line checks that nsec_scale calculated below
 +	 * doesn't overflow 32-bit unsigned integer, so that it can multiply
 +	 * another 32-bit integer without overflowing 64-bit.
 +	 * Thus minimum supported TSC frequency is 62.5MHz.
 +	 */
 +	KASSERT(tsc_f > (NANOSEC >> (32 - SCALE_SHIFT)), ("TSC frequency is too low"));
 +
 +	/*
 +	 * We scale up NANOSEC/tsc_f ratio to preserve as much precision
 +	 * as possible.
 +	 * 2^28 factor was chosen quite arbitrarily from practical
 +	 * considerations:
 +	 * - it supports TSC frequencies as low as 62.5MHz (see above);
 +	 * - it provides quite good precision (e < 0.01%) up to THz
 +	 *   (terahertz) values;
 +	 */
 +	nsec_scale = ((uint64_t)NANOSEC << SCALE_SHIFT) / tsc_f;
 +
  	/* The current CPU is the reference one. */
  	tsc_skew[curcpu] = 0;
  
 @@ -439,7 +471,21 @@ SYSINIT(dtrace_gethrtime_init, SI_SUB_SM
  uint64_t
  dtrace_gethrtime()
  {
 -	return ((rdtsc() + tsc_skew[curcpu]) * (int64_t) 1000000000 / tsc_freq);
 +	uint64_t tsc;
 +	uint32_t lo;
 +	uint32_t hi;
 +
 +	/*
 +	 * We split TSC value into lower and higher 32-bit halves and separately
 +	 * scale them with nsec_scale, then we scale them down by 2^28
 +	 * (see nsec_scale calculations) taking into account 32-bit shift of
 +	 * the higher half and finally add.
 +	 */
 +	tsc = rdtsc() + tsc_skew[curcpu];
 +	lo = tsc;
 +	hi = tsc >> 32;
 +	return (((lo * nsec_scale) >> SCALE_SHIFT) +
 +	    ((hi * nsec_scale) << (32 - SCALE_SHIFT)));
  }
  
  uint64_t
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
Responsible-Changed-From-To: jb->freebsd-bugs 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Mon Dec 14 12:06:18 UTC 2009 
Responsible-Changed-Why:  
RIP John Birrell: please see http://www.freebsd.org/releases/8.0R/announce.html. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=127441 
State-Changed-From-To: open->closed 
State-Changed-By: linimon 
State-Changed-When: Tue Mar 1 04:40:12 UTC 2011 
State-Changed-Why:  
Has been MFCed to 7, and 6 is now EOL. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=127441 
>Unformatted:
