1424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// found in the LICENSE file.
4424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
5424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include <cstdlib>
6424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include <fstream>
7424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include <iostream>
8424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include <string>
9424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include <vector>
10424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
11424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/at_exit.h"
12424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/bind.h"
13424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/callback.h"
14424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/command_line.h"
15424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/files/file_path.h"
16424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/logging.h"
17424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/memory/scoped_vector.h"
19424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/message_loop/message_loop.h"
20424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
21424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/run_loop.h"
22424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
23424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/strings/string_piece.h"
24424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/strings/string_split.h"
25424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/strings/stringprintf.h"
26424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "net/base/cache_type.h"
27424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "net/base/net_errors.h"
28424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "net/disk_cache/disk_cache.h"
29424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "net/disk_cache/simple/simple_backend_impl.h"
30424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "net/disk_cache/simple/simple_index.h"
31424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
32424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)namespace disk_cache {
33424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)namespace {
34424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
35424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kBlockFileBackendType[] = "block_file";
36424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kSimpleBackendType[] = "simple";
37424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
38424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kDiskCacheType[] = "disk_cache";
39424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kAppCacheType[] = "app_cache";
40424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
41424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kPrivateDirty[] = "Private_Dirty:";
42424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kReadWrite[] = "rw-";
43424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kHeap[] = "[heap]";
44424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kKb[] = "kB";
45424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)struct CacheSpec {
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public:
4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  static scoped_ptr<CacheSpec> Parse(const std::string& spec_string) {
4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    std::vector<std::string> tokens;
5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    base::SplitString(spec_string, ':', &tokens);
5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (tokens.size() != 3)
5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return scoped_ptr<CacheSpec>();
5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (tokens[0] != kBlockFileBackendType && tokens[0] != kSimpleBackendType)
5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return scoped_ptr<CacheSpec>();
5558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (tokens[1] != kDiskCacheType && tokens[1] != kAppCacheType)
5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return scoped_ptr<CacheSpec>();
5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return scoped_ptr<CacheSpec>(new CacheSpec(
5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        tokens[0] == kBlockFileBackendType ? net::CACHE_BACKEND_BLOCKFILE
5958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                           : net::CACHE_BACKEND_SIMPLE,
6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        tokens[1] == kDiskCacheType ? net::DISK_CACHE : net::APP_CACHE,
6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        base::FilePath(tokens[2])));
6258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const net::BackendType backend_type;
6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const net::CacheType cache_type;
6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const base::FilePath path;
6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) private:
6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  CacheSpec(net::BackendType backend_type,
7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            net::CacheType cache_type,
7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            const base::FilePath& path)
7258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      : backend_type(backend_type),
7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        cache_type(cache_type),
7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        path(path) {
7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)};
7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
78424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void SetSuccessCodeOnCompletion(base::RunLoop* run_loop,
79424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                bool* succeeded,
80424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                int net_error) {
81424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (net_error == net::OK) {
82424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    *succeeded = true;
83424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  } else {
84424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    *succeeded = false;
85424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
86424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  run_loop->Quit();
87424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
88424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)scoped_ptr<Backend> CreateAndInitBackend(const CacheSpec& spec) {
90424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  scoped_ptr<Backend> result;
91424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  scoped_ptr<Backend> backend;
92424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  bool succeeded = false;
93424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  base::RunLoop run_loop;
94424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  const net::CompletionCallback callback = base::Bind(
95424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      &SetSuccessCodeOnCompletion,
96424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      base::Unretained(&run_loop),
97424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      base::Unretained(&succeeded));
98424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  const int net_error = CreateCacheBackend(
9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      spec.cache_type, spec.backend_type, spec.path, 0, false,
100424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      base::MessageLoopProxy::current(), NULL, &backend, callback);
101424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (net_error == net::OK)
102424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    callback.Run(net::OK);
103424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  else
104424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    run_loop.Run();
105424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!succeeded) {
106424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    LOG(ERROR) << "Could not initialize backend in "
10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)               << spec.path.LossyDisplayName();
108424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return result.Pass();
109424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
110424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // For the simple cache, the index may not be initialized yet.
11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (spec.backend_type == net::CACHE_BACKEND_SIMPLE) {
112424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    base::RunLoop index_run_loop;
113424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const net::CompletionCallback index_callback = base::Bind(
114424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        &SetSuccessCodeOnCompletion,
115424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        base::Unretained(&index_run_loop),
116424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        base::Unretained(&succeeded));
117424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    SimpleBackendImpl* simple_backend =
118424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        static_cast<SimpleBackendImpl*>(backend.get());
119424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const int index_net_error =
120424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        simple_backend->index()->ExecuteWhenReady(index_callback);
121424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (index_net_error == net::OK)
122424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      index_callback.Run(net::OK);
123424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    else
124424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      index_run_loop.Run();
125424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (!succeeded) {
126424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      LOG(ERROR) << "Could not initialize Simple Cache in "
12758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                 << spec.path.LossyDisplayName();
128424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return result.Pass();
129424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
130424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
131424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(backend);
132424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  result.swap(backend);
133424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return result.Pass();
134424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
135424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
136424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Parses range lines from /proc/<PID>/smaps, e.g. (anonymous read write):
137424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// 7f819d88b000-7f819d890000 rw-p 00000000 00:00 0
138424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)bool ParseRangeLine(const std::string& line,
139424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                    std::vector<std::string>* tokens,
140424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                    bool* is_anonymous_read_write) {
141424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  tokens->clear();
142424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  base::SplitStringAlongWhitespace(line, tokens);
143424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (tokens->size() == 5) {
144424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const std::string& mode = (*tokens)[1];
145424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    *is_anonymous_read_write = !mode.compare(0, 3, kReadWrite);
146424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return true;
147424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
148424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // On Android, most of the memory is allocated in the heap, instead of being
149424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // mapped.
150424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (tokens->size() == 6) {
151424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const std::string& type = (*tokens)[5];
152424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    *is_anonymous_read_write = (type == kHeap);
153424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return true;
154424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
155424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return false;
156424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
157424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
158424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Parses range property lines from /proc/<PID>/smaps, e.g.:
159424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Private_Dirty:        16 kB
160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)//
161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Returns |false| iff it recognizes a new range line. Outputs non-zero |size|
162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// only if parsing succeeded.
163424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)bool ParseRangeProperty(const std::string& line,
164424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        std::vector<std::string>* tokens,
165424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        uint64* size,
166424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        bool* is_private_dirty) {
167424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  tokens->clear();
168424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  base::SplitStringAlongWhitespace(line, tokens);
169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // If the line is long, attempt to parse new range outside of this scope.
171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (tokens->size() > 3)
172424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Skip the line on other parsing error occasions.
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (tokens->size() < 3)
176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return true;
177424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  const std::string& type = (*tokens)[0];
178424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (type != kPrivateDirty)
179424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return true;
180424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  const std::string& unit = (*tokens)[2];
181424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (unit != kKb) {
182424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    LOG(WARNING) << "Discarding value not in kB: " << line;
183424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return true;
184424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
185424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  const std::string& size_str = (*tokens)[1];
186424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  uint64 map_size = 0;
187424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!base::StringToUint64(size_str, &map_size))
188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return true;
189424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  *is_private_dirty = true;
190424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  *size = map_size;
191424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return true;
192424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
193424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
194424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)uint64 GetMemoryConsumption() {
195424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  std::ifstream maps_file(
196424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      base::StringPrintf("/proc/%d/smaps", getpid()).c_str());
197424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!maps_file.good()) {
198424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    LOG(ERROR) << "Could not open smaps file.";
199424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
200424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
201424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  std::string line;
202424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  std::vector<std::string> tokens;
203424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  uint64 total_size = 0;
204424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!std::getline(maps_file, line) || line.empty())
205424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return total_size;
206424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  while (true) {
207424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    bool is_anonymous_read_write = false;
208424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (!ParseRangeLine(line, &tokens, &is_anonymous_read_write)) {
209424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      LOG(WARNING) << "Parsing smaps - did not expect line: " << line;
210424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
211424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (!std::getline(maps_file, line) || line.empty())
212424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return total_size;
213424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    bool is_private_dirty = false;
214424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    uint64 size = 0;
215424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    while (ParseRangeProperty(line, &tokens, &size, &is_private_dirty)) {
216424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      if (is_anonymous_read_write && is_private_dirty) {
217424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        total_size += size;
218424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        is_private_dirty = false;
219424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      }
220424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      if (!std::getline(maps_file, line) || line.empty())
221424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        return total_size;
222424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
223424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
224424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return total_size;
225424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
226424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
22758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool CacheMemTest(const ScopedVector<CacheSpec>& specs) {
22858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  ScopedVector<Backend> backends;
22958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  ScopedVector<CacheSpec>::const_iterator it;
23058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (it = specs.begin(); it != specs.end(); ++it) {
23158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    scoped_ptr<Backend> backend = CreateAndInitBackend(**it);
23258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!backend)
23358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return false;
23458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    std::cout << "Number of entries in " << (*it)->path.LossyDisplayName()
23558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              << " : " << backend->GetEntryCount() << std::endl;
23658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    backends.push_back(backend.release());
23758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
238424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  const uint64 memory_consumption = GetMemoryConsumption();
239424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  std::cout << "Private dirty memory: " << memory_consumption << " kB"
240424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            << std::endl;
241424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return true;
242424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
243424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
244424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void PrintUsage(std::ostream* stream) {
24558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  *stream << "Usage: disk_cache_mem_test "
24658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          << "--spec-1=<spec> "
24758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          << "[--spec-2=<spec>]"
248424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          << std::endl
24958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          << "  with <cache_spec>=<backend_type>:<cache_type>:<cache_path>"
25058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          << std::endl
25158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          << "       <backend_type>='block_file'|'simple'" << std::endl
252424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          << "       <cache_type>='disk_cache'|'app_cache'" << std::endl
253424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          << "       <cache_path>=file system path" << std::endl;
254424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
255424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
25658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool ParseAndStoreSpec(const std::string& spec_str,
25758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                       ScopedVector<CacheSpec>* specs) {
25858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  scoped_ptr<CacheSpec> spec = CacheSpec::Parse(spec_str);
25958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!spec) {
26058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    PrintUsage(&std::cerr);
26158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
26258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
26358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  specs->push_back(spec.release());
26458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return true;
26558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
26658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
267424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)bool Main(int argc, char** argv) {
268424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  base::AtExitManager at_exit_manager;
269424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  base::MessageLoopForIO message_loop;
27046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::CommandLine::Init(argc, argv);
27146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const base::CommandLine& command_line =
27246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      *base::CommandLine::ForCurrentProcess();
273424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (command_line.HasSwitch("help")) {
274424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    PrintUsage(&std::cout);
275424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return true;
276424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
27758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if ((command_line.GetSwitches().size() != 1 &&
27858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)       command_line.GetSwitches().size() != 2) ||
27958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      !command_line.HasSwitch("spec-1") ||
28058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      (command_line.GetSwitches().size() == 2 &&
28158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)       !command_line.HasSwitch("spec-2"))) {
282424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    PrintUsage(&std::cerr);
283424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
284424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
28558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  ScopedVector<CacheSpec> specs;
28658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const std::string spec_str_1 = command_line.GetSwitchValueASCII("spec-1");
28758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!ParseAndStoreSpec(spec_str_1, &specs))
288424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
28958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (command_line.HasSwitch("spec-2")) {
29058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string spec_str_2 = command_line.GetSwitchValueASCII("spec-2");
29158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!ParseAndStoreSpec(spec_str_2, &specs))
29258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return false;
293424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
29458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return CacheMemTest(specs);
295424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
296424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
297424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}  // namespace
298424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}  // namespace disk_cache
299424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
300424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)int main(int argc, char** argv) {
301424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return !disk_cache::Main(argc, argv);
302424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
303