npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@agoric/transform-metering

v1.4.27

Published

transform-metering

Downloads

256

Readme

Transform Metering

The purpose of this package is to provide a loose, but deterministic way to interrupt Javascript code that exceeds a "meter".

This technique is not airtight, but it is at least is a best approximation in the absence of an instrumented host platform.

Quickstart

import { tameMetering } from '@agoric/tame-metering';
import { lockdown } from 'ses';
import { makeMeteredEvaluator } from '@agoric/transform-metering';

// Override all the global objects with metered versions.
const replaceGlobalMeter = tameMetering();

// Enter SES.
lockdown();

const meteredEval = makeMeteredEvaluator({
  // Needed for enabling metering of the global builtins.
  replaceGlobalMeter,
  // Create an object with an `evaluate(src, endowments)` method
  makeEvaluator: opts => {
    const c = new Compartment(undefined, undefined, opts);
    return {
      evaluate(src, endowments = {}) {
        return c.evaluate(src, { endowments });
      }
    }
  },
  // Call a callback when the code inside the meteredEval is done evaluating.
  quiesceCallback: cb => setTimeout(cb),
});

Using the new meteredEval

import { makeMeter } from '@agoric/transform-metering';

const { meter } = makeMeter();

// Then to evaluate some source with endowments:
meteredEval(meter, 'abc + def', {abc: 123, def: 456}).then(
  ([normalReturn, value, seenMeters]) => {
    for (const m of seenMeters) {
      const ex = m.isExhausted();
      if (ex) {
        console.log('meter', m, 'was exhausted with', ex);;
      }
    }
    if (normalReturn) {
      console.log('normal return', value);
    } else {
      console.log('exception', value);
    }
  }
);

Implementation Details

Meter types

There are three types of meters:

  • Allocation meters. These decrement a budget by a cost roughly proportional to the storage size of the provided argument.

  • Compute meters. These only decrement a budget by a cost roughly proportional to the execution time of the code that follows them.

  • Stack meters. These track the depth of stack used between nested calls to decrement and increment the meter.

Another type of meter is the "combined" meter, which can measure the consumption of more than one of the above against the same budget.

The transformation

To instrument source code robustly, the metering transform should be installed as part of an 3-argument evaluator call (such as the one provided by SES, Secure EcmaScript).

The deterministic results of exceeding any meter is a thrown exception. That same exception is rethrown by any meter adjustment, until the exceeded meter is reset. No user code can execute after a meter exception because any attempt to catch or finally handle that exception is instrumented with another meter check.

Thus, an exceeded meter for any reason throws a RangeError all the way to the top of the evaluation, in the calling host code.

Function bodies

This transformation replaces every function body (including single-expression arrow functions) with:

  try {
    [decrement stack meter, throw if exceeded]
    ... // existing function body
  } finally {
    [increment stack meter]
  }

Loop statements

Every loop body (including single-statement bodies), and catch and finally bodies are preceded with:

   {
     [decrement compute meter, throw if exceeded]
     ... // existing loop body
   }

RegExp literals

All regular expression literals (such as /some-regexp/g) are rewritten as follows:

const $h_re_1 = RegExp('some-regexp', 'g');
... // existing use of /some-regexp/g replaced by $h_re_1

The $h_re_-prefixed identifiers are blacklisted for pre-transformed evaluated sources.

This makes it possible for an endowedd RegExp constructor to prevent "catastrophic backtracking". One such suitable constructor is RE2.

Host endowments

Without precisely instrumenting the host platform code, this package provides an option to wrap a global object with code that does a rough instrumentation of function calls.

The reason for this wrapping is to provide some basic accounting for the resources consumed by the host platform methods. The wrapping makes some assumptions about the host, such as:

  1. only flat objects are allocated by builtins, and they are returned by the builtin
  2. builtins that are costly in time- or space-complexity have large return values, or many calls to a supplied function argument
  3. builtins have been "tamed" by the SES platform to prevent nondeterminism and pathological behaviour

This at least prevents user code from running after a builtin has exceeded a meter.