190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/process/process_metrics.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <windows.h>
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <psapi.h>
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/logging.h"
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/sys_info.h"
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace base {
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// System pagesize. This value remains constant on x86/64 architectures.
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int PAGESIZE_KB = 4;
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)ProcessMetrics::~ProcessMetrics() { }
1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return new ProcessMetrics(process);
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)size_t ProcessMetrics::GetPagefileUsage() const {
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  PROCESS_MEMORY_COUNTERS pmc;
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return pmc.PagefileUsage;
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return 0;
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Returns the peak space allocated for the pagefile, in bytes.
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)size_t ProcessMetrics::GetPeakPagefileUsage() const {
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  PROCESS_MEMORY_COUNTERS pmc;
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return pmc.PeakPagefileUsage;
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return 0;
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Returns the current working set size, in bytes.
4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)size_t ProcessMetrics::GetWorkingSetSize() const {
4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  PROCESS_MEMORY_COUNTERS pmc;
4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return pmc.WorkingSetSize;
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return 0;
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Returns the peak working set size, in bytes.
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)size_t ProcessMetrics::GetPeakWorkingSetSize() const {
5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  PROCESS_MEMORY_COUNTERS pmc;
5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return pmc.PeakWorkingSetSize;
5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return 0;
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                    size_t* shared_bytes) {
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // PROCESS_MEMORY_COUNTERS_EX is not supported until XP SP2.
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // GetProcessMemoryInfo() will simply fail on prior OS. So the requested
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // information is simply not available. Hence, we will return 0 on unsupported
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // OSes. Unlike most Win32 API, we don't need to initialize the "cb" member.
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  PROCESS_MEMORY_COUNTERS_EX pmcx;
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (private_bytes &&
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      GetProcessMemoryInfo(process_,
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmcx),
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           sizeof(pmcx))) {
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    *private_bytes = pmcx.PrivateUsage;
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (shared_bytes) {
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    WorkingSetKBytes ws_usage;
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!GetWorkingSetKBytes(&ws_usage))
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return false;
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    *shared_bytes = ws_usage.shared * 1024;
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return true;
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const {
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  MEMORY_BASIC_INFORMATION mbi = {0};
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  size_t committed_private = 0;
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  size_t committed_mapped = 0;
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  size_t committed_image = 0;
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void* base_address = NULL;
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  while (VirtualQueryEx(process_, base_address, &mbi, sizeof(mbi)) ==
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      sizeof(mbi)) {
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (mbi.State == MEM_COMMIT) {
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (mbi.Type == MEM_PRIVATE) {
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        committed_private += mbi.RegionSize;
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      } else if (mbi.Type == MEM_MAPPED) {
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        committed_mapped += mbi.RegionSize;
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      } else if (mbi.Type == MEM_IMAGE) {
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        committed_image += mbi.RegionSize;
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      } else {
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        NOTREACHED();
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    void* new_base = (static_cast<BYTE*>(mbi.BaseAddress)) + mbi.RegionSize;
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Avoid infinite loop by weird MEMORY_BASIC_INFORMATION.
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // If we query 64bit processes in a 32bit process, VirtualQueryEx()
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // returns such data.
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (new_base <= base_address) {
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      usage->image = 0;
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      usage->mapped = 0;
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      usage->priv = 0;
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return;
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base_address = new_base;
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  usage->image = committed_image / 1024;
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  usage->mapped = committed_mapped / 1024;
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  usage->priv = committed_private / 1024;
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  size_t ws_private = 0;
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  size_t ws_shareable = 0;
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  size_t ws_shared = 0;
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(ws_usage);
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  memset(ws_usage, 0, sizeof(*ws_usage));
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DWORD number_of_entries = 4096;  // Just a guess.
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  PSAPI_WORKING_SET_INFORMATION* buffer = NULL;
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int retries = 5;
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (;;) {
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) +
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                        (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK));
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // if we can't expand the buffer, don't leak the previous
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // contents or pass a NULL pointer to QueryWorkingSet
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    PSAPI_WORKING_SET_INFORMATION* new_buffer =
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        reinterpret_cast<PSAPI_WORKING_SET_INFORMATION*>(
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            realloc(buffer, buffer_size));
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!new_buffer) {
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      free(buffer);
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return false;
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    buffer = new_buffer;
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Call the function once to get number of items
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (QueryWorkingSet(process_, buffer, buffer_size))
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;  // Success
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (GetLastError() != ERROR_BAD_LENGTH) {
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      free(buffer);
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return false;
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    number_of_entries = static_cast<DWORD>(buffer->NumberOfEntries);
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Maybe some entries are being added right now. Increase the buffer to
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // take that into account.
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    number_of_entries = static_cast<DWORD>(number_of_entries * 1.25);
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (--retries == 0) {
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      free(buffer);  // If we're looping, eventually fail.
16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return false;
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // On windows 2000 the function returns 1 even when the buffer is too small.
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The number of entries that we are going to parse is the minimum between the
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // size we allocated and the real number of entries.
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  number_of_entries =
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      std::min(number_of_entries, static_cast<DWORD>(buffer->NumberOfEntries));
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (unsigned int i = 0; i < number_of_entries; i++) {
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (buffer->WorkingSetInfo[i].Shared) {
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      ws_shareable++;
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (buffer->WorkingSetInfo[i].ShareCount > 1)
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        ws_shared++;
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    } else {
17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      ws_private++;
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ws_usage->priv = ws_private * PAGESIZE_KB;
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ws_usage->shareable = ws_shareable * PAGESIZE_KB;
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ws_usage->shared = ws_shared * PAGESIZE_KB;
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  free(buffer);
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return true;
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)static uint64 FileTimeToUTC(const FILETIME& ftime) {
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  LARGE_INTEGER li;
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  li.LowPart = ftime.dwLowDateTime;
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  li.HighPart = ftime.dwHighDateTime;
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return li.QuadPart;
19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)double ProcessMetrics::GetCPUUsage() {
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FILETIME now;
19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FILETIME creation_time;
20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FILETIME exit_time;
20190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FILETIME kernel_time;
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FILETIME user_time;
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GetSystemTimeAsFileTime(&now);
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!GetProcessTimes(process_, &creation_time, &exit_time,
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       &kernel_time, &user_time)) {
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // We don't assert here because in some cases (such as in the Task Manager)
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // we may call this function on a process that has just exited but we have
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // not yet received the notification.
21190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return 0;
21290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int64 system_time = (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) /
21490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                        processor_count_;
21590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int64 time = FileTimeToUTC(now);
21690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if ((last_system_time_ == 0) || (last_time_ == 0)) {
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // First call, just set the last values.
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    last_system_time_ = system_time;
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    last_time_ = time;
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return 0;
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int64 system_time_delta = system_time - last_system_time_;
22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int64 time_delta = time - last_time_;
22690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_NE(0U, time_delta);
22790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (time_delta == 0)
22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return 0;
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // We add time_delta / 2 so the result is rounded.
23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int cpu = static_cast<int>((system_time_delta * 100 + time_delta / 2) /
23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                             time_delta);
23390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  last_system_time_ = system_time;
23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  last_time_ = time;
23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return cpu;
23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
23990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool ProcessMetrics::CalculateFreeMemory(FreeMBytes* free) const {
24190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const SIZE_T kTopAddress = 0x7F000000;
24290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const SIZE_T kMegabyte = 1024 * 1024;
24390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SIZE_T accumulated = 0;
24490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  MEMORY_BASIC_INFORMATION largest = {0};
24690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  UINT_PTR scan = 0;
24790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  while (scan < kTopAddress) {
24890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    MEMORY_BASIC_INFORMATION info;
24990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!::VirtualQueryEx(process_, reinterpret_cast<void*>(scan),
25090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          &info, sizeof(info)))
25190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return false;
25290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (info.State == MEM_FREE) {
25390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      accumulated += info.RegionSize;
25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (info.RegionSize > largest.RegionSize)
25590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        largest = info;
25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    scan += info.RegionSize;
25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  free->largest = largest.RegionSize / kMegabyte;
26090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  free->largest_ptr = largest.BaseAddress;
26190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  free->total = accumulated / kMegabyte;
26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return true;
26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return GetProcessIoCounters(process_, io_counters) != FALSE;
26790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
26890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
26990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)ProcessMetrics::ProcessMetrics(ProcessHandle process)
27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    : process_(process),
27190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      processor_count_(base::SysInfo::NumberOfProcessors()),
27290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      last_time_(0),
27390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      last_system_time_(0) {
27490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
27590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
27690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// GetPerformanceInfo is not available on WIN2K.  So we'll
27790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// load it on-the-fly.
27890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const wchar_t kPsapiDllName[] = L"psapi.dll";
27990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)typedef BOOL (WINAPI *GetPerformanceInfoFunction) (
28090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    PPERFORMANCE_INFORMATION pPerformanceInformation,
28190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DWORD cb);
28290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
28390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Beware of races if called concurrently from multiple threads.
28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)static BOOL InternalGetPerformanceInfo(
28590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    PPERFORMANCE_INFORMATION pPerformanceInformation, DWORD cb) {
28690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  static GetPerformanceInfoFunction GetPerformanceInfo_func = NULL;
28790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!GetPerformanceInfo_func) {
28890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    HMODULE psapi_dll = ::GetModuleHandle(kPsapiDllName);
28990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (psapi_dll)
29090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      GetPerformanceInfo_func = reinterpret_cast<GetPerformanceInfoFunction>(
29190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          GetProcAddress(psapi_dll, "GetPerformanceInfo"));
29290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!GetPerformanceInfo_func) {
29490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // The function could be loaded!
29590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      memset(pPerformanceInformation, 0, cb);
29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return FALSE;
29790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
29890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return GetPerformanceInfo_func(pPerformanceInformation, cb);
30090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
30190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
30290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)size_t GetSystemCommitCharge() {
30390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Get the System Page Size.
30490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SYSTEM_INFO system_info;
30590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GetSystemInfo(&system_info);
30690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
30790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  PERFORMANCE_INFORMATION info;
30890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!InternalGetPerformanceInfo(&info, sizeof(info))) {
30990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DLOG(ERROR) << "Failed to fetch internal performance info.";
31090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return 0;
31190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
31290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return (info.CommitTotal * system_info.dwPageSize) / 1024;
31390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
31490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
31590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace base
316