Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(203)

Side by Side Diff: chrome/browser/private_working_set_snapshot_win.cc

Issue 2098713003: Moved a bunch of win-specific files to the new win folder in chrome/browser (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/private_working_set_snapshot.h"
6
7 #include <pdh.h>
8 #include <pdhmsg.h>
9 #include <stddef.h>
10
11 #include <algorithm>
12
13 #include "base/numerics/safe_conversions.h"
14 #include "base/win/windows_version.h"
15
16 PrivateWorkingSetSnapshot::PrivateWorkingSetSnapshot() {}
17
18 PrivateWorkingSetSnapshot::~PrivateWorkingSetSnapshot() {}
19
20 void PrivateWorkingSetSnapshot::Initialize() {
21 DCHECK(!initialized_);
22
23 // Set this to true whether initialization succeeds or not. That is, only try
24 // once.
25 initialized_ = true;
26
27 // The Pdh APIs are supported on Windows XP and above, but the "Working Set -
28 // Private" counter that PrivateWorkingSetSnapshot depends on is not defined
29 // until Windows Vista and is not reliable until Windows 7. Early-out to avoid
30 // wasted effort. All queries will return zero and will have to use the
31 // fallback calculations.
32 if (base::win::GetVersion() <= base::win::VERSION_VISTA) {
33 process_names_.clear();
34 return;
35 }
36
37 // Pdh.dll has a format-string bug that causes crashes on Windows 8 and 8.1.
38 // This was patched (around October 2014) but the broken versions are still on
39 // a few machines. CreateFileVersionInfoForModule touches the disk so it
40 // be used on the main thread. If this call gets moved off of the main thread
41 // then pdh.dll version checking can be found in the history of
42 // https://codereview.chromium.org/1269223005
43
44 // Create a Pdh query
45 PDH_HQUERY query_handle;
46 if (PdhOpenQuery(NULL, NULL, &query_handle) != ERROR_SUCCESS) {
47 process_names_.clear();
48 return;
49 }
50
51 query_handle_.Set(query_handle);
52
53 for (const auto& process_name : process_names_) {
54 AddToMonitorList(process_name);
55 }
56 process_names_.clear();
57 }
58
59 void PrivateWorkingSetSnapshot::AddToMonitorList(
60 const std::string& process_name) {
61 if (!query_handle_.IsValid()) {
62 // Save the name for later.
63 if (!initialized_)
64 process_names_.push_back(process_name);
65 return;
66 }
67
68 // Create the magic strings that will return a list of process IDs and a list
69 // of private working sets. The 'process_name' variable should be something
70 // like "chrome". The '*' character indicates that we want records for all
71 // processes whose names start with process_name - all chrome processes, but
72 // also all 'chrome_editor.exe' processes or other matching names. The excess
73 // information is unavoidable but harmless.
74 std::string process_id_query = "\\Process(" + process_name + "*)\\ID Process";
75 std::string private_ws_query =
76 "\\Process(" + process_name + "*)\\Working Set - Private";
77
78 // Add the two counters to the query.
79 PdhCounterPair new_counters;
80 if (PdhAddCounterA(query_handle_.Get(), process_id_query.c_str(), NULL,
81 &new_counters.process_id_handle) != ERROR_SUCCESS) {
82 return;
83 }
84
85 // If adding the second counter fails then we should remove the first one.
86 if (PdhAddCounterA(query_handle_.Get(), private_ws_query.c_str(), NULL,
87 &new_counters.private_ws_handle) != ERROR_SUCCESS) {
88 PdhRemoveCounter(new_counters.process_id_handle);
89 }
90
91 // Record the pair of counter query handles so that we can query them later.
92 counter_pairs_.push_back(new_counters);
93 }
94
95 void PrivateWorkingSetSnapshot::Sample() {
96 // Make sure this is called once.
97 if (!initialized_)
98 Initialize();
99
100 if (counter_pairs_.empty())
101 return;
102
103 // Destroy all previous data.
104 records_.resize(0);
105 // Record the requested data into PDH's internal buffers.
106 if (PdhCollectQueryData(query_handle_.Get()) != ERROR_SUCCESS)
107 return;
108
109 for (auto& counter_pair : counter_pairs_) {
110 // Find out how much space is required for the two counter arrays.
111 // A return code of PDH_MORE_DATA indicates that we should call again with
112 // the buffer size returned.
113 DWORD buffer_size1 = 0;
114 DWORD item_count1 = 0;
115 // Process IDs should be retrieved as PDH_FMT_LONG
116 if (PdhGetFormattedCounterArray(
117 counter_pair.process_id_handle, PDH_FMT_LONG, &buffer_size1,
118 &item_count1, nullptr) != static_cast<PDH_STATUS>(PDH_MORE_DATA))
119 continue;
120 if (buffer_size1 == 0 || item_count1 == 0)
121 continue;
122
123 DWORD buffer_size2 = 0;
124 DWORD item_count2 = 0;
125 // Working sets should be retrieved as PDH_FMT_LARGE (LONGLONG)
126 // Note that if this second call to PdhGetFormattedCounterArray with the
127 // buffer size and count variables being zero is omitted then the PID and
128 // working-set results are not reliably correlated.
129 if (PdhGetFormattedCounterArray(
130 counter_pair.private_ws_handle, PDH_FMT_LARGE, &buffer_size2,
131 &item_count2, nullptr) != static_cast<PDH_STATUS>(PDH_MORE_DATA))
132 continue;
133
134 // It is not clear whether Pdh guarantees that the two counters in the same
135 // query will execute atomically - if they will see the same set of
136 // processes. If they do not then the correspondence between "ID Process"
137 // and "Working Set - Private" is lost and we have to discard these results.
138 // In testing these values have always matched. If this check fails then
139 // the old per-process memory calculations will be used instead.
140 if (buffer_size1 != buffer_size2 || item_count1 != item_count2)
141 continue;
142
143 // Allocate enough space for the results of both queries.
144 std::vector<char> buffer(buffer_size1 * 2);
145 // Retrieve the process ID data.
146 auto process_id_data =
147 reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(&buffer[0]);
148 if (PdhGetFormattedCounterArray(counter_pair.process_id_handle,
149 PDH_FMT_LONG, &buffer_size1, &item_count1,
150 process_id_data) != ERROR_SUCCESS)
151 continue;
152 // Retrieve the private working set data.
153 auto private_ws_data =
154 reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(&buffer[buffer_size1]);
155 if (PdhGetFormattedCounterArray(counter_pair.private_ws_handle,
156 PDH_FMT_LARGE, &buffer_size1, &item_count1,
157 private_ws_data) != ERROR_SUCCESS)
158 continue;
159
160 // Make room for the new set of records.
161 size_t start_offset = records_.size();
162 records_.resize(start_offset + item_count1);
163
164 for (DWORD i = 0; i < item_count1; ++i) {
165 records_[start_offset + i].process_id =
166 process_id_data[i].FmtValue.longValue;
167 // Integer overflow can happen here if a 32-bit process is monitoring a
168 // 64-bit process so we do a saturated_cast.
169 records_[start_offset + i].private_ws =
170 base::saturated_cast<size_t>(private_ws_data[i].FmtValue.largeValue);
171 }
172 }
173
174 // The results will include all processes that match the passed in name,
175 // regardless of whether they are spawned by the calling process.
176 // The results must be sorted by process ID for efficient lookup.
177 std::sort(records_.begin(), records_.end());
178 }
179
180 size_t PrivateWorkingSetSnapshot::GetPrivateWorkingSet(
181 base::ProcessId process_id) const {
182 // Do a binary search for the requested process ID and return the working set
183 // if found.
184 auto p = std::lower_bound(records_.begin(), records_.end(), process_id);
185 if (p != records_.end() && p->process_id == process_id)
186 return p->private_ws;
187
188 return 0;
189 }
OLDNEW
« no previous file with comments | « chrome/browser/private_working_set_snapshot.h ('k') | chrome/browser/private_working_set_snapshot_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698