Repository: nodejs/node
Pull request: benchmark: add webstorage benchmark

This PR adds benchmarks to web storage feature.

There are 3 main categories covered by this PR:

### Set item
| Storage Type | Method | Performance (n=100000) |
|--------------|--------|------------------------|
| localStorage | setItem | 32,226.011329779365 |
| localStorage | property setter | 31,983.078822509164 |
| sessionStorage | setItem | 99,525.92487767464 |
| sessionStorage | property setter | 96,256.61628876119 |

### Get item
| Storage Type | Method | Performance (n=100000) |
|--------------|--------|------------------------|
| localStorage | getItem | 339,745.7512670393 |
| localStorage | property getter | 318,879.11897832097 |
| sessionStorage | getItem | 546,089.0025795224 |
| sessionStorage | property getter | 605,112.5963263614 |

### Remove item
| Storage Type | Method | Performance (n=100000) |
|--------------|--------|------------------------|
| localStorage | removeItem | 43,976.48979563462 |
| localStorage | delete property | 41,734.89234719278 |
| sessionStorage | removeItem | 228,343.04220928214 |
| sessionStorage | delete property | 507,564.5105229822 |

Some quick observations:
* The `sessionStorage` is faster than `localStorage` in general
* Delete property seems faster than `removeItem` in `sessionStorage`

Changed files:
filename: benchmark/webstorage/getItem.js
patch: @@ -0,0 +1,75 @@
+'use strict';
+const { join } = require('node:path');
+const common = require('../common.js');
+const tmpdir = require('../../test/common/tmpdir');
+
+let cnt = 0;
+
+tmpdir.refresh();
+
+function nextLocalStorage() {
+  return join(tmpdir.path, `${++cnt}.localstorage`);
+}
+
+const options = {
+  flags: ['--experimental-webstorage', `--localstorage-file=${nextLocalStorage()}`],
+};
+
+const bench = common.createBenchmark(main, {
+  type: ['localStorage-getItem',
+         'localStorage-getter',
+         'sessionStorage-getItem',
+         'sessionStorage-getter'],
+  // Note: web storage has only 10mb quota
+  n: [1e5],
+}, options);
+
+function fillStorage(storage, n) {
+  for (let i = 0; i < n; i++) {
+    storage.setItem(i, i);
+  }
+}
+
+function main({ n, type }) {
+  const localStorage = globalThis.localStorage;
+  const sessionStorage = globalThis.sessionStorage;
+
+  switch (type) {
+    case 'localStorage-getItem':
+      fillStorage(localStorage, n);
+      bench.start();
+      for (let i = 0; i < n; i++) {
+        localStorage.getItem(i);
+      }
+      bench.end(n);
+      break;
+    case 'localStorage-getter':
+      fillStorage(localStorage, n);
+      bench.start();
+      for (let i = 0; i < n; i++) {
+        // eslint-disable-next-line no-unused-expressions
+        localStorage[i];
+      }
+      bench.end(n);
+      break;
+    case 'sessionStorage-getItem':
+      fillStorage(sessionStorage, n);
+      bench.start();
+      for (let i = 0; i < n; i++) {
+        sessionStorage.getItem(i);
+      }
+      bench.end(n);
+      break;
+    case 'sessionStorage-getter':
+      fillStorage(sessionStorage, n);
+      bench.start();
+      for (let i = 0; i < n; i++) {
+        // eslint-disable-next-line no-unused-expressions
+        sessionStorage[i];
+      }
+      bench.end(n);
+      break;
+    default:
+      new Error('Invalid type');
+  }
+}

filename: benchmark/webstorage/removeItem.js
patch: @@ -0,0 +1,75 @@
+'use strict';
+const { join } = require('node:path');
+const common = require('../common.js');
+const tmpdir = require('../../test/common/tmpdir');
+
+let cnt = 0;
+
+tmpdir.refresh();
+
+function nextLocalStorage() {
+  return join(tmpdir.path, `${++cnt}.localstorage`);
+}
+
+const options = {
+  flags: ['--experimental-webstorage', `--localstorage-file=${nextLocalStorage()}`],
+};
+
+const bench = common.createBenchmark(main, {
+  type: ['localStorage-removeItem',
+         'localStorage-delete',
+         'sessionStorage-removeItem',
+         'sessionStorage-delete',
+  ],
+  // Note: web storage has only 10mb quota
+  n: [1e5],
+}, options);
+
+function fillStorage(storage, n) {
+  for (let i = 0; i < n; i++) {
+    storage.setItem(i, i);
+  }
+}
+
+function main({ n, type }) {
+  const localStorage = globalThis.localStorage;
+  const sessionStorage = globalThis.sessionStorage;
+
+  switch (type) {
+    case 'localStorage-removeItem':
+      fillStorage(localStorage, n);
+      bench.start();
+      for (let i = 0; i < n; i++) {
+        localStorage.removeItem(i);
+      }
+      bench.end(n);
+      break;
+    case 'localStorage-delete':
+      fillStorage(localStorage, n);
+      bench.start();
+      for (let i = 0; i < n; i++) {
+        delete localStorage[i];
+      }
+      bench.end(n);
+      break;
+    case 'sessionStorage-removeItem':
+      fillStorage(sessionStorage, n);
+      bench.start();
+      for (let i = 0; i < n; i++) {
+        sessionStorage.removeItem(i);
+      }
+      bench.end(n);
+      break;
+
+    case 'sessionStorage-delete':
+      fillStorage(localStorage, n);
+      bench.start();
+      for (let i = 0; i < n; i++) {
+        delete sessionStorage[i];
+      }
+      bench.end(n);
+      break;
+    default:
+      new Error('Invalid type');
+  }
+}

filename: benchmark/webstorage/setItem.js
patch: @@ -0,0 +1,63 @@
+'use strict';
+const { join } = require('node:path');
+const common = require('../common.js');
+const tmpdir = require('../../test/common/tmpdir');
+
+let cnt = 0;
+
+tmpdir.refresh();
+
+function nextLocalStorage() {
+  return join(tmpdir.path, `${++cnt}.localstorage`);
+}
+
+const options = {
+  flags: ['--experimental-webstorage', `--localstorage-file=${nextLocalStorage()}`],
+};
+
+const bench = common.createBenchmark(main, {
+  type: ['localStorage-setItem',
+         'localStorage-setter',
+         'sessionStorage-setItem',
+         'sessionStorage-setter'],
+  // Note: web storage has only 10mb quota
+  n: [1e5],
+}, options);
+
+function main({ n, type }) {
+  const localStorage = globalThis.localStorage;
+  const sessionStorage = globalThis.sessionStorage;
+
+  switch (type) {
+    case 'localStorage-setItem':
+      bench.start();
+      for (let i = 0; i < n; i++) {
+        localStorage.setItem(i, i);
+      }
+      bench.end(n);
+      break;
+    case 'localStorage-setter':
+      bench.start();
+      for (let i = 0; i < n; i++) {
+        localStorage[i] = i;
+      }
+      bench.end(n);
+      break;
+    case 'sessionStorage-setItem':
+      bench.start();
+      for (let i = 0; i < n; i++) {
+        sessionStorage.setItem(i, i);
+      }
+      bench.end(n);
+      break;
+    case 'sessionStorage-setter':
+      bench.start();
+      for (let i = 0; i < n; i++) {
+        sessionStorage[i] = i;
+      }
+      bench.end(n);
+      break;
+    default:
+      new Error('Invalid type');
+  }
+}