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

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

Issue 1219233002: Revert of Make task manager memory data more efficient and meaningful. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 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
10 #include <algorithm>
11
12 #include "base/numerics/safe_conversions.h"
13 #include "base/win/windows_version.h"
14
15 // Link pdh.lib (import library for pdh.dll) whenever this file is linked in.
16 #pragma comment(lib, "pdh.lib")
17
18 PrivateWorkingSetSnapshot::PrivateWorkingSetSnapshot() {
19 // The Pdh APIs are supported on Windows XP, but the "Working Set - Private"
20 // counter that PrivateWorkingSetSnapshot depends on is not defined until
21 // Windows Vista. Early-out to avoid wasted effort. All queries will return
22 // zero and will have to use the fallback calculations.
23 if (base::win::GetVersion() < base::win::VERSION_VISTA)
24 return;
25
26 // Create a Pdh query
27 PDH_HQUERY query_handle;
28 if (PdhOpenQuery(NULL, NULL, &query_handle) != ERROR_SUCCESS) {
29 return;
30 }
31
32 query_handle_.Set(query_handle);
33 }
34
35 PrivateWorkingSetSnapshot::~PrivateWorkingSetSnapshot() {
36 }
37
38 void PrivateWorkingSetSnapshot::AddToMonitorList(
39 const std::string& process_name) {
40 if (!query_handle_.IsValid())
41 return;
42
43 // Create the magic strings that will return a list of process IDs and a list
44 // of private working sets. The 'process_name' variable should be something
45 // like "chrome". The '*' character indicates that we want records for all
46 // processes whose names start with process_name - all chrome processes, but
47 // also all 'chrome_editor.exe' processes or other matching names. The excess
48 // information is unavoidable but harmless.
49 std::string process_id_query = "\\Process(" + process_name + "*)\\ID Process";
50 std::string private_ws_query =
51 "\\Process(" + process_name + "*)\\Working Set - Private";
52
53 // Add the two counters to the query.
54 PdhCounterPair new_counters;
55 if (PdhAddCounterA(query_handle_.Get(), process_id_query.c_str(), NULL,
56 &new_counters.process_id_handle) != ERROR_SUCCESS) {
57 return;
58 }
59
60 // If adding the second counter fails then we should remove the first one.
61 if (PdhAddCounterA(query_handle_.Get(), private_ws_query.c_str(), NULL,
62 &new_counters.private_ws_handle) != ERROR_SUCCESS) {
63 PdhRemoveCounter(new_counters.process_id_handle);
64 }
65
66 // Record the pair of counter query handles so that we can query them later.
67 counter_pairs_.push_back(new_counters);
68 }
69
70 void PrivateWorkingSetSnapshot::Sample() {
71 if (counter_pairs_.empty())
72 return;
73
74 // Destroy all previous data.
75 records_.resize(0);
76 // Record the requested data into PDH's internal buffers.
77 if (PdhCollectQueryData(query_handle_.Get()) != ERROR_SUCCESS)
78 return;
79
80 for (auto& counter_pair : counter_pairs_) {
81 // Find out how much space is required for the two counter arrays.
82 // A return code of PDH_MORE_DATA indicates that we should call again with
83 // the buffer size returned.
84 DWORD buffer_size1 = 0;
85 DWORD item_count1 = 0;
86 // Process IDs should be retrieved as PDH_FMT_LONG
87 if (PdhGetFormattedCounterArray(counter_pair.process_id_handle,
88 PDH_FMT_LONG, &buffer_size1, &item_count1,
89 nullptr) != PDH_MORE_DATA)
90 continue;
91 if (buffer_size1 == 0 || item_count1 == 0)
92 continue;
93
94 DWORD buffer_size2 = 0;
95 DWORD item_count2 = 0;
96 // Working sets should be retrieved as PDH_FMT_LARGE (LONGLONG)
97 // Note that if this second call to PdhGetFormattedCounterArray with the
98 // buffer size and count variables being zero is omitted then the PID and
99 // working-set results are not reliably correlated.
100 if (PdhGetFormattedCounterArray(counter_pair.private_ws_handle,
101 PDH_FMT_LARGE, &buffer_size2, &item_count2,
102 nullptr) != PDH_MORE_DATA)
103 continue;
104
105 // It is not clear whether Pdh guarantees that the two counters in the same
106 // query will execute atomically - if they will see the same set of
107 // processes. If they do not then the correspondence between "ID Process"
108 // and "Working Set - Private" is lost and we have to discard these results.
109 // In testing these values have always matched. If this check fails then
110 // the old per-process memory calculations will be used instead.
111 if (buffer_size1 != buffer_size2 || item_count1 != item_count2)
112 continue;
113
114 // Allocate enough space for the results of both queries.
115 std::vector<char> buffer(buffer_size1 * 2);
116 // Retrieve the process ID data.
117 auto process_id_data =
118 reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(&buffer[0]);
119 if (PdhGetFormattedCounterArray(counter_pair.process_id_handle,
120 PDH_FMT_LONG, &buffer_size1, &item_count1,
121 process_id_data) != ERROR_SUCCESS)
122 continue;
123 // Retrieve the private working set data.
124 auto private_ws_data =
125 reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(&buffer[buffer_size1]);
126 if (PdhGetFormattedCounterArray(counter_pair.private_ws_handle,
127 PDH_FMT_LARGE, &buffer_size1, &item_count1,
128 private_ws_data) != ERROR_SUCCESS)
129 continue;
130
131 // Make room for the new set of records.
132 size_t start_offset = records_.size();
133 records_.resize(start_offset + item_count1);
134
135 for (DWORD i = 0; i < item_count1; ++i) {
136 records_[start_offset + i].process_id =
137 process_id_data[i].FmtValue.longValue;
138 // Integer overflow can happen here if a 32-bit process is monitoring a
139 // 64-bit process so we do a saturated_cast.
140 records_[start_offset + i].private_ws =
141 base::saturated_cast<size_t>(private_ws_data[i].FmtValue.largeValue);
142 }
143 }
144
145 // The results will include all processes that match the passed in name,
146 // regardless of whether they are spawned by the calling process.
147 // The results must be sorted by process ID for efficient lookup.
148 std::sort(records_.begin(), records_.end());
149 }
150
151 size_t PrivateWorkingSetSnapshot::GetPrivateWorkingSet(
152 base::ProcessId process_id) const {
153 // Do a binary search for the requested process ID and return the working set
154 // if found.
155 auto p = std::lower_bound(records_.begin(), records_.end(), process_id);
156 if (p != records_.end() && p->process_id == process_id)
157 return p->private_ws;
158
159 return 0;
160 }
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