Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/devtools/client/performance-new/shared/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 17 kB image not shown  

Quelle  utils.js   Sprache: JAVA

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @ts-check
/**
 * @typedef {import("../@types/perf").NumberScaler} NumberScaler
 * @typedef {import("../@types/perf").ScaleFunctions} ScaleFunctions
 * @typedef {import("../@types/perf").FeatureDescription} FeatureDescription
 */

"use strict";

const UNITS = ["B""kiB""MiB""GiB""TiB""PiB""EiB""ZiB""YiB"];

const AppConstants = ChromeUtils.importESModule(
  "resource://gre/modules/AppConstants.sys.mjs"
).AppConstants;

/**
 * Linearly interpolate between values.
 * https://en.wikipedia.org/wiki/Linear_interpolation
 *
 * @param {number} frac - Value ranged 0 - 1 to interpolate between the range start and range end.
 * @param {number} rangeStart - The value to start from.
 * @param {number} rangeEnd - The value to interpolate to.
 * @returns {number}
 */

function lerp(frac, rangeStart, rangeEnd) {
  return (1 - frac) * rangeStart + frac * rangeEnd;
}

/**
 * Make sure a value is clamped between a min and max value.
 *
 * @param {number} val - The value to clamp.
 * @param {number} min - The minimum value.
 * @param {number} max - The max value.
 * @returns {number}
 */

function clamp(val, min, max) {
  return Math.max(min, Math.min(max, val));
}

/**
 * Formats a file size.
 * @param {number} num - The number (in bytes) to format.
 * @returns {string} e.g. "10 B", "100 MiB"
 */

function formatFileSize(num) {
  if (!Number.isFinite(num)) {
    throw new TypeError(`Expected a finite number, got ${typeof num}: ${num}`);
  }

  const neg = num < 0;

  if (neg) {
    num = -num;
  }

  if (num < 1) {
    return (neg ? "-" : "") + num + " B";
  }

  const exponent = Math.min(
    Math.floor(Math.log2(num) / Math.log2(1024)),
    UNITS.length - 1
  );
  const numStr = Number((num / Math.pow(1024, exponent)).toPrecision(3));
  const unit = UNITS[exponent];

  return (neg ? "-" : "") + numStr + " " + unit;
}

/**
 * Creates numbers that increment linearly within a base 10 scale:
 * 0.1, 0.2, 0.3, ..., 0.8, 0.9, 1, 2, 3, ..., 9, 10, 20, 30, etc.
 *
 * @param {number} rangeStart
 * @param {number} rangeEnd
 *
 * @returns {ScaleFunctions}
 */

function makeLinear10Scale(rangeStart, rangeEnd) {
  const start10 = Math.log10(rangeStart);
  const end10 = Math.log10(rangeEnd);

  if (!Number.isInteger(start10)) {
    throw new Error(`rangeStart is not a power of 10: ${rangeStart}`);
  }

  if (!Number.isInteger(end10)) {
    throw new Error(`rangeEnd is not a power of 10: ${rangeEnd}`);
  }

  // Intervals are base 10 intervals:
  // - [0.01 .. 0.09]
  // - [0.1 .. 0.9]
  // - [1 .. 9]
  // - [10 .. 90]
  const intervals = end10 - start10;

  // Note that there are only 9 steps per interval, not 10:
  // 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9
  const STEP_PER_INTERVAL = 9;

  const steps = intervals * STEP_PER_INTERVAL;

  /** @type {NumberScaler} */
  const fromFractionToValue = frac => {
    const step = Math.round(frac * steps);
    const base = Math.floor(step / STEP_PER_INTERVAL);
    const factor = (step % STEP_PER_INTERVAL) + 1;
    return Math.pow(10, base) * factor * rangeStart;
  };

  /** @type {NumberScaler} */
  const fromValueToFraction = value => {
    const interval = Math.floor(Math.log10(value / rangeStart));
    const base = rangeStart * Math.pow(10, interval);
    return (interval * STEP_PER_INTERVAL + value / base - 1) / steps;
  };

  /** @type {NumberScaler} */
  const fromFractionToSingleDigitValue = frac => {
    return +fromFractionToValue(frac).toPrecision(1);
  };

  return {
    // Takes a number ranged 0-1 and returns it within the range.
    fromFractionToValue,
    // Takes a number in the range, and returns a value between 0-1
    fromValueToFraction,
    // Takes a number ranged 0-1 and returns a value in the range, but with
    // a single digit value.
    fromFractionToSingleDigitValue,
    // The number of steps available on this scale.
    steps,
  };
}

/**
 * Creates numbers that scale exponentially as powers of 2.
 *
 * @param {number} rangeStart
 * @param {number} rangeEnd
 *
 * @returns {ScaleFunctions}
 */

function makePowerOf2Scale(rangeStart, rangeEnd) {
  const startExp = Math.log2(rangeStart);
  const endExp = Math.log2(rangeEnd);

  if (!Number.isInteger(startExp)) {
    throw new Error(`rangeStart is not a power of 2: ${rangeStart}`);
  }

  if (!Number.isInteger(endExp)) {
    throw new Error(`rangeEnd is not a power of 2: ${rangeEnd}`);
  }

  const steps = endExp - startExp;

  /** @type {NumberScaler} */
  const fromFractionToValue = frac =>
    Math.pow(2, Math.round((1 - frac) * startExp + frac * endExp));

  /** @type {NumberScaler} */
  const fromValueToFraction = value =>
    (Math.log2(value) - startExp) / (endExp - startExp);

  /** @type {NumberScaler} */
  const fromFractionToSingleDigitValue = frac => {
    // fromFractionToValue returns an exact power of 2, we don't want to change
    // its precision. Note that formatFileSize will display it in a nice binary
    // unit with up to 3 digits.
    return fromFractionToValue(frac);
  };

  return {
    // Takes a number ranged 0-1 and returns it within the range.
    fromFractionToValue,
    // Takes a number in the range, and returns a value between 0-1
    fromValueToFraction,
    // Takes a number ranged 0-1 and returns a value in the range, but with
    // a single digit value.
    fromFractionToSingleDigitValue,
    // The number of steps available on this scale.
    steps,
  };
}

/**
 * Scale a source range to a destination range, but clamp it within the
 * destination range.
 * @param {number} val - The source range value to map to the destination range,
 * @param {number} sourceRangeStart,
 * @param {number} sourceRangeEnd,
 * @param {number} destRangeStart,
 * @param {number} destRangeEnd
 */

function scaleRangeWithClamping(
  val,
  sourceRangeStart,
  sourceRangeEnd,
  destRangeStart,
  destRangeEnd
) {
  const frac = clamp(
    (val - sourceRangeStart) / (sourceRangeEnd - sourceRangeStart),
    0,
    1
  );
  return lerp(frac, destRangeStart, destRangeEnd);
}

/**
 * Use some heuristics to guess at the overhead of the recording settings.
 *
 * TODO - Bug 1597383. The UI for this has been removed, but it needs to be reworked
 * for new overhead calculations. Keep it for now in tree.
 *
 * @param {number} interval
 * @param {number} bufferSize
 * @param {string[]} features - List of the selected features.
 */

function calculateOverhead(interval, bufferSize, features) {
  // NOT "nostacksampling" (double negative) means periodic sampling is on.
  const periodicSampling = !features.includes("nostacksampling");
  const overheadFromSampling = periodicSampling
    ? scaleRangeWithClamping(
        Math.log(interval),
        Math.log(0.05),
        Math.log(1),
        1,
        0
      ) +
      scaleRangeWithClamping(
        Math.log(interval),
        Math.log(1),
        Math.log(100),
        0.1,
        0
      )
    : 0;
  const overheadFromBuffersize = scaleRangeWithClamping(
    Math.log(bufferSize),
    Math.log(10),
    Math.log(1000000),
    0,
    0.1
  );
  const overheadFromStackwalk =
    features.includes("stackwalk") && periodicSampling ? 0.05 : 0;
  const overheadFromJavaScript =
    features.includes("js") && periodicSampling ? 0.05 : 0;
  const overheadFromJSTracer = features.includes("jstracer") ? 0.05 : 0;
  const overheadFromJSAllocations = features.includes("jsallocations")
    ? 0.05
    : 0;
  const overheadFromNativeAllocations = features.includes("nativeallocations")
    ? 0.5
    : 0;

  return clamp(
    overheadFromSampling +
      overheadFromBuffersize +
      overheadFromStackwalk +
      overheadFromJavaScript +
      overheadFromJSTracer +
      overheadFromJSAllocations +
      overheadFromNativeAllocations,
    0,
    1
  );
}

/**
 * Given an array of absolute paths on the file system, return an array that
 * doesn't contain the common prefix of the paths; in other words, if all paths
 * share a common ancestor directory, cut off the path to that ancestor
 * directory and only leave the path components that differ.
 * This makes some lists look a little nicer. For example, this turns the list
 * ["/Users/foo/code/obj-m-android-opt", "/Users/foo/code/obj-m-android-debug"]
 * into the list ["obj-m-android-opt", "obj-m-android-debug"].
 *
 * @param {string[]} pathArray The array of absolute paths.
 * @returns {string[]} A new array with the described adjustment.
 */

function withCommonPathPrefixRemoved(pathArray) {
  if (pathArray.length === 0) {
    return [];
  }

  const firstPath = pathArray[0];
  const isWin = /^[A-Za-z]:/.test(firstPath);
  const firstWinDrive = getWinDrive(firstPath);
  for (const path of pathArray) {
    const winDrive = getWinDrive(path);

    if (!PathUtils.isAbsolute(path) || winDrive !== firstWinDrive) {
      // We expect all paths to be absolute and on Windows we expect all
      // paths to be on the same disk. If this is not the case return the
      // original array.
      return pathArray;
    }
  }

  // At this point we're either not on Windows or all paths are on the same
  // Windows disk and all paths are absolute.
  // Find the common prefix. Start by assuming the entire path except for the
  // last folder is shared.
  const splitPaths = pathArray.map(path => PathUtils.split(path));
  const [firstSplitPath, ...otherSplitPaths] = splitPaths;
  const prefix = firstSplitPath.slice(0, -1);
  for (const sp of otherSplitPaths) {
    prefix.length = Math.min(prefix.length, sp.length - 1);
    for (let i = 0; i < prefix.length; i++) {
      if (prefix[i] !== sp[i]) {
        prefix.length = i;
        break;
      }
    }
  }
  if (
    prefix.length === 0 ||
    (prefix.length === 1 && (prefix[0] === firstWinDrive || prefix[0] === "/"))
  ) {
    // There is no shared prefix.
    // We treat a prefix of ["/"] as "no prefix", too: Absolute paths on
    // non-Windows start with a slash, so PathUtils.split(path) always returns
    // an array whose first element is "/" on those platforms.
    // Stripping off a prefix of ["/"] from the split paths would simply remove
    // the leading slash from the un-split paths, which is not useful.
    return pathArray;
  }

  // Strip the common prefix from all paths.
  return splitPaths.map(sp => {
    return sp.slice(prefix.length).join(isWin ? "\\" : "/");
  });
}

/**
 * This method has been copied from `ospath_win.jsm` as part of the migration
 * from `OS.Path` to `PathUtils`.
 *
 * Return the windows drive name of a path, or |null| if the path does
 * not contain a drive name.
 *
 * Drive name appear either as "DriveName:..." (the return drive
 * name includes the ":") or "\\\\DriveName..." (the returned drive name
 * includes "\\\\").
 *
 * @param {string} path The path from which we are to return the Windows drive name.
 * @returns {?string} Windows drive name e.g. "C:" or null if path is not a Windows path.
 */

function getWinDrive(path) {
  if (path == null) {
    throw new TypeError("path is invalid");
  }

  if (path.startsWith("\\\\")) {
    // UNC path
    if (path.length == 2) {
      return null;
    }
    const index = path.indexOf("\\", 2);
    if (index == -1) {
      return path;
    }
    return path.slice(0, index);
  }
  // Non-UNC path
  const index = path.indexOf(":");
  if (index <= 0) {
    return null;
  }
  return path.slice(0, index + 1);
}

class UnhandledCaseError extends Error {
  /**
   * @param {never} value - Check that
   * @param {string} typeName - A friendly type name.
   */

  constructor(value, typeName) {
    super(`There was an unhandled case for "${typeName}": ${value}`);
    this.name = "UnhandledCaseError";
  }
}

/**
 * @type {FeatureDescription[]}
 */

const featureDescriptions = [
  {
    name: "Native Stacks",
    value: "stackwalk",
    title:
      "Record native stacks (C++ and Rust). This is not available on all platforms.",
    recommended: true,
    disabledReason: "Native stack walking is not supported on this platform.",
  },
  {
    name: "JavaScript",
    value: "js",
    title:
      "Record JavaScript stack information, and interleave it with native stacks.",
    recommended: true,
  },
  {
    name: "CPU Utilization",
    value: "cpu",
    title:
      "Record how much CPU has been used between samples by each profiled thread.",
    recommended: true,
  },
  {
    name: "Memory Tracking",
    value: "memory",
    title:
      "Track the memory allocations and deallocations per process over time.",
    recommended: true,
  },
  {
    name: "Java",
    value: "java",
    title: "Profile Java code",
    disabledReason: "This feature is only available on Android.",
  },
  {
    name: "No Periodic Sampling",
    value: "nostacksampling",
    title: "Disable interval-based stack sampling",
  },
  {
    name: "Main Thread File IO",
    value: "mainthreadio",
    title: "Record main thread File I/O markers.",
  },
  {
    name: "Profiled Threads File IO",
    value: "fileio",
    title: "Record File I/O markers from only profiled threads.",
  },
  {
    name: "All File IO",
    value: "fileioall",
    title:
      "Record File I/O markers from all threads, even unregistered threads.",
  },
  {
    name: "No Marker Stacks",
    value: "nomarkerstacks",
    title: "Do not capture stacks when recording markers, to reduce overhead.",
  },
  {
    name: "Sequential Styling",
    value: "seqstyle",
    title: "Disable parallel traversal in styling.",
  },
  {
    name: "Screenshots",
    value: "screenshots",
    title: "Record screenshots of all browser windows.",
  },
  {
    name: "IPC Messages",
    value: "ipcmessages",
    title: "Track IPC messages.",
  },
  {
    name: "JS Allocations",
    value: "jsallocations",
    title: "Track JavaScript allocations",
  },
  {
    name: "Native Allocations",
    value: "nativeallocations",
    title: "Track native allocations",
  },
  {
    name: "Audio Callback Tracing",
    value: "audiocallbacktracing",
    title: "Trace real-time audio callbacks.",
  },
  {
    name: "No Timer Resolution Change",
    value: "notimerresolutionchange",
    title:
      "Do not enhance the timer resolution for sampling intervals < 10ms, to " +
      "avoid affecting timer-sensitive code. Warning: Sampling interval may " +
      "increase in some processes.",
    disabledReason: "Windows only.",
  },
  {
    name: "CPU Utilization - All Threads",
    value: "cpuallthreads",
    title:
      "Record CPU usage of all known threads, even threads which are not being profiled.",
    experimental: true,
  },
  {
    name: "Periodic Sampling - All Threads",
    value: "samplingallthreads",
    title: "Capture stack samples in ALL registered thread.",
    experimental: true,
  },
  {
    name: "Markers - All Threads",
    value: "markersallthreads",
    title: "Record markers in ALL registered threads.",
    experimental: true,
  },
  {
    name: "Unregistered Threads",
    value: "unregisteredthreads",
    title:
      "Periodically discover unregistered threads and record them and their " +
      "CPU utilization as markers in the main thread -- Beware: expensive!",
    experimental: true,
  },
  {
    name: "Process CPU Utilization",
    value: "processcpu",
    title:
      "Record how much CPU has been used between samples by each process. " +
      "To see graphs: When viewing the profile, open the JS console and run: " +
      "experimental.enableProcessCPUTracks()",
    experimental: true,
  },
  {
    name: "Power Use",
    value: "power",
    title: (() => {
      switch (AppConstants.platform) {
        case "win":
          return (
            "Record the value of every energy meter available on the system with " +
            "each sample. Only available on Windows 11 with Intel CPUs."
          );
        case "linux":
          return (
            "Record the power used by the entire system with each sample. " +
            "Only available with Intel CPUs and requires setting the sysctl kernel.perf_event_paranoid to 0."
          );
        case "macosx":
          return "Record the power used by the entire system (Intel) or each process (Apple Silicon) with each sample.";
        default:
          return "Not supported on this platform.";
      }
    })(),
    experimental: true,
  },
  {
    name: "CPU Frequency",
    value: "cpufreq",
    title:
      "Record the clock frequency of every CPU core for every profiler sample.",
    experimental: true,
    disabledReason:
      "This feature is only available on Windows, Linux and Android.",
  },
  {
    name: "Network Bandwidth",
    value: "bandwidth",
    title: "Record the network bandwidth used between every profiler sample.",
  },
  {
    name: "JS Execution Tracing",
    value: "tracing",
    title:
      "Disable periodic stack sampling, and capture information about every JS function executed.",
    experimental: true,
  },
  {
    name: "Sandbox profiling",
    value: "sandbox",
    title: "Report sandbox syscalls and logs in the profiler.",
  },
  {
    name: "Flows",
    value: "flows",
    title:
      "Include all flow-related markers. These markers show the program flow better but " +
      "can cause more overhead in some places than normal.",
  },
];

module.exports = {
  formatFileSize,
  makeLinear10Scale,
  makePowerOf2Scale,
  scaleRangeWithClamping,
  calculateOverhead,
  withCommonPathPrefixRemoved,
  UnhandledCaseError,
  featureDescriptions,
};

92%


¤ Dauer der Verarbeitung: 0.31 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.