InspectorProfilerAgent.cpp [plain text]
#include "config.h"
#include "InspectorProfilerAgent.h"
#if ENABLE(INSPECTOR)
#include "InspectorValues.h"
#include "LegacyProfiler.h"
#include "Profile.h"
#include "ScriptDebugServer.h"
#include "ScriptObject.h"
#include <wtf/CurrentTime.h>
#include <wtf/text/StringConcatenate.h>
namespace Inspector {
static const char* const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
static const char* const CPUProfileType = "CPU";
InspectorProfilerAgent::InspectorProfilerAgent()
: InspectorAgentBase(ASCIILiteral("Profiler"))
, m_scriptDebugServer(nullptr)
, m_enabled(false)
, m_profileHeadersRequested(false)
, m_recordingProfileCount(0)
, m_nextUserInitiatedProfileNumber(1)
{
}
InspectorProfilerAgent::~InspectorProfilerAgent()
{
}
void InspectorProfilerAgent::didCreateFrontendAndBackend(InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
{
m_frontendDispatcher = std::make_unique<InspectorProfilerFrontendDispatcher>(frontendChannel);
m_backendDispatcher = InspectorProfilerBackendDispatcher::create(backendDispatcher, this);
}
void InspectorProfilerAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason reason)
{
m_frontendDispatcher = nullptr;
m_backendDispatcher.clear();
reset();
disable(reason == InspectorDisconnectReason::InspectedTargetDestroyed ? SkipRecompile : Recompile);
}
void InspectorProfilerAgent::addProfile(PassRefPtr<JSC::Profile> prpProfile)
{
RefPtr<JSC::Profile> profile = prpProfile;
m_profiles.add(profile->uid(), profile);
if (m_frontendDispatcher && m_profileHeadersRequested)
m_frontendDispatcher->addProfileHeader(createProfileHeader(*profile));
}
PassRefPtr<TypeBuilder::Profiler::ProfileHeader> InspectorProfilerAgent::createProfileHeader(const JSC::Profile& profile)
{
return TypeBuilder::Profiler::ProfileHeader::create()
.setTypeId(TypeBuilder::Profiler::ProfileHeader::TypeId::CPU)
.setUid(profile.uid())
.setTitle(profile.title())
.release();
}
void InspectorProfilerAgent::enable(ErrorString*)
{
enable(Recompile);
}
void InspectorProfilerAgent::disable(ErrorString*)
{
disable(Recompile);
}
void InspectorProfilerAgent::enable(ShouldRecompile shouldRecompile)
{
if (m_enabled)
return;
m_enabled = true;
if (shouldRecompile == Recompile)
m_scriptDebugServer->recompileAllJSFunctions();
}
void InspectorProfilerAgent::disable(ShouldRecompile shouldRecompile)
{
if (!m_enabled)
return;
m_enabled = false;
m_profileHeadersRequested = false;
if (shouldRecompile == Recompile)
m_scriptDebugServer->recompileAllJSFunctions();
}
String InspectorProfilerAgent::getUserInitiatedProfileName()
{
return makeString(UserInitiatedProfileName, '.', String::number(m_nextUserInitiatedProfileNumber++));
}
void InspectorProfilerAgent::getProfileHeaders(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::ProfileHeader>>& headers)
{
m_profileHeadersRequested = true;
headers = TypeBuilder::Array<TypeBuilder::Profiler::ProfileHeader>::create();
for (auto& profile : m_profiles.values())
headers->addItem(createProfileHeader(*profile.get()));
}
static PassRefPtr<TypeBuilder::Profiler::CPUProfileNodeCall> buildInspectorObject(const JSC::ProfileNode::Call& call)
{
RefPtr<TypeBuilder::Profiler::CPUProfileNodeCall> result = TypeBuilder::Profiler::CPUProfileNodeCall::create()
.setStartTime(call.startTime())
.setTotalTime(call.totalTime());
return result.release();
}
static PassRefPtr<TypeBuilder::Profiler::CPUProfileNode> buildInspectorObject(const JSC::ProfileNode* node)
{
RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNodeCall>> calls = TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNodeCall>::create();
for (const JSC::ProfileNode::Call& call : node->calls())
calls->addItem(buildInspectorObject(call));
RefPtr<TypeBuilder::Profiler::CPUProfileNode> result = TypeBuilder::Profiler::CPUProfileNode::create()
.setId(node->id())
.setCalls(calls.release());
if (!node->functionName().isEmpty())
result->setFunctionName(node->functionName());
if (!node->url().isEmpty()) {
result->setUrl(node->url());
result->setLineNumber(node->lineNumber());
result->setColumnNumber(node->columnNumber());
}
if (!node->children().isEmpty()) {
RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>> children = TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>::create();
for (RefPtr<JSC::ProfileNode> profileNode : node->children())
children->addItem(buildInspectorObject(profileNode.get()));
result->setChildren(children);
}
return result.release();
}
PassRefPtr<TypeBuilder::Profiler::CPUProfile> InspectorProfilerAgent::buildProfileInspectorObject(const JSC::Profile* profile)
{
RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>> rootNodes = TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>::create();
for (RefPtr<JSC::ProfileNode> profileNode : profile->head()->children())
rootNodes->addItem(buildInspectorObject(profileNode.get()));
RefPtr<TypeBuilder::Profiler::CPUProfile> result = TypeBuilder::Profiler::CPUProfile::create()
.setRootNodes(rootNodes);
if (profile->idleTime())
result->setIdleTime(profile->idleTime());
return result.release();
}
void InspectorProfilerAgent::getCPUProfile(ErrorString* errorString, int rawUid, RefPtr<TypeBuilder::Profiler::CPUProfile>& profileObject)
{
unsigned uid = static_cast<unsigned>(rawUid);
auto it = m_profiles.find(uid);
if (it == m_profiles.end()) {
*errorString = ASCIILiteral("Profile wasn't found");
return;
}
profileObject = buildProfileInspectorObject(it->value.get());
}
void InspectorProfilerAgent::removeProfile(ErrorString*, const String& type, int rawUid)
{
unsigned uid = static_cast<unsigned>(rawUid);
if (type == CPUProfileType)
m_profiles.remove(uid);
}
void InspectorProfilerAgent::reset()
{
stop();
m_profiles.clear();
m_nextUserInitiatedProfileNumber = 1;
m_profileHeadersRequested = false;
if (m_frontendDispatcher && m_profileHeadersRequested)
m_frontendDispatcher->resetProfiles();
}
void InspectorProfilerAgent::start(ErrorString*)
{
startProfiling();
}
void InspectorProfilerAgent::stop(ErrorString*)
{
stopProfiling();
}
void InspectorProfilerAgent::setRecordingProfile(bool isProfiling)
{
if (m_frontendDispatcher)
m_frontendDispatcher->setRecordingProfile(isProfiling);
}
String InspectorProfilerAgent::startProfiling(const String &title, JSC::ExecState* exec)
{
if (!enabled())
enable(Recompile);
bool wasNotRecording = !m_recordingProfileCount;
++m_recordingProfileCount;
String resolvedTitle = title;
if (title.isEmpty())
resolvedTitle = getUserInitiatedProfileName();
if (!exec)
exec = profilingGlobalExecState();
ASSERT(exec);
JSC::LegacyProfiler::profiler()->startProfiling(exec, resolvedTitle);
if (wasNotRecording)
setRecordingProfile(true);
return resolvedTitle;
}
PassRefPtr<JSC::Profile> InspectorProfilerAgent::stopProfiling(const String& title, JSC::ExecState* exec)
{
if (!m_recordingProfileCount)
return nullptr;
--m_recordingProfileCount;
if (!exec)
exec = profilingGlobalExecState();
ASSERT(exec);
RefPtr<JSC::Profile> profile = JSC::LegacyProfiler::profiler()->stopProfiling(exec, title);
if (profile)
addProfile(profile);
if (!m_recordingProfileCount)
setRecordingProfile(false);
return profile.release();
}
}
#endif // ENABLE(INSPECTOR)