Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { MemoryAttribution } from '../MemoryAttribution/MemoryAttribution.ts'
import * as GetUrlName from '../GetUrlName/GetUrlName.ts'

export const getAttributionName = (attribution: MemoryAttribution): string => {
const scope = attribution.scope || 'memory'
const url = attribution.url ? GetUrlName.getUrlName(attribution.url) : ''
if (url) {
return `${scope}: ${url}`
}
return scope
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { MemoryBreakdownEntry } from '../MemoryBreakdownEntry/MemoryBreakdownEntry.ts'
import * as GetAttributionName from '../GetAttributionName/GetAttributionName.ts'

export const getBreakdownName = (
entry: MemoryBreakdownEntry,
index: number,
): string => {
if (entry.attribution && entry.attribution.length > 0) {
return entry.attribution
.map(GetAttributionName.getAttributionName)
.join(', ')
}
if (entry.types && entry.types.length > 0) {
return entry.types.join(', ')
}
return `breakdown ${index + 1}`
}
Original file line number Diff line number Diff line change
@@ -1,116 +1,34 @@
import type { ProcessInfo } from '../ProcessInfo/ProcessInfo.ts'

interface MemoryAttribution {
readonly scope?: string
readonly url?: string
}

interface MemoryBreakdownEntry {
readonly attribution?: readonly MemoryAttribution[]
readonly bytes: number
readonly types?: readonly string[]
}

interface MemoryMeasurement {
readonly breakdown?: readonly MemoryBreakdownEntry[]
readonly bytes: number
}

interface PerformanceWithMemory extends Performance {
readonly measureUserAgentSpecificMemory?: () => Promise<MemoryMeasurement>
}

const WindowPid = -1

const QueryOrHashRegex = /[?#]/

const isValidMemoryValue = (value: unknown): value is number => {
return typeof value === 'number' && Number.isFinite(value) && value >= 0
}

const getMeasureMemory = (): (() => Promise<MemoryMeasurement>) | undefined => {
const { measureUserAgentSpecificMemory } =
performance as PerformanceWithMemory
if (typeof measureUserAgentSpecificMemory !== 'function') {
return undefined
}
return measureUserAgentSpecificMemory.bind(performance)
}

const getUrlName = (url: string): string => {
if (!url || url === 'cross-origin-url') {
return url
}
try {
const parsed = new URL(url)
const parts = parsed.pathname.split('/').filter(Boolean)
return parts.at(-1) || parsed.hostname || url
} catch {
const withoutQuery = url.split(QueryOrHashRegex, 1)[0]
const parts = withoutQuery.split('/').filter(Boolean)
return parts.at(-1) || url
}
}

const getAttributionName = (attribution: MemoryAttribution): string => {
const scope = attribution.scope || 'memory'
const url = attribution.url ? getUrlName(attribution.url) : ''
if (url) {
return `${scope}: ${url}`
}
return scope
}

const getBreakdownName = (
entry: MemoryBreakdownEntry,
index: number,
): string => {
if (entry.attribution && entry.attribution.length > 0) {
return entry.attribution.map(getAttributionName).join(', ')
}
if (entry.types && entry.types.length > 0) {
return entry.types.join(', ')
}
return `breakdown ${index + 1}`
}

const toBreakdownProcess = (
entry: MemoryBreakdownEntry,
index: number,
): ProcessInfo => {
const name = getBreakdownName(entry, index)
return {
cmd: name,
memory: entry.bytes,
name,
pid: -2 - index,
ppid: WindowPid,
synthetic: true,
}
}
import * as GetMeasureMemory from '../GetMeasureMemory/GetMeasureMemory.ts'
import * as IsValidMemoryValue from '../IsValidMemoryValue/IsValidMemoryValue.ts'
import * as ToBreakdownProcess from '../ToBreakdownProcess/ToBreakdownProcess.ts'
import * as WindowPid from '../WindowPid/WindowPid.ts'

export const getFrontendMemoryUsage = async (
rootPid: number,
): Promise<readonly ProcessInfo[]> => {
const measureMemory = getMeasureMemory()
const measureMemory = GetMeasureMemory.getMeasureMemory()
if (!measureMemory) {
return []
}
try {
const measurement = await measureMemory()
if (!isValidMemoryValue(measurement.bytes)) {
if (!IsValidMemoryValue.isValidMemoryValue(measurement.bytes)) {
return []
}
const breakdown = measurement.breakdown || []
const breakdownProcesses = breakdown
.filter((entry) => isValidMemoryValue(entry.bytes) && entry.bytes > 0)
.map(toBreakdownProcess)
.filter(
(entry) =>
IsValidMemoryValue.isValidMemoryValue(entry.bytes) && entry.bytes > 0,
)
.map(ToBreakdownProcess.toBreakdownProcess)
return [
{
cmd: 'window',
memory: measurement.bytes,
name: 'window',
pid: WindowPid,
pid: WindowPid.WindowPid,
ppid: rootPid,
synthetic: true,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { MemoryMeasurement } from '../MemoryMeasurement/MemoryMeasurement.ts'
import type { PerformanceWithMemory } from '../PerformanceWithMemory/PerformanceWithMemory.ts'

export const getMeasureMemory = ():
(() => Promise<MemoryMeasurement>) | undefined => {
const { measureUserAgentSpecificMemory } =
performance as PerformanceWithMemory
if (typeof measureUserAgentSpecificMemory !== 'function') {
return undefined
}
return measureUserAgentSpecificMemory.bind(performance)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const QueryOrHashRegex = /[?#]/

export const getUrlName = (url: string): string => {
if (!url || url === 'cross-origin-url') {
return url
}
try {
const parsed = new URL(url)
const parts = parsed.pathname.split('/').filter(Boolean)
return parts.at(-1) || parsed.hostname || url
} catch {
const withoutQuery = url.split(QueryOrHashRegex, 1)[0]
const parts = withoutQuery.split('/').filter(Boolean)
return parts.at(-1) || url
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const isValidMemoryValue = (value: unknown): value is number => {
return typeof value === 'number' && Number.isFinite(value) && value >= 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface MemoryAttribution {
readonly scope?: string
readonly url?: string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { MemoryAttribution } from '../MemoryAttribution/MemoryAttribution.ts'

export interface MemoryBreakdownEntry {
readonly attribution?: readonly MemoryAttribution[]
readonly bytes: number
readonly types?: readonly string[]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { MemoryBreakdownEntry } from '../MemoryBreakdownEntry/MemoryBreakdownEntry.ts'

export interface MemoryMeasurement {
readonly breakdown?: readonly MemoryBreakdownEntry[]
readonly bytes: number
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { MemoryMeasurement } from '../MemoryMeasurement/MemoryMeasurement.ts'

export interface PerformanceWithMemory extends Performance {
readonly measureUserAgentSpecificMemory?: () => Promise<MemoryMeasurement>
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import { RendererWorker } from '@lvce-editor/rpc-registry'

interface RendererWorkerWithProcessExplorer {
readonly sendMessagePortToProcessExplorer: (
port: MessagePort,
) => Promise<void>
}

export const sendMessagePortToProcessExplorer = async (
port: MessagePort,
): Promise<void> => {
const rendererWorker =
RendererWorker as unknown as RendererWorkerWithProcessExplorer
await rendererWorker.sendMessagePortToProcessExplorer(port)
await RendererWorker.sendMessagePortToProcessExplorer(port)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { MemoryBreakdownEntry } from '../MemoryBreakdownEntry/MemoryBreakdownEntry.ts'
import type { ProcessInfo } from '../ProcessInfo/ProcessInfo.ts'
import * as GetBreakdownName from '../GetBreakdownName/GetBreakdownName.ts'
import * as WindowPid from '../WindowPid/WindowPid.ts'

export const toBreakdownProcess = (
entry: MemoryBreakdownEntry,
index: number,
): ProcessInfo => {
const name = GetBreakdownName.getBreakdownName(entry, index)
return {
cmd: name,
memory: entry.bytes,
name,
pid: -2 - index,
ppid: WindowPid.WindowPid,
synthetic: true,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const WindowPid = -1