Update expectations after WebKit roll.
[chromium-blink-merge.git] / net / base / load_log_util.cc
blobcad20a5976f13bf957e7932780abc238c9b383f7
1 // Copyright (c) 2009 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 "net/base/load_log_util.h"
7 #include "base/format_macros.h"
8 #include "base/string_util.h"
9 #include "net/base/net_errors.h"
11 namespace net {
12 namespace {
14 class FormatHelper {
15 public:
16 std::string ToString(const LoadLog* log) {
17 entries_.clear();
19 // Pass 1: Match the start/end of indentation blocks. Fills |entries_|
20 // with the results.
21 PopulateEntries(log);
23 // Pass 2: Figure out the maximum width of each column. This allows us
24 // to right-justify text within each column.
25 size_t max_time_width, max_indentation, max_type_width, max_dt_width;
26 GetMaxExtent(
27 &max_time_width, &max_indentation, &max_type_width, &max_dt_width);
29 // Pass 3: Assemble the string.
30 std::string result;
32 const int kSpacesPerIndentation = 2;
34 for (size_t i = 0; i < entries_.size(); ++i) {
35 if (log->num_entries_truncated() > 0 && i + 1 == entries_.size()) {
36 StringAppendF(&result, " ... Truncated %" PRIuS " entries ...\n",
37 log->num_entries_truncated());
40 if (entries_[i].block_index != -1 &&
41 static_cast<size_t>(entries_[i].block_index + 1) == i) {
42 // If there were no entries in between the START/END block then don't
43 // bother printing a line for END (it just adds noise, and we already
44 // show the time delta besides START anyway).
45 continue;
48 int indentation_spaces = entries_[i].indentation * kSpacesPerIndentation;
49 std::string entry_str = GetEntryString(i);
51 StringAppendF(&result, "t=%s: %s%s",
52 PadStringLeft(GetTimeString(i), max_time_width).c_str(),
53 PadStringLeft("", indentation_spaces).c_str(),
54 entry_str.c_str());
56 if (entries_[i].IsBeginEvent()) {
57 // Summarize how long this block lasted.
58 int padding = ((max_indentation - entries_[i].indentation) *
59 kSpacesPerIndentation) + (max_type_width - entry_str.size());
60 StringAppendF(&result, "%s [dt=%s]",
61 PadStringLeft("", padding).c_str(),
62 PadStringLeft(GetBlockDtString(i), max_dt_width).c_str());
65 if (i + 1 != entries_.size())
66 result += "\n";
69 return result;
72 private:
73 struct Entry {
74 explicit Entry(const LoadLog::Entry* log_entry)
75 : log_entry(log_entry), indentation(0), block_index(-1) {}
77 bool IsBeginEvent() const {
78 return log_entry->type == LoadLog::Entry::TYPE_EVENT &&
79 log_entry->event.phase == LoadLog::PHASE_BEGIN;
82 bool IsEndEvent() const {
83 return log_entry->type == LoadLog::Entry::TYPE_EVENT &&
84 log_entry->event.phase == LoadLog::PHASE_END;
87 const LoadLog::Entry* log_entry;
88 size_t indentation;
89 int block_index; // The index of the matching start / end of block.
92 void PopulateEntries(const LoadLog* log) {
93 int current_indentation = 0;
95 for (size_t i = 0; i < log->entries().size(); ++i) {
96 Entry entry(&log->entries()[i]);
98 entry.indentation = current_indentation;
100 if (entry.IsBeginEvent()) {
101 // Indent everything contained in this block.
102 current_indentation++;
105 if (entry.IsEndEvent()) {
106 int start_index = FindStartOfBlockIndex(entry);
107 if (start_index != -1) {
108 // Point the start / end of block at each other.
109 entry.block_index = start_index;
110 entries_[start_index].block_index = i;
112 // Restore the indentation prior to the block.
113 // (Could be more than 1 level if close of blocks are missing).
114 current_indentation = entries_[start_index].indentation;
115 entry.indentation = current_indentation;
119 entries_.push_back(entry);
123 int FindStartOfBlockIndex(const Entry& entry) {
124 DCHECK(entry.IsEndEvent());
126 // Find the matching start of block by scanning backwards.
127 for (int i = entries_.size() - 1; i >= 0; --i) {
128 if (entries_[i].IsBeginEvent() &&
129 entries_[i].log_entry->event.type == entry.log_entry->event.type) {
130 return i;
133 return -1; // Start not found.
136 void GetMaxExtent(size_t* max_time_width,
137 size_t* max_indentation,
138 size_t* max_type_width,
139 size_t* max_dt_width) {
140 *max_time_width = *max_indentation = *max_type_width = *max_dt_width = 0;
141 for (size_t i = 0; i < entries_.size(); ++i) {
142 *max_time_width = std::max(*max_time_width, GetTimeString(i).size());
143 if (entries_[i].log_entry->type == LoadLog::Entry::TYPE_EVENT)
144 *max_type_width = std::max(*max_type_width, GetEntryString(i).size());
145 *max_indentation = std::max(*max_indentation, entries_[i].indentation);
147 if (entries_[i].IsBeginEvent())
148 *max_dt_width = std::max(*max_dt_width, GetBlockDtString(i).size());
152 std::string GetBlockDtString(size_t start_index) {
153 int end_index = entries_[start_index].block_index;
154 if (end_index == -1) {
155 // Block is not closed, implicitly close it at EOF.
156 end_index = entries_.size() - 1;
158 int64 dt_ms = (entries_[end_index].log_entry->time -
159 entries_[start_index].log_entry->time).InMilliseconds();
161 return Int64ToString(dt_ms);
164 std::string GetTimeString(size_t index) {
165 int64 t_ms = (entries_[index].log_entry->time -
166 base::TimeTicks()).InMilliseconds();
167 return Int64ToString(t_ms);
170 std::string GetEntryString(size_t index) {
171 const LoadLog::Entry* entry = entries_[index].log_entry;
173 std::string entry_str;
174 LoadLog::EventPhase phase = LoadLog::PHASE_NONE;
175 switch (entry->type) {
176 case LoadLog::Entry::TYPE_EVENT:
177 entry_str = LoadLog::EventTypeToString(entry->event.type);
178 phase = entry->event.phase;
180 if (phase == LoadLog::PHASE_BEGIN &&
181 index + 1 < entries_.size() &&
182 static_cast<size_t>(entries_[index + 1].block_index) == index) {
183 // If this starts an empty block, we will pretend it is a PHASE_NONE
184 // so we don't print the "+" prefix.
185 phase = LoadLog::PHASE_NONE;
187 break;
188 case LoadLog::Entry::TYPE_ERROR_CODE:
189 entry_str = StringPrintf("error code: %d (%s)",
190 entry->error_code,
191 ErrorToString(entry->error_code));
192 break;
193 case LoadLog::Entry::TYPE_STRING:
194 entry_str = StringPrintf("\"%s\"", entry->string.c_str());
195 break;
196 case LoadLog::Entry::TYPE_STRING_LITERAL:
197 entry_str = StringPrintf("\"%s\"", entry->literal);
198 break;
199 default:
200 NOTREACHED();
203 switch (phase) {
204 case LoadLog::PHASE_BEGIN:
205 return std::string("+") + entry_str;
206 case LoadLog::PHASE_END:
207 return std::string("-") + entry_str;
208 case LoadLog::PHASE_NONE:
209 return std::string(" ") + entry_str;
210 default:
211 NOTREACHED();
212 return std::string();
216 static std::string PadStringLeft(const std::string& str, size_t width) {
217 DCHECK_LE(str.size(), width);
218 std::string padding;
219 padding.resize(width - str.size(), ' ');
220 return padding + str;
223 std::vector<Entry> entries_;
226 } // namespace
228 // static
229 std::string LoadLogUtil::PrettyPrintAsEventTree(const LoadLog* log) {
230 FormatHelper helper;
231 return helper.ToString(log);
234 } // namespace net