Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/toolkit/components/telemetry/other/TelemetryIOInterposeObserver.cpp
Line
Count
Source (jump to first uncovered line)
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
#include "TelemetryIOInterposeObserver.h"
8
#include "core/TelemetryCommon.h"
9
10
namespace mozilla {
11
namespace Telemetry {
12
13
TelemetryIOInterposeObserver::TelemetryIOInterposeObserver(nsIFile* aXreDir)
14
  : mCurStage(STAGE_STARTUP)
15
3
{
16
3
  nsAutoString xreDirPath;
17
3
  nsresult rv = aXreDir->GetPath(xreDirPath);
18
3
  if (NS_SUCCEEDED(rv)) {
19
3
    AddPath(xreDirPath, NS_LITERAL_STRING("{xre}"));
20
3
  }
21
3
}
22
23
void TelemetryIOInterposeObserver::AddPath(const nsAString& aPath,
24
                                           const nsAString& aSubstName)
25
3
{
26
3
  mSafeDirs.AppendElement(SafeDir(aPath, aSubstName));
27
3
}
28
29
// Threshold for reporting slow main-thread I/O (50 milliseconds).
30
const TimeDuration kTelemetryReportThreshold = TimeDuration::FromMilliseconds(50);
31
32
void TelemetryIOInterposeObserver::Observe(Observation& aOb)
33
54
{
34
54
  // We only report main-thread I/O
35
54
  if (!IsMainThread()) {
36
0
    return;
37
0
  }
38
54
39
54
  if (aOb.ObservedOperation() == OpNextStage) {
40
0
    mCurStage = NextStage(mCurStage);
41
0
    MOZ_ASSERT(mCurStage < NUM_STAGES);
42
0
    return;
43
0
  }
44
54
45
54
  if (aOb.Duration() < kTelemetryReportThreshold) {
46
54
    return;
47
54
  }
48
0
49
0
  // Get the filename
50
0
  nsAutoString filename;
51
0
  aOb.Filename(filename);
52
0
53
0
  // Discard observations without filename
54
0
  if (filename.IsEmpty()) {
55
0
    return;
56
0
  }
57
0
58
#if defined(XP_WIN)
59
  nsCaseInsensitiveStringComparator comparator;
60
#else
61
0
  nsDefaultStringComparator comparator;
62
0
#endif
63
0
  nsAutoString      processedName;
64
0
  uint32_t safeDirsLen = mSafeDirs.Length();
65
0
  for (uint32_t i = 0; i < safeDirsLen; ++i) {
66
0
    if (StringBeginsWith(filename, mSafeDirs[i].mPath, comparator)) {
67
0
      processedName = mSafeDirs[i].mSubstName;
68
0
      processedName += Substring(filename, mSafeDirs[i].mPath.Length());
69
0
      break;
70
0
    }
71
0
  }
72
0
73
0
  if (processedName.IsEmpty()) {
74
0
    return;
75
0
  }
76
0
77
0
  // Create a new entry or retrieve the existing one
78
0
  FileIOEntryType* entry = mFileStats.PutEntry(processedName);
79
0
  if (entry) {
80
0
    FileStats& stats = entry->mData.mStats[mCurStage];
81
0
    // Update the statistics
82
0
    stats.totalTime += (double) aOb.Duration().ToMilliseconds();
83
0
    switch (aOb.ObservedOperation()) {
84
0
      case OpCreateOrOpen:
85
0
        stats.creates++;
86
0
        break;
87
0
      case OpRead:
88
0
        stats.reads++;
89
0
        break;
90
0
      case OpWrite:
91
0
        stats.writes++;
92
0
        break;
93
0
      case OpFSync:
94
0
        stats.fsyncs++;
95
0
        break;
96
0
      case OpStat:
97
0
        stats.stats++;
98
0
        break;
99
0
      default:
100
0
        break;
101
0
    }
102
0
  }
103
0
}
104
105
bool TelemetryIOInterposeObserver::ReflectFileStats(FileIOEntryType* entry,
106
                                                    JSContext *cx,
107
                                                    JS::Handle<JSObject*> obj)
108
0
{
109
0
  JS::AutoValueArray<NUM_STAGES> stages(cx);
110
0
111
0
  FileStatsByStage& statsByStage = entry->mData;
112
0
  for (int s = STAGE_STARTUP; s < NUM_STAGES; ++s) {
113
0
    FileStats& fileStats = statsByStage.mStats[s];
114
0
115
0
    if (fileStats.totalTime == 0 && fileStats.creates == 0 &&
116
0
        fileStats.reads == 0 && fileStats.writes == 0 &&
117
0
        fileStats.fsyncs == 0 && fileStats.stats == 0) {
118
0
      // Don't add an array that contains no information
119
0
      stages[s].setNull();
120
0
      continue;
121
0
    }
122
0
123
0
    // Array we want to report
124
0
    JS::AutoValueArray<6> stats(cx);
125
0
    stats[0].setNumber(fileStats.totalTime);
126
0
    stats[1].setNumber(fileStats.creates);
127
0
    stats[2].setNumber(fileStats.reads);
128
0
    stats[3].setNumber(fileStats.writes);
129
0
    stats[4].setNumber(fileStats.fsyncs);
130
0
    stats[5].setNumber(fileStats.stats);
131
0
132
0
    // Create jsStats as array of elements above
133
0
    JS::RootedObject jsStats(cx, JS_NewArrayObject(cx, stats));
134
0
    if (!jsStats) {
135
0
      continue;
136
0
    }
137
0
138
0
    stages[s].setObject(*jsStats);
139
0
  }
140
0
141
0
  JS::Rooted<JSObject*> jsEntry(cx, JS_NewArrayObject(cx, stages));
142
0
  if (!jsEntry) {
143
0
    return false;
144
0
  }
145
0
146
0
  // Add jsEntry to top-level dictionary
147
0
  const nsAString& key = entry->GetKey();
148
0
  return JS_DefineUCProperty(cx, obj, key.Data(), key.Length(),
149
0
                             jsEntry, JSPROP_ENUMERATE | JSPROP_READONLY);
150
0
}
151
152
bool TelemetryIOInterposeObserver::ReflectIntoJS(JSContext *cx,
153
                                                 JS::Handle<JSObject*> rootObj)
154
0
{
155
0
  return mFileStats.ReflectIntoJS(ReflectFileStats, cx, rootObj);
156
0
}
157
158
/**
159
 * Get size of hash table with file stats
160
 */
161
162
size_t TelemetryIOInterposeObserver::SizeOfIncludingThis
163
(mozilla::MallocSizeOf aMallocSizeOf) const
164
0
{
165
0
  return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
166
0
}
167
168
size_t TelemetryIOInterposeObserver::SizeOfExcludingThis
169
(mozilla::MallocSizeOf aMallocSizeOf) const
170
0
{
171
0
  size_t size = 0;
172
0
  size += mFileStats.ShallowSizeOfExcludingThis(aMallocSizeOf);
173
0
  for (auto iter = mFileStats.ConstIter(); !iter.Done(); iter.Next()) {
174
0
    size += iter.Get()->GetKey().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
175
0
  }
176
0
  size += mSafeDirs.ShallowSizeOfExcludingThis(aMallocSizeOf);
177
0
  uint32_t safeDirsLen = mSafeDirs.Length();
178
0
  for (uint32_t i = 0; i < safeDirsLen; ++i) {
179
0
    size += mSafeDirs[i].SizeOfExcludingThis(aMallocSizeOf);
180
0
  }
181
0
  return size;
182
0
}
183
184
} // namespace Telemetry
185
} // namespace mozilla