TimeStamp.cpp (4362B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * Implementation of the OS-independent methods of the TimeStamp class 9 */ 10 11 #include "mozilla/TimeStamp.h" 12 #include "mozilla/Uptime.h" 13 #include <string.h> 14 #include <stdlib.h> 15 16 namespace mozilla { 17 18 /** 19 * Wrapper class used to initialize static data used by the TimeStamp class 20 */ 21 struct TimeStampInitialization { 22 /** 23 * First timestamp taken when the class static initializers are run. This 24 * timestamp is used to sanitize timestamps coming from different sources. 25 */ 26 TimeStamp mFirstTimeStamp; 27 28 /** 29 * Timestamp representing the time when the process was created. This field 30 * is populated lazily the first time this information is required and is 31 * replaced every time the process is restarted. 32 */ 33 TimeStamp mProcessCreation; 34 35 TimeStampInitialization() { 36 TimeStamp::Startup(); 37 mFirstTimeStamp = TimeStamp::Now(); 38 // On Windows < 10, initializing the uptime requires `mFirstTimeStamp` to be 39 // valid. 40 mozilla::InitializeUptime(); 41 } 42 43 ~TimeStampInitialization() { TimeStamp::Shutdown(); } 44 }; 45 46 MOZ_RUNINIT static TimeStampInitialization sInitOnce; 47 48 MFBT_API TimeStamp TimeStamp::ProcessCreation() { 49 if (sInitOnce.mProcessCreation.IsNull()) { 50 char* mozAppRestart = getenv("MOZ_APP_RESTART"); 51 TimeStamp ts; 52 53 /* When calling PR_SetEnv() with an empty value the existing variable may 54 * be unset or set to the empty string depending on the underlying platform 55 * thus we have to check if the variable is present and not empty. */ 56 if (mozAppRestart && (strcmp(mozAppRestart, "") != 0)) { 57 /* Firefox was restarted, use the first time-stamp we've taken as the new 58 * process startup time. */ 59 ts = sInitOnce.mFirstTimeStamp; 60 } else { 61 TimeStamp now = Now(); 62 uint64_t uptime = ComputeProcessUptime(); 63 64 ts = now - TimeDuration::FromMicroseconds(static_cast<double>(uptime)); 65 66 if ((ts > sInitOnce.mFirstTimeStamp) || (uptime == 0)) { 67 ts = sInitOnce.mFirstTimeStamp; 68 } 69 } 70 71 sInitOnce.mProcessCreation = ts; 72 } 73 74 return sInitOnce.mProcessCreation; 75 } 76 77 void TimeStamp::RecordProcessRestart() { 78 sInitOnce.mProcessCreation = TimeStamp(); 79 } 80 81 MFBT_API TimeStamp TimeStamp::FirstTimeStamp() { 82 return sInitOnce.mFirstTimeStamp; 83 } 84 85 class TimeStampTests { 86 // Check that nullity is set/not set correctly. 87 static_assert(TimeStamp{TimeStampValue{0}}.IsNull()); 88 static_assert(!TimeStamp{TimeStampValue{1}}.IsNull()); 89 90 // Check that some very basic comparisons work correctly. 91 static constexpr uint64_t sMidTime = (uint64_t)1 << 63; 92 static_assert(TimeStampValue{sMidTime + 5} > TimeStampValue{sMidTime - 5}); 93 static_assert(TimeStampValue{sMidTime + 5} >= TimeStampValue{sMidTime - 5}); 94 static_assert(TimeStampValue{sMidTime - 5} < TimeStampValue{sMidTime + 5}); 95 static_assert(TimeStampValue{sMidTime - 5} <= TimeStampValue{sMidTime + 5}); 96 static_assert(TimeStampValue{sMidTime} == TimeStampValue{sMidTime}); 97 static_assert(TimeStampValue{sMidTime} >= TimeStampValue{sMidTime}); 98 static_assert(TimeStampValue{sMidTime} <= TimeStampValue{sMidTime}); 99 static_assert(TimeStampValue{sMidTime - 5} != TimeStampValue{sMidTime + 5}); 100 101 // Check that comparisons involving very large and very small TimeStampValue's 102 // work correctly. This may seem excessive, but these asserts would have 103 // failed in the past due to a comparison such as "a > b" being implemented as 104 // "<cast to signed 64-bit value>(a - b) > 0". When a-b didn't fit into a 105 // signed 64-bit value, this would have given an incorrect result. 106 static_assert(TimeStampValue{UINT64_MAX} > TimeStampValue{1}); 107 static_assert(TimeStampValue{1} < TimeStampValue{UINT64_MAX}); 108 109 // NOTE/TODO: It would be nice to add some additional tests here that involve 110 // arithmetic between TimeStamps and TimeDurations (and verifying some of the 111 // special behaviors in some cases such as not wrapping around below zero) but 112 // that is not possible right now because those operators are not constexpr. 113 }; 114 115 } // namespace mozilla