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.
4
5#include "chrome/test/perf/perf_test.h"
6
7#include <stdio.h>
8
9#include "base/logging.h"
10#include "base/strings/string_number_conversions.h"
11#include "base/strings/stringprintf.h"
12#include "chrome/test/base/chrome_process_util.h"
13#include "testing/perf/perf_test.h"
14
15namespace perf_test {
16
17void PrintIOPerfInfo(const std::string& test_name,
18                     const ChromeProcessList& chrome_processes,
19                     base::ProcessId browser_pid) {
20  PrintIOPerfInfo(stdout, test_name, chrome_processes, browser_pid);
21}
22
23void PrintIOPerfInfo(FILE* target,
24                     const std::string& test_name,
25                     const ChromeProcessList& chrome_processes,
26                     base::ProcessId browser_pid) {
27  fprintf(target, "%s", IOPerfInfoToString(test_name, chrome_processes,
28                                           browser_pid).c_str());
29}
30
31std::string IOPerfInfoToString(const std::string& test_name,
32                               const ChromeProcessList& chrome_processes,
33                               base::ProcessId browser_pid) {
34  size_t read_op_b = 0;
35  size_t read_op_r = 0;
36  size_t write_op_b = 0;
37  size_t write_op_r = 0;
38  size_t other_op_b = 0;
39  size_t other_op_r = 0;
40  size_t total_op_b = 0;
41  size_t total_op_r = 0;
42
43  size_t read_byte_b = 0;
44  size_t read_byte_r = 0;
45  size_t write_byte_b = 0;
46  size_t write_byte_r = 0;
47  size_t other_byte_b = 0;
48  size_t other_byte_r = 0;
49  size_t total_byte_b = 0;
50  size_t total_byte_r = 0;
51
52  std::string output;
53  ChromeProcessList::const_iterator it;
54  for (it = chrome_processes.begin(); it != chrome_processes.end(); ++it) {
55    base::ProcessHandle process_handle;
56    if (!base::OpenProcessHandle(*it, &process_handle)) {
57      NOTREACHED();
58      return output;
59    }
60
61    // TODO(sgk):  if/when base::ProcessMetrics returns real stats on mac:
62    // scoped_ptr<base::ProcessMetrics> process_metrics(
63    //     base::ProcessMetrics::CreateProcessMetrics(process_handle));
64    scoped_ptr<ChromeTestProcessMetrics> process_metrics(
65        ChromeTestProcessMetrics::CreateProcessMetrics(process_handle));
66    base::IoCounters io_counters;
67    memset(&io_counters, 0, sizeof(io_counters));
68
69    if (process_metrics.get()->GetIOCounters(&io_counters)) {
70      // Print out IO performance.  We assume that the values can be
71      // converted to size_t (they're reported as ULONGLONG, 64-bit numbers).
72      std::string chrome_name = (*it == browser_pid) ? "_b" : "_r";
73
74      size_t read_op = static_cast<size_t>(io_counters.ReadOperationCount);
75      size_t write_op = static_cast<size_t>(io_counters.WriteOperationCount);
76      size_t other_op = static_cast<size_t>(io_counters.OtherOperationCount);
77      size_t total_op = static_cast<size_t>(io_counters.ReadOperationCount +
78                                            io_counters.WriteOperationCount +
79                                            io_counters.OtherOperationCount);
80
81      size_t read_byte = static_cast<size_t>(io_counters.ReadTransferCount
82                                             / 1024);
83      size_t write_byte = static_cast<size_t>(io_counters.WriteTransferCount
84                                              / 1024);
85      size_t other_byte = static_cast<size_t>(io_counters.OtherTransferCount
86                                              / 1024);
87      size_t total_byte = static_cast<size_t>((io_counters.ReadTransferCount +
88                                               io_counters.WriteTransferCount +
89                                               io_counters.OtherTransferCount)
90                                              / 1024);
91
92      if (*it == browser_pid) {
93        read_op_b = read_op;
94        write_op_b = write_op;
95        other_op_b = other_op;
96        total_op_b = total_op;
97        read_byte_b = read_byte;
98        write_byte_b = write_byte;
99        other_byte_b = other_byte;
100        total_byte_b = total_byte;
101      } else {
102        read_op_r += read_op;
103        write_op_r += write_op;
104        other_op_r += other_op;
105        total_op_r += total_op;
106        read_byte_r += read_byte;
107        write_byte_r += write_byte;
108        other_byte_r += other_byte;
109        total_byte_r += total_byte;
110      }
111    }
112
113    base::CloseProcessHandle(process_handle);
114  }
115
116  std::string t_name(test_name);
117  AppendResult(output,
118               "read_op_b",
119               std::string(),
120               "r_op_b" + t_name,
121               read_op_b,
122               "ops",
123               false);
124  AppendResult(output,
125               "write_op_b",
126               std::string(),
127               "w_op_b" + t_name,
128               write_op_b,
129               "ops",
130               false);
131  AppendResult(output,
132               "other_op_b",
133               std::string(),
134               "o_op_b" + t_name,
135               other_op_b,
136               "ops",
137               false);
138  AppendResult(output,
139               "total_op_b",
140               std::string(),
141               "IO_op_b" + t_name,
142               total_op_b,
143               "ops",
144               false);
145
146  AppendResult(output,
147               "read_byte_b",
148               std::string(),
149               "r_b" + t_name,
150               read_byte_b,
151               "kb",
152               false);
153  AppendResult(output,
154               "write_byte_b",
155               std::string(),
156               "w_b" + t_name,
157               write_byte_b,
158               "kb",
159               false);
160  AppendResult(output,
161               "other_byte_b",
162               std::string(),
163               "o_b" + t_name,
164               other_byte_b,
165               "kb",
166               false);
167  AppendResult(output,
168               "total_byte_b",
169               std::string(),
170               "IO_b" + t_name,
171               total_byte_b,
172               "kb",
173               false);
174
175  AppendResult(output,
176               "read_op_r",
177               std::string(),
178               "r_op_r" + t_name,
179               read_op_r,
180               "ops",
181               false);
182  AppendResult(output,
183               "write_op_r",
184               std::string(),
185               "w_op_r" + t_name,
186               write_op_r,
187               "ops",
188               false);
189  AppendResult(output,
190               "other_op_r",
191               std::string(),
192               "o_op_r" + t_name,
193               other_op_r,
194               "ops",
195               false);
196  AppendResult(output,
197               "total_op_r",
198               std::string(),
199               "IO_op_r" + t_name,
200               total_op_r,
201               "ops",
202               false);
203
204  AppendResult(output,
205               "read_byte_r",
206               std::string(),
207               "r_r" + t_name,
208               read_byte_r,
209               "kb",
210               false);
211  AppendResult(output,
212               "write_byte_r",
213               std::string(),
214               "w_r" + t_name,
215               write_byte_r,
216               "kb",
217               false);
218  AppendResult(output,
219               "other_byte_r",
220               std::string(),
221               "o_r" + t_name,
222               other_byte_r,
223               "kb",
224               false);
225  AppendResult(output,
226               "total_byte_r",
227               std::string(),
228               "IO_r" + t_name,
229               total_byte_r,
230               "kb",
231               false);
232
233  return output;
234}
235
236void PrintMemoryUsageInfo(const std::string& test_name,
237                          const ChromeProcessList& chrome_processes,
238                          base::ProcessId browser_pid) {
239  PrintMemoryUsageInfo(stdout, test_name, chrome_processes, browser_pid);
240}
241
242void PrintMemoryUsageInfo(FILE* target,
243                          const std::string& test_name,
244                          const ChromeProcessList& chrome_processes,
245                          base::ProcessId browser_pid) {
246  fprintf(target, "%s", MemoryUsageInfoToString(test_name, chrome_processes,
247                                                browser_pid).c_str());
248}
249
250std::string MemoryUsageInfoToString(const std::string& test_name,
251                                    const ChromeProcessList& chrome_processes,
252                                    base::ProcessId browser_pid) {
253  size_t browser_virtual_size = 0;
254  size_t browser_working_set_size = 0;
255  size_t renderer_virtual_size = 0;
256  size_t renderer_working_set_size = 0;
257  size_t total_virtual_size = 0;
258  size_t total_working_set_size = 0;
259#if defined(OS_WIN)
260  size_t browser_peak_virtual_size = 0;
261  size_t browser_peak_working_set_size = 0;
262  size_t renderer_total_peak_virtual_size = 0;
263  size_t renderer_total_peak_working_set_size = 0;
264  size_t renderer_single_peak_virtual_size = 0;
265  size_t renderer_single_peak_working_set_size = 0;
266#endif
267
268  std::string output;
269  ChromeProcessList::const_iterator it;
270  for (it = chrome_processes.begin(); it != chrome_processes.end(); ++it) {
271    base::ProcessHandle process_handle;
272    if (!base::OpenProcessHandle(*it, &process_handle)) {
273      NOTREACHED();
274      return output;
275    }
276
277    // TODO(sgk):  if/when base::ProcessMetrics returns real stats on mac:
278    // scoped_ptr<base::ProcessMetrics> process_metrics(
279    //     base::ProcessMetrics::CreateProcessMetrics(process_handle));
280    scoped_ptr<ChromeTestProcessMetrics> process_metrics(
281        ChromeTestProcessMetrics::CreateProcessMetrics(process_handle));
282
283    size_t current_virtual_size = process_metrics->GetPagefileUsage();
284    size_t current_working_set_size = process_metrics->GetWorkingSetSize();
285
286    if (*it == browser_pid) {
287      browser_virtual_size = current_virtual_size;
288      browser_working_set_size = current_working_set_size;
289    } else {
290      renderer_virtual_size += current_virtual_size;
291      renderer_working_set_size += current_working_set_size;
292    }
293    total_virtual_size += current_virtual_size;
294    total_working_set_size += current_working_set_size;
295
296#if defined(OS_WIN)
297    size_t peak_virtual_size = process_metrics->GetPeakPagefileUsage();
298    size_t peak_working_set_size = process_metrics->GetPeakWorkingSetSize();
299    if (*it == browser_pid) {
300      browser_peak_virtual_size = peak_virtual_size;
301      browser_peak_working_set_size = peak_working_set_size;
302    } else {
303      if (peak_virtual_size > renderer_single_peak_virtual_size) {
304        renderer_single_peak_virtual_size = peak_virtual_size;
305      }
306      if (peak_working_set_size > renderer_single_peak_working_set_size) {
307        renderer_single_peak_working_set_size = peak_working_set_size;
308      }
309      renderer_total_peak_virtual_size += peak_virtual_size;
310      renderer_total_peak_working_set_size += peak_working_set_size;
311    }
312#endif
313
314    base::CloseProcessHandle(process_handle);
315  }
316
317  std::string trace_name(test_name);
318#if defined(OS_WIN)
319  AppendResult(output, "vm_peak_b", "", "vm_pk_b" + trace_name,
320               browser_peak_virtual_size, "bytes",
321               false /* not important */);
322  AppendResult(output, "ws_peak_b", "", "ws_pk_b" + trace_name,
323               browser_peak_working_set_size, "bytes",
324               false /* not important */);
325  AppendResult(output, "vm_peak_r", "", "vm_pk_r" + trace_name,
326               renderer_total_peak_virtual_size, "bytes",
327               false /* not important */);
328  AppendResult(output, "ws_peak_r", "", "ws_pk_r" + trace_name,
329               renderer_total_peak_working_set_size, "bytes",
330               false /* not important */);
331  AppendResult(output, "vm_single_peak_r", "", "vm_spk_r" + trace_name,
332               renderer_single_peak_virtual_size, "bytes",
333               false /* not important */);
334  AppendResult(output, "ws_single_peak_r", "", "ws_spk_r" + trace_name,
335               renderer_single_peak_working_set_size, "bytes",
336               false /* important */);
337  AppendResult(output, "vm_final_b", "", "vm_f_b" + trace_name,
338               browser_virtual_size, "bytes",
339               false /* not important */);
340  AppendResult(output, "ws_final_b", "", "ws_f_b" + trace_name,
341               browser_working_set_size, "bytes",
342               false /* not important */);
343  AppendResult(output, "vm_final_r", "", "vm_f_r" + trace_name,
344               renderer_virtual_size, "bytes",
345               false /* not important */);
346  AppendResult(output, "ws_final_r", "", "ws_f_r" + trace_name,
347               renderer_working_set_size, "bytes",
348               false /* not important */);
349  AppendResult(output, "vm_final_t", "", "vm_f_t" + trace_name,
350               total_virtual_size, "bytes",
351               false /* not important */);
352  AppendResult(output, "ws_final_t", "", "ws_f_t" + trace_name,
353               total_working_set_size, "bytes",
354               false /* not important */);
355#elif defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_ANDROID)
356  AppendResult(output,
357               "vm_size_final_b",
358               std::string(),
359               "vm_size_f_b" + trace_name,
360               browser_virtual_size,
361               "bytes",
362               false /* not important */);
363  AppendResult(output,
364               "vm_rss_final_b",
365               std::string(),
366               "vm_rss_f_b" + trace_name,
367               browser_working_set_size,
368               "bytes",
369               false /* not important */);
370  AppendResult(output,
371               "vm_size_final_r",
372               std::string(),
373               "vm_size_f_r" + trace_name,
374               renderer_virtual_size,
375               "bytes",
376               false /* not important */);
377  AppendResult(output,
378               "vm_rss_final_r",
379               std::string(),
380               "vm_rss_f_r" + trace_name,
381               renderer_working_set_size,
382               "bytes",
383               false /* not important */);
384  AppendResult(output,
385               "vm_size_final_t",
386               std::string(),
387               "vm_size_f_t" + trace_name,
388               total_virtual_size,
389               "bytes",
390               false /* not important */);
391  AppendResult(output,
392               "vm_rss_final_t",
393               std::string(),
394               "vm_rss_f_t" + trace_name,
395               total_working_set_size,
396               "bytes",
397               false /* not important */);
398#else
399  NOTIMPLEMENTED();
400#endif
401  AppendResult(output,
402               "processes",
403               std::string(),
404               "proc_" + trace_name,
405               chrome_processes.size(),
406               "count",
407               false /* not important */);
408
409  return output;
410}
411
412}  // namespace perf_test
413