current commit
260820.7 · build,win: add PGO workload scripts
'use strict';

/* eslint-disable no-void */

// PGO Training Script: Module Loading and Startup
//
// Module loading (require/import) is one of Node.js's most performance-critical
// paths, especially for:
// - Application startup time (serverless cold starts, CLI tools)
// - require() resolution algorithm (stat cascade, package.json parsing)
// - ESM vs CJS loading (import() dynamic imports)
// - Circular dependency resolution
// - Built-in module loading
// - JSON module loading (package.json, config files)
//
// This exercises: module resolver (fs.stat/readFile cascade), V8 script
// compilation, source code parsing, JSON parsing, path resolution,
// module wrapper function, exports/require machinery.

const path = require('path');
const fs = require('fs');
const os = require('os');
const vm = require('vm');
const Module = require('module');

const DURATION_MS = parseInt(process.env.PGO_TRAINING_DURATION, 10) || 15_000;
const TEMP_DIR = path.join(
  os.tmpdir(),
  `node-pgo-module-${process.pid}-${Date.now()}`,
);

function setup() {
  fs.mkdirSync(TEMP_DIR, { recursive: true });

  // Create a realistic module tree
  // node_modules/
  //   express/
  //     package.json
  //     index.js
  //     lib/router.js, lib/request.js, lib/response.js
  //   lodash/
  //     package.json
  //     lodash.js
  //   config/
  //     package.json
  //     index.js
  //  src/
  //    index.js, utils.js, helpers.js, constants.js
  //    models/user.js, models/product.js
  //    middleware/auth.js, middleware/logger.js

  const dirs = [
    'node_modules/express/lib',
    'node_modules/lodash',
    'node_modules/config',
    'node_modules/debug',
    'node_modules/body-parser',
    'src/models',
    'src/middleware',
    'src/routes',
    'src/utils',
    'lib',
  ];

  for (const dir of dirs) {
    fs.mkdirSync(path.join(TEMP_DIR, dir), { recursive: true });
  }

  // Express-like module
  writeFile(
    'node_modules/express/package.json',
    JSON.stringify({
      name: 'express',
      version: '4.18.2',
      main: 'index.js',
    }),
  );
  writeFile(
    'node_modules/express/index.js',
    `
    'use strict';
    const router = require('./lib/router');
    const request = require('./lib/request');
    const response = require('./lib/response');
    function createApp() {
      const app = { routes: [], use(fn) { this.routes.push(fn); return this; } };
      Object.assign(app, router, request, response);
      return app;
    }
    module.exports = createApp;
    module.exports.Router = router.Router;
    module.exports.static = function(root) { return function(req, res, next) { next(); }; };
  `,
  );
  writeFile(
    'node_modules/express/lib/router.js',
    `
    'use strict';
    class Router { constructor() { this.stack = []; } route(path) { return this; } }
    exports.Router = function() { return new Router(); };
    exports.handle = function(req, res) {};
    exports.param = function(name, fn) {};
  `,
  );
  writeFile(
    'node_modules/express/lib/request.js',
    `
    'use strict';
    exports.get = function(field) { return ''; };
    exports.accepts = function() { return true; };
    exports.is = function(type) { return type; };
  `,
  );
  writeFile(
    'node_modules/express/lib/response.js',
    `
    'use strict';
    exports.send = function(body) { return this; };
    exports.json = function(obj) { return this; };
    exports.status = function(code) { return this; };
  `,
  );

  // Lodash-like module
  writeFile(
    'node_modules/lodash/package.json',
    JSON.stringify({
      name: 'lodash',
      version: '4.17.21',
      main: 'lodash.js',
    }),
  );
  writeFile(
    'node_modules/lodash/lodash.js',
    `
    'use strict';
    const _ = {};
    _.map = (arr, fn) => arr.map(fn);
    _.filter = (arr, fn) => arr.filter(fn);
    _.reduce = (arr, fn, init) => arr.reduce(fn, init);
    _.get = (obj, path, def) => { const keys = path.split('.'); let val = obj; for (const k of keys) { val = val?.[k]; } return val ?? def; };
    _.set = (obj, path, val) => { const keys = path.split('.'); let cur = obj; for (let i = 0; i < keys.length - 1; i++) { cur = cur[keys[i]] ??= {}; } cur[keys[keys.length-1]] = val; return obj; };
    _.cloneDeep = (obj) => JSON.parse(JSON.stringify(obj));
    _.debounce = (fn, wait) => { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), wait); }; };
    _.chunk = (arr, size) => { const res = []; for (let i = 0; i < arr.length; i += size) res.push(arr.slice(i, i + size)); return res; };
    _.flatten = (arr) => arr.flat();
    _.uniq = (arr) => [...new Set(arr)];
    module.exports = _;
  `,
  );

  // Config module
  writeFile(
    'node_modules/config/package.json',
    JSON.stringify({
      name: 'config',
      version: '3.3.9',
      main: 'index.js',
    }),
  );
  writeFile(
    'node_modules/config/index.js',
    `
    'use strict';
    const config = { db: { host: 'localhost', port: 5432 }, app: { port: 3000 } };
    module.exports = { get(key) { return key.split('.').reduce((o, k) => o?.[k], config); }, has(key) { return this.get(key) !== undefined; } };
  `,
  );

  // Debug module
  writeFile(
    'node_modules/debug/package.json',
    JSON.stringify({
      name: 'debug',
      version: '4.3.4',
      main: 'index.js',
    }),
  );
  writeFile(
    'node_modules/debug/index.js',
    `
    'use strict';
    module.exports = function(namespace) {
      return function(...args) { /* noop in production */ };
    };
  `,
  );

  // Body-parser module
  writeFile(
    'node_modules/body-parser/package.json',
    JSON.stringify({
      name: 'body-parser',
      version: '1.20.2',
      main: 'index.js',
    }),
  );
  writeFile(
    'node_modules/body-parser/index.js',
    `
    'use strict';
    exports.json = function(options) { return function(req, res, next) { next(); }; };
    exports.urlencoded = function(options) { return function(req, res, next) { next(); }; };
    exports.raw = function(options) { return function(req, res, next) { next(); }; };
  `,
  );

  // Application source files
  writeFile(
    'src/index.js',
    `
    'use strict';
    const express = require('express');
    const bodyParser = require('body-parser');
    const debug = require('debug');
    const config = require('config');
    const { authenticate } = require('./middleware/auth');
    const { logger } = require('./middleware/logger');
    const userRoutes = require('./routes/users');
    const { formatDate, generateId } = require('./utils/helpers');
    const { ROLES, STATUS } = require('./utils/constants');
    module.exports = { express, bodyParser, debug, config, authenticate, logger, userRoutes, formatDate, generateId, ROLES, STATUS };
  `,
  );

  writeFile(
    'src/utils/helpers.js',
    `
    'use strict';
    const crypto = require('crypto');
    exports.formatDate = (d) => new Date(d).toISOString();
    exports.generateId = () => crypto.randomUUID();
    exports.sanitize = (str) => str.replace(/[<>&"']/g, '');
    exports.paginate = (arr, page, size) => arr.slice((page - 1) * size, page * size);
  `,
  );

  writeFile(
    'src/utils/constants.js',
    `
    'use strict';
    exports.ROLES = Object.freeze({ ADMIN: 'admin', USER: 'user', GUEST: 'guest' });
    exports.STATUS = Object.freeze({ ACTIVE: 'active', INACTIVE: 'inactive', PENDING: 'pending' });
    exports.LIMITS = Object.freeze({ MAX_PAGE_SIZE: 100, MAX_UPLOAD: 10 * 1024 * 1024 });
  `,
  );

  writeFile(
    'src/models/user.js',
    `
    'use strict';
    const { generateId } = require('../utils/helpers');
    const { ROLES, STATUS } = require('../utils/constants');
    class User { constructor(data) { this.id = generateId(); this.role = ROLES.USER; this.status = STATUS.PENDING; Object.assign(this, data); } toJSON() { return { id: this.id, name: this.name, role: this.role }; } }
    module.exports = User;
  `,
  );

  writeFile(
    'src/models/product.js',
    `
    'use strict';
    const { generateId } = require('../utils/helpers');
    class Product { constructor(data) { this.id = generateId(); Object.assign(this, data); } toJSON() { return { id: this.id, name: this.name, price: this.price }; } }
    module.exports = Product;
  `,
  );

  writeFile(
    'src/middleware/auth.js',
    `
    'use strict';
    const crypto = require('crypto');
    exports.authenticate = function(req, res, next) { const token = req?.headers?.authorization; return !!token; };
    exports.authorize = function(...roles) { return function(req, res, next) { return roles.length > 0; }; };
  `,
  );

  writeFile(
    'src/middleware/logger.js',
    `
    'use strict';
    exports.logger = function(req, res, next) {
      const start = Date.now();
      return { duration: Date.now() - start, method: req?.method, url: req?.url };
    };
  `,
  );

  writeFile(
    'src/routes/users.js',
    `
    'use strict';
    const User = require('../models/user');
    const { paginate } = require('../utils/helpers');
    const { authenticate } = require('../middleware/auth');
    exports.getUsers = function(page, size) { return paginate([], page, size); };
    exports.createUser = function(data) { return new User(data); };
    exports.getUser = function(id) { return null; };
  `,
  );

  // ESM modules
  writeFile(
    'src/esm-entry.mjs',
    `
    import { createRequire } from 'module';
    import { fileURLToPath } from 'url';
    import { dirname, join } from 'path';
    const __filename = fileURLToPath(import.meta.url);
    const __dirname = dirname(__filename);
    const require = createRequire(import.meta.url);
    export const config = { loaded: true, dir: __dirname };
    export function greet(name) { return \`Hello, \${name}!\`; }
    export default { config, greet };
  `,
  );

  // JSON file (loaded as module)
  writeFile(
    'config/default.json',
    JSON.stringify(
      {
        server: { port: 3000, host: '0.0.0.0' },
        database: {
          url: 'postgres://localhost:5432/myapp',
          pool: { min: 2, max: 10 },
        },
        redis: { url: 'redis://localhost:6379' },
        jwt: { secret: 'test-secret', expiresIn: '1h' },
        logging: { level: 'info' },
      },
      null,
      2,
    ),
  );

  // package.json at root
  writeFile(
    'package.json',
    JSON.stringify(
      {
        name: 'pgo-test-app',
        version: '1.0.0',
        main: 'src/index.js',
        dependencies: {
          'express': '^4.18.0',
          'lodash': '^4.17.0',
          'config': '^3.3.0',
          'debug': '^4.3.0',
          'body-parser': '^1.20.0',
        },
      },
      null,
      2,
    ),
  );
}

function writeFile(relPath, content) {
  const fullPath = path.join(TEMP_DIR, relPath);
  fs.mkdirSync(path.dirname(fullPath), { recursive: true });
  fs.writeFileSync(fullPath, content);
}

function cleanup() {
  try {
    fs.rmSync(TEMP_DIR, { recursive: true, force: true });
  } catch {
    // best effort
  }
}

// Workload 1: require() with full resolution (CJS — the dominant pattern)
function workloadCJSRequire(iterations) {
  let ops = 0;

  for (let i = 0; i < iterations; i++) {
    // Clear module cache to force re-resolution
    const keys = Object.keys(require.cache).filter((k) =>
      k.startsWith(TEMP_DIR),
    );
    for (const key of keys) {
      delete require.cache[key];
    }

    // Require the full app (cascading dependencies)
    require(path.join(TEMP_DIR, 'src', 'index.js'));
    ops++;

    // Require individual modules
    require(path.join(TEMP_DIR, 'node_modules', 'lodash', 'lodash.js'));
    require(path.join(TEMP_DIR, 'src', 'models', 'user.js'));
    require(path.join(TEMP_DIR, 'src', 'models', 'product.js'));
    ops += 3;

    // JSON require (package.json resolution)
    delete require.cache[path.join(TEMP_DIR, 'package.json')];
    require(path.join(TEMP_DIR, 'package.json'));
    delete require.cache[path.join(TEMP_DIR, 'config', 'default.json')];
    require(path.join(TEMP_DIR, 'config', 'default.json'));
    ops += 2;
  }
  return ops;
}

// Workload 2: Built-in module loading (no resolution needed, but exercises native binding)
function workloadBuiltinRequire(iterations) {
  let ops = 0;
  const builtins = [
    'fs',
    'path',
    'http',
    'https',
    'crypto',
    'os',
    'url',
    'util',
    'events',
    'stream',
    'buffer',
    'net',
    'dns',
    'zlib',
    'child_process',
    'querystring',
    'string_decoder',
    'timers',
    'assert',
    'tls',
    'fs/promises',
    'stream/promises',
    'timers/promises',
    'node:fs',
    'node:path',
    'node:http',
    'node:crypto',
    'node:os',
  ];

  for (let i = 0; i < iterations; i++) {
    for (const mod of builtins) {
      require(mod);
    }
    ops += builtins.length;
  }
  return ops;
}

// Workload 3: Module.createRequire and resolution
function workloadModuleResolution(iterations) {
  let ops = 0;

  for (let i = 0; i < iterations; i++) {
    // createRequire (used in ESM ↔ CJS interop)
    const customRequire = Module.createRequire(
      path.join(TEMP_DIR, 'src', 'index.js'),
    );

    // Resolve module paths (this is the hot path in require())
    try {
      customRequire.resolve('express');
    } catch {
      // expected
    }
    try {
      customRequire.resolve('lodash');
    } catch {
      // expected
    }
    try {
      customRequire.resolve('./models/user');
    } catch {
      // expected
    }
    try {
      customRequire.resolve('../package.json');
    } catch {
      // expected
    }
    ops += 4;

    // Module._resolveFilename (internal but exercises the same path)
    try {
      Module._resolveFilename('fs');
    } catch {
      // expected
    }
    try {
      Module._resolveFilename('path');
    } catch {
      // expected
    }
    ops += 2;

    // Module.builtinModules
    void Module.builtinModules;
    ops++;
  }
  return ops;
}

// Workload 4: vm.Script compilation (V8 script compilation path)
function workloadVMCompilation(iterations) {
  let ops = 0;

  const scripts = [
    // Simple expression
    'const x = 1 + 2; x;',
    // Function definition
    'function add(a, b) { return a + b; } add(1, 2);',
    // Object manipulation
    'const obj = { a: 1, b: { c: [1, 2, 3] } }; JSON.stringify(obj);',
    // Loop
    'let sum = 0; for (let i = 0; i < 1000; i++) sum += i; sum;',
    // Async-like pattern
    'const p = Promise.resolve(42); p.then(v => v * 2);',
    // Class definition (modern JS)
    `class Foo { constructor(x) { this.x = x; } get value() { return this.x; } }
     const f = new Foo(42); f.value;`,
    // Destructuring + spread
    'const { a, b, ...rest } = { a: 1, b: 2, c: 3, d: 4 }; [a, b, ...Object.values(rest)];',
    // Map/Set
    'const m = new Map([[1,"a"],[2,"b"]]); const s = new Set([1,2,3]); m.size + s.size;',
    // Regex
    'const re = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/; re.test("test@example.com");',
    // Template literals
    // eslint-disable-next-line no-template-curly-in-string
    'const name = "World"; const greeting = `Hello, ${name}! Today is ${new Date().toISOString()}`; greeting;',
  ];

  for (let i = 0; i < iterations; i++) {
    for (const code of scripts) {
      const script = new vm.Script(code, {
        filename: `script-${i}.js`,
        produceCachedData: i % 5 === 0, // Some with code caching
      });

      const context = vm.createContext({
        JSON,
        Date,
        Promise,
        Map,
        Set,
        console,
      });
      script.runInContext(context, { timeout: 1000 });
      ops++;
    }
  }
  return ops;
}

// Workload 5: Dynamic import() (ESM loading — growing usage)
async function workloadDynamicImport(iterations) {
  let ops = 0;

  for (let i = 0; i < iterations; i++) {
    // Dynamic import of built-in modules (common in ESM code)
    await import('node:fs');
    await import('node:path');
    await import('node:crypto');
    await import('node:os');
    await import('node:util');
    await import('node:url');
    await import('node:events');
    await import('node:stream');
    ops += 8;
  }
  return ops;
}

// Workload 6: Module._compile simulation (exercises V8 compilation)
function workloadCompilePatterns(iterations) {
  let ops = 0;

  // Source code patterns that exercise different V8 compilation paths
  const sourcePatterns = [
    // Arrow functions (very common in modern JS)
    'module.exports = {\n' +
      Array.from(
        { length: 20 },
        (_, i) => `  fn${i}: (x) => x * ${i + 1},`,
      ).join('\n') +
      '\n};',

    // async/await (extremely common in server code)
    `module.exports = async function(data) {
      const result = await Promise.resolve(data);
      const items = await Promise.all(
        Array.from({length: 10}, (_, i) => Promise.resolve(i * 2))
      );
      return { result, items, total: items.reduce((a,b) => a+b, 0) };
    };`,

    // try/catch with specific error types
    `module.exports = function(input) {
      try {
        const data = JSON.parse(input);
        if (!data.id) throw new TypeError('Missing id');
        if (data.age < 0) throw new RangeError('Invalid age');
        return data;
      } catch (err) {
        if (err instanceof SyntaxError) return { error: 'Invalid JSON' };
        if (err instanceof TypeError) return { error: err.message };
        throw err;
      }
    };`,

    // Generator function (used in Koa, some ORMs)
    `module.exports = function* paginate(items, pageSize) {
      for (let i = 0; i < items.length; i += pageSize) {
        yield items.slice(i, i + pageSize);
      }
    };`,

    // Proxy/Reflect (used in Vue.js reactivity, ORMs)
    `module.exports = function createReactive(target) {
      return new Proxy(target, {
        get(obj, prop) { return Reflect.get(obj, prop); },
        set(obj, prop, value) { return Reflect.set(obj, prop, value); },
        has(obj, prop) { return Reflect.has(obj, prop); },
      });
    };`,
  ];

  for (let i = 0; i < iterations; i++) {
    for (const source of sourcePatterns) {
      const script = new vm.Script(
        `(function(exports, require, module, __filename, __dirname) { ${source} })`,
        { filename: `compile-${i}.js` },
      );
      const context = vm.createContext({
        JSON,
        Promise,
        Array,
        Object,
        Map,
        Set,
        Proxy,
        Reflect,
        TypeError,
        RangeError,
        SyntaxError,
        Error,
      });
      script.runInContext(context);
      ops++;
    }
  }
  return ops;
}

async function main() {
  console.log('[pgo-module-loading] Starting module loading workload...');

  setup();
  const startTime = Date.now();
  let totalOps = 0;
  let round = 0;

  const remaining = () => DURATION_MS - (Date.now() - startTime);

  try {
    while (remaining() > 0) {
      round++;
      const scale = Math.max(0.1, remaining() / DURATION_MS);
      const iterScale = (base) => Math.max(1, Math.floor(base * scale));

      // CJS require (the most common module operation)
      if (round === 1)
        console.log('[pgo-module-loading] Running CJS require...');
      totalOps += workloadCJSRequire(iterScale(100));
      if (remaining() <= 0) break;

      // Built-in module loading
      if (round === 1)
        console.log('[pgo-module-loading] Running built-in require...');
      totalOps += workloadBuiltinRequire(iterScale(200));
      if (remaining() <= 0) break;

      // Module resolution
      if (round === 1)
        console.log('[pgo-module-loading] Running module resolution...');
      totalOps += workloadModuleResolution(iterScale(200));
      if (remaining() <= 0) break;

      // VM compilation
      if (round === 1)
        console.log('[pgo-module-loading] Running VM compilation...');
      totalOps += workloadVMCompilation(iterScale(50));
      if (remaining() <= 0) break;

      // Compilation patterns
      if (round === 1)
        console.log('[pgo-module-loading] Running compile patterns...');
      totalOps += workloadCompilePatterns(iterScale(100));
      if (remaining() <= 0) break;

      // Dynamic import
      if (round === 1)
        console.log('[pgo-module-loading] Running dynamic import...');
      totalOps += await workloadDynamicImport(iterScale(50));
    }

    const elapsed = (Date.now() - startTime) / 1000;
    console.log(
      `[pgo-module-loading] Completed ${totalOps} ops in ${elapsed.toFixed(1)}s (${(totalOps / elapsed).toFixed(0)} ops/s) [${round} rounds]`,
    );
  } finally {
    cleanup();
  }
}

main().catch((err) => {
  console.error('[pgo-module-loading] Error:', err);
  cleanup();
  process.exit(1);
});