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

Side by Side Diff: base/process/private_working_set_snapshot_win.cc

Issue 1181263005: Make task manager memory data more efficient and meaningful. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Reduced PdhGetFormattedCounterArray calls and now presubmit clean 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 "base/process/private_working_set_snapshot.h"
6
7 #include <algorithm>
8
9 #if defined(OS_WIN)
10 #include <pdh.h>
11 #include <pdhmsg.h>
12 #include <windows.h>
13 #endif
ncarter (slow) 2015/06/29 20:03:19 I'm fine For questions like this the best thing to
brucedawson 2015/06/29 22:09:52 I guess if I think of Windows header files as bein
14
15 #include "base/numerics/safe_conversions.h"
16 #include "base/win/windows_version.h"
17
18 namespace base {
19
20 PrivateWorkingSetSnapshot::PrivateWorkingSetSnapshot() {
21 // The Pdh APIs are supported on Windows XP, but the "Working Set - Private"
22 // counter that PrivateWorkingSetSnapshot depends on is not defined until
23 // Windows Vista. Early-out to avoid wasted effort. All queries will return
24 // zero and will have to use the fallback calculations.
25 if (base::win::GetVersion() < base::win::VERSION_VISTA)
26 return;
27
28 // Create a Pdh query
29 PDH_HQUERY query_handle;
30 if (PdhOpenQuery(NULL, NULL, &query_handle) != ERROR_SUCCESS) {
31 return;
32 }
33
34 query_handle_.Set(query_handle);
35 }
36
37 void PrivateWorkingSetSnapshot::AddToMonitorList(
38 const std::string& process_name) {
39 if (!query_handle_.IsValid())
40 return;
41
42 // Create the magic strings that will return a list of process IDs and a list
43 // of private working sets. The 'process_name' variable should be something
44 // like "chrome". The '*' character indicates that we want records for all
45 // processes whose names start with process_name - all chrome processes, but
46 // also all 'chrome_editor.exe' processes or other matching names. The excess
47 // information is unavoidable but harmless.
48 std::string process_id_query = "\\Process(" + process_name + "*)\\ID Process";
49 std::string private_ws_query =
50 "\\Process(" + process_name + "*)\\Working Set - Private";
51
52 // Add the two counters to the query.
53 PdhCounterPair new_counters;
54 if (PdhAddCounterA(query_handle_.Get(), process_id_query.c_str(), NULL,
55 &new_counters.process_id_handle) != ERROR_SUCCESS) {
56 return;
57 }
58
59 // If adding the second counter fails then we should remove the first one.
60 if (PdhAddCounterA(query_handle_.Get(), private_ws_query.c_str(), NULL,
61 &new_counters.private_ws_handle) != ERROR_SUCCESS) {
62 PdhRemoveCounter(new_counters.process_id_handle);
63 }
64
65 // Record the pair of counter query handles so that we can query them later.
66 counter_pairs_.push_back(new_counters);
67 }
68
69 void PrivateWorkingSetSnapshot::Sample() {
70 if (counter_pairs_.empty())
71 return;
72
73 // Destroy all previous data.
74 records_.resize(0);
75 // Record the requested data into PDH's internal buffers.
76 if (PdhCollectQueryData(query_handle_.Get()) != ERROR_SUCCESS)
77 return;
78
79 for (auto& counter_pair : counter_pairs_) {
80 // Find out how much space is required for the two counter arrays.
81 // A return code of PDH_MORE_DATA indicates that we should call again with
82 // the buffer size returned.
83 DWORD buffer_size1 = 0;
84 DWORD item_count1 = 0;
85 // Process IDs should be retrieved as PDH_FMT_LONG
86 if (PdhGetFormattedCounterArray(counter_pair.process_id_handle,
87 PDH_FMT_LONG, &buffer_size1, &item_count1,
88 nullptr) != PDH_MORE_DATA)
89 continue;
90
91 // Allocate enough space for the results of both queries.
92 std::vector<char> buffer(buffer_size1 * 2);
93 // Retrieve the process ID data.
94 auto process_id_data =
95 reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(&buffer[0]);
ncarter (slow) 2015/06/29 20:03:19 I'm fine leaving this as &buffer[0], but do we nee
brucedawson 2015/06/29 22:09:52 Good point. I meant to add a zero-size check to av
96 DWORD buffer_size2 = buffer_size1;
97 DWORD item_count2 = item_count1;
98 if (PdhGetFormattedCounterArray(counter_pair.process_id_handle,
99 PDH_FMT_LONG, &buffer_size2, &item_count2,
100 process_id_data) != ERROR_SUCCESS)
101 continue;
102 // Make sure we retrieved exactly the amount of data we expected.
103 if (buffer_size2 != buffer_size1 || item_count2 != item_count1)
104 continue;
105
106 // Retrieve the private working set data.
107 auto private_ws_data =
108 reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(&buffer[buffer_size1]);
109 if (PdhGetFormattedCounterArray(counter_pair.private_ws_handle,
110 PDH_FMT_LARGE, &buffer_size2, &item_count2,
111 private_ws_data) != ERROR_SUCCESS)
112 continue;
113 // Make sure the working-set data size/count matches the process id
114 // size/count - otherwise matching them up won't make sense. They do seem to
115 // always match.
116 if (buffer_size2 != buffer_size1 || item_count2 != item_count1)
117 continue;
118
119 // Make room for the new set of records.
120 size_t start_offset = records_.size();
121 records_.resize(start_offset + item_count1);
122
123 for (DWORD i = 0; i < item_count1; ++i) {
124 records_[start_offset + i].process_id =
125 process_id_data[i].FmtValue.longValue;
126 // Integer overflow can happen here if a 32-bit process is monitoring a
127 // 64-bit process so we do a saturated_cast.
128 records_[start_offset + i].private_ws =
129 saturated_cast<size_t>(private_ws_data[i].FmtValue.largeValue);
130 }
131 }
132
133 // The results will include all processes that match the passed in name,
134 // regardless of whether they are spawned by the calling process.
135 // The results must be sorted by process ID for efficient lookup.
136 std::sort(records_.begin(), records_.end());
137 }
138
139 size_t PrivateWorkingSetSnapshot::GetPrivateWorkingSet(
140 base::ProcessId process_id) const {
141 // Do a binary search for the requested process ID and return the working set
142 // if found.
143 auto p = std::lower_bound(records_.begin(), records_.end(), process_id);
144 if (p != records_.end() && p->process_id == process_id)
145 return p->private_ws;
146
147 return 0;
148 }
149
150 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698