|
16 | 16 | #if WITH_EDITOR
|
17 | 17 | #include "ScopedTransaction.h"
|
18 | 18 | #endif
|
19 |
| - |
20 |
| -DECLARE_STATS_GROUP(TEXT("Javascript"), STATGROUP_Javascript, STATCAT_Advanced); |
21 |
| - |
22 |
| -DECLARE_CYCLE_STAT(TEXT("Scavenge"), STAT_Scavenge, STATGROUP_Javascript); |
23 |
| -DECLARE_CYCLE_STAT(TEXT("MarkSweepCompact"), STAT_MarkSweepCompact, STATGROUP_Javascript); |
24 |
| -DECLARE_CYCLE_STAT(TEXT("IncrementalMarking"), STAT_IncrementalMarking, STATGROUP_Javascript); |
25 |
| -DECLARE_CYCLE_STAT(TEXT("ProcessWeakCallbacks"), STAT_ProcessWeakCallbacks, STATGROUP_Javascript); |
26 |
| - |
27 |
| -DECLARE_MEMORY_STAT(TEXT("NewSpace"), STAT_NewSpace, STATGROUP_Javascript); |
28 |
| -DECLARE_MEMORY_STAT(TEXT("OldSpace"), STAT_OldSpace, STATGROUP_Javascript); |
29 |
| -DECLARE_MEMORY_STAT(TEXT("CodeSpace"), STAT_CodeSpace, STATGROUP_Javascript); |
30 |
| -DECLARE_MEMORY_STAT(TEXT("MapSpace"), STAT_MapSpace, STATGROUP_Javascript); |
31 |
| -DECLARE_MEMORY_STAT(TEXT("LoSpace"), STAT_LoSpace, STATGROUP_Javascript); |
| 19 | +#include "JavascriptStats.h" |
32 | 20 |
|
33 | 21 | using namespace v8;
|
34 | 22 |
|
@@ -98,6 +86,10 @@ class FJavascriptIsolateImplementation : public FJavascriptIsolate
|
98 | 86 |
|
99 | 87 | if (IsValid(Object))
|
100 | 88 | {
|
| 89 | + FScopeCycleCounterUObject ContextScope(Object); |
| 90 | + FScopeCycleCounterUObject PropertyScope(Property); |
| 91 | + SCOPE_CYCLE_COUNTER(STAT_JavascriptPropertyGet); |
| 92 | + |
101 | 93 | if (auto p = Cast<UMulticastDelegateProperty>(Property))
|
102 | 94 | {
|
103 | 95 | return GetSelf(isolate)->Delegates->GetProxy(self, Object, p);
|
@@ -168,6 +160,10 @@ class FJavascriptIsolateImplementation : public FJavascriptIsolate
|
168 | 160 |
|
169 | 161 | if (IsValid(Object))
|
170 | 162 | {
|
| 163 | + FScopeCycleCounterUObject ContextScope(Object); |
| 164 | + FScopeCycleCounterUObject PropertyScope(Property); |
| 165 | + SCOPE_CYCLE_COUNTER(STAT_JavascriptPropertySet); |
| 166 | + |
171 | 167 | // Multicast delegate
|
172 | 168 | if (auto p = Cast<UMulticastDelegateProperty>(Property))
|
173 | 169 | {
|
@@ -342,6 +338,8 @@ class FJavascriptIsolateImplementation : public FJavascriptIsolate
|
342 | 338 | ExportMemory(ObjectTemplate);
|
343 | 339 |
|
344 | 340 | ExportMisc(ObjectTemplate);
|
| 341 | + |
| 342 | + ExportProfiler(ObjectTemplate); |
345 | 343 | }
|
346 | 344 |
|
347 | 345 | ~FJavascriptIsolateImplementation()
|
@@ -555,8 +553,24 @@ class FJavascriptIsolateImplementation : public FJavascriptIsolate
|
555 | 553 |
|
556 | 554 | void ReadOffStruct(Local<Object> v8_obj, UStruct* Struct, uint8* struct_buffer)
|
557 | 555 | {
|
| 556 | + SCOPE_CYCLE_COUNTER(STAT_JavascriptReadOffStruct); |
| 557 | + FScopeCycleCounterUObject StructContext(Struct); |
| 558 | + |
558 | 559 | FIsolateHelper I(isolate_);
|
559 | 560 |
|
| 561 | + /* |
| 562 | + MaybeLocal<Array> _arr = v8_obj->GetOwnPropertyNames(); |
| 563 | + if (_arr.IsEmpty()) return; |
| 564 | +
|
| 565 | + auto arr = _arr.ToLocalChecked(); |
| 566 | +
|
| 567 | + auto len = arr->Length(); |
| 568 | +
|
| 569 | + for (decltype(len) Index = 0; Index < len; ++Index) |
| 570 | + { |
| 571 | + } |
| 572 | + */ |
| 573 | + |
560 | 574 | for (TFieldIterator<UProperty> PropertyIt(Struct, EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt)
|
561 | 575 | {
|
562 | 576 | auto Property = *PropertyIt;
|
@@ -782,6 +796,173 @@ class FJavascriptIsolateImplementation : public FJavascriptIsolate
|
782 | 796 | ReadOnly);
|
783 | 797 | }
|
784 | 798 |
|
| 799 | + static Local<Object> Visit(Isolate* isolate, const v8::CpuProfileNode* node) |
| 800 | + { |
| 801 | + static TMap<const v8::CpuProfileNode*, Handle<Object>> Visited; |
| 802 | + |
| 803 | + if (!isolate) |
| 804 | + { |
| 805 | + Visited.Empty(); |
| 806 | + return Local<Object>(); |
| 807 | + } |
| 808 | + auto Existing = Visited.Find(node); |
| 809 | + if (Existing) return *Existing; |
| 810 | + |
| 811 | + FIsolateHelper I(isolate); |
| 812 | + |
| 813 | + auto Out = Object::New(isolate); |
| 814 | + |
| 815 | + Visited.Add(node, Out); |
| 816 | + |
| 817 | + Out->Set(I.Keyword("ScriptResourceName"), node->GetScriptResourceName()); |
| 818 | + Out->Set(I.Keyword("FunctionName"), node->GetFunctionName()); |
| 819 | + Out->Set(I.Keyword("HitCount"), Integer::NewFromUnsigned(isolate,node->GetHitCount())); |
| 820 | + Out->Set(I.Keyword("LineNumber"), Integer::New(isolate,node->GetLineNumber())); |
| 821 | + Out->Set(I.Keyword("ColumnNumber"), Integer::New(isolate,node->GetColumnNumber())); |
| 822 | + Out->Set(I.Keyword("ScriptId"), Integer::New(isolate, node->GetScriptId())); |
| 823 | + |
| 824 | + { |
| 825 | + uint32_t Num = node->GetHitLineCount(); |
| 826 | + TArray<v8::CpuProfileNode::LineTick> Buffer; |
| 827 | + Buffer.AddDefaulted(Num); |
| 828 | + node->GetLineTicks(Buffer.GetData(), Num); |
| 829 | + |
| 830 | + auto Arr = Array::New(isolate, Num); |
| 831 | + for (uint32_t Index = 0; Index < Num; ++Index) |
| 832 | + { |
| 833 | + const auto& info = Buffer[Index]; |
| 834 | + auto item = Object::New(isolate); |
| 835 | + item->Set(I.Keyword("line"), Integer::New(isolate,info.line)); |
| 836 | + item->Set(I.Keyword("hit_count"), Integer::New(isolate, info.hit_count)); |
| 837 | + Arr->Set(Index, item); |
| 838 | + } |
| 839 | + Out->Set(I.Keyword("LineTicks"), Arr); |
| 840 | + } |
| 841 | + |
| 842 | + auto BailOutReason = node->GetBailoutReason(); |
| 843 | + if (BailOutReason) |
| 844 | + { |
| 845 | + Out->Set(I.Keyword("BailOutReason"), I.Keyword(BailOutReason)); |
| 846 | + } |
| 847 | + |
| 848 | + { |
| 849 | + const auto& deopt = node->GetDeoptInfos(); |
| 850 | + uint32_t Num = deopt.size(); |
| 851 | + if (Num) |
| 852 | + { |
| 853 | + auto Arr = Array::New(isolate, deopt.size()); |
| 854 | + for (uint32_t Index = 0; Index < Num; ++Index) |
| 855 | + { |
| 856 | + const auto& info = deopt[Index]; |
| 857 | + FString out; |
| 858 | + for (const auto& frame : info.stack) |
| 859 | + { |
| 860 | + out.Append(FString::Printf(TEXT("%d:%d "), (int)frame.script_id, (int)frame.position)); |
| 861 | + } |
| 862 | + auto item = Object::New(isolate); |
| 863 | + item->Set(I.Keyword("reason"), I.Keyword(deopt[Index].deopt_reason)); |
| 864 | + item->Set(I.Keyword("stack"), I.String(out)); |
| 865 | + Arr->Set(Index, item); |
| 866 | + } |
| 867 | + Out->Set(I.Keyword("DeoptInfos"), Arr); |
| 868 | + } |
| 869 | + } |
| 870 | + |
| 871 | + uint32_t Num = node->GetChildrenCount(); |
| 872 | + if (Num) |
| 873 | + { |
| 874 | + auto Arr = Array::New(isolate, Num); |
| 875 | + for (uint32_t Index = 0; Index < Num; ++Index) |
| 876 | + { |
| 877 | + Arr->Set(Index, Visit(isolate, node->GetChild(Index))); |
| 878 | + } |
| 879 | + Out->Set(I.Keyword("Children"), Arr); |
| 880 | + } |
| 881 | + return Out; |
| 882 | + }; |
| 883 | + |
| 884 | + void ExportProfiler(Local<ObjectTemplate> global_templ) |
| 885 | + { |
| 886 | + FIsolateHelper I(isolate_); |
| 887 | + |
| 888 | + Local<FunctionTemplate> Template = I.FunctionTemplate(); |
| 889 | + |
| 890 | + auto add_fn = [&](const char* name, FunctionCallback fn) { |
| 891 | + Template->PrototypeTemplate()->Set(I.Keyword(name), I.FunctionTemplate(fn)); |
| 892 | + }; |
| 893 | + |
| 894 | + add_fn("SetSamplingInterval", [](const FunctionCallbackInfo<Value>& info) |
| 895 | + { |
| 896 | + FIsolateHelper I(info.GetIsolate()); |
| 897 | + |
| 898 | + auto profiler = info.GetIsolate()->GetCpuProfiler(); |
| 899 | + |
| 900 | + if (info.Length() == 1) |
| 901 | + { |
| 902 | + profiler->SetSamplingInterval(info[0]->IntegerValue()); |
| 903 | + } |
| 904 | + }); |
| 905 | + |
| 906 | + add_fn("StartProfiling", [](const FunctionCallbackInfo<Value>& info) |
| 907 | + { |
| 908 | + FIsolateHelper I(info.GetIsolate()); |
| 909 | + |
| 910 | + auto profiler = info.GetIsolate()->GetCpuProfiler(); |
| 911 | + |
| 912 | + if (info.Length() == 2) |
| 913 | + { |
| 914 | + profiler->StartProfiling(info[0].As<String>(), info[1]->BooleanValue()); |
| 915 | + info.GetReturnValue().Set(true); |
| 916 | + } |
| 917 | + }); |
| 918 | + |
| 919 | + add_fn("StopProfiling", [](const FunctionCallbackInfo<Value>& info) |
| 920 | + { |
| 921 | + auto isolate = info.GetIsolate(); |
| 922 | + FIsolateHelper I(isolate); |
| 923 | + |
| 924 | + auto profiler = isolate->GetCpuProfiler(); |
| 925 | + |
| 926 | + if (info.Length() == 1) |
| 927 | + { |
| 928 | + auto Profile = profiler->StopProfiling(info[0].As<String>()); |
| 929 | + if (!Profile) return; |
| 930 | + |
| 931 | + auto Out = Object::New(isolate); |
| 932 | + Out->Set(I.Keyword("Root"), Visit(isolate, Profile->GetTopDownRoot())); |
| 933 | + Out->Set(I.Keyword("Title"), Profile->GetTitle()); |
| 934 | + |
| 935 | + { |
| 936 | + uint32_t Num = Profile->GetSamplesCount(); |
| 937 | + if (Num) |
| 938 | + { |
| 939 | + auto Arr = Array::New(isolate, Num); |
| 940 | + for (uint32_t Index = 0; Index < Num; ++Index) |
| 941 | + { |
| 942 | + Arr->Set(Index, Visit(isolate, Profile->GetSample(Index))); |
| 943 | + } |
| 944 | + Out->Set(I.Keyword("Samples"), Arr); |
| 945 | + } |
| 946 | + } |
| 947 | + |
| 948 | + |
| 949 | + // cleanup |
| 950 | + Visit(nullptr, nullptr); |
| 951 | + |
| 952 | + info.GetReturnValue().Set(Out); |
| 953 | + |
| 954 | + Profile->Delete(); |
| 955 | + } |
| 956 | + }); |
| 957 | + |
| 958 | + global_templ->Set( |
| 959 | + I.Keyword("v8"), |
| 960 | + // Create an instance |
| 961 | + Template->GetFunction()->NewInstance(), |
| 962 | + // Do not modify! |
| 963 | + ReadOnly); |
| 964 | + } |
| 965 | + |
785 | 966 | void ExportMisc(Local<ObjectTemplate> global_templ)
|
786 | 967 | {
|
787 | 968 | FIsolateHelper I(isolate_);
|
@@ -961,6 +1142,8 @@ class FJavascriptIsolateImplementation : public FJavascriptIsolate
|
961 | 1142 | template <typename Fn>
|
962 | 1143 | static Local<Value> CallFunction(Isolate* isolate, Local<Value> self, UFunction* Function, UObject* Object, Fn&& GetArg)
|
963 | 1144 | {
|
| 1145 | + SCOPE_CYCLE_COUNTER(STAT_JavascriptFunctionCall); |
| 1146 | + |
964 | 1147 | FIsolateHelper I(isolate);
|
965 | 1148 |
|
966 | 1149 | EscapableHandleScope handle_scope(isolate);
|
|
0 commit comments