LCOV - code coverage report
Current view: directory - xpcom/ds - TimeStamp_posix.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 54 45 83.3 %
Date: 2012-06-02 Functions: 15 12 80.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is the Mozilla Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *  Chris Jones <jones.chris.g@gmail.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : //
      40                 : // Implement TimeStamp::Now() with POSIX clocks.
      41                 : //
      42                 : // The "tick" unit for POSIX clocks is simply a nanosecond, as this is
      43                 : // the smallest unit of time representable by struct timespec.  That
      44                 : // doesn't mean that a nanosecond is the resolution of TimeDurations
      45                 : // obtained with this API; see TimeDuration::Resolution;
      46                 : //
      47                 : 
      48                 : #include <time.h>
      49                 : 
      50                 : #include "mozilla/TimeStamp.h"
      51                 : 
      52                 : // Estimate of the smallest duration of time we can measure.
      53                 : static PRUint64 sResolution;
      54                 : static PRUint64 sResolutionSigDigs;
      55                 : 
      56                 : static const PRUint16 kNsPerUs   =       1000;
      57                 : static const PRUint64 kNsPerMs   =    1000000;
      58                 : static const PRUint64 kNsPerSec  = 1000000000; 
      59                 : static const double kNsPerMsd    =    1000000.0;
      60                 : static const double kNsPerSecd   = 1000000000.0;
      61                 : 
      62                 : static PRUint64
      63         1902456 : TimespecToNs(const struct timespec& ts)
      64                 : {
      65         1902456 :   PRUint64 baseNs = PRUint64(ts.tv_sec) * kNsPerSec;
      66         1902456 :   return baseNs + PRUint64(ts.tv_nsec);
      67                 : }
      68                 : 
      69                 : static PRUint64
      70         1901698 : ClockTimeNs()
      71                 : {
      72                 :   struct timespec ts;
      73                 :   // this can't fail: we know &ts is valid, and TimeStamp::Init()
      74                 :   // checks that CLOCK_MONOTONIC is supported (and aborts if not)
      75         1901698 :   clock_gettime(CLOCK_MONOTONIC, &ts);
      76                 : 
      77                 :   // tv_sec is defined to be relative to an arbitrary point in time,
      78                 :   // but it would be madness for that point in time to be earlier than
      79                 :   // the Epoch.  So we can safely assume that even if time_t is 32
      80                 :   // bits, tv_sec won't overflow while the browser is open.  Revisit
      81                 :   // this argument if we're still building with 32-bit time_t around
      82                 :   // the year 2037.
      83         1901711 :   return TimespecToNs(ts);
      84                 : }
      85                 : 
      86                 : static PRUint64
      87            1464 : ClockResolutionNs()
      88                 : {
      89                 :   // NB: why not rely on clock_getres()?  Two reasons: (i) it might
      90                 :   // lie, and (ii) it might return an "ideal" resolution that while
      91                 :   // theoretically true, could never be measured in practice.  Since
      92                 :   // clock_gettime() likely involves a system call on your platform,
      93                 :   // the "actual" timing resolution shouldn't be lower than syscall
      94                 :   // overhead.
      95                 : 
      96            1464 :   PRUint64 start = ClockTimeNs();
      97            1464 :   PRUint64 end = ClockTimeNs();
      98            1464 :   PRUint64 minres = (end - start);
      99                 : 
     100                 :   // 10 total trials is arbitrary: what we're trying to avoid by
     101                 :   // looping is getting unlucky and being interrupted by a context
     102                 :   // switch or signal, or being bitten by paging/cache effects
     103           14640 :   for (int i = 0; i < 9; ++i) {
     104           13176 :     start = ClockTimeNs();
     105           13176 :     end = ClockTimeNs();
     106                 : 
     107           13176 :     PRUint64 candidate = (start - end);
     108           13176 :     if (candidate < minres)
     109              39 :       minres = candidate;
     110                 :   }
     111                 : 
     112            1464 :   if (0 == minres) {
     113                 :     // measurable resolution is either incredibly low, ~1ns, or very
     114                 :     // high.  fall back on clock_getres()
     115                 :     struct timespec ts;
     116             745 :     if (0 == clock_getres(CLOCK_MONOTONIC, &ts)) {
     117             745 :       minres = TimespecToNs(ts);
     118                 :     }
     119                 :   }
     120                 : 
     121            1464 :   if (0 == minres) {
     122                 :     // clock_getres probably failed.  fall back on NSPR's resolution
     123                 :     // assumption
     124               0 :     minres = 1 * kNsPerMs;
     125                 :   }
     126                 : 
     127            1464 :   return minres;
     128                 : }
     129                 : 
     130                 : 
     131                 : namespace mozilla {
     132                 : 
     133                 : double
     134          905803 : TimeDuration::ToSeconds() const
     135                 : {
     136          905803 :   return double(mValue) / kNsPerSecd;
     137                 : }
     138                 : 
     139                 : double
     140               0 : TimeDuration::ToSecondsSigDigits() const
     141                 : {
     142                 :   // don't report a value < mResolution ...
     143               0 :   PRInt64 valueSigDigs = sResolution * (mValue / sResolution);
     144                 :   // and chop off insignificant digits
     145               0 :   valueSigDigs = sResolutionSigDigs * (valueSigDigs / sResolutionSigDigs);
     146               0 :   return double(valueSigDigs) / kNsPerSecd;
     147                 : }
     148                 : 
     149                 : TimeDuration
     150           72098 : TimeDuration::FromMilliseconds(double aMilliseconds)
     151                 : {
     152           72098 :   return TimeDuration::FromTicks(aMilliseconds * kNsPerMsd);
     153                 : }
     154                 : 
     155                 : TimeDuration
     156               0 : TimeDuration::Resolution()
     157                 : {
     158               0 :   return TimeDuration::FromTicks(PRInt64(sResolution));
     159                 : }
     160                 : 
     161                 : struct TimeStampInitialization
     162                 : {
     163            1464 :   TimeStampInitialization() {
     164            1464 :     TimeStamp::Startup();
     165            1464 :   }
     166            1487 :   ~TimeStampInitialization() {
     167            1487 :     TimeStamp::Shutdown();
     168            1487 :   }
     169                 : };
     170                 : 
     171            1464 : static TimeStampInitialization initOnce;
     172                 : static bool gInitialized = false;
     173                 : 
     174                 : nsresult
     175            1464 : TimeStamp::Startup()
     176                 : {
     177            1464 :   if (gInitialized)
     178               0 :     return NS_OK;
     179                 : 
     180                 :   struct timespec dummy;
     181            1464 :   if (0 != clock_gettime(CLOCK_MONOTONIC, &dummy))
     182               0 :       NS_RUNTIMEABORT("CLOCK_MONOTONIC is absent!");
     183                 : 
     184            1464 :   sResolution = ClockResolutionNs();
     185                 : 
     186                 :   // find the number of significant digits in sResolution, for the
     187                 :   // sake of ToSecondsSigDigits()
     188           14094 :   for (sResolutionSigDigs = 1;
     189                 :        !(sResolutionSigDigs == sResolution
     190           14094 :          || 10*sResolutionSigDigs > sResolution);
     191                 :        sResolutionSigDigs *= 10);
     192                 : 
     193            1464 :   gInitialized = true;
     194            1464 :   return NS_OK;
     195                 : }
     196                 : 
     197                 : void
     198            1487 : TimeStamp::Shutdown()
     199                 : {
     200            1487 : }
     201                 : 
     202                 : TimeStamp
     203         1872421 : TimeStamp::Now()
     204                 : {
     205         1872421 :   return TimeStamp(ClockTimeNs());
     206                 : }
     207                 : 
     208            4392 : }

Generated by: LCOV version 1.7