OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This program generates a user profile and history by randomly generating | 5 #include "chrome/test/perf/generate_profile.h" |
6 // data and feeding it to the history service. | |
7 | |
8 #include "chrome/tools/profiles/thumbnail-inl.h" | |
9 | 6 |
10 #include "base/at_exit.h" | 7 #include "base/at_exit.h" |
11 #include "base/command_line.h" | 8 #include "base/command_line.h" |
12 #include "base/file_util.h" | 9 #include "base/file_util.h" |
13 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
14 #include "base/i18n/icu_util.h" | 11 #include "base/i18n/icu_util.h" |
15 #include "base/logging.h" | 12 #include "base/logging.h" |
16 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
17 #include "base/path_service.h" | 14 #include "base/path_service.h" |
18 #include "base/process_util.h" | 15 #include "base/process_util.h" |
19 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
20 #include "base/time.h" | 17 #include "base/time.h" |
21 #include "base/utf_string_conversions.h" | 18 #include "base/utf_string_conversions.h" |
22 #include "chrome/browser/history/history_service.h" | 19 #include "chrome/browser/history/history_service.h" |
23 #include "chrome/browser/history/history_service_factory.h" | 20 #include "chrome/browser/history/history_service_factory.h" |
24 #include "chrome/browser/history/top_sites.h" | 21 #include "chrome/browser/history/top_sites.h" |
25 #include "chrome/common/chrome_paths.h" | 22 #include "chrome/common/chrome_paths.h" |
26 #include "chrome/common/thumbnail_score.h" | 23 #include "chrome/common/thumbnail_score.h" |
27 #include "chrome/test/base/testing_browser_process.h" | 24 #include "chrome/test/base/testing_browser_process.h" |
28 #include "chrome/test/base/testing_profile.h" | 25 #include "chrome/test/base/testing_profile.h" |
29 #include "content/browser/browser_thread_impl.h" | 26 #include "chrome/tools/profiles/thumbnail-inl.h" |
30 #include "content/public/browser/browser_thread.h" | 27 #include "content/public/browser/browser_thread.h" |
31 #include "content/public/browser/notification_service.h" | 28 #include "content/public/browser/notification_service.h" |
| 29 #include "content/public/test/test_browser_thread.h" |
32 #include "third_party/skia/include/core/SkBitmap.h" | 30 #include "third_party/skia/include/core/SkBitmap.h" |
33 #include "ui/base/resource/resource_bundle.h" | 31 #include "ui/base/resource/resource_bundle.h" |
34 #include "ui/base/ui_base_paths.h" | 32 #include "ui/base/ui_base_paths.h" |
35 #include "ui/gfx/codec/jpeg_codec.h" | 33 #include "ui/gfx/codec/jpeg_codec.h" |
36 | 34 |
37 #if defined(TOOLKIT_GTK) | |
38 #include <gtk/gtk.h> | |
39 #endif | |
40 | |
41 using base::Time; | 35 using base::Time; |
42 using content::BrowserThread; | 36 using content::BrowserThread; |
43 | 37 |
44 // Addition types data can be generated for. By default only urls/visits are | 38 namespace { |
45 // added. | |
46 enum Types { | |
47 TOP_SITES = 1 << 0, | |
48 FULL_TEXT = 1 << 1 | |
49 }; | |
50 | 39 |
51 // RAII for initializing and shutting down the TestBrowserProcess | 40 // RAII for initializing and shutting down the TestBrowserProcess |
52 class InitBrowserProcess { | 41 class InitBrowserProcess { |
53 public: | 42 public: |
54 InitBrowserProcess() { | 43 InitBrowserProcess() { |
55 DCHECK(!g_browser_process); | 44 DCHECK(!g_browser_process); |
56 g_browser_process = new TestingBrowserProcess; | 45 g_browser_process = new TestingBrowserProcess; |
57 } | 46 } |
58 | 47 |
59 ~InitBrowserProcess() { | 48 ~InitBrowserProcess() { |
60 DCHECK(g_browser_process); | 49 DCHECK(g_browser_process); |
61 delete g_browser_process; | 50 delete g_browser_process; |
62 g_browser_process = NULL; | 51 g_browser_process = NULL; |
63 } | 52 } |
64 }; | 53 }; |
65 | 54 |
66 // Probabilities of different word lengths, as measured from Darin's profile. | 55 // Probabilities of different word lengths, as measured from Darin's profile. |
67 // kWordLengthProbabilities[n-1] = P(word of length n) | 56 // kWordLengthProbabilities[n-1] = P(word of length n) |
68 const float kWordLengthProbabilities[] = { 0.069f, 0.132f, 0.199f, | 57 const float kWordLengthProbabilities[] = { 0.069f, 0.132f, 0.199f, |
69 0.137f, 0.088f, 0.115f, 0.081f, 0.055f, 0.034f, 0.021f, 0.019f, 0.018f, | 58 0.137f, 0.088f, 0.115f, 0.081f, 0.055f, 0.034f, 0.021f, 0.019f, 0.018f, |
70 0.007f, 0.007f, 0.005f, 0.004f, 0.003f, 0.003f, 0.003f }; | 59 0.007f, 0.007f, 0.005f, 0.004f, 0.003f, 0.003f, 0.003f }; |
71 | 60 |
72 // Return a float uniformly in [0,1]. | 61 // Return a float uniformly in [0,1]. |
73 // Useful for making probabilistic decisions. | 62 // Useful for making probabilistic decisions. |
74 float RandomFloat() { | 63 inline float RandomFloat() { |
75 return rand() / static_cast<float>(RAND_MAX); | 64 return rand() / static_cast<float>(RAND_MAX); |
76 } | 65 } |
77 | 66 |
78 // Return an integer uniformly in [min,max). | 67 // Return an integer uniformly in [min,max). |
79 int RandomInt(int min, int max) { | 68 inline int RandomInt(int min, int max) { |
80 return min + (rand() % (max-min)); | 69 return min + (rand() % (max-min)); |
81 } | 70 } |
82 | 71 |
83 // Return a string of |count| lowercase random characters. | 72 // Return a string of |count| lowercase random characters. |
84 string16 RandomChars(int count) { | 73 string16 RandomChars(int count) { |
85 string16 str; | 74 string16 str; |
86 for (int i = 0; i < count; ++i) | 75 for (int i = 0; i < count; ++i) |
87 str += L'a' + rand() % 26; | 76 str += L'a' + rand() % 26; |
88 return str; | 77 return str; |
89 } | 78 } |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 const float kRevisitableURLProbability = 0.05f; | 136 const float kRevisitableURLProbability = 0.05f; |
148 // Probability of a URL being the end of a redirect chain. | 137 // Probability of a URL being the end of a redirect chain. |
149 const float kRedirectProbability = 0.05f; | 138 const float kRedirectProbability = 0.05f; |
150 | 139 |
151 // A list of URLs that we sometimes revisit. | 140 // A list of URLs that we sometimes revisit. |
152 std::vector<GURL> revisit_urls; | 141 std::vector<GURL> revisit_urls; |
153 | 142 |
154 // Scoping value for page IDs (required by the history service). | 143 // Scoping value for page IDs (required by the history service). |
155 void* id_scope = reinterpret_cast<void*>(1); | 144 void* id_scope = reinterpret_cast<void*>(1); |
156 | 145 |
157 scoped_ptr<SkBitmap> google_bitmap( | 146 scoped_refptr<base::RefCountedMemory> google_bitmap( |
158 gfx::JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail))); | 147 new base::RefCountedStaticMemory(kGoogleThumbnail, |
159 scoped_ptr<SkBitmap> weewar_bitmap( | 148 sizeof(kGoogleThumbnail))); |
160 gfx::JPEGCodec::Decode(kWeewarThumbnail, sizeof(kWeewarThumbnail))); | 149 scoped_refptr<base::RefCountedMemory> weewar_bitmap( |
| 150 new base::RefCountedStaticMemory(kWeewarThumbnail, |
| 151 sizeof(kWeewarThumbnail))); |
161 | 152 |
162 printf("Inserting %d URLs...\n", batch_size); | 153 printf("Inserting %d URLs...\n", batch_size); |
163 GURL previous_url; | 154 GURL previous_url; |
164 content::PageTransition transition = content::PAGE_TRANSITION_TYPED; | 155 content::PageTransition transition = content::PAGE_TRANSITION_TYPED; |
165 const int end_page_id = page_id + batch_size; | 156 const int end_page_id = page_id + batch_size; |
166 history::TopSites* top_sites = profile->GetTopSites(); | 157 history::TopSites* top_sites = profile->GetTopSites(); |
167 for (; page_id < end_page_id; ++page_id) { | 158 for (; page_id < end_page_id; ++page_id) { |
168 // Randomly decide whether this new URL simulates following a link or | 159 // Randomly decide whether this new URL simulates following a link or |
169 // whether it's a jump to a new URL. | 160 // whether it's a jump to a new URL. |
170 if (!previous_url.is_empty() && RandomFloat() < kFollowLinkProbability) { | 161 if (!previous_url.is_empty() && RandomFloat() < kFollowLinkProbability) { |
(...skipping 25 matching lines...) Expand all Loading... |
196 // Add all of this information to the history service. | 187 // Add all of this information to the history service. |
197 history_service->AddPage(url, base::Time::Now(), | 188 history_service->AddPage(url, base::Time::Now(), |
198 id_scope, page_id, | 189 id_scope, page_id, |
199 previous_url, redirects, | 190 previous_url, redirects, |
200 transition, history::SOURCE_BROWSED, true); | 191 transition, history::SOURCE_BROWSED, true); |
201 ThumbnailScore score(0.75, false, false); | 192 ThumbnailScore score(0.75, false, false); |
202 history_service->SetPageTitle(url, ConstructRandomTitle()); | 193 history_service->SetPageTitle(url, ConstructRandomTitle()); |
203 if (types & FULL_TEXT) | 194 if (types & FULL_TEXT) |
204 history_service->SetPageContents(url, ConstructRandomPage()); | 195 history_service->SetPageContents(url, ConstructRandomPage()); |
205 if (types & TOP_SITES && top_sites) { | 196 if (types & TOP_SITES && top_sites) { |
206 const SkBitmap& bitmap = (RandomInt(0, 2) == 0) ? *google_bitmap : | 197 top_sites->SetPageThumbnailToJPEGBytes( |
207 *weewar_bitmap; | 198 url, |
208 gfx::Image image = gfx::Image::CreateFrom1xBitmap(bitmap); | 199 (RandomInt(0, 2) == 0) ? google_bitmap.get() : weewar_bitmap.get(), |
209 top_sites->SetPageThumbnail(url, image, score); | 200 score); |
210 } | 201 } |
211 | 202 |
212 previous_url = url; | 203 previous_url = url; |
213 | 204 |
214 if (revisit_urls.empty() || RandomFloat() < kRevisitableURLProbability) | 205 if (revisit_urls.empty() || RandomFloat() < kRevisitableURLProbability) |
215 revisit_urls.push_back(url); | 206 revisit_urls.push_back(url); |
216 } | 207 } |
217 } | 208 } |
218 | 209 |
219 int main(int argc, char* argv[]) { | 210 } // namespace |
220 CommandLine::Init(argc, argv); | |
221 base::EnableTerminationOnHeapCorruption(); | |
222 base::AtExitManager exit_manager; | |
223 CommandLine* cl = CommandLine::ForCurrentProcess(); | |
224 | 211 |
225 int types = 0; | 212 bool GenerateProfile(GenerateProfileTypes types, |
226 if (cl->HasSwitch("top-sites")) | 213 int url_count, |
227 types |= TOP_SITES; | 214 const base::FilePath& dst_dir) { |
228 if (cl->HasSwitch("full-text")) | 215 if (!file_util::CreateDirectory(dst_dir)) { |
229 types |= FULL_TEXT; | 216 PLOG(ERROR) << "Unable to create directory " << dst_dir.value().c_str(); |
230 | 217 return false; |
231 // We require two arguments: urlcount and profiledir. | |
232 const CommandLine::StringVector& args = cl->GetArgs(); | |
233 if (args.size() < 2) { | |
234 printf("usage: %s [--top-sites] [--full-text] <urlcount> " | |
235 "<profiledir>\n", argv[0]); | |
236 printf("\n --top-sites Generate thumbnails\n"); | |
237 printf("\n --full-text Generate full text index\n"); | |
238 return -1; | |
239 } | 218 } |
240 | 219 |
241 int url_count = 0; | 220 // We want this profile to be as deterministic as possible, so seed the |
242 base::StringToInt(args[0], &url_count); | 221 // random number generator with the number of urls we're generating. |
243 base::FilePath dst_dir(args[1]); | 222 srand(static_cast<unsigned int>(url_count)); |
244 if (!dst_dir.IsAbsolute()) { | |
245 base::FilePath current_dir; | |
246 file_util::GetCurrentDirectory(¤t_dir); | |
247 dst_dir = current_dir.Append(dst_dir); | |
248 } | |
249 if (!file_util::CreateDirectory(dst_dir)) { | |
250 PLOG(ERROR) << "Unable to create directory " << dst_dir.value().c_str(); | |
251 } | |
252 | 223 |
253 icu_util::Initialize(); | 224 printf("Creating profiles for testing...\n"); |
254 // Copied from base/test/test_suite.cc. | |
255 #if defined(TOOLKIT_GTK) | |
256 gtk_init_check(&argc, &argv); | |
257 #endif | |
258 | 225 |
259 InitBrowserProcess initialize_browser_process; | 226 InitBrowserProcess initialize_browser_process; |
260 chrome::RegisterPathProvider(); | 227 base::MessageLoopForUI message_loop; |
261 ui::RegisterPathProvider(); | 228 content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop); |
262 MessageLoopForUI message_loop; | 229 content::TestBrowserThread db_thread(BrowserThread::DB, &message_loop); |
263 content::BrowserThreadImpl ui_thread(BrowserThread::UI, &message_loop); | |
264 content::BrowserThreadImpl db_thread(BrowserThread::DB, &message_loop); | |
265 ResourceBundle::InitSharedInstanceWithLocale("en-US", NULL); | |
266 TestingProfile profile; | 230 TestingProfile profile; |
267 profile.CreateHistoryService(false, false); | 231 profile.CreateHistoryService(false, false); |
268 if (types & TOP_SITES) { | 232 if (types & TOP_SITES) { |
269 profile.CreateTopSites(); | 233 profile.CreateTopSites(); |
270 profile.BlockUntilTopSitesLoaded(); | 234 profile.BlockUntilTopSitesLoaded(); |
271 } | 235 } |
272 | 236 |
273 srand(static_cast<unsigned int>(Time::Now().ToInternalValue())); | |
274 | |
275 // The maximum number of URLs to insert into history in one batch. | 237 // The maximum number of URLs to insert into history in one batch. |
276 const int kBatchSize = 2000; | 238 const int kBatchSize = 2000; |
277 int page_id = 0; | 239 int page_id = 0; |
278 while (page_id < url_count) { | 240 while (page_id < url_count) { |
279 const int batch_size = std::min(kBatchSize, url_count - page_id); | 241 const int batch_size = std::min(kBatchSize, url_count - page_id); |
280 InsertURLBatch(&profile, page_id, batch_size, types); | 242 InsertURLBatch(&profile, page_id, batch_size, types); |
281 // Run all pending messages to give TopSites a chance to catch up. | 243 // Run all pending messages to give TopSites a chance to catch up. |
282 message_loop.RunUntilIdle(); | 244 message_loop.RunUntilIdle(); |
283 page_id += batch_size; | 245 page_id += batch_size; |
284 } | 246 } |
285 | 247 |
286 printf("Writing to disk\n"); | |
287 | |
288 profile.DestroyTopSites(); | 248 profile.DestroyTopSites(); |
289 profile.DestroyHistoryService(); | 249 profile.DestroyHistoryService(); |
290 | 250 |
291 message_loop.RunUntilIdle(); | 251 message_loop.RunUntilIdle(); |
292 | 252 |
293 file_util::FileEnumerator file_iterator(profile.GetPath(), false, | 253 file_util::FileEnumerator file_iterator(profile.GetPath(), false, |
294 file_util::FileEnumerator::FILES); | 254 file_util::FileEnumerator::FILES); |
295 base::FilePath path = file_iterator.Next(); | 255 base::FilePath path = file_iterator.Next(); |
296 while (!path.empty()) { | 256 while (!path.empty()) { |
297 base::FilePath dst_file = dst_dir.Append(path.BaseName()); | 257 base::FilePath dst_file = dst_dir.Append(path.BaseName()); |
298 file_util::Delete(dst_file, false); | 258 file_util::Delete(dst_file, false); |
299 printf("Copying file %" PRFilePath " to " | |
300 "%" PRFilePath "\n", path.value().c_str(), | |
301 dst_file.value().c_str()); | |
302 if (!file_util::CopyFile(path, dst_file)) { | 259 if (!file_util::CopyFile(path, dst_file)) { |
303 PLOG(ERROR) << "Copying file failed"; | 260 PLOG(ERROR) << "Copying file failed"; |
304 return -1; | 261 return false; |
305 } | 262 } |
306 path = file_iterator.Next(); | 263 path = file_iterator.Next(); |
307 } | 264 } |
308 | 265 |
309 return 0; | 266 printf("Finished creating profiles for testing.\n"); |
| 267 |
| 268 // Restore the random seed. |
| 269 srand(static_cast<unsigned int>(Time::Now().ToInternalValue())); |
| 270 |
| 271 return true; |
310 } | 272 } |
OLD | NEW |