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"
16 std::string
ToString(const LoadLog
* log
) {
19 // Pass 1: Match the start/end of indentation blocks. Fills |entries_|
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
;
27 &max_time_width
, &max_indentation
, &max_type_width
, &max_dt_width
);
29 // Pass 3: Assemble the string.
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).
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(),
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())
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
;
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
) {
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
;
188 case LoadLog::Entry::TYPE_ERROR_CODE
:
189 entry_str
= StringPrintf("error code: %d (%s)",
191 ErrorToString(entry
->error_code
));
193 case LoadLog::Entry::TYPE_STRING
:
194 entry_str
= StringPrintf("\"%s\"", entry
->string
.c_str());
196 case LoadLog::Entry::TYPE_STRING_LITERAL
:
197 entry_str
= StringPrintf("\"%s\"", entry
->literal
);
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
;
212 return std::string();
216 static std::string
PadStringLeft(const std::string
& str
, size_t width
) {
217 DCHECK_LE(str
.size(), width
);
219 padding
.resize(width
- str
.size(), ' ');
220 return padding
+ str
;
223 std::vector
<Entry
> entries_
;
229 std::string
LoadLogUtil::PrettyPrintAsEventTree(const LoadLog
* log
) {
231 return helper
.ToString(log
);