@@ -816,6 +816,116 @@ void Worker::Unref(const FunctionCallbackInfo<Value>& args) {
816
816
}
817
817
}
818
818
819
+ class WorkerHeapStatisticsTaker : public AsyncWrap {
820
+ public:
821
+ WorkerHeapStatisticsTaker (Environment* env, Local<Object> obj)
822
+ : AsyncWrap(env, obj, AsyncWrap::PROVIDER_WORKERHEAPSTATISTICS) {}
823
+
824
+ SET_NO_MEMORY_INFO ()
825
+ SET_MEMORY_INFO_NAME (WorkerHeapStatisticsTaker)
826
+ SET_SELF_SIZE (WorkerHeapStatisticsTaker)
827
+ };
828
+
829
+ void Worker::GetHeapStatistics (const FunctionCallbackInfo<Value>& args) {
830
+ Worker* w;
831
+ ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
832
+
833
+ Environment* env = w->env ();
834
+ AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope (w);
835
+ Local<Object> wrap;
836
+ if (!env->worker_heap_statistics_taker_template ()
837
+ ->NewInstance (env->context ())
838
+ .ToLocal (&wrap)) {
839
+ return ;
840
+ }
841
+
842
+ // The created WorkerHeapStatisticsTaker is an object owned by main
843
+ // thread's Isolate, it can not be accessed by worker thread
844
+ std::unique_ptr<BaseObjectPtr<WorkerHeapStatisticsTaker>> taker =
845
+ std::make_unique<BaseObjectPtr<WorkerHeapStatisticsTaker>>(
846
+ MakeDetachedBaseObject<WorkerHeapStatisticsTaker>(env, wrap));
847
+
848
+ // Interrupt the worker thread and take a snapshot, then schedule a call
849
+ // on the parent thread that turns that snapshot into a readable stream.
850
+ bool scheduled = w->RequestInterrupt ([taker = std::move (taker),
851
+ env](Environment* worker_env) mutable {
852
+ // We create a unique pointer to HeapStatistics so that the actual object
853
+ // it's not copied in the lambda, but only the pointer is.
854
+ auto heap_stats = std::make_unique<v8::HeapStatistics>();
855
+ worker_env->isolate ()->GetHeapStatistics (heap_stats.get ());
856
+
857
+ // Here, the worker thread temporarily owns the WorkerHeapStatisticsTaker
858
+ // object.
859
+
860
+ env->SetImmediateThreadsafe (
861
+ [taker = std::move (taker),
862
+ heap_stats = std::move (heap_stats)](Environment* env) mutable {
863
+ Isolate* isolate = env->isolate ();
864
+ HandleScope handle_scope (isolate);
865
+ Context::Scope context_scope (env->context ());
866
+
867
+ AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope (taker->get ());
868
+
869
+ Local<v8::Name> heap_stats_names[] = {
870
+ FIXED_ONE_BYTE_STRING (isolate, " total_heap_size" ),
871
+ FIXED_ONE_BYTE_STRING (isolate, " total_heap_size_executable" ),
872
+ FIXED_ONE_BYTE_STRING (isolate, " total_physical_size" ),
873
+ FIXED_ONE_BYTE_STRING (isolate, " total_available_size" ),
874
+ FIXED_ONE_BYTE_STRING (isolate, " used_heap_size" ),
875
+ FIXED_ONE_BYTE_STRING (isolate, " heap_size_limit" ),
876
+ FIXED_ONE_BYTE_STRING (isolate, " malloced_memory" ),
877
+ FIXED_ONE_BYTE_STRING (isolate, " peak_malloced_memory" ),
878
+ FIXED_ONE_BYTE_STRING (isolate, " does_zap_garbage" ),
879
+ FIXED_ONE_BYTE_STRING (isolate, " number_of_native_contexts" ),
880
+ FIXED_ONE_BYTE_STRING (isolate, " number_of_detached_contexts" ),
881
+ FIXED_ONE_BYTE_STRING (isolate, " total_global_handles_size" ),
882
+ FIXED_ONE_BYTE_STRING (isolate, " used_global_handles_size" ),
883
+ FIXED_ONE_BYTE_STRING (isolate, " external_memory" )};
884
+
885
+ // Define an array of property values
886
+ Local<Value> heap_stats_values[] = {
887
+ Number::New (isolate, heap_stats->total_heap_size ()),
888
+ Number::New (isolate, heap_stats->total_heap_size_executable ()),
889
+ Number::New (isolate, heap_stats->total_physical_size ()),
890
+ Number::New (isolate, heap_stats->total_available_size ()),
891
+ Number::New (isolate, heap_stats->used_heap_size ()),
892
+ Number::New (isolate, heap_stats->heap_size_limit ()),
893
+ Number::New (isolate, heap_stats->malloced_memory ()),
894
+ Number::New (isolate, heap_stats->peak_malloced_memory ()),
895
+ Boolean::New (isolate, heap_stats->does_zap_garbage ()),
896
+ Number::New (isolate, heap_stats->number_of_native_contexts ()),
897
+ Number::New (isolate, heap_stats->number_of_detached_contexts ()),
898
+ Number::New (isolate, heap_stats->total_global_handles_size ()),
899
+ Number::New (isolate, heap_stats->used_global_handles_size ()),
900
+ Number::New (isolate, heap_stats->external_memory ())};
901
+
902
+ DCHECK_EQ (arraysize (heap_stats_names), arraysize (heap_stats_values));
903
+
904
+ // Create the object with the property names and values
905
+ Local<Object> stats = Object::New (isolate,
906
+ Null (isolate),
907
+ heap_stats_names,
908
+ heap_stats_values,
909
+ arraysize (heap_stats_names));
910
+
911
+ Local<Value> args[] = {stats};
912
+ taker->get ()->MakeCallback (
913
+ env->ondone_string (), arraysize (args), args);
914
+ // implicitly delete `taker`
915
+ },
916
+ CallbackFlags::kUnrefed );
917
+
918
+ // Now, the lambda is delivered to the main thread, as a result, the
919
+ // WorkerHeapStatisticsTaker object is delivered to the main thread, too.
920
+ });
921
+
922
+ if (scheduled) {
923
+ args.GetReturnValue ().Set (wrap);
924
+ } else {
925
+ args.GetReturnValue ().Set (Local<Object>());
926
+ }
927
+ }
928
+
819
929
void Worker::GetResourceLimits (const FunctionCallbackInfo<Value>& args) {
820
930
Worker* w;
821
931
ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
@@ -996,6 +1106,7 @@ void CreateWorkerPerIsolateProperties(IsolateData* isolate_data,
996
1106
SetProtoMethod (isolate, w, " takeHeapSnapshot" , Worker::TakeHeapSnapshot);
997
1107
SetProtoMethod (isolate, w, " loopIdleTime" , Worker::LoopIdleTime);
998
1108
SetProtoMethod (isolate, w, " loopStartTime" , Worker::LoopStartTime);
1109
+ SetProtoMethod (isolate, w, " getHeapStatistics" , Worker::GetHeapStatistics);
999
1110
1000
1111
SetConstructorFunction (isolate, target, " Worker" , w);
1001
1112
}
@@ -1014,6 +1125,20 @@ void CreateWorkerPerIsolateProperties(IsolateData* isolate_data,
1014
1125
wst->InstanceTemplate ());
1015
1126
}
1016
1127
1128
+ {
1129
+ Local<FunctionTemplate> wst = NewFunctionTemplate (isolate, nullptr );
1130
+
1131
+ wst->InstanceTemplate ()->SetInternalFieldCount (
1132
+ WorkerHeapSnapshotTaker::kInternalFieldCount );
1133
+ wst->Inherit (AsyncWrap::GetConstructorTemplate (isolate_data));
1134
+
1135
+ Local<String> wst_string =
1136
+ FIXED_ONE_BYTE_STRING (isolate, " WorkerHeapStatisticsTaker" );
1137
+ wst->SetClassName (wst_string);
1138
+ isolate_data->set_worker_heap_statistics_taker_template (
1139
+ wst->InstanceTemplate ());
1140
+ }
1141
+
1017
1142
SetMethod (isolate, target, " getEnvMessagePort" , GetEnvMessagePort);
1018
1143
}
1019
1144
@@ -1079,6 +1204,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1079
1204
registry->Register (Worker::TakeHeapSnapshot);
1080
1205
registry->Register (Worker::LoopIdleTime);
1081
1206
registry->Register (Worker::LoopStartTime);
1207
+ registry->Register (Worker::GetHeapStatistics);
1082
1208
}
1083
1209
1084
1210
} // anonymous namespace
0 commit comments