Skip to content

Commit fcce479

Browse files
jaro-sevcikCommit bot
authored andcommitted
[profiler] Graphical front-end for tick processor.
Improvements: - top-down call tree. - interactive restriction to time interval. Review-Url: https://codereview.chromium.org/2696903002 Cr-Commit-Position: refs/heads/master@{#43599}
1 parent 885ec93 commit fcce479

11 files changed

Lines changed: 1464 additions & 36 deletions

File tree

test/mjsunit/tools/profile.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,12 @@ ProfileTestDriver.prototype.enter = function(funcName) {
8888
// Stack looks like this: [pc, caller, ..., main].
8989
// Therefore, we are adding entries at the beginning.
9090
this.stack_.unshift(this.funcAddrs_[funcName]);
91-
this.profile.recordTick(this.stack_);
91+
this.profile.recordTick(0, 0, this.stack_);
9292
};
9393

9494

9595
ProfileTestDriver.prototype.stay = function() {
96-
this.profile.recordTick(this.stack_);
96+
this.profile.recordTick(0, 0, this.stack_);
9797
};
9898

9999

test/mjsunit/tools/tickprocessor.js

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -131,15 +131,14 @@
131131
// shell executable
132132
MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
133133
this.symbols = [[
134-
' U operator delete[]',
135-
'00001000 A __mh_execute_header',
136-
'00001b00 T start',
137-
'00001b40 t dyld_stub_binding_helper',
138-
'0011b710 T v8::internal::RegExpMacroAssembler::CheckPosition',
139-
'00134250 t v8::internal::Runtime_StringReplaceRegExpWithString',
140-
'00137220 T v8::internal::Runtime::GetElementOrCharAt',
141-
'00137400 t v8::internal::Runtime_DebugGetPropertyDetails',
142-
'001c1a80 b _private_mem\n'
134+
' operator delete[]',
135+
'00001000 __mh_execute_header',
136+
'00001b00 start',
137+
'00001b40 dyld_stub_binding_helper',
138+
'0011b710 v8::internal::RegExpMacroAssembler::CheckPosition',
139+
'00134250 v8::internal::Runtime_StringReplaceRegExpWithString',
140+
'00137220 v8::internal::Runtime::GetElementOrCharAt',
141+
'00137400 v8::internal::Runtime_DebugGetPropertyDetails\n'
143142
].join('\n'), ''];
144143
};
145144

@@ -161,10 +160,10 @@
161160
// stdc++ library
162161
MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
163162
this.symbols = [[
164-
'0000107a T __gnu_cxx::balloc::__mini_vector<std::pair<__gnu_cxx::bitmap_allocator<char>::_Alloc_block*, __gnu_cxx::bitmap_allocator<char>::_Alloc_block*> >::__mini_vector',
165-
'0002c410 T std::basic_streambuf<char, std::char_traits<char> >::pubseekoff',
166-
'0002c488 T std::basic_streambuf<char, std::char_traits<char> >::pubseekpos',
167-
'000466aa T ___cxa_pure_virtual\n'].join('\n'), ''];
163+
'0000107a __gnu_cxx::balloc::__mini_vector<std::pair<__gnu_cxx::bitmap_allocator<char>::_Alloc_block*, __gnu_cxx::bitmap_allocator<char>::_Alloc_block*> >::__mini_vector',
164+
'0002c410 std::basic_streambuf<char, std::char_traits<char> >::pubseekoff',
165+
'0002c488 std::basic_streambuf<char, std::char_traits<char> >::pubseekpos',
166+
'000466aa ___cxa_pure_virtual\n'].join('\n'), ''];
168167
};
169168
var stdc_prov = new MacCppEntriesProvider();
170169
var stdc_syms = [];

tools/codemap.js

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -175,40 +175,58 @@ CodeMap.prototype.isAddressBelongsTo_ = function(addr, node) {
175175
*/
176176
CodeMap.prototype.findInTree_ = function(tree, addr) {
177177
var node = tree.findGreatestLessThan(addr);
178-
return node && this.isAddressBelongsTo_(addr, node) ? node.value : null;
178+
return node && this.isAddressBelongsTo_(addr, node) ? node : null;
179179
};
180180

181181

182182
/**
183183
* Finds a code entry that contains the specified address. Both static and
184-
* dynamic code entries are considered.
184+
* dynamic code entries are considered. Returns the code entry and the offset
185+
* within the entry.
185186
*
186187
* @param {number} addr Address.
187188
*/
188-
CodeMap.prototype.findEntry = function(addr) {
189+
CodeMap.prototype.findAddress = function(addr) {
189190
var pageAddr = addr >>> CodeMap.PAGE_ALIGNMENT;
190191
if (pageAddr in this.pages_) {
191192
// Static code entries can contain "holes" of unnamed code.
192193
// In this case, the whole library is assigned to this address.
193-
return this.findInTree_(this.statics_, addr) ||
194-
this.findInTree_(this.libraries_, addr);
194+
var result = this.findInTree_(this.statics_, addr);
195+
if (!result) {
196+
result = this.findInTree_(this.libraries_, addr);
197+
if (!result) return null;
198+
}
199+
return { entry : result.value, offset : addr - result.key };
195200
}
196201
var min = this.dynamics_.findMin();
197202
var max = this.dynamics_.findMax();
198203
if (max != null && addr < (max.key + max.value.size) && addr >= min.key) {
199204
var dynaEntry = this.findInTree_(this.dynamics_, addr);
200205
if (dynaEntry == null) return null;
201206
// Dedupe entry name.
202-
if (!dynaEntry.nameUpdated_) {
203-
dynaEntry.name = this.dynamicsNameGen_.getName(dynaEntry.name);
204-
dynaEntry.nameUpdated_ = true;
207+
var entry = dynaEntry.value;
208+
if (!entry.nameUpdated_) {
209+
entry.name = this.dynamicsNameGen_.getName(entry.name);
210+
entry.nameUpdated_ = true;
205211
}
206-
return dynaEntry;
212+
return { entry : entry, offset : addr - dynaEntry.key };
207213
}
208214
return null;
209215
};
210216

211217

218+
/**
219+
* Finds a code entry that contains the specified address. Both static and
220+
* dynamic code entries are considered.
221+
*
222+
* @param {number} addr Address.
223+
*/
224+
CodeMap.prototype.findEntry = function(addr) {
225+
var result = this.findAddress(addr);
226+
return result ? result.entry : null;
227+
};
228+
229+
212230
/**
213231
* Returns a dynamic code entry using its starting address.
214232
*

tools/mac-nm

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@
1414
if [ "`which c++filt`" == "" ]; then
1515
nm "$@"
1616
else
17-
nm "$@" | c++filt -p -i
17+
nm "$@" | sed -n "s/\([0-9a-fA-F]\{8,16\}\) [iItT] \(.*\)/\\1 \\2/p"\
18+
| c++filt -p -i
1819
fi

tools/profile.js

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ function Profile() {
3737
this.topDownTree_ = new CallTree();
3838
this.bottomUpTree_ = new CallTree();
3939
this.c_entries_ = {};
40+
this.ticks_ = [];
4041
};
4142

4243

@@ -235,7 +236,7 @@ Profile.prototype.findEntry = function(addr) {
235236
*
236237
* @param {Array<number>} stack Stack sample.
237238
*/
238-
Profile.prototype.recordTick = function(stack) {
239+
Profile.prototype.recordTick = function(time_ns, vmState, stack) {
239240
var processedStack = this.resolveAndFilterFuncs_(stack);
240241
this.bottomUpTree_.addPath(processedStack);
241242
processedStack.reverse();
@@ -832,3 +833,146 @@ CallTree.Node.prototype.descendToChild = function(
832833
}
833834
return curr;
834835
};
836+
837+
function JsonProfile() {
838+
this.codeMap_ = new CodeMap();
839+
this.codeEntries_ = [];
840+
this.functionEntries_ = [];
841+
this.ticks_ = [];
842+
}
843+
844+
JsonProfile.prototype.addLibrary = function(
845+
name, startAddr, endAddr) {
846+
var entry = new CodeMap.CodeEntry(
847+
endAddr - startAddr, name, 'SHARED_LIB');
848+
this.codeMap_.addLibrary(startAddr, entry);
849+
850+
entry.codeId = this.codeEntries_.length;
851+
this.codeEntries_.push({name : entry.name, type : entry.type});
852+
return entry;
853+
};
854+
855+
JsonProfile.prototype.addStaticCode = function(
856+
name, startAddr, endAddr) {
857+
var entry = new CodeMap.CodeEntry(
858+
endAddr - startAddr, name, 'CPP');
859+
this.codeMap_.addStaticCode(startAddr, entry);
860+
861+
entry.codeId = this.codeEntries_.length;
862+
this.codeEntries_.push({name : entry.name, type : entry.type});
863+
return entry;
864+
};
865+
866+
JsonProfile.prototype.addCode = function(
867+
kind, name, start, size) {
868+
var entry = new CodeMap.CodeEntry(size, name, 'CODE');
869+
this.codeMap_.addCode(start, entry);
870+
871+
entry.codeId = this.codeEntries_.length;
872+
this.codeEntries_.push({name : entry.name, type : entry.type, kind : kind});
873+
874+
return entry;
875+
};
876+
877+
JsonProfile.prototype.addFuncCode = function(
878+
kind, name, start, size, funcAddr, state) {
879+
// As code and functions are in the same address space,
880+
// it is safe to put them in a single code map.
881+
var func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
882+
if (!func) {
883+
var func = new CodeMap.CodeEntry(0, name, 'SFI');
884+
this.codeMap_.addCode(funcAddr, func);
885+
886+
func.funcId = this.functionEntries_.length;
887+
this.functionEntries_.push({name : name, codes : []});
888+
} else if (func.name !== name) {
889+
// Function object has been overwritten with a new one.
890+
func.name = name;
891+
892+
func.funcId = this.functionEntries_.length;
893+
this.functionEntries_.push({name : name, codes : []});
894+
}
895+
// TODO(jarin): Insert the code object into the SFI's code list.
896+
var entry = this.codeMap_.findDynamicEntryByStartAddress(start);
897+
if (entry) {
898+
// TODO(jarin) This does not look correct, we should really
899+
// update the code object (remove the old one and insert this one).
900+
if (entry.size === size && entry.func === func) {
901+
// Entry state has changed.
902+
entry.state = state;
903+
}
904+
} else {
905+
var entry = new CodeMap.CodeEntry(size, name, 'JS');
906+
this.codeMap_.addCode(start, entry);
907+
908+
entry.codeId = this.codeEntries_.length;
909+
910+
this.functionEntries_[func.funcId].codes.push(entry.codeId);
911+
912+
if (state === 0) {
913+
kind = "Builtin";
914+
} else if (state === 1) {
915+
kind = "Unopt";
916+
} else if (state === 2) {
917+
kind = "Opt";
918+
}
919+
920+
this.codeEntries_.push({
921+
name : entry.name,
922+
type : entry.type,
923+
kind : kind,
924+
func : func.funcId
925+
});
926+
}
927+
return entry;
928+
};
929+
930+
JsonProfile.prototype.moveCode = function(from, to) {
931+
try {
932+
this.codeMap_.moveCode(from, to);
933+
} catch (e) {
934+
printErr("Move: unknown source " + from);
935+
}
936+
};
937+
938+
JsonProfile.prototype.deleteCode = function(start) {
939+
try {
940+
this.codeMap_.deleteCode(start);
941+
} catch (e) {
942+
printErr("Delete: unknown address " + start);
943+
}
944+
};
945+
946+
JsonProfile.prototype.moveFunc = function(from, to) {
947+
if (this.codeMap_.findDynamicEntryByStartAddress(from)) {
948+
this.codeMap_.moveCode(from, to);
949+
}
950+
};
951+
952+
JsonProfile.prototype.findEntry = function(addr) {
953+
return this.codeMap_.findEntry(addr);
954+
};
955+
956+
JsonProfile.prototype.recordTick = function(time_ns, vmState, stack) {
957+
// TODO(jarin) Resolve the frame-less case (when top of stack is
958+
// known code).
959+
var processedStack = [];
960+
for (var i = 0; i < stack.length; i++) {
961+
var resolved = this.codeMap_.findAddress(stack[i]);
962+
if (resolved) {
963+
processedStack.push(resolved.entry.codeId, resolved.offset);
964+
} else {
965+
processedStack.push(-1, stack[i]);
966+
}
967+
}
968+
this.ticks_.push({ tm : time_ns, vm : vmState, s : processedStack });
969+
};
970+
971+
JsonProfile.prototype.writeJson = function() {
972+
var toplevel = {
973+
code : this.codeEntries_,
974+
functions : this.functionEntries_,
975+
ticks : this.ticks_
976+
};
977+
write(JSON.stringify(toplevel));
978+
};

0 commit comments

Comments
 (0)