summaryrefslogtreecommitdiffstats
path: root/mozglue/misc/TimeStamp.cpp
blob: 0c02413e985db69078cdaf72c1482b42e87a9bed (plain)
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
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*
 * Implementation of the OS-independent methods of the TimeStamp class
 */

#include "mozilla/Atomics.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Uptime.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

namespace mozilla {

/**
 * Wrapper class used to initialize static data used by the TimeStamp class
 */
struct TimeStampInitialization {
  /**
   * First timestamp taken when the class static initializers are run. This
   * timestamp is used to sanitize timestamps coming from different sources.
   */
  TimeStamp mFirstTimeStamp;

  /**
   * Timestamp representing the time when the process was created. This field
   * is populated lazily the first time this information is required and is
   * replaced every time the process is restarted.
   */
  TimeStamp mProcessCreation;

  TimeStampInitialization() {
    TimeStamp::Startup();
    mFirstTimeStamp = TimeStamp::Now();
    // On Windows < 10, initializing the uptime requires `mFirstTimeStamp` to be
    // valid.
    mozilla::InitializeUptime();
  };

  ~TimeStampInitialization() { TimeStamp::Shutdown(); };
};

static bool sFuzzyfoxEnabled;

/* static */
bool TimeStamp::GetFuzzyfoxEnabled() { return sFuzzyfoxEnabled; }

/* static */
void TimeStamp::SetFuzzyfoxEnabled(bool aValue) { sFuzzyfoxEnabled = aValue; }

// These variables store the frozen time (as a TimeStamp) for FuzzyFox that
// will be reported if FuzzyFox is enabled.
// We overload the top bit of sCanonicalNow and sCanonicalGTC to
// indicate if a Timestamp is a fuzzed timestamp (bit set) or not
// (bit unset).
#ifdef XP_WIN
static Atomic<uint64_t> sCanonicalGTC;
static Atomic<uint64_t> sCanonicalQPC;
static Atomic<bool> sCanonicalHasQPC;
#else
static Atomic<uint64_t> sCanonicalNowTimeStamp;
#endif
static Atomic<int64_t> sCanonicalNowTime;
// This variable stores the frozen time (as ms since the epoch) for FuzzyFox
// to report if FuzzyFox is enabled.
static TimeStampInitialization sInitOnce;

MFBT_API TimeStamp TimeStamp::ProcessCreation(bool* aIsInconsistent) {
  if (aIsInconsistent) {
    *aIsInconsistent = false;
  }

  if (sInitOnce.mProcessCreation.IsNull()) {
    char* mozAppRestart = getenv("MOZ_APP_RESTART");
    TimeStamp ts;

    /* When calling PR_SetEnv() with an empty value the existing variable may
     * be unset or set to the empty string depending on the underlying platform
     * thus we have to check if the variable is present and not empty. */
    if (mozAppRestart && (strcmp(mozAppRestart, "") != 0)) {
      /* Firefox was restarted, use the first time-stamp we've taken as the new
       * process startup time. */
      ts = sInitOnce.mFirstTimeStamp;
    } else {
      TimeStamp now = Now();
      uint64_t uptime = ComputeProcessUptime();

      ts = now - TimeDuration::FromMicroseconds(uptime);

      if ((ts > sInitOnce.mFirstTimeStamp) || (uptime == 0)) {
        /* If the process creation timestamp was inconsistent replace it with
         * the first one instead and notify that a telemetry error was
         * detected. */
        if (aIsInconsistent) {
          *aIsInconsistent = true;
        }
        ts = sInitOnce.mFirstTimeStamp;
      }
    }

    sInitOnce.mProcessCreation = ts;
  }

  return sInitOnce.mProcessCreation;
}

void TimeStamp::RecordProcessRestart() {
  sInitOnce.mProcessCreation = TimeStamp();
}

MFBT_API TimeStamp TimeStamp::NowFuzzy(TimeStampValue aValue) {
#ifdef XP_WIN
  TimeStampValue canonicalNow =
      TimeStampValue(sCanonicalGTC, sCanonicalQPC, sCanonicalHasQPC, true);
#else
  TimeStampValue canonicalNow = TimeStampValue(sCanonicalNowTimeStamp);
#endif

  if (TimeStamp::GetFuzzyfoxEnabled()) {
    if (MOZ_LIKELY(!canonicalNow.IsNull())) {
      return TimeStamp(canonicalNow);
    }
  }
  // When we disable Fuzzyfox, time may goes backwards, so we need to make sure
  // we don't do that.
  else if (MOZ_UNLIKELY(canonicalNow > aValue)) {
    return TimeStamp(canonicalNow);
  }

  return TimeStamp(aValue);
}

MFBT_API void TimeStamp::UpdateFuzzyTimeStamp(TimeStamp aValue) {
#ifdef XP_WIN
  sCanonicalGTC = aValue.mValue.mGTC;
  sCanonicalQPC = aValue.mValue.mQPC;
  sCanonicalHasQPC = aValue.mValue.mHasQPC;
#else
  sCanonicalNowTimeStamp = aValue.mValue.mTimeStamp;
#endif
}

MFBT_API int64_t TimeStamp::NowFuzzyTime() { return sCanonicalNowTime; }

MFBT_API void TimeStamp::UpdateFuzzyTime(int64_t aValue) {
  sCanonicalNowTime = aValue;
}

}  // namespace mozilla