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