@@ -271,6 +271,105 @@ class WorkerThreadData {
271271 friend class Worker ;
272272};
273273
274+ class WorkerMemoryUsageTaker : public AsyncWrap {
275+ public:
276+ WorkerMemoryUsageTaker (Environment* env, Local<Object> obj)
277+ : AsyncWrap(env, obj, AsyncWrap::PROVIDER_WORKERMEMORYUSAGE) {}
278+
279+ SET_NO_MEMORY_INFO ()
280+ SET_MEMORY_INFO_NAME (WorkerMemoryUsageTaker)
281+ SET_SELF_SIZE (WorkerMemoryUsageTaker)
282+ };
283+
284+ void Worker::GetMemoryUsage (const FunctionCallbackInfo<Value>& args) {
285+ Worker* w;
286+ ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
287+
288+ Environment* env = w->env ();
289+ AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope (w);
290+ Local<Object> wrap;
291+ if (!env->worker_memory_usage_taker_template ()
292+ ->NewInstance (env->context ())
293+ .ToLocal (&wrap)) {
294+ return ;
295+ }
296+
297+ std::unique_ptr<BaseObjectPtr<WorkerMemoryUsageTaker>> taker =
298+ std::make_unique<BaseObjectPtr<WorkerMemoryUsageTaker>>(
299+ MakeDetachedBaseObject<WorkerMemoryUsageTaker>(env, wrap));
300+
301+ bool scheduled = w->RequestInterrupt ([taker = std::move (taker),
302+ env](Environment* worker_env) mutable {
303+ auto stats = std::make_unique<uv_rusage_t >();
304+ int rss_err = uv_getrusage_thread (stats.get ());
305+ HeapStatistics heap_stats;
306+ worker_env->isolate ()->GetHeapStatistics (&heap_stats);
307+ NodeArrayBufferAllocator* allocator =
308+ worker_env->isolate_data ()->node_allocator ();
309+
310+ env->SetImmediateThreadsafe (
311+ [taker = std::move (taker),
312+ rss_err,
313+ stats = std::move (stats),
314+ heap_stats,
315+ allocator](Environment* env) mutable {
316+ Isolate* isolate = env->isolate ();
317+ HandleScope handle_scope (isolate);
318+ Context::Scope context_scope (env->context ());
319+ AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope (taker->get ());
320+
321+ auto tmpl = env->memory_usage_template ();
322+ if (tmpl.IsEmpty ()) {
323+ static constexpr std::string_view names[] = {
324+ " rss" ,
325+ " heapTotal" ,
326+ " heapUsed" ,
327+ " external" ,
328+ " arrayBuffers" ,
329+ };
330+ tmpl = DictionaryTemplate::New (isolate, names);
331+ env->set_memory_usage_template (tmpl);
332+ }
333+
334+ MaybeLocal<Value> values[] = {
335+ Number::New (isolate, rss_err ? 0 : stats->ru_maxrss * 1024 ),
336+ Number::New (isolate, heap_stats.total_heap_size ()),
337+ Number::New (isolate, heap_stats.used_heap_size ()),
338+ Number::New (isolate, heap_stats.external_memory ()),
339+ Number::New (isolate, allocator == nullptr
340+ ? 0
341+ : allocator->total_mem_usage ()),
342+ };
343+
344+ Local<Value> argv[] = {
345+ Null (isolate),
346+ Undefined (isolate),
347+ };
348+
349+ if (rss_err) {
350+ argv[0 ] = UVException (isolate,
351+ rss_err,
352+ " uv_getrusage_thread" ,
353+ nullptr ,
354+ nullptr ,
355+ nullptr );
356+ } else if (!NewDictionaryInstanceNullProto (
357+ env->context (), tmpl, values)
358+ .ToLocal (&argv[1 ])) {
359+ return ;
360+ }
361+
362+ taker->get ()->MakeCallback (
363+ env->ondone_string (), arraysize (argv), argv);
364+ },
365+ CallbackFlags::kUnrefed );
366+ });
367+
368+ if (scheduled) {
369+ args.GetReturnValue ().Set (wrap);
370+ }
371+ }
372+
274373size_t Worker::NearHeapLimit (void * data, size_t current_heap_limit,
275374 size_t initial_heap_limit) {
276375 Worker* worker = static_cast <Worker*>(data);
@@ -1489,6 +1588,7 @@ void CreateWorkerPerIsolateProperties(IsolateData* isolate_data,
14891588 SetProtoMethod (isolate, w, " loopIdleTime" , Worker::LoopIdleTime);
14901589 SetProtoMethod (isolate, w, " loopStartTime" , Worker::LoopStartTime);
14911590 SetProtoMethod (isolate, w, " getHeapStatistics" , Worker::GetHeapStatistics);
1591+ SetProtoMethod (isolate, w, " getMemoryUsage" , Worker::GetMemoryUsage);
14921592 SetProtoMethod (isolate, w, " cpuUsage" , Worker::CpuUsage);
14931593 SetProtoMethod (isolate, w, " startCpuProfile" , Worker::StartCpuProfile);
14941594 SetProtoMethod (isolate, w, " stopCpuProfile" , Worker::StopCpuProfile);
@@ -1539,6 +1639,20 @@ void CreateWorkerPerIsolateProperties(IsolateData* isolate_data,
15391639 isolate_data->set_worker_cpu_usage_taker_template (wst->InstanceTemplate ());
15401640 }
15411641
1642+ {
1643+ Local<FunctionTemplate> wst = NewFunctionTemplate (isolate, nullptr );
1644+
1645+ wst->InstanceTemplate ()->SetInternalFieldCount (
1646+ WorkerMemoryUsageTaker::kInternalFieldCount );
1647+ wst->Inherit (AsyncWrap::GetConstructorTemplate (isolate_data));
1648+
1649+ Local<String> wst_string =
1650+ FIXED_ONE_BYTE_STRING (isolate, " WorkerMemoryUsageTaker" );
1651+ wst->SetClassName (wst_string);
1652+ isolate_data->set_worker_memory_usage_taker_template (
1653+ wst->InstanceTemplate ());
1654+ }
1655+
15421656 {
15431657 Local<FunctionTemplate> wst = NewFunctionTemplate (isolate, nullptr );
15441658
@@ -1643,6 +1757,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
16431757 registry->Register (Worker::LoopIdleTime);
16441758 registry->Register (Worker::LoopStartTime);
16451759 registry->Register (Worker::GetHeapStatistics);
1760+ registry->Register (Worker::GetMemoryUsage);
16461761 registry->Register (Worker::CpuUsage);
16471762 registry->Register (Worker::StartCpuProfile);
16481763 registry->Register (Worker::StopCpuProfile);
0 commit comments