Can you please describe your setup? If you are running two instances
of Chrome, are you using separate profiles for them, as described
here: http://blog.chromium.org/2011/05/remote-debugging-with-chrome-developer.html?
This will not work. You need a separate Chrome instance. You can
either run Chrome + Chromium (they use separate profile dirs, so they
can co-exist), or specify --user-data-dir with some directory to the
second instance.
As long as the remote debugging scenario works, we assume our code is OK.
Oh, by the way. I don't know, why it isn't shown, but DevTools
definitely invokes this operation (in DevTools, the setting
"Preferences.profilerAlwaysEnabled" is true):
http://codesearch.google.com/codesearch#OAMlx_jo-ck/src/third_party/WebKit/Source/WebCore/inspector/front-end/ProfilesPanel.js&l=138
I tried sniffing FE<>BE messages using the technique that Ilya has
proposed, and found that what you see isn't really a full log. The
initialization messages are skipped because you enable messages
logging _after_ the frontend has been initialized. To get a complete
dump from the beginning, I have done the following trick:
- do the usual setup (two Chrome instances, connect to DevTools from
a remote instance, then evaluate "window.dumpInspectorProtocolMessages
= 1" in the remote console);
- check that message logging works (do something in the debugged DevTools);
- now clean the remote console to get rid of previous messages;
- navigate to some other page (from another domain) in the tab that
you inspect with the debugger DevTools;
- now the backend will be re-initializing the frontend from scratch,
and you will be able to observe something similar to this:
backend: {"method":"Profiler.profilerWasEnabled"}
backend: {"method":"Profiler.resetProfiles"}
backend: {"method":"Network.requestWillBeSent","params":{"identifier":1,"frameId":"5029A00","loaderId":"380BE00","documentURL":"http://www.google.com/","request":{"url":"http://www.google.com/","method":"GET","headers":{"User-Agent":"Mozilla/5.0
(Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/535.1 (KHTML, like
Gecko) Chrome/14.0.785.0
Safari/535.1","Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"}},"timestamp":1307734578.457265,"stackTrace":[]}}
... and so on.
As you see, profiler gets enabled from the very beginning. You were
just missing the corresponding messages in your log.
And, of course, without enabling the profiler, no profiles will be
collected at all. Commands are just being ignored by the profiler
agent.
Good news. I have found why the code wasn't working. Besides
"Profiler.enable", you were expected to invoke "Debugger.enable"
(although it may appear as if the debugger isn't needed here). I've
pasted my working 'background.html' version below.
Masoomeh: a couple of notes for you.
- you should wait for "setRecordingProfile" state change prior to
stopping profiling, and for "addProfileHeader" prior to trying to
retrieve the profile; as the things happen very asynchronously, you
may encounter a situation, when you are trying to act too early;
- there seems a bug that causes the renderer you open to crash if
you are trying to attach to it immediately after opening.
DevTools team:
- we need to investigate, why V8 crashes if we try to attach too
fast -- something wrong happens in EnterDebugger:
#4 0x0000000001897200 in CheckHelper (file=0x3abf0b3
"v8/src/objects-inl.h", line=2021,
source=0x3abf558 "object->IsSharedFunctionInfo()",
condition=false) at v8/src/checks.h:60
#5 0x00000000018b61f9 in v8::internal::SharedFunctionInfo::cast (object=0x0)
at v8/src/objects-inl.h:2021
#6 0x00000000018b6adf in v8::internal::JSFunction::shared (this=0x7f2f351a0291)
at v8/src/objects-inl.h:3179
#7 0x000000000193fc2c in
v8::internal::Heap::InitializeJSObjectFromMap (this=0x7f2f454d1098,
obj=0x7f2f36016601, properties=0x7f2f360165d1, map=0x7f2f14fa0af9)
at v8/src/heap.cc:3197
#8 0x000000000193fea1 in v8::internal::Heap::AllocateJSObjectFromMap
(this=0x7f2f454d1098,
map=0x7f2f14fa0af9, pretenure=v8::internal::NOT_TENURED) at
v8/src/heap.cc:3243
#9 0x000000000193ffa0 in v8::internal::Heap::AllocateJSObject
(this=0x7f2f454d1098,
constructor=0x7f2f351a0291, pretenure=v8::internal::NOT_TENURED)
at v8/src/heap.cc:3262
#10 0x000000000193f3df in
v8::internal::Heap::AllocateFunctionPrototype (this=0x7f2f454d1098,
function=0x7f2f351b0bf9) at v8/src/heap.cc:3002
#11 0x000000000190a7fd in v8::internal::Factory::NewFunctionPrototype
(this=0x7f2f454d1000, function=...)
at v8/src/factory.cc:378
#12 0x000000000190d9a3 in v8::internal::Factory::NewFunction
(this=0x7f2f454d1000, name=...,
type=v8::internal::JS_GLOBAL_OBJECT_TYPE, instance_size=48,
code=..., force_initial_map=true)
at v8/src/factory.cc:657
#13 0x00000000018c5120 in v8::internal::Genesis::CreateNewGlobals
(this=0x7fffbf185a50,
global_template=..., global_object=..., inner_global_out=0x7fffbf1859c0)
at v8/src/bootstrapper.cc:716
#14 0x00000000018cc4d5 in v8::internal::Genesis::Genesis
(this=0x7fffbf185a50, isolate=0x7f2f454d1000,
global_object=..., global_template=..., extensions=0x0) at
v8/src/bootstrapper.cc:2128
#15 0x00000000018c33da in
v8::internal::Bootstrapper::CreateEnvironment (this=0x7f2f454c1f00,
isolate=0x7f2f454d1000, global_object=..., global_template=...,
extensions=0x0)
at v8/src/bootstrapper.cc:291
#16 0x00000000018ece69 in v8::internal::Debug::Load
(this=0x7f2f454e3000) at v8/src/debug.cc:820
#17 0x00000000018f6047 in v8::internal::EnterDebugger::EnterDebugger
(this=0x7fffbf185c40)
at v8/src/debug.h:892
- and we need to set up debug events handler on profiler enable as
well, as the presence of handler is required for V8 to process
messages from the debugger queue. Perhaps, we can fix it in V8?
=========================
<script>
var tabId = null;
chrome.experimental.debugger.onEvent.addListener(eventHandler);
chrome.experimental.debugger.onDetach.addListener(detached);
function detached(eTabId)
{
console.log("Detached from " + eTabId);
}
chrome.tabs.create({url:"http://www.google.com"}, function(tab) {
tabId = tab.id;
chrome.experimental.debugger.attach(tabId);
// Note this: absense of a delay may crash the renderer!
setTimeout(attached, 1000);
});
function attached()
{
chrome.experimental.debugger.sendRequest(tabId, "Debugger.enable");
chrome.experimental.debugger.sendRequest(tabId, "Profiler.enable");
chrome.experimental.debugger.sendRequest(tabId, "Profiler.start",
null, callback);
function callback(result)
{
console.log(result);
}
}
function eventHandler(eTabId, method, params) {
if (eTabId !== tabId)
return;
if (method === "Profiler.setRecordingProfile") {
if (params.isProfiling)
stop();
} else if (method === "Profiler.addProfileHeader") {
getProfile(params.header.typeId, params.header.uid);
}
}
function stop()
{
chrome.experimental.debugger.sendRequest(tabId, "Profiler.stop");
}
function getProfile(type, uid)
{
chrome.experimental.debugger.sendRequest(tabId,
"Profiler.getProfile", {"type":type,"uid":uid}, response);
function response(profile)
{
console.log(profile);
}
}
</script>
I'd advice you to use the following classes:
WebInspector.HeapSnapshotEdge
WebInspector.HeapSnapshotNode
WebInspector.HeapSnapshot
They provide a level of abstraction that is sufficient for most of the tasks.
Internally, heap snapshot is just a big array of heap nodes and edges.
You can look at the LayoutTests/inspector/profiler/heap-snapshot.html
test to get more insights.
What do you mean by "CPU usage of a whole page" -- parsing, rendering
and layout times? The only source currently is timeline (which doesn't
give CPU usage, only processing times).