Skip to content

Commit 4bcabdb

Browse files
committed
V8 profiler
1 parent 8723d1d commit 4bcabdb

File tree

2 files changed

+169
-0
lines changed

2 files changed

+169
-0
lines changed

Plugins/UnrealJS/Source/V8/Private/JavascriptIsolate_Private.cpp

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,8 @@ class FJavascriptIsolateImplementation : public FJavascriptIsolate
330330
ExportMemory(ObjectTemplate);
331331

332332
ExportMisc(ObjectTemplate);
333+
334+
ExportProfiler(ObjectTemplate);
333335
}
334336

335337
~FJavascriptIsolateImplementation()
@@ -770,6 +772,172 @@ class FJavascriptIsolateImplementation : public FJavascriptIsolate
770772
ReadOnly);
771773
}
772774

775+
static Local<Object> Visit(Isolate* isolate, const v8::CpuProfileNode* node)
776+
{
777+
static TMap<const v8::CpuProfileNode*, Handle<Object>> Visited;
778+
779+
if (!isolate)
780+
{
781+
Visited.Empty();
782+
return Local<Object>();
783+
}
784+
auto Existing = Visited.Find(node);
785+
if (Existing) return *Existing;
786+
787+
FIsolateHelper I(isolate);
788+
789+
auto Out = Object::New(isolate);
790+
791+
Visited.Add(node, Out);
792+
793+
Out->Set(I.Keyword("ScriptResourceName"), node->GetScriptResourceName());
794+
Out->Set(I.Keyword("FunctionName"), node->GetFunctionName());
795+
Out->Set(I.Keyword("HitCount"), Integer::NewFromUnsigned(isolate,node->GetHitCount()));
796+
Out->Set(I.Keyword("LineNumber"), Integer::New(isolate,node->GetLineNumber()));
797+
Out->Set(I.Keyword("ColumnNumber"), Integer::New(isolate,node->GetColumnNumber()));
798+
Out->Set(I.Keyword("ScriptId"), Integer::New(isolate, node->GetScriptId()));
799+
800+
{
801+
uint32_t Num = node->GetHitLineCount();
802+
TArray<v8::CpuProfileNode::LineTick> Buffer;
803+
Buffer.AddDefaulted(Num);
804+
node->GetLineTicks(Buffer.GetData(), Num);
805+
806+
auto Arr = Array::New(isolate, Num);
807+
for (uint32_t Index = 0; Index < Num; ++Index)
808+
{
809+
const auto& info = Buffer[Index];
810+
auto item = Object::New(isolate);
811+
item->Set(I.Keyword("line"), Integer::New(isolate,info.line));
812+
item->Set(I.Keyword("hit_count"), Integer::New(isolate, info.hit_count));
813+
Arr->Set(Index, item);
814+
}
815+
Out->Set(I.Keyword("LineTicks"), Arr);
816+
}
817+
818+
auto BailOutReason = node->GetBailoutReason();
819+
if (BailOutReason)
820+
{
821+
Out->Set(I.Keyword("BailOutReason"), I.Keyword(BailOutReason));
822+
}
823+
824+
{
825+
const auto& deopt = node->GetDeoptInfos();
826+
uint32_t Num = deopt.size();
827+
if (Num)
828+
{
829+
auto Arr = Array::New(isolate, deopt.size());
830+
for (uint32_t Index = 0; Index < Num; ++Index)
831+
{
832+
const auto& info = deopt[Index];
833+
FString out;
834+
for (const auto& frame : info.stack)
835+
{
836+
out.Append(FString::Printf(TEXT("%d:%d "), (int)frame.script_id, (int)frame.position));
837+
}
838+
auto item = Object::New(isolate);
839+
item->Set(I.Keyword("reason"), I.Keyword(deopt[Index].deopt_reason));
840+
item->Set(I.Keyword("stack"), I.String(out));
841+
Arr->Set(Index, item);
842+
}
843+
Out->Set(I.Keyword("DeoptInfos"), Arr);
844+
}
845+
}
846+
847+
uint32_t Num = node->GetChildrenCount();
848+
if (Num)
849+
{
850+
auto Arr = Array::New(isolate, Num);
851+
for (uint32_t Index = 0; Index < Num; ++Index)
852+
{
853+
Arr->Set(Index, Visit(isolate, node->GetChild(Index)));
854+
}
855+
Out->Set(I.Keyword("Children"), Arr);
856+
}
857+
return Out;
858+
};
859+
860+
void ExportProfiler(Local<ObjectTemplate> global_templ)
861+
{
862+
FIsolateHelper I(isolate_);
863+
864+
Local<FunctionTemplate> Template = I.FunctionTemplate();
865+
866+
auto add_fn = [&](const char* name, FunctionCallback fn) {
867+
Template->PrototypeTemplate()->Set(I.Keyword(name), I.FunctionTemplate(fn));
868+
};
869+
870+
add_fn("SetSamplingInterval", [](const FunctionCallbackInfo<Value>& info)
871+
{
872+
FIsolateHelper I(info.GetIsolate());
873+
874+
auto profiler = info.GetIsolate()->GetCpuProfiler();
875+
876+
if (info.Length() == 1)
877+
{
878+
profiler->SetSamplingInterval(info[0]->IntegerValue());
879+
}
880+
});
881+
882+
add_fn("StartProfiling", [](const FunctionCallbackInfo<Value>& info)
883+
{
884+
FIsolateHelper I(info.GetIsolate());
885+
886+
auto profiler = info.GetIsolate()->GetCpuProfiler();
887+
888+
if (info.Length() == 2)
889+
{
890+
profiler->StartProfiling(info[0].As<String>(), info[1]->BooleanValue());
891+
info.GetReturnValue().Set(true);
892+
}
893+
});
894+
895+
add_fn("StopProfiling", [](const FunctionCallbackInfo<Value>& info)
896+
{
897+
auto isolate = info.GetIsolate();
898+
FIsolateHelper I(isolate);
899+
900+
auto profiler = isolate->GetCpuProfiler();
901+
902+
if (info.Length() == 1)
903+
{
904+
auto Profile = profiler->StopProfiling(info[0].As<String>());
905+
906+
auto Out = Object::New(isolate);
907+
Out->Set(I.Keyword("Root"), Visit(isolate, Profile->GetTopDownRoot()));
908+
Out->Set(I.Keyword("Title"), Profile->GetTitle());
909+
910+
{
911+
uint32_t Num = Profile->GetSamplesCount();
912+
if (Num)
913+
{
914+
auto Arr = Array::New(isolate, Num);
915+
for (uint32_t Index = 0; Index < Num; ++Index)
916+
{
917+
Arr->Set(Index, Visit(isolate, Profile->GetSample(Index)));
918+
}
919+
Out->Set(I.Keyword("Samples"), Arr);
920+
}
921+
}
922+
923+
924+
// cleanup
925+
Visit(nullptr, nullptr);
926+
927+
info.GetReturnValue().Set(Out);
928+
929+
Profile->Delete();
930+
}
931+
});
932+
933+
global_templ->Set(
934+
I.Keyword("v8"),
935+
// Create an instance
936+
Template->GetFunction()->NewInstance(),
937+
// Do not modify!
938+
ReadOnly);
939+
}
940+
773941
void ExportMisc(Local<ObjectTemplate> global_templ)
774942
{
775943
FIsolateHelper I(isolate_);

Plugins/UnrealJS/Source/V8/Private/V8PCH.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "v8.h"
1111
#include <v8-debug.h>
12+
#include <v8-profiler.h>
1213

1314
#pragma warning( pop )
1415

0 commit comments

Comments
 (0)