GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_report.cc Lines: 338 341 99.1 %
Date: 2020-05-27 22:15:15 Branches: 73 96 76.0 %

Line Branch Exec Source
1
#include "env-inl.h"
2
#include "json_utils.h"
3
#include "node_report.h"
4
#include "debug_utils-inl.h"
5
#include "diagnosticfilename-inl.h"
6
#include "node_internals.h"
7
#include "node_metadata.h"
8
#include "node_mutex.h"
9
#include "node_worker.h"
10
#include "util.h"
11
12
#ifdef _WIN32
13
#include <Windows.h>
14
#else  // !_WIN32
15
#include <sys/resource.h>
16
#include <cxxabi.h>
17
#include <dlfcn.h>
18
#endif
19
20
#include <iostream>
21
#include <cstring>
22
#include <ctime>
23
#include <cwctype>
24
#include <fstream>
25
26
constexpr int NODE_REPORT_VERSION = 2;
27
constexpr int NANOS_PER_SEC = 1000 * 1000 * 1000;
28
constexpr double SEC_PER_MICROS = 1e-6;
29
30
namespace report {
31
using node::arraysize;
32
using node::ConditionVariable;
33
using node::DiagnosticFilename;
34
using node::Environment;
35
using node::JSONWriter;
36
using node::Mutex;
37
using node::NativeSymbolDebuggingContext;
38
using node::TIME_TYPE;
39
using node::worker::Worker;
40
using v8::HeapSpaceStatistics;
41
using v8::HeapStatistics;
42
using v8::Isolate;
43
using v8::Local;
44
using v8::Number;
45
using v8::StackTrace;
46
using v8::String;
47
using v8::V8;
48
using v8::Value;
49
50
namespace per_process = node::per_process;
51
52
// Internal/static function declarations
53
static void WriteNodeReport(Isolate* isolate,
54
                            Environment* env,
55
                            const char* message,
56
                            const char* trigger,
57
                            const std::string& filename,
58
                            std::ostream& out,
59
                            Local<String> stackstr,
60
                            bool compact);
61
static void PrintVersionInformation(JSONWriter* writer);
62
static void PrintJavaScriptStack(JSONWriter* writer,
63
                                 Isolate* isolate,
64
                                 Local<String> stackstr,
65
                                 const char* trigger);
66
static void PrintNativeStack(JSONWriter* writer);
67
static void PrintResourceUsage(JSONWriter* writer);
68
static void PrintGCStatistics(JSONWriter* writer, Isolate* isolate);
69
static void PrintSystemInformation(JSONWriter* writer);
70
static void PrintLoadedLibraries(JSONWriter* writer);
71
static void PrintComponentVersions(JSONWriter* writer);
72
static void PrintRelease(JSONWriter* writer);
73
static void PrintCpuInfo(JSONWriter* writer);
74
static void PrintNetworkInterfaceInfo(JSONWriter* writer);
75
76
// External function to trigger a report, writing to file.
77
12
std::string TriggerNodeReport(Isolate* isolate,
78
                              Environment* env,
79
                              const char* message,
80
                              const char* trigger,
81
                              const std::string& name,
82
                              Local<String> stackstr) {
83
24
  std::string filename;
84
85
  // Determine the required report filename. In order of priority:
86
  //   1) supplied on API 2) configured on startup 3) default generated
87
12
  if (!name.empty()) {
88
    // Filename was specified as API parameter.
89
4
    filename = name;
90
  } else {
91
16
    std::string report_filename;
92
    {
93
16
      Mutex::ScopedLock lock(per_process::cli_options_mutex);
94
8
      report_filename = per_process::cli_options->report_filename;
95
    }
96
8
    if (report_filename.length() > 0) {
97
      // File name was supplied via start-up option.
98
1
      filename = report_filename;
99
    } else {
100
14
      filename = *DiagnosticFilename(env != nullptr ? env->thread_id() : 0,
101
7
          "report", "json");
102
    }
103
  }
104
105
  // Open the report file stream for writing. Supports stdout/err,
106
  // user-specified or (default) generated name
107
24
  std::ofstream outfile;
108
  std::ostream* outstream;
109
12
  if (filename == "stdout") {
110
1
    outstream = &std::cout;
111
11
  } else if (filename == "stderr") {
112
1
    outstream = &std::cerr;
113
  } else {
114
19
    std::string report_directory;
115
    {
116
20
      Mutex::ScopedLock lock(per_process::cli_options_mutex);
117
10
      report_directory = per_process::cli_options->report_directory;
118
    }
119
    // Regular file. Append filename to directory path if one was specified
120
10
    if (report_directory.length() > 0) {
121
20
      std::string pathname = report_directory;
122
10
      pathname += node::kPathSeparator;
123
10
      pathname += filename;
124
10
      outfile.open(pathname, std::ios::out | std::ios::binary);
125
    } else {
126
      outfile.open(filename, std::ios::out | std::ios::binary);
127
    }
128
    // Check for errors on the file open
129
10
    if (!outfile.is_open()) {
130
1
      std::cerr << "\nFailed to open Node.js report file: " << filename;
131
132
1
      if (report_directory.length() > 0)
133
1
        std::cerr << " directory: " << report_directory;
134
135
1
      std::cerr << " (errno: " << errno << ")" << std::endl;
136
1
      return "";
137
    }
138
9
    outstream = &outfile;
139
9
    std::cerr << "\nWriting Node.js report to file: " << filename;
140
  }
141
142
  bool compact;
143
  {
144
22
    Mutex::ScopedLock lock(per_process::cli_options_mutex);
145
11
    compact = per_process::cli_options->report_compact;
146
  }
147
11
  WriteNodeReport(isolate, env, message, trigger, filename, *outstream,
148
11
                  stackstr, compact);
149
150
  // Do not close stdout/stderr, only close files we opened.
151
11
  if (outfile.is_open()) {
152
9
    outfile.close();
153
  }
154
155
  // Do not mix JSON and free-form text on stderr.
156
11
  if (filename != "stderr") {
157
10
    std::cerr << "\nNode.js report completed" << std::endl;
158
  }
159
11
  return filename;
160
}
161
162
// External function to trigger a report, writing to a supplied stream.
163
9
void GetNodeReport(Isolate* isolate,
164
                   Environment* env,
165
                   const char* message,
166
                   const char* trigger,
167
                   Local<String> stackstr,
168
                   std::ostream& out) {
169
9
  WriteNodeReport(isolate, env, message, trigger, "", out, stackstr, false);
170
9
}
171
172
// Internal function to coordinate and write the various
173
// sections of the report to the supplied stream
174
20
static void WriteNodeReport(Isolate* isolate,
175
                            Environment* env,
176
                            const char* message,
177
                            const char* trigger,
178
                            const std::string& filename,
179
                            std::ostream& out,
180
                            Local<String> stackstr,
181
                            bool compact) {
182
  // Obtain the current time and the pid.
183
  TIME_TYPE tm_struct;
184
20
  DiagnosticFilename::LocalTime(&tm_struct);
185
20
  uv_pid_t pid = uv_os_getpid();
186
187
  // Save formatting for output stream.
188
40
  std::ios old_state(nullptr);
189
20
  old_state.copyfmt(out);
190
191
  // File stream opened OK, now start printing the report content:
192
  // the title and header information (event, filename, timestamp and pid)
193
194
20
  JSONWriter writer(out, compact);
195
20
  writer.json_start();
196
20
  writer.json_objectstart("header");
197
20
  writer.json_keyvalue("reportVersion", NODE_REPORT_VERSION);
198
20
  writer.json_keyvalue("event", message);
199
20
  writer.json_keyvalue("trigger", trigger);
200
20
  if (!filename.empty())
201
11
    writer.json_keyvalue("filename", filename);
202
  else
203
9
    writer.json_keyvalue("filename", JSONWriter::Null{});
204
205
  // Report dump event and module load date/time stamps
206
  char timebuf[64];
207
#ifdef _WIN32
208
  snprintf(timebuf,
209
           sizeof(timebuf),
210
           "%4d-%02d-%02dT%02d:%02d:%02dZ",
211
           tm_struct.wYear,
212
           tm_struct.wMonth,
213
           tm_struct.wDay,
214
           tm_struct.wHour,
215
           tm_struct.wMinute,
216
           tm_struct.wSecond);
217
  writer.json_keyvalue("dumpEventTime", timebuf);
218
#else  // UNIX, OSX
219
60
  snprintf(timebuf,
220
           sizeof(timebuf),
221
           "%4d-%02d-%02dT%02d:%02d:%02dZ",
222
20
           tm_struct.tm_year + 1900,
223
20
           tm_struct.tm_mon + 1,
224
           tm_struct.tm_mday,
225
           tm_struct.tm_hour,
226
           tm_struct.tm_min,
227
20
           tm_struct.tm_sec);
228
20
  writer.json_keyvalue("dumpEventTime", timebuf);
229
#endif
230
231
  uv_timeval64_t ts;
232
20
  if (uv_gettimeofday(&ts) == 0) {
233
    writer.json_keyvalue("dumpEventTimeStamp",
234
20
                         std::to_string(ts.tv_sec * 1000 + ts.tv_usec / 1000));
235
  }
236
237
  // Report native process ID
238
20
  writer.json_keyvalue("processId", pid);
239
20
  if (env != nullptr)
240
20
    writer.json_keyvalue("threadId", env->thread_id());
241
  else
242
    writer.json_keyvalue("threadId", JSONWriter::Null{});
243
244
  {
245
    // Report the process cwd.
246
    char buf[PATH_MAX_BYTES];
247
20
    size_t cwd_size = sizeof(buf);
248
20
    if (uv_cwd(buf, &cwd_size) == 0)
249
20
      writer.json_keyvalue("cwd", buf);
250
  }
251
252
  // Report out the command line.
253
20
  if (!node::per_process::cli_options->cmdline.empty()) {
254
20
    writer.json_arraystart("commandLine");
255
68
    for (const std::string& arg : node::per_process::cli_options->cmdline) {
256
48
      writer.json_element(arg);
257
    }
258
20
    writer.json_arrayend();
259
  }
260
261
  // Report Node.js and OS version information
262
20
  PrintVersionInformation(&writer);
263
20
  writer.json_objectend();
264
265
  // Report summary JavaScript stack backtrace
266
20
  PrintJavaScriptStack(&writer, isolate, stackstr, trigger);
267
268
  // Report native stack backtrace
269
20
  PrintNativeStack(&writer);
270
271
  // Report V8 Heap and Garbage Collector information
272
20
  PrintGCStatistics(&writer, isolate);
273
274
  // Report OS and current thread resource usage
275
20
  PrintResourceUsage(&writer);
276
277
20
  writer.json_arraystart("libuv");
278
20
  if (env != nullptr) {
279
20
    uv_walk(env->event_loop(), WalkHandle, static_cast<void*>(&writer));
280
281
20
    writer.json_start();
282
20
    writer.json_keyvalue("type", "loop");
283
    writer.json_keyvalue("is_active",
284
20
        static_cast<bool>(uv_loop_alive(env->event_loop())));
285
    writer.json_keyvalue("address",
286
20
        ValueToHexString(reinterpret_cast<int64_t>(env->event_loop())));
287
20
    writer.json_end();
288
  }
289
290
20
  writer.json_arrayend();
291
292
20
  writer.json_arraystart("workers");
293
20
  if (env != nullptr) {
294
40
    Mutex workers_mutex;
295
40
    ConditionVariable notify;
296
40
    std::vector<std::string> worker_infos;
297
20
    size_t expected_results = 0;
298
299
42
    env->ForEachWorker([&](Worker* w) {
300
12
      expected_results += w->RequestInterrupt([&](Environment* env) {
301
4
        std::ostringstream os;
302
303
4
        GetNodeReport(env->isolate(),
304
                      env,
305
                      "Worker thread subreport",
306
4
                      trigger,
307
                      Local<String>(),
308
2
                      os);
309
310
6
        Mutex::ScopedLock lock(workers_mutex);
311
4
        worker_infos.emplace_back(os.str());
312
4
        notify.Signal(lock);
313
4
      });
314
22
    });
315
316
40
    Mutex::ScopedLock lock(workers_mutex);
317
20
    worker_infos.reserve(expected_results);
318
24
    while (worker_infos.size() < expected_results)
319
2
      notify.Wait(lock);
320
22
    for (const std::string& worker_info : worker_infos)
321
2
      writer.json_element(JSONWriter::ForeignJSON { worker_info });
322
  }
323
20
  writer.json_arrayend();
324
325
  // Report operating system information
326
20
  PrintSystemInformation(&writer);
327
328
20
  writer.json_objectend();
329
330
  // Restore output stream formatting.
331
20
  out.copyfmt(old_state);
332
20
}
333
334
// Report Node.js version, OS version and machine information.
335
20
static void PrintVersionInformation(JSONWriter* writer) {
336
40
  std::ostringstream buf;
337
  // Report Node version
338
20
  buf << "v" << NODE_VERSION_STRING;
339
20
  writer->json_keyvalue("nodejsVersion", buf.str());
340
20
  buf.str("");
341
342
#ifndef _WIN32
343
  // Report compiler and runtime glibc versions where possible.
344
  const char* (*libc_version)();
345
40
  *(reinterpret_cast<void**>(&libc_version)) =
346
20
      dlsym(RTLD_DEFAULT, "gnu_get_libc_version");
347
20
  if (libc_version != nullptr)
348
20
    writer->json_keyvalue("glibcVersionRuntime", (*libc_version)());
349
#endif /* _WIN32 */
350
351
#ifdef __GLIBC__
352
20
  buf << __GLIBC__ << "." << __GLIBC_MINOR__;
353
20
  writer->json_keyvalue("glibcVersionCompiler", buf.str());
354
20
  buf.str("");
355
#endif
356
357
  // Report Process word size
358
20
  writer->json_keyvalue("wordSize", sizeof(void*) * 8);
359
20
  writer->json_keyvalue("arch", node::per_process::metadata.arch);
360
20
  writer->json_keyvalue("platform", node::per_process::metadata.platform);
361
362
  // Report deps component versions
363
20
  PrintComponentVersions(writer);
364
365
  // Report release metadata.
366
20
  PrintRelease(writer);
367
368
  // Report operating system and machine information
369
  uv_utsname_t os_info;
370
371
20
  if (uv_os_uname(&os_info) == 0) {
372
20
    writer->json_keyvalue("osName", os_info.sysname);
373
20
    writer->json_keyvalue("osRelease", os_info.release);
374
20
    writer->json_keyvalue("osVersion", os_info.version);
375
20
    writer->json_keyvalue("osMachine", os_info.machine);
376
  }
377
378
20
  PrintCpuInfo(writer);
379
20
  PrintNetworkInterfaceInfo(writer);
380
381
  char host[UV_MAXHOSTNAMESIZE];
382
20
  size_t host_size = sizeof(host);
383
384
20
  if (uv_os_gethostname(host, &host_size) == 0)
385
20
    writer->json_keyvalue("host", host);
386
20
}
387
388
// Report CPU info
389
20
static void PrintCpuInfo(JSONWriter* writer) {
390
  uv_cpu_info_t* cpu_info;
391
  int count;
392
20
  if (uv_cpu_info(&cpu_info, &count) == 0) {
393
20
    writer->json_arraystart("cpus");
394
180
    for (int i = 0; i < count; i++) {
395
160
      writer->json_start();
396
160
      writer->json_keyvalue("model", cpu_info[i].model);
397
160
      writer->json_keyvalue("speed", cpu_info[i].speed);
398
160
      writer->json_keyvalue("user", cpu_info[i].cpu_times.user);
399
160
      writer->json_keyvalue("nice", cpu_info[i].cpu_times.nice);
400
160
      writer->json_keyvalue("sys", cpu_info[i].cpu_times.sys);
401
160
      writer->json_keyvalue("idle", cpu_info[i].cpu_times.idle);
402
160
      writer->json_keyvalue("irq", cpu_info[i].cpu_times.irq);
403
160
      writer->json_end();
404
    }
405
20
    writer->json_arrayend();
406
20
    uv_free_cpu_info(cpu_info, count);
407
  }
408
20
}
409
410
20
static void PrintNetworkInterfaceInfo(JSONWriter* writer) {
411
  uv_interface_address_t* interfaces;
412
  char ip[INET6_ADDRSTRLEN];
413
  char netmask[INET6_ADDRSTRLEN];
414
  char mac[18];
415
  int count;
416
417
20
  if (uv_interface_addresses(&interfaces, &count) == 0) {
418
20
    writer->json_arraystart("networkInterfaces");
419
420
140
    for (int i = 0; i < count; i++) {
421
120
      writer->json_start();
422
120
      writer->json_keyvalue("name", interfaces[i].name);
423
120
      writer->json_keyvalue("internal", !!interfaces[i].is_internal);
424
720
      snprintf(mac,
425
               sizeof(mac),
426
               "%02x:%02x:%02x:%02x:%02x:%02x",
427
120
               static_cast<unsigned char>(interfaces[i].phys_addr[0]),
428
120
               static_cast<unsigned char>(interfaces[i].phys_addr[1]),
429
120
               static_cast<unsigned char>(interfaces[i].phys_addr[2]),
430
120
               static_cast<unsigned char>(interfaces[i].phys_addr[3]),
431
120
               static_cast<unsigned char>(interfaces[i].phys_addr[4]),
432
240
               static_cast<unsigned char>(interfaces[i].phys_addr[5]));
433
120
      writer->json_keyvalue("mac", mac);
434
435
120
      if (interfaces[i].address.address4.sin_family == AF_INET) {
436
60
        uv_ip4_name(&interfaces[i].address.address4, ip, sizeof(ip));
437
60
        uv_ip4_name(&interfaces[i].netmask.netmask4, netmask, sizeof(netmask));
438
60
        writer->json_keyvalue("address", ip);
439
60
        writer->json_keyvalue("netmask", netmask);
440
60
        writer->json_keyvalue("family", "IPv4");
441
60
      } else if (interfaces[i].address.address4.sin_family == AF_INET6) {
442
60
        uv_ip6_name(&interfaces[i].address.address6, ip, sizeof(ip));
443
60
        uv_ip6_name(&interfaces[i].netmask.netmask6, netmask, sizeof(netmask));
444
60
        writer->json_keyvalue("address", ip);
445
60
        writer->json_keyvalue("netmask", netmask);
446
60
        writer->json_keyvalue("family", "IPv6");
447
60
        writer->json_keyvalue("scopeid",
448
120
                              interfaces[i].address.address6.sin6_scope_id);
449
      } else {
450
        writer->json_keyvalue("family", "unknown");
451
      }
452
453
120
      writer->json_end();
454
    }
455
456
20
    writer->json_arrayend();
457
20
    uv_free_interface_addresses(interfaces, count);
458
  }
459
20
}
460
461
// Report the JavaScript stack.
462
20
static void PrintJavaScriptStack(JSONWriter* writer,
463
                                 Isolate* isolate,
464
                                 Local<String> stackstr,
465
                                 const char* trigger) {
466
20
  writer->json_objectstart("javascriptStack");
467
468
40
  std::string ss;
469

40
  if ((!strcmp(trigger, "FatalError")) ||
470
20
      (!strcmp(trigger, "Signal"))) {
471
1
    ss = "No stack.\nUnavailable.\n";
472
  } else {
473
38
    String::Utf8Value sv(isolate, stackstr);
474
19
    ss = std::string(*sv, sv.length());
475
  }
476
20
  int line = ss.find('\n');
477
20
  if (line == -1) {
478
4
    writer->json_keyvalue("message", ss);
479
  } else {
480
32
    std::string l = ss.substr(0, line);
481
16
    writer->json_keyvalue("message", l);
482
16
    writer->json_arraystart("stack");
483
16
    ss = ss.substr(line + 1);
484
16
    line = ss.find('\n');
485
198
    while (line != -1) {
486
91
      l = ss.substr(0, line);
487
451
      l.erase(l.begin(), std::find_if(l.begin(), l.end(), [](int ch) {
488
451
                return !std::iswspace(ch);
489
542
              }));
490
91
      writer->json_element(l);
491
91
      ss = ss.substr(line + 1);
492
91
      line = ss.find('\n');
493
    }
494
16
    writer->json_arrayend();
495
  }
496
20
  writer->json_objectend();
497
20
}
498
499
// Report a native stack backtrace
500
20
static void PrintNativeStack(JSONWriter* writer) {
501
40
  auto sym_ctx = NativeSymbolDebuggingContext::New();
502
  void* frames[256];
503
20
  const int size = sym_ctx->GetStackTrace(frames, arraysize(frames));
504
20
  writer->json_arraystart("nativeStack");
505
  int i;
506
175
  for (i = 1; i < size; i++) {
507
155
    void* frame = frames[i];
508
155
    writer->json_start();
509
    writer->json_keyvalue("pc",
510
155
                          ValueToHexString(reinterpret_cast<uintptr_t>(frame)));
511
155
    writer->json_keyvalue("symbol", sym_ctx->LookupSymbol(frame).Display());
512
155
    writer->json_end();
513
  }
514
20
  writer->json_arrayend();
515
20
}
516
517
// Report V8 JavaScript heap information.
518
// This uses the existing V8 HeapStatistics and HeapSpaceStatistics APIs.
519
// The isolate->GetGCStatistics(&heap_stats) internal V8 API could potentially
520
// provide some more useful information - the GC history and the handle counts
521
20
static void PrintGCStatistics(JSONWriter* writer, Isolate* isolate) {
522
20
  HeapStatistics v8_heap_stats;
523
20
  isolate->GetHeapStatistics(&v8_heap_stats);
524
20
  HeapSpaceStatistics v8_heap_space_stats;
525
526
20
  writer->json_objectstart("javascriptHeap");
527
20
  writer->json_keyvalue("totalMemory", v8_heap_stats.total_heap_size());
528
  writer->json_keyvalue("totalCommittedMemory",
529
20
                        v8_heap_stats.total_physical_size());
530
20
  writer->json_keyvalue("usedMemory", v8_heap_stats.used_heap_size());
531
  writer->json_keyvalue("availableMemory",
532
20
                        v8_heap_stats.total_available_size());
533
20
  writer->json_keyvalue("memoryLimit", v8_heap_stats.heap_size_limit());
534
535
20
  writer->json_objectstart("heapSpaces");
536
  // Loop through heap spaces
537
180
  for (size_t i = 0; i < isolate->NumberOfHeapSpaces(); i++) {
538
160
    isolate->GetHeapSpaceStatistics(&v8_heap_space_stats, i);
539
160
    writer->json_objectstart(v8_heap_space_stats.space_name());
540
160
    writer->json_keyvalue("memorySize", v8_heap_space_stats.space_size());
541
    writer->json_keyvalue(
542
        "committedMemory",
543
160
        v8_heap_space_stats.physical_space_size());
544
    writer->json_keyvalue(
545
        "capacity",
546
480
        v8_heap_space_stats.space_used_size() +
547
320
            v8_heap_space_stats.space_available_size());
548
160
    writer->json_keyvalue("used", v8_heap_space_stats.space_used_size());
549
    writer->json_keyvalue(
550
160
        "available", v8_heap_space_stats.space_available_size());
551
160
    writer->json_objectend();
552
  }
553
554
20
  writer->json_objectend();
555
20
  writer->json_objectend();
556
20
}
557
558
20
static void PrintResourceUsage(JSONWriter* writer) {
559
  // Get process uptime in seconds
560
  uint64_t uptime =
561
20
      (uv_hrtime() - node::per_process::node_start_time) / (NANOS_PER_SEC);
562
20
  if (uptime == 0) uptime = 1;  // avoid division by zero.
563
564
  // Process and current thread usage statistics
565
  uv_rusage_t rusage;
566
20
  writer->json_objectstart("resourceUsage");
567
20
  if (uv_getrusage(&rusage) == 0) {
568
    double user_cpu =
569
20
        rusage.ru_utime.tv_sec + SEC_PER_MICROS * rusage.ru_utime.tv_usec;
570
    double kernel_cpu =
571
20
        rusage.ru_stime.tv_sec + SEC_PER_MICROS * rusage.ru_stime.tv_usec;
572
20
    writer->json_keyvalue("userCpuSeconds", user_cpu);
573
20
    writer->json_keyvalue("kernelCpuSeconds", kernel_cpu);
574
20
    double cpu_abs = user_cpu + kernel_cpu;
575
20
    double cpu_percentage = (cpu_abs / uptime) * 100.0;
576
20
    writer->json_keyvalue("cpuConsumptionPercent", cpu_percentage);
577
20
    writer->json_keyvalue("maxRss", rusage.ru_maxrss * 1024);
578
20
    writer->json_objectstart("pageFaults");
579
20
    writer->json_keyvalue("IORequired", rusage.ru_majflt);
580
20
    writer->json_keyvalue("IONotRequired", rusage.ru_minflt);
581
20
    writer->json_objectend();
582
20
    writer->json_objectstart("fsActivity");
583
20
    writer->json_keyvalue("reads", rusage.ru_inblock);
584
20
    writer->json_keyvalue("writes", rusage.ru_oublock);
585
20
    writer->json_objectend();
586
  }
587
20
  writer->json_objectend();
588
#ifdef RUSAGE_THREAD
589
  struct rusage stats;
590
20
  if (getrusage(RUSAGE_THREAD, &stats) == 0) {
591
20
    writer->json_objectstart("uvthreadResourceUsage");
592
    double user_cpu =
593
20
        stats.ru_utime.tv_sec + SEC_PER_MICROS * stats.ru_utime.tv_usec;
594
    double kernel_cpu =
595
20
        stats.ru_stime.tv_sec + SEC_PER_MICROS * stats.ru_stime.tv_usec;
596
20
    writer->json_keyvalue("userCpuSeconds", user_cpu);
597
20
    writer->json_keyvalue("kernelCpuSeconds", kernel_cpu);
598
20
    double cpu_abs = user_cpu + kernel_cpu;
599
20
    double cpu_percentage = (cpu_abs / uptime) * 100.0;
600
20
    writer->json_keyvalue("cpuConsumptionPercent", cpu_percentage);
601
20
    writer->json_objectstart("fsActivity");
602
20
    writer->json_keyvalue("reads", stats.ru_inblock);
603
20
    writer->json_keyvalue("writes", stats.ru_oublock);
604
20
    writer->json_objectend();
605
20
    writer->json_objectend();
606
  }
607
#endif
608
20
}
609
610
// Report operating system information.
611
20
static void PrintSystemInformation(JSONWriter* writer) {
612
  uv_env_item_t* envitems;
613
  int envcount;
614
  int r;
615
616
20
  writer->json_objectstart("environmentVariables");
617
618
  {
619
40
    Mutex::ScopedLock lock(node::per_process::env_var_mutex);
620
20
    r = uv_os_environ(&envitems, &envcount);
621
  }
622
623
20
  if (r == 0) {
624
1400
    for (int i = 0; i < envcount; i++)
625
1380
      writer->json_keyvalue(envitems[i].name, envitems[i].value);
626
627
20
    uv_os_free_environ(envitems, envcount);
628
  }
629
630
20
  writer->json_objectend();
631
632
#ifndef _WIN32
633
  static struct {
634
    const char* description;
635
    int id;
636
  } rlimit_strings[] = {
637
    {"core_file_size_blocks", RLIMIT_CORE},
638
    {"data_seg_size_kbytes", RLIMIT_DATA},
639
    {"file_size_blocks", RLIMIT_FSIZE},
640
#if !(defined(_AIX) || defined(__sun))
641
    {"max_locked_memory_bytes", RLIMIT_MEMLOCK},
642
#endif
643
#ifndef __sun
644
    {"max_memory_size_kbytes", RLIMIT_RSS},
645
#endif
646
    {"open_files", RLIMIT_NOFILE},
647
    {"stack_size_bytes", RLIMIT_STACK},
648
    {"cpu_time_seconds", RLIMIT_CPU},
649
#ifndef __sun
650
    {"max_user_processes", RLIMIT_NPROC},
651
#endif
652
#ifndef __OpenBSD__
653
    {"virtual_memory_kbytes", RLIMIT_AS}
654
#endif
655
  };
656
657
20
  writer->json_objectstart("userLimits");
658
  struct rlimit limit;
659
40
  std::string soft, hard;
660
661
220
  for (size_t i = 0; i < arraysize(rlimit_strings); i++) {
662
200
    if (getrlimit(rlimit_strings[i].id, &limit) == 0) {
663
200
      writer->json_objectstart(rlimit_strings[i].description);
664
665
200
      if (limit.rlim_cur == RLIM_INFINITY)
666
120
        writer->json_keyvalue("soft", "unlimited");
667
      else
668
80
        writer->json_keyvalue("soft", limit.rlim_cur);
669
670
200
      if (limit.rlim_max == RLIM_INFINITY)
671
140
        writer->json_keyvalue("hard", "unlimited");
672
      else
673
60
        writer->json_keyvalue("hard", limit.rlim_max);
674
675
200
      writer->json_objectend();
676
    }
677
  }
678
20
  writer->json_objectend();
679
#endif  // _WIN32
680
681
20
  PrintLoadedLibraries(writer);
682
20
}
683
684
// Report a list of loaded native libraries.
685
20
static void PrintLoadedLibraries(JSONWriter* writer) {
686
20
  writer->json_arraystart("sharedObjects");
687
  std::vector<std::string> modules =
688
40
      NativeSymbolDebuggingContext::GetLoadedLibraries();
689
20
  for (auto const& module_name : modules) writer->json_element(module_name);
690
20
  writer->json_arrayend();
691
20
}
692
693
// Obtain and report the node and subcomponent version strings.
694
20
static void PrintComponentVersions(JSONWriter* writer) {
695
40
  std::stringstream buf;
696
697
20
  writer->json_objectstart("componentVersions");
698
699
#define V(key)                                                                 \
700
  writer->json_keyvalue(#key, node::per_process::metadata.versions.key);
701
20
  NODE_VERSIONS_KEYS(V)
702
#undef V
703
704
20
  writer->json_objectend();
705
20
}
706
707
// Report runtime release information.
708
20
static void PrintRelease(JSONWriter* writer) {
709
20
  writer->json_objectstart("release");
710
20
  writer->json_keyvalue("name", node::per_process::metadata.release.name);
711
#if NODE_VERSION_IS_LTS
712
  writer->json_keyvalue("lts", node::per_process::metadata.release.lts);
713
#endif
714
715
#ifdef NODE_HAS_RELEASE_URLS
716
  writer->json_keyvalue("headersUrl",
717
                        node::per_process::metadata.release.headers_url);
718
  writer->json_keyvalue("sourceUrl",
719
                        node::per_process::metadata.release.source_url);
720
#ifdef _WIN32
721
  writer->json_keyvalue("libUrl", node::per_process::metadata.release.lib_url);
722
#endif  // _WIN32
723
#endif  // NODE_HAS_RELEASE_URLS
724
725
20
  writer->json_objectend();
726
20
}
727
728

12978
}  // namespace report