Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / test / perf / generate_profile.cc
blobc749dfdd6652edb056ab0f8ccebf2cb8a510cf85
1 // Copyright (c) 2012 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.
5 #include "chrome/test/perf/generate_profile.h"
7 #include "base/at_exit.h"
8 #include "base/command_line.h"
9 #include "base/file_util.h"
10 #include "base/files/file_enumerator.h"
11 #include "base/files/file_path.h"
12 #include "base/i18n/icu_util.h"
13 #include "base/logging.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/path_service.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/time/time.h"
19 #include "chrome/browser/history/history_service.h"
20 #include "chrome/browser/history/history_service_factory.h"
21 #include "chrome/browser/history/top_sites.h"
22 #include "chrome/common/chrome_paths.h"
23 #include "chrome/common/thumbnail_score.h"
24 #include "chrome/test/base/testing_browser_process.h"
25 #include "chrome/test/base/testing_profile.h"
26 #include "chrome/tools/profiles/thumbnail-inl.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/test/test_browser_thread.h"
30 #include "third_party/skia/include/core/SkBitmap.h"
31 #include "ui/base/resource/resource_bundle.h"
32 #include "ui/base/ui_base_paths.h"
33 #include "ui/gfx/codec/jpeg_codec.h"
35 using base::Time;
36 using content::BrowserThread;
38 namespace {
40 // Probabilities of different word lengths, as measured from Darin's profile.
41 // kWordLengthProbabilities[n-1] = P(word of length n)
42 const float kWordLengthProbabilities[] = { 0.069f, 0.132f, 0.199f,
43 0.137f, 0.088f, 0.115f, 0.081f, 0.055f, 0.034f, 0.021f, 0.019f, 0.018f,
44 0.007f, 0.007f, 0.005f, 0.004f, 0.003f, 0.003f, 0.003f };
46 // Return a float uniformly in [0,1].
47 // Useful for making probabilistic decisions.
48 inline float RandomFloat() {
49 return rand() / static_cast<float>(RAND_MAX);
52 // Return an integer uniformly in [min,max).
53 inline int RandomInt(int min, int max) {
54 return min + (rand() % (max-min));
57 // Return a string of |count| lowercase random characters.
58 base::string16 RandomChars(int count) {
59 base::string16 str;
60 for (int i = 0; i < count; ++i)
61 str += L'a' + rand() % 26;
62 return str;
65 base::string16 RandomWord() {
66 // TODO(evanm): should we instead use the markov chain based
67 // version of this that I already wrote?
69 // Sample a word length from kWordLengthProbabilities.
70 float sample = RandomFloat();
71 size_t i;
72 for (i = 0; i < arraysize(kWordLengthProbabilities); ++i) {
73 sample -= kWordLengthProbabilities[i];
74 if (sample < 0) break;
76 const int word_length = i + 1;
77 return RandomChars(word_length);
80 // Return a string of |count| random words.
81 base::string16 RandomWords(int count) {
82 base::string16 str;
83 for (int i = 0; i < count; ++i) {
84 if (!str.empty())
85 str += L' ';
86 str += RandomWord();
88 return str;
91 // Return a random URL-looking string.
92 GURL ConstructRandomURL() {
93 return GURL(base::ASCIIToUTF16("http://") + RandomChars(3) +
94 base::ASCIIToUTF16(".com/") + RandomChars(RandomInt(5, 20)));
97 // Return a random page title-looking string.
98 base::string16 ConstructRandomTitle() {
99 return RandomWords(RandomInt(3, 15));
102 // Insert a batch of |batch_size| URLs, starting at pageid |page_id|.
103 void InsertURLBatch(Profile* profile,
104 int page_id,
105 int batch_size,
106 int types) {
107 HistoryService* history_service =
108 HistoryServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS);
110 // Probability of following a link on the current "page"
111 // (vs randomly jumping to a new page).
112 const float kFollowLinkProbability = 0.85f;
113 // Probability of visiting a page we've visited before.
114 const float kRevisitLinkProbability = 0.1f;
115 // Probability of a URL being "good enough" to revisit.
116 const float kRevisitableURLProbability = 0.05f;
117 // Probability of a URL being the end of a redirect chain.
118 const float kRedirectProbability = 0.05f;
120 // A list of URLs that we sometimes revisit.
121 std::vector<GURL> revisit_urls;
123 // Scoping value for page IDs (required by the history service).
124 void* id_scope = reinterpret_cast<void*>(1);
126 scoped_refptr<base::RefCountedMemory> google_bitmap(
127 new base::RefCountedStaticMemory(kGoogleThumbnail,
128 sizeof(kGoogleThumbnail)));
129 scoped_refptr<base::RefCountedMemory> weewar_bitmap(
130 new base::RefCountedStaticMemory(kWeewarThumbnail,
131 sizeof(kWeewarThumbnail)));
133 printf("Inserting %d URLs...\n", batch_size);
134 GURL previous_url;
135 content::PageTransition transition = content::PAGE_TRANSITION_TYPED;
136 const int end_page_id = page_id + batch_size;
137 history::TopSites* top_sites = profile->GetTopSites();
138 for (; page_id < end_page_id; ++page_id) {
139 // Randomly decide whether this new URL simulates following a link or
140 // whether it's a jump to a new URL.
141 if (!previous_url.is_empty() && RandomFloat() < kFollowLinkProbability) {
142 transition = content::PAGE_TRANSITION_LINK;
143 } else {
144 previous_url = GURL();
145 transition = content::PAGE_TRANSITION_TYPED;
148 // Pick a URL, either newly at random or from our list of previously
149 // visited URLs.
150 GURL url;
151 if (!revisit_urls.empty() && RandomFloat() < kRevisitLinkProbability) {
152 // Draw a URL from revisit_urls at random.
153 url = revisit_urls[RandomInt(0, static_cast<int>(revisit_urls.size()))];
154 } else {
155 url = ConstructRandomURL();
158 // Randomly construct a redirect chain.
159 history::RedirectList redirects;
160 if (RandomFloat() < kRedirectProbability) {
161 const int redir_count = RandomInt(1, 4);
162 for (int i = 0; i < redir_count; ++i)
163 redirects.push_back(ConstructRandomURL());
164 redirects.push_back(url);
167 // Add all of this information to the history service.
168 history_service->AddPage(url, base::Time::Now(),
169 id_scope, page_id,
170 previous_url, redirects,
171 transition, history::SOURCE_BROWSED, true);
172 ThumbnailScore score(0.75, false, false);
173 history_service->SetPageTitle(url, ConstructRandomTitle());
174 if (types & TOP_SITES && top_sites) {
175 top_sites->SetPageThumbnailToJPEGBytes(
176 url,
177 (RandomInt(0, 2) == 0) ? google_bitmap.get() : weewar_bitmap.get(),
178 score);
181 previous_url = url;
183 if (revisit_urls.empty() || RandomFloat() < kRevisitableURLProbability)
184 revisit_urls.push_back(url);
188 } // namespace
190 bool GenerateProfile(GenerateProfileTypes types,
191 int url_count,
192 const base::FilePath& dst_dir) {
193 if (!base::CreateDirectory(dst_dir)) {
194 PLOG(ERROR) << "Unable to create directory " << dst_dir.value().c_str();
195 return false;
198 // We want this profile to be as deterministic as possible, so seed the
199 // random number generator with the number of urls we're generating.
200 srand(static_cast<unsigned int>(url_count));
202 printf("Creating profiles for testing...\n");
204 TestingBrowserProcessInitializer initialize_browser_process;
205 base::MessageLoopForUI message_loop;
206 content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
207 content::TestBrowserThread db_thread(BrowserThread::DB, &message_loop);
208 TestingProfile profile;
209 if (!profile.CreateHistoryService(false, false)) {
210 PLOG(ERROR) << "Creating history service failed";
211 return false;
213 if (types & TOP_SITES) {
214 profile.CreateTopSites();
215 profile.BlockUntilTopSitesLoaded();
218 // The maximum number of URLs to insert into history in one batch.
219 const int kBatchSize = 2000;
220 int page_id = 0;
221 while (page_id < url_count) {
222 const int batch_size = std::min(kBatchSize, url_count - page_id);
223 InsertURLBatch(&profile, page_id, batch_size, types);
224 // Run all pending messages to give TopSites a chance to catch up.
225 message_loop.RunUntilIdle();
226 page_id += batch_size;
229 profile.DestroyTopSites();
230 profile.DestroyHistoryService();
232 message_loop.RunUntilIdle();
234 base::FileEnumerator file_iterator(profile.GetPath(), false,
235 base::FileEnumerator::FILES);
236 base::FilePath path = file_iterator.Next();
237 while (!path.empty()) {
238 base::FilePath dst_file = dst_dir.Append(path.BaseName());
239 base::DeleteFile(dst_file, false);
240 if (!base::CopyFile(path, dst_file)) {
241 PLOG(ERROR) << "Copying file failed";
242 return false;
244 path = file_iterator.Next();
247 printf("Finished creating profiles for testing.\n");
249 // Restore the random seed.
250 srand(static_cast<unsigned int>(Time::Now().ToInternalValue()));
252 return true;