Skip to content

[Bug?]: Performance impact of process.report.getReport() is undesirable #5167

Closed
@oliversalzburg

Description

@oliversalzburg

Self-service

  • I'd be willing to implement a fix

Describe the bug

Yarn calls process.report.getReport internally to retrieve a list of loaded shared libraries to determine the C library in use. This can be seen following the code path at

// Doing these calls early is important: it seems calling it after we've started the resolution incurs very high
// performance penalty on WSL, with the Gatsby benchmark jumping from ~28s to ~130s. It's possible this is due to
// the number of async tasks being listed in the report, although it's strange this doesn't occur on other systems.
. The comment highlighted here already hints at the larger issue.

Yarn will grab this report and to generate the report, Node will go through all open handles in UV and retrieve information about them. Most importantly here, it will query information about all open socket handles. There handles are processed with https://github.com/nodejs/node/blob/9eb363a3e00dbba572756c7ed314273f17ea8e2e/src/node_report_utils.cc#L12.

  • This function will try to resolve the name for at least the local IP address used on the socket (as I observed).
  • This process is applied for all socket handles in series.
  • This can potentially take minutes to fully generate.

As the above quoted comment implies, there is a larger issue on WSL. From my observations, WSL will, by default, register a very poor DNS resolver into the Linux distribution. This resolver is not only extremely slow, it also responds to all queries with an answer with a TTL of 0. I expect that this causes the RDNS request for every single socket to go through the entire stack every single time.

While this behavior is generally prevented in yarn by calling out to the report generator early, when using plugins like upgrade-interactive, a lot of sockets have been opened from the resolution process and this causes a very long hang when the report is being generated. This approach seems unreliable. Determination of platform specifics should not be hindered by DNS performance.

To reproduce

const https = require("node:https");

const SOCKET_COUNT = 10;
const sockets = [];
let allResolved = false;

const keepAliveAgent = new https.Agent({ keepAlive: true });

const performRequest = () => {
  const socketPromise = new Promise((resolve) => {
    https
      .get(
        {
          agent: keepAliveAgent,
          hostname: "registry.npmjs.org",
        },
        () => {
          process.stdout.write(".");
          resolve();
        }
      )
      .on("error", (error) => {
        console.error(error);
        resolve();
      });
  });
  sockets.push(socketPromise);
};

process.stdout.write(`${new Date().toISOString()} opening ${SOCKET_COUNT} sockets`);
for (let loops = 0; loops < SOCKET_COUNT; ++loops) {
  performRequest();
}

Promise.all(sockets).then(() => {
  allResolved = true;
  console.log(
    `\n${new Date().toISOString()} all sockets created. requesting report...`
  );
  process.report.getReport();

  console.log(`${new Date().toISOString()} destroying client`);
  keepAliveAgent.destroy();

  console.log(`${new Date().toISOString()} end`);
});

const check = () => {
  if (!allResolved) {
    setTimeout(check, 200);
    return;
  }
};

check();

Environment

System:
    OS: Linux 5.10 Ubuntu 20.04.3 LTS (Focal Fossa)
    CPU: (12) x64 Intel(R) Core(TM) i7-6850K CPU @ 3.60GHz
  Binaries:
    Node: 18.12.0 - /tmp/xfs-ec34c936/node
    Yarn: 1.22.19 - /tmp/xfs-ec34c936/yarn
    npm: 8.19.2 - /usr/local/bin/npm

Additional context

This problem is amplified by poor WSL default behavior, but the underlying issue should apply generally.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingexternal bugThis issue highlights a bug in another projectwaiting for feedbackWill autoclose in a while unless more data are provided

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions