diff --git a/docs-developer/CHANGELOG-formats.md b/docs-developer/CHANGELOG-formats.md index 7a3c44138a..5210dc1932 100644 --- a/docs-developer/CHANGELOG-formats.md +++ b/docs-developer/CHANGELOG-formats.md @@ -6,6 +6,18 @@ Note that this is not an exhaustive list. Processed profile format upgraders can ## Processed profile format +### Version 67 + +The following raw columns can now optionally be stored as typed arrays, for profiles loaded from [JsonSlabs](https://github.com/mstange/json-slabs/) files (.jslb, .jslb.gz). Regular JS / JSON arrays are still accepted. + +- `thread.samples.time` and `thread.samples.timeDeltas` (`Float64Array`) +- `counter.samples.time` and `counter.samples.timeDeltas` (`Float64Array`) +- `thread.jsAllocations.time` (`Float64Array`) +- `thread.nativeAllocations.time` (`Float64Array`) +- `profile.shared.frameTable.func` (`Int32Array`) +- `profile.shared.frameTable.address` (`Int32Array`, with `-1` as the sentinel for missing addresses) +- `profile.shared.frameTable.inlineDepth` (`Uint8Array`) + ### Version 66 The `prefix` column of `profile.shared.stackTable` was replaced with a `prefixOffset` column, to improve compressibility. diff --git a/src/app-logic/constants.ts b/src/app-logic/constants.ts index 2979163779..ebd546bdca 100644 --- a/src/app-logic/constants.ts +++ b/src/app-logic/constants.ts @@ -12,7 +12,7 @@ export const GECKO_PROFILE_VERSION = 34; // The current version of the "processed" profile format. // Please don't forget to update the processed profile format changelog in // `docs-developer/CHANGELOG-formats.md`. -export const PROCESSED_PROFILE_VERSION = 66; +export const PROCESSED_PROFILE_VERSION = 67; // The following are the margin sizes for the left and right of the timeline. Independent // components need to share these values. diff --git a/src/profile-logic/combined-cpu.ts b/src/profile-logic/combined-cpu.ts index a7a7efa163..6966e779f3 100644 --- a/src/profile-logic/combined-cpu.ts +++ b/src/profile-logic/combined-cpu.ts @@ -2,14 +2,14 @@ * 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/. */ -import type { SamplesTable } from 'firefox-profiler/types'; +import type { Milliseconds, SamplesTable } from 'firefox-profiler/types'; import { bisectionLeft } from '../utils/bisect'; /** * Represents CPU usage over time for a single thread. */ export type CpuRatioTimeSeries = { - time: number[]; + time: Float64Array; cpuRatio: Float64Array; maxCpuRatio: number; length: number; @@ -87,7 +87,7 @@ export function combineCPUDataFromThreads( } const cursors = new Array(threadsWithCPU.length).fill(0); - const combinedTime: number[] = []; + const combinedTime: Milliseconds[] = []; const combinedCPURatio: number[] = []; let combinedMaxCpuRatio = 0; @@ -126,7 +126,7 @@ export function combineCPUDataFromThreads( } return { - time: combinedTime, + time: Float64Array.from(combinedTime), cpuRatio: Float64Array.from(combinedCPURatio), maxCpuRatio: combinedMaxCpuRatio, length: combinedTime.length, diff --git a/src/profile-logic/cpu.ts b/src/profile-logic/cpu.ts index 4ed904bc5c..4048a0d0de 100644 --- a/src/profile-logic/cpu.ts +++ b/src/profile-logic/cpu.ts @@ -103,7 +103,7 @@ export function computeReferenceCPUDeltaPerMs(profile: Profile): number { */ export function computeThreadCPUPercent( threadCPUDelta: Array, - timeDeltas: number[], + timeDeltas: number[] | Float64Array, referenceCPUDeltaPerMs: number ): Uint8Array { const threadCPUPercent: Uint8Array = new Uint8Array( diff --git a/src/profile-logic/data-structures.ts b/src/profile-logic/data-structures.ts index 476745de1a..b5f287a8b5 100644 --- a/src/profile-logic/data-structures.ts +++ b/src/profile-logic/data-structures.ts @@ -11,13 +11,13 @@ import type { RawProfileSharedData, RawThread, RawSamplesTable, - FrameTable, + RawFrameTable, RawStackTable, + RawJsAllocationsTable, + RawUnbalancedNativeAllocationsTable, + RawBalancedNativeAllocationsTable, FuncTable, RawMarkerTable, - JsAllocationsTable, - UnbalancedNativeAllocationsTable, - BalancedNativeAllocationsTable, ResourceTable, NativeSymbolTable, Profile, @@ -28,14 +28,100 @@ import type { SourceTable, SourceLocationTable, IndexIntoFrameTable, + IndexIntoFuncTable, IndexIntoStackTable, + IndexIntoCategoryList, + IndexIntoSubcategoryListForCategory, + IndexIntoNativeSymbolTable, + IndexIntoSourceLocationTable, + InnerWindowID, + Address, + Bytes, + Milliseconds, + Tid, + WeightType, } from 'firefox-profiler/types'; +/** + * Builder-variants of various tables. The columns here use plain + * arrays so that elements can be added one-by-one by pushing to + * the column arrays. + * + * The "raw" variants of these arrays (i.e. what's stored in the + * profile files) may be using typed arrays for some of the columns, + * and you can't push to a typed array. + */ +export type RawSamplesTableBuilder = { + responsiveness?: Array; + eventDelay?: Array; + stack: Array; + time?: Milliseconds[]; + timeDeltas?: Milliseconds[]; + argumentValues?: Array; + weight: null | number[]; + weightType: WeightType; + threadCPUDelta?: Array; + threadId?: Tid[]; + length: number; +}; + +export type RawJsAllocationsTableBuilder = { + time: Milliseconds[]; + className: string[]; + typeName: string[]; + coarseType: string[]; + weight: Bytes[]; + weightType: 'bytes'; + inNursery: boolean[]; + stack: Array; + length: number; +}; + +export type RawUnbalancedNativeAllocationsTableBuilder = { + time: Milliseconds[]; + weight: Bytes[]; + weightType: 'bytes'; + stack: Array; + argumentValues?: Array; + length: number; +}; + +export type RawBalancedNativeAllocationsTableBuilder = { + time: Milliseconds[]; + weight: Bytes[]; + weightType: 'bytes'; + stack: Array; + argumentValues?: Array; + memoryAddress: number[]; + threadId: number[]; + length: number; +}; + +export type RawFrameTableBuilder = { + address: Array
; + inlineDepth: number[]; + category: (IndexIntoCategoryList | null)[]; + subcategory: (IndexIntoSubcategoryListForCategory | null)[]; + func: IndexIntoFuncTable[]; + nativeSymbol: (IndexIntoNativeSymbolTable | null)[]; + innerWindowID: (InnerWindowID | null)[]; + line: (number | null)[]; + column: (number | null)[]; + originalLocation: Array; + length: number; +}; + +export type RawStackTableBuilder = { + frame: IndexIntoFrameTable[]; + prefix: Array; + length: number; +}; + /** * This module collects all of the creation of new empty profile data structures. */ -export function getEmptySamplesTable(): RawSamplesTable { +export function getRawSamplesTableBuilder(): RawSamplesTableBuilder { return { // Important! // If modifying this structure, please update all callers of this function to ensure @@ -49,12 +135,6 @@ export function getEmptySamplesTable(): RawSamplesTable { }; } -export type RawStackTableBuilder = { - frame: IndexIntoFrameTable[]; - prefix: Array; - length: number; -}; - export function getRawStackTableBuilder(): RawStackTableBuilder { return { // Important! @@ -67,6 +147,53 @@ export function getRawStackTableBuilder(): RawStackTableBuilder { }; } +/** + * Return a `RawSamplesTableBuilder` view of an existing samples table. If the + * table's time / timeDeltas columns are already plain arrays, they are aliased + * through so that in-place mutations on the builder are visible via the + * returned reference. If they are typed arrays (only produced by the JSLB + * loader), they are copied into plain arrays. + * + * The returned builder shares object identity with `existing` in the common + * (plain-array) case, so callers do not need to reassign it back onto the + * thread. In the typed-array case a new object is returned; callers should + * reassign it (`thread.samples = builder`) to preserve mutations. + */ +export function getRawSamplesTableBuilderFromExisting( + existing: RawSamplesTable +): RawSamplesTableBuilder { + const time = existing.time; + const timeDeltas = existing.timeDeltas; + if ( + (time === undefined || Array.isArray(time)) && + (timeDeltas === undefined || Array.isArray(timeDeltas)) + ) { + return existing as RawSamplesTableBuilder; + } + return { + ...existing, + time: time === undefined || Array.isArray(time) ? time : Array.from(time), + timeDeltas: + timeDeltas === undefined || Array.isArray(timeDeltas) + ? timeDeltas + : Array.from(timeDeltas), + }; +} + +export function finishRawSamplesTableBuilder( + builder: RawSamplesTableBuilder +): RawSamplesTable { + return { + ...builder, + time: + builder.time === undefined ? undefined : new Float64Array(builder.time), + timeDeltas: + builder.timeDeltas === undefined + ? undefined + : new Float64Array(builder.timeDeltas), + }; +} + export function getRawStackTableBuilderWithExistingContents( existing: RawStackTable ): RawStackTableBuilder { @@ -103,7 +230,7 @@ export function finishRawStackTableBuilder( * eventDelay is a new field and it replaced responsiveness. We should still * account for older profiles and use both of the flavors if needed. */ -export function getEmptySamplesTableWithEventDelay(): RawSamplesTable { +export function getRawSamplesTableBuilderWithEventDelay(): RawSamplesTableBuilder { return { // Important! // If modifying this structure, please update all callers of this function to ensure @@ -118,7 +245,7 @@ export function getEmptySamplesTableWithEventDelay(): RawSamplesTable { }; } -export function getEmptyFrameTable(): FrameTable { +export function getRawFrameTableBuilder(): RawFrameTableBuilder { return { // Important! // If modifying this structure, please update all callers of this function to ensure @@ -138,17 +265,19 @@ export function getEmptyFrameTable(): FrameTable { }; } -export function shallowCloneFrameTable(frameTable: FrameTable): FrameTable { +export function getRawFrameTableBuilderWithExistingContents( + frameTable: RawFrameTable +): RawFrameTableBuilder { return { // Important! // If modifying this structure, please update all callers of this function to ensure // that they are pushing on correctly to the data structure. These pushes may not // be caught by the type system. - address: frameTable.address.slice(), - inlineDepth: frameTable.inlineDepth.slice(), + address: Array.from(frameTable.address), + inlineDepth: Array.from(frameTable.inlineDepth), category: frameTable.category.slice(), subcategory: frameTable.subcategory.slice(), - func: frameTable.func.slice(), + func: Array.from(frameTable.func), nativeSymbol: frameTable.nativeSymbol.slice(), innerWindowID: frameTable.innerWindowID.slice(), line: frameTable.line.slice(), @@ -158,6 +287,17 @@ export function shallowCloneFrameTable(frameTable: FrameTable): FrameTable { }; } +export function finishRawFrameTableBuilder( + builder: RawFrameTableBuilder +): RawFrameTable { + return { + ...builder, + address: new Int32Array(builder.address), + inlineDepth: new Uint8Array(builder.inlineDepth), + func: new Int32Array(builder.func), + }; +} + export function getEmptyFuncTable(): FuncTable { return { // Important! @@ -274,7 +414,7 @@ export function getEmptyRawMarkerTable(): RawMarkerTable { }; } -export function getEmptyJsAllocationsTable(): JsAllocationsTable { +export function getEmptyRawJsAllocationsTable(): RawJsAllocationsTableBuilder { // Important! // If modifying this structure, please update all callers of this function to ensure // that they are pushing on correctly to the data structure. These pushes may not @@ -296,7 +436,7 @@ export function getEmptyJsAllocationsTable(): JsAllocationsTable { * The native allocation tables come in two varieties. Get one of the members of the * union. */ -export function getEmptyUnbalancedNativeAllocationsTable(): UnbalancedNativeAllocationsTable { +export function getEmptyRawUnbalancedNativeAllocationsTable(): RawUnbalancedNativeAllocationsTableBuilder { // Important! // If modifying this structure, please update all callers of this function to ensure // that they are pushing on correctly to the data structure. These pushes may not @@ -314,7 +454,7 @@ export function getEmptyUnbalancedNativeAllocationsTable(): UnbalancedNativeAllo * The native allocation tables come in two varieties. Get one of the members of the * union. */ -export function getEmptyBalancedNativeAllocationsTable(): BalancedNativeAllocationsTable { +export function getEmptyRawBalancedNativeAllocationsTable(): RawBalancedNativeAllocationsTableBuilder { // Important! // If modifying this structure, please update all callers of this function to ensure // that they are pushing on correctly to the data structure. These pushes may not @@ -330,6 +470,33 @@ export function getEmptyBalancedNativeAllocationsTable(): BalancedNativeAllocati }; } +export function finishRawJsAllocationsTableBuilder( + builder: RawJsAllocationsTableBuilder +): RawJsAllocationsTable { + return { + ...builder, + time: new Float64Array(builder.time), + }; +} + +export function finishRawUnbalancedNativeAllocationsTableBuilder( + builder: RawUnbalancedNativeAllocationsTableBuilder +): RawUnbalancedNativeAllocationsTable { + return { + ...builder, + time: new Float64Array(builder.time), + }; +} + +export function finishRawBalancedNativeAllocationsTableBuilder( + builder: RawBalancedNativeAllocationsTableBuilder +): RawBalancedNativeAllocationsTable { + return { + ...builder, + time: new Float64Array(builder.time), + }; +} + export function shallowCloneRawMarkerTable( markerTable: RawMarkerTable ): RawMarkerTable { @@ -420,7 +587,9 @@ export function getEmptyThread(overrides?: Partial): RawThread { pid: '0', tid: 0, // Creating samples with event delay since it's the new samples table. - samples: getEmptySamplesTableWithEventDelay(), + samples: finishRawSamplesTableBuilder( + getRawSamplesTableBuilderWithEventDelay() + ), markers: getEmptyRawMarkerTable(), }; @@ -433,7 +602,7 @@ export function getEmptyThread(overrides?: Partial): RawThread { export function getEmptySharedData(): RawProfileSharedData { return { stackTable: finishRawStackTableBuilder(getRawStackTableBuilder()), - frameTable: getEmptyFrameTable(), + frameTable: finishRawFrameTableBuilder(getRawFrameTableBuilder()), funcTable: getEmptyFuncTable(), resourceTable: getEmptyResourceTable(), nativeSymbols: getEmptyNativeSymbolTable(), diff --git a/src/profile-logic/global-data-collector.ts b/src/profile-logic/global-data-collector.ts index c52e170293..03333b58c7 100644 --- a/src/profile-logic/global-data-collector.ts +++ b/src/profile-logic/global-data-collector.ts @@ -4,8 +4,9 @@ import { StringTable } from '../utils/string-table'; import { + finishRawFrameTableBuilder, finishRawStackTableBuilder, - getEmptyFrameTable, + getRawFrameTableBuilder, getEmptyFuncTable, getEmptyNativeSymbolTable, getEmptyResourceTable, @@ -22,7 +23,6 @@ import type { IndexIntoSourceTable, RawProfileSharedData, SourceTable, - FrameTable, FuncTable, ResourceTable, NativeSymbolTable, @@ -34,7 +34,10 @@ import type { Bytes, } from 'firefox-profiler/types'; import { ResourceType } from 'firefox-profiler/types'; -import type { RawStackTableBuilder } from './data-structures'; +import type { + RawFrameTableBuilder, + RawStackTableBuilder, +} from './data-structures'; /** * GlobalDataCollector collects data which is global in the processed profile @@ -50,7 +53,7 @@ export class GlobalDataCollector { _stringArray: string[] = []; _stringTable: StringTable = StringTable.withBackingArray(this._stringArray); _sources: SourceTable = getEmptySourceTable(); - _frameTable: FrameTable = getEmptyFrameTable(); + _frameTable: RawFrameTableBuilder = getRawFrameTableBuilder(); _stackTableBuilder: RawStackTableBuilder = getRawStackTableBuilder(); _funcTable: FuncTable = getEmptyFuncTable(); _resourceTable: ResourceTable = getEmptyResourceTable(); @@ -299,7 +302,7 @@ export class GlobalDataCollector { return this._stringTable; } - getFrameTable(): FrameTable { + getFrameTable(): RawFrameTableBuilder { return this._frameTable; } @@ -312,7 +315,7 @@ export class GlobalDataCollector { finish(): { libs: Lib[]; shared: RawProfileSharedData } { const shared: RawProfileSharedData = { stackTable: finishRawStackTableBuilder(this._stackTableBuilder), - frameTable: this._frameTable, + frameTable: finishRawFrameTableBuilder(this._frameTable), funcTable: this._funcTable, resourceTable: this._resourceTable, nativeSymbols: this._nativeSymbols, diff --git a/src/profile-logic/import/chrome.ts b/src/profile-logic/import/chrome.ts index fefc76f986..e670e3afd8 100644 --- a/src/profile-logic/import/chrome.ts +++ b/src/profile-logic/import/chrome.ts @@ -10,8 +10,11 @@ import type { } from 'firefox-profiler/types'; import { + finishRawSamplesTableBuilder, getEmptyProfile, getEmptyThread, + getRawSamplesTableBuilderWithEventDelay, + type RawSamplesTableBuilder, type RawStackTableBuilder, } from '../data-structures'; import type { StringTable } from '../../utils/string-table'; @@ -270,6 +273,7 @@ export function attemptToConvertChromeProfile( type ThreadInfo = { thread: RawThread; + samples: RawSamplesTableBuilder; nodeIdToStackId: Map; lastSeenTime: number; lastSampledTime: number; @@ -316,7 +320,8 @@ function getThreadInfo( if (cachedThreadInfo) { return cachedThreadInfo; } - const thread = getEmptyThread(); + const samples = getRawSamplesTableBuilderWithEventDelay(); + const thread = getEmptyThread({ samples }); thread.pid = `${chunk.pid}`; // It looks like the TID information in Chrome's data isn't the system's TID // but some internal values only unique for a pid. Therefore let's generate a @@ -401,6 +406,7 @@ function getThreadInfo( const threadInfo: ThreadInfo = { thread, + samples, nodeIdToStackId, lastSeenTime: chunk.ts / 1000, lastSampledTime: 0, @@ -531,7 +537,7 @@ async function processTracingEvents( profile, profileEvent ); - const { thread, nodeIdToStackId } = threadInfo; + const { samples: samplesTable, nodeIdToStackId } = threadInfo; let profileChunks: any[] = []; if (profileEvent.name === 'Profile') { @@ -565,8 +571,6 @@ async function processTracingEvents( continue; } - const { samples: samplesTable } = thread; - if (nodes) { const parentMap = new Map(); for (const node of nodes) { @@ -785,6 +789,10 @@ async function processTracingEvents( const { shared } = globalDataCollector.finish(); profile.shared = shared; + for (const [thread, threadInfo] of threadInfoByThread) { + thread.samples = finishRawSamplesTableBuilder(threadInfo.samples); + } + return profile; } diff --git a/src/profile-logic/import/dhat.ts b/src/profile-logic/import/dhat.ts index 6f883c2e29..e0dd3f240c 100644 --- a/src/profile-logic/import/dhat.ts +++ b/src/profile-logic/import/dhat.ts @@ -10,9 +10,10 @@ import type { } from 'firefox-profiler/types'; import { + finishRawUnbalancedNativeAllocationsTableBuilder, getEmptyProfile, getEmptyThread, - getEmptyUnbalancedNativeAllocationsTable, + getEmptyRawUnbalancedNativeAllocationsTable, } from 'firefox-profiler/profile-logic/data-structures'; import { GlobalDataCollector } from 'firefox-profiler/profile-logic/global-data-collector'; @@ -154,7 +155,7 @@ type WriteCount = number; /** * The dhat convertor converts to the processed profile format, rather than to the Gecko - * format, as it needs the UnbalancedNativeAllocationsTable type, which is unavailable + * format, as it needs the RawUnbalancedNativeAllocationsTable type, which is unavailable * in the Gecko format. In the Gecko format, that data comes in the form of markers, which * would be awkard to target. */ @@ -187,7 +188,7 @@ export function attemptToConvertDhat(json: unknown): Profile | null { const frameTable = globalDataCollector.getFrameTable(); const stringTable = globalDataCollector.getStringTable(); - const allocationsTable = getEmptyUnbalancedNativeAllocationsTable(); + const allocationsTable = getEmptyRawUnbalancedNativeAllocationsTable(); // dhat profiles do no support categories. Fill the category and subcategory information // with 0s. @@ -372,13 +373,15 @@ export function attemptToConvertDhat(json: unknown): Profile | null { thread.tid = i; thread.name = name; - thread.nativeAllocations = { - time: allocationsTable.time.slice(), - stack: allocationsTable.stack.slice(), - weight, - weightType: 'bytes', - length: allocationsTable.length, - }; + thread.nativeAllocations = finishRawUnbalancedNativeAllocationsTableBuilder( + { + time: allocationsTable.time.slice(), + stack: allocationsTable.stack.slice(), + weight, + weightType: 'bytes', + length: allocationsTable.length, + } + ); return thread; }); diff --git a/src/profile-logic/import/flame-graph.ts b/src/profile-logic/import/flame-graph.ts index b468d4d008..6a7e4a1fff 100644 --- a/src/profile-logic/import/flame-graph.ts +++ b/src/profile-logic/import/flame-graph.ts @@ -11,8 +11,10 @@ import type { Profile, } from 'firefox-profiler/types/profile'; import { + finishRawSamplesTableBuilder, getEmptyProfile, getEmptyThread, + getRawSamplesTableBuilderWithEventDelay, } from 'firefox-profiler/profile-logic/data-structures'; import { GlobalDataCollector } from 'firefox-profiler/profile-logic/global-data-collector'; import { ensureExists } from 'firefox-profiler/utils/types'; @@ -61,7 +63,7 @@ export function convertFlameGraphProfile(profileText: string): Profile { const frameTable = globalDataCollector.getFrameTable(); const stackTable = globalDataCollector.getStackTableBuilder(); - const { samples } = thread; + const samples = getRawSamplesTableBuilderWithEventDelay(); // Maps to deduplicate stacks, frames, and functions. const stackMap = new Map(); @@ -170,6 +172,7 @@ export function convertFlameGraphProfile(profileText: string): Profile { } // Finalize the profile. + thread.samples = finishRawSamplesTableBuilder(samples); profile.threads.push(thread); const { shared } = globalDataCollector.finish(); profile.shared = shared; diff --git a/src/profile-logic/import/simpleperf.ts b/src/profile-logic/import/simpleperf.ts index 83c38d8929..75fce1f0d9 100644 --- a/src/profile-logic/import/simpleperf.ts +++ b/src/profile-logic/import/simpleperf.ts @@ -5,7 +5,7 @@ import type { Milliseconds } from 'firefox-profiler/types/units'; import type { CategoryList, CategoryColor, - FrameTable, + RawFrameTable, FuncTable, IndexIntoCategoryList, IndexIntoFrameTable, @@ -14,7 +14,6 @@ import type { IndexIntoStackTable, ProfileMeta, ResourceTable, - RawSamplesTable, Profile, RawProfileSharedData, RawThread, @@ -23,11 +22,15 @@ import type { import { getEmptyFuncTable, getEmptyResourceTable, - getEmptyFrameTable, + getRawFrameTableBuilder, getRawStackTableBuilder, + finishRawFrameTableBuilder, + finishRawSamplesTableBuilder, finishRawStackTableBuilder, + type RawFrameTableBuilder, type RawStackTableBuilder, - getEmptySamplesTable, + getRawSamplesTableBuilder, + type RawSamplesTableBuilder, getEmptyRawMarkerTable, getEmptyNativeSymbolTable, getEmptySourceTable, @@ -150,15 +153,15 @@ class FirefoxFuncTable { class FirefoxFrameTable { strings: StringTable; - frameTable: FrameTable = getEmptyFrameTable(); + frameTable: RawFrameTableBuilder = getRawFrameTableBuilder(); frameMap: Map = new Map(); constructor(strings: StringTable) { this.strings = strings; } - toJson(): FrameTable { - return this.frameTable; + toJson(): RawFrameTable { + return finishRawFrameTableBuilder(this.frameTable); } findOrAddFrame( @@ -252,7 +255,7 @@ class FirefoxThread { strings: StringTable; - sampleTable: RawSamplesTable = getEmptySamplesTable(); + sampleTable: RawSamplesTableBuilder = getRawSamplesTableBuilder(); stackTable: FirefoxSampleTable; frameTable: FirefoxFrameTable; @@ -287,7 +290,7 @@ class FirefoxThread { isMainThread: this.isMainThread, pid: this.pid.toString(), tid: this.tid, - samples: this.sampleTable, + samples: finishRawSamplesTableBuilder(this.sampleTable), markers: getEmptyRawMarkerTable(), }; } diff --git a/src/profile-logic/insert-stack-labels.ts b/src/profile-logic/insert-stack-labels.ts index 5d281bf46a..e614569e82 100644 --- a/src/profile-logic/insert-stack-labels.ts +++ b/src/profile-logic/insert-stack-labels.ts @@ -10,7 +10,8 @@ import type { Category, } from '../types/profile'; import { - shallowCloneFrameTable, + finishRawFrameTableBuilder, + getRawFrameTableBuilderWithExistingContents, shallowCloneFuncTable, } from 'firefox-profiler/profile-logic/data-structures'; import { StringTable } from 'firefox-profiler/utils/string-table'; @@ -105,7 +106,7 @@ export function insertStackLabels( sources, stringArray, } = profile.shared; - const frameTable = shallowCloneFrameTable(oldFrameTable); + const frameTable = getRawFrameTableBuilderWithExistingContents(oldFrameTable); const funcTable = shallowCloneFuncTable(oldFuncTable); const stringTable = StringTable.withBackingArray(stringArray); @@ -274,7 +275,12 @@ export function insertStackLabels( length: newStackCount, }; - const newShared = { ...profile.shared, stackTable, frameTable, funcTable }; + const newShared = { + ...profile.shared, + stackTable, + frameTable: finishRawFrameTableBuilder(frameTable), + funcTable, + }; const newThreads = updateRawThreadStacks(profile.threads, (oldStack) => oldStack !== null ? oldStackToNewStackPlusOne[oldStack] - 1 : null ); diff --git a/src/profile-logic/js-tracer.ts b/src/profile-logic/js-tracer.ts index e4664aee95..92ef451f82 100644 --- a/src/profile-logic/js-tracer.ts +++ b/src/profile-logic/js-tracer.ts @@ -2,10 +2,14 @@ * 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/. */ import { - getEmptySamplesTableWithEventDelay, + getRawSamplesTableBuilderWithEventDelay, getEmptyRawMarkerTable, + finishRawFrameTableBuilder, + finishRawSamplesTableBuilder, finishRawStackTableBuilder, getRawStackTableBuilderWithExistingContents, + getRawFrameTableBuilderWithExistingContents, + type RawSamplesTableBuilder, } from './data-structures'; import { StringTable } from '../utils/string-table'; import { ensureExists } from '../utils/types'; @@ -501,8 +505,8 @@ export function convertJsTracerToThreadWithoutSamples( thread: RawThread; stackMap: Map; } { - const samples: RawSamplesTable = { - ...getEmptySamplesTableWithEventDelay(), + const samples: RawSamplesTableBuilder = { + ...getRawSamplesTableBuilderWithEventDelay(), weight: [], weightType: 'tracing-ms', }; @@ -514,7 +518,10 @@ export function convertJsTracerToThreadWithoutSamples( samples, }; - const { funcTable, frameTable } = shared; + const { funcTable } = shared; + const frameTable = getRawFrameTableBuilderWithExistingContents( + shared.frameTable + ); const stackTable = getRawStackTableBuilderWithExistingContents( shared.stackTable ); @@ -625,8 +632,10 @@ export function convertJsTracerToThreadWithoutSamples( unmatchedEventEnds[unmatchedIndex] = end; } - // Write the augmented stackTable back to the shared data. + // Write the augmented stackTable and frameTable back to the shared data. shared.stackTable = finishRawStackTableBuilder(stackTable); + shared.frameTable = finishRawFrameTableBuilder(frameTable); + thread.samples = finishRawSamplesTableBuilder(samples); return { thread, stackMap }; } @@ -798,7 +807,7 @@ export function getSelfTimeSamplesFromJsTracer( const isNearlyEqual = (a: number, b: number) => Math.abs(a - b) < epsilon; // Each event type will have it's own timing information, later collapse these into // a single array. - const samples = getEmptySamplesTableWithEventDelay(); + const samples = getRawSamplesTableBuilderWithEventDelay(); const sampleWeights: number[] = []; samples.weight = sampleWeights; @@ -1003,5 +1012,5 @@ export function getSelfTimeSamplesFromJsTracer( ); } - return samples; + return finishRawSamplesTableBuilder(samples); } diff --git a/src/profile-logic/merge-compare.ts b/src/profile-logic/merge-compare.ts index 3e6f600dcf..d4173e7179 100644 --- a/src/profile-logic/merge-compare.ts +++ b/src/profile-logic/merge-compare.ts @@ -11,12 +11,14 @@ import { getEmptyProfile, getEmptyResourceTable, getEmptyNativeSymbolTable, - getEmptyFrameTable, + finishRawFrameTableBuilder, + finishRawSamplesTableBuilder, + getRawFrameTableBuilder, getEmptyFuncTable, getRawStackTableBuilder, finishRawStackTableBuilder, getEmptyRawMarkerTable, - getEmptySamplesTableWithEventDelay, + getRawSamplesTableBuilderWithEventDelay, shallowCloneRawMarkerTable, getEmptySourceTable, } from './data-structures'; @@ -51,7 +53,7 @@ import type { IndexIntoSourceTable, IndexIntoSourceLocationTable, FuncTable, - FrameTable, + RawFrameTable, Lib, NativeSymbolTable, ResourceTable, @@ -1057,9 +1059,9 @@ function mergeFrameTables( translationMapsForNativeSymbols: TranslationMapForNativeSymbols[], translationMapsForOriginalLocation: TranslationMapForOriginalLocation[], translationMapsForCategories: TranslationMapForCategories[] -): { frameTable: FrameTable; translationMaps: TranslationMapForFrames[] } { +): { frameTable: RawFrameTable; translationMaps: TranslationMapForFrames[] } { const translationMaps: TranslationMapForFrames[] = []; - const newFrameTable = getEmptyFrameTable(); + const newFrameTable = getRawFrameTableBuilder(); profiles.forEach((profile, profileIndex) => { const { frameTable } = profile.shared; @@ -1108,7 +1110,10 @@ function mergeFrameTables( translationMaps.push(oldFrameToNewFramePlusOne); }); - return { frameTable: newFrameTable, translationMaps }; + return { + frameTable: finishRawFrameTableBuilder(newFrameTable), + translationMaps, + }; } /** @@ -1184,7 +1189,7 @@ function combineSamplesDiffing( const newWeight: number[] = []; const newThreadId: Tid[] = []; const newSamples = { - ...getEmptySamplesTableWithEventDelay(), + ...getRawSamplesTableBuilderWithEventDelay(), weight: newWeight, threadId: newThreadId, }; @@ -1237,7 +1242,7 @@ function combineSamplesDiffing( } } - return newSamples; + return finishRawSamplesTableBuilder(newSamples); } type ThreadAndWeightMultiplier = { @@ -1352,9 +1357,8 @@ function combineSamplesForMerging(threads: RawThread[]): RawSamplesTable { const samplesPerThread: RawSamplesTable[] = threads.map( (thread) => thread.samples ); - const sampleTimesPerThread: Milliseconds[][] = samplesPerThread.map( - computeTimeColumnForRawSamplesTable - ); + const sampleTimesPerThread: Float64Array[] = + samplesPerThread.map(computeTimeColumnForRawSamplesTable); // This is the array that holds the latest processed sample index for each // thread's samplesTable. const nextSampleIndexPerThread: number[] = Array( @@ -1365,7 +1369,7 @@ function combineSamplesForMerging(threads: RawThread[]): RawSamplesTable { const newThreadId: Tid[] = []; // Creating a new empty samples table to fill. const newSamples = { - ...getEmptySamplesTableWithEventDelay(), + ...getRawSamplesTableBuilderWithEventDelay(), threadId: newThreadId, }; @@ -1451,9 +1455,12 @@ function combineSamplesForMerging(threads: RawThread[]): RawSamplesTable { } if (newThreadCPUDelta !== undefined) { - return { ...newSamples, threadCPUDelta: newThreadCPUDelta }; + return finishRawSamplesTableBuilder({ + ...newSamples, + threadCPUDelta: newThreadCPUDelta, + }); } - return newSamples; + return finishRawSamplesTableBuilder(newSamples); } /** diff --git a/src/profile-logic/process-profile.ts b/src/profile-logic/process-profile.ts index 2f38fcb4a8..3e5278f474 100644 --- a/src/profile-logic/process-profile.ts +++ b/src/profile-logic/process-profile.ts @@ -12,10 +12,14 @@ import { attemptToConvertDhat } from './import/dhat'; import { GlobalDataCollector } from './global-data-collector'; import { AddressLocator } from './address-locator'; import { + finishRawBalancedNativeAllocationsTableBuilder, + finishRawJsAllocationsTableBuilder, + finishRawUnbalancedNativeAllocationsTableBuilder, getEmptyExtensions, getEmptyRawMarkerTable, - getEmptyJsAllocationsTable, - getEmptyUnbalancedNativeAllocationsTable, + getEmptyRawJsAllocationsTable, + getEmptyRawUnbalancedNativeAllocationsTable, + type RawFrameTableBuilder, type RawStackTableBuilder, } from './data-structures'; import { immutableUpdate, ensureExists } from '../utils/types'; @@ -52,7 +56,6 @@ import type { RawThread, RawCounter, ExtensionTable, - FrameTable, RawCounterSamplesTable, RawSamplesTable, RawMarkerTable, @@ -61,9 +64,9 @@ import type { IndexIntoFuncTable, IndexIntoStringTable, JsTracerTable, - JsAllocationsTable, + RawJsAllocationsTable, ProfilerOverhead, - NativeAllocationsTable, + RawNativeAllocationsTable, Milliseconds, Microseconds, Address, @@ -521,7 +524,7 @@ function _extractUnknownFunctionType( */ function _processFrameTable( geckoFrameStruct: GeckoFrameStruct, - sharedFrameTable: FrameTable, + sharedFrameTable: RawFrameTableBuilder, frameFuncs: IndexIntoFuncTable[], frameAddresses: (Address | null)[] ): IndexIntoFrameTable { @@ -631,8 +634,8 @@ function _convertPayloadStackToIndex( * Process the markers. * Convert stacks to causes. * Process GC markers. - * Extract JS allocations into the JsAllocationsTable. - * Extract Native allocations into the NativeAllocationsTable. + * Extract JS allocations into the RawJsAllocationsTable. + * Extract Native allocations into the RawNativeAllocationsTable. */ function _processMarkers( geckoMarkers: GeckoMarkerStruct, @@ -642,13 +645,13 @@ function _processMarkers( stackIndexOffset: IndexIntoStackTable ): { markers: RawMarkerTable; - jsAllocations: JsAllocationsTable | null; - nativeAllocations: NativeAllocationsTable | null; + jsAllocations: RawJsAllocationsTable | null; + nativeAllocations: RawNativeAllocationsTable | null; } { const markers = getEmptyRawMarkerTable(); - const jsAllocations = getEmptyJsAllocationsTable(); + const jsAllocations = getEmptyRawJsAllocationsTable(); const inProgressNativeAllocations = - getEmptyUnbalancedNativeAllocationsTable(); + getEmptyRawUnbalancedNativeAllocationsTable(); const memoryAddress: number[] = []; const threadId: number[] = []; @@ -756,29 +759,24 @@ function _processMarkers( nativeAllocations = null; } else if (hasMemoryAddresses) { // This is the newer native allocations with memory addresses. - nativeAllocations = { - time: inProgressNativeAllocations.time, - weight: inProgressNativeAllocations.weight, - weightType: inProgressNativeAllocations.weightType, - stack: inProgressNativeAllocations.stack, + nativeAllocations = finishRawBalancedNativeAllocationsTableBuilder({ + ...inProgressNativeAllocations, memoryAddress, threadId, - length: inProgressNativeAllocations.length, - }; + }); } else { // There is the older native allocations, without memory addresses. - nativeAllocations = { - time: inProgressNativeAllocations.time, - weight: inProgressNativeAllocations.weight, - weightType: inProgressNativeAllocations.weightType, - stack: inProgressNativeAllocations.stack, - length: inProgressNativeAllocations.length, - }; + nativeAllocations = finishRawUnbalancedNativeAllocationsTableBuilder( + inProgressNativeAllocations + ); } return { markers: markers, - jsAllocations: jsAllocations.length === 0 ? null : jsAllocations, + jsAllocations: + jsAllocations.length === 0 + ? null + : finishRawJsAllocationsTableBuilder(jsAllocations), nativeAllocations, }; } @@ -1471,10 +1469,9 @@ function _processThread( * has its own timebase, and we don't want to keep converting timestamps when * we deal with the integrated profile. */ -export function adjustTableTimestamps( - table: Table, - delta: Milliseconds -): Table { +export function adjustTableTimestamps< + Table extends { time: Milliseconds[] | Float64Array }, +>(table: Table, delta: Milliseconds): Table { return { ...table, time: table.time.map((time) => time + delta), @@ -1482,7 +1479,7 @@ export function adjustTableTimestamps
( } export function adjustTableTimeDeltas< - Table extends { timeDeltas?: Milliseconds[] }, + Table extends { timeDeltas?: Milliseconds[] | Float64Array }, >(table: Table, delta: Milliseconds): Table { const { timeDeltas } = table; if (timeDeltas === undefined) { diff --git a/src/profile-logic/processed-profile-versioning.ts b/src/profile-logic/processed-profile-versioning.ts index 059fde27e1..ad89075c47 100644 --- a/src/profile-logic/processed-profile-versioning.ts +++ b/src/profile-logic/processed-profile-versioning.ts @@ -3276,6 +3276,18 @@ const _upgraders: { stackTable.prefixOffset = prefixOffset; delete stackTable.prefix; }, + [67]: (_profile: any) => { + // Various raw columns can now optionally be stored as typed arrays: + // - `thread.samples.time` / `timeDeltas` (`Float64Array`) + // - `counter.samples.time` / `timeDeltas` (`Float64Array`) + // - `thread.jsAllocations.time` (`Float64Array`) + // - `thread.nativeAllocations.time` (`Float64Array`) + // - `profile.shared.frameTable.func` (`Int32Array`) + // - `profile.shared.frameTable.address` (`Int32Array`, `-1` sentinel) + // - `profile.shared.frameTable.inlineDepth` (`Uint8Array`) + // Regular JS / JSON arrays are still accepted. All valid v66 profiles + // are valid v67 profiles, so no upgrader is needed. + }, // If you add a new upgrader here, please document the change in // `docs-developer/CHANGELOG-formats.md`. }; diff --git a/src/profile-logic/profile-compacting.ts b/src/profile-logic/profile-compacting.ts index 3704452a0c..9adb8404a7 100644 --- a/src/profile-logic/profile-compacting.ts +++ b/src/profile-logic/profile-compacting.ts @@ -12,7 +12,7 @@ import type { RawMarkerTable, IndexIntoStackTable, RawStackTable, - FrameTable, + RawFrameTable, FuncTable, ResourceTable, NativeSymbolTable, @@ -61,7 +61,10 @@ type ColumnDescription = null extends ( | { type: 'NO_REF' }; type TableDescription = { - [K in keyof T as T[K] extends Array | Int32Array + [K in keyof T as T[K] extends + | Array + | Int32Array + | Uint8Array ? K : never]: ColumnDescription; }; @@ -159,12 +162,12 @@ export function computeCompactedProfile( frame: ColDesc.indexRefInt32(tcs.frameTable), prefixOffset: ColDesc.selfPrefixOffset(), }; - const frameTableDesc: TableDescription = { + const frameTableDesc: TableDescription = { address: ColDesc.noRef(), inlineDepth: ColDesc.noRef(), category: ColDesc.noRef(), subcategory: ColDesc.noRef(), - func: ColDesc.indexRef(tcs.funcTable), + func: ColDesc.indexRefInt32(tcs.funcTable), nativeSymbol: ColDesc.indexRefOrNull(tcs.nativeSymbols), innerWindowID: ColDesc.noRef(), line: ColDesc.noRef(), diff --git a/src/profile-logic/profile-data.ts b/src/profile-logic/profile-data.ts index 865efbd41f..8c5356d17d 100644 --- a/src/profile-logic/profile-data.ts +++ b/src/profile-logic/profile-data.ts @@ -7,9 +7,10 @@ import MixedTupleMap from 'mixedtuplemap'; import { oneLine } from 'common-tags'; import { getRawStackTableBuilder, + finishRawFrameTableBuilder, finishRawStackTableBuilder, getEmptyCallNodeTable, - shallowCloneFrameTable, + getRawFrameTableBuilderWithExistingContents, shallowCloneFuncTable, } from './data-structures'; import { @@ -54,6 +55,7 @@ import type { RawStackTable, SampleUnits, StackTable, + RawFrameTable, FrameTable, FuncTable, NativeSymbolTable, @@ -73,6 +75,9 @@ import type { CounterIndex, RawCounterSamplesTable, CounterSamplesTable, + RawJsAllocationsTable, + JsAllocationsTable, + RawNativeAllocationsTable, NativeAllocationsTable, InnerWindowID, BalancedNativeAllocationsTable, @@ -1936,9 +1941,12 @@ function _computeStackMatchesFromFuncMatches( export function computeTimeColumnForRawSamplesTable( samples: RawSamplesTable | RawCounterSamplesTable -): number[] { +): Float64Array { const { time, timeDeltas } = samples; - return time ?? numberSeriesFromDeltas(ensureExists(timeDeltas)); + if (time !== undefined) { + return time instanceof Float64Array ? time : new Float64Array(time); + } + return numberSeriesFromDeltas(ensureExists(timeDeltas)); } export function computeSampleCategoriesAndSubcategories( @@ -2011,7 +2019,10 @@ export function hasUsefulSamples( * This function takes both a SamplesTable and can be used on CounterSamplesTable. */ export function getSampleIndexRangeForSelection( - times: { time: Milliseconds[]; length: number }, + times: { + time: Milliseconds[] | Float64Array; + length: number; + }, rangeStart: number, rangeEnd: number ): [IndexIntoSamplesTable, IndexIntoSamplesTable] { @@ -2019,7 +2030,7 @@ export function getSampleIndexRangeForSelection( } export function getIndexRangeForSelection( - times: Milliseconds[], + times: Milliseconds[] | Float64Array, rangeStart: number, rangeEnd: number ): [IndexIntoSamplesTable, IndexIntoSamplesTable] { @@ -2034,7 +2045,10 @@ export function getIndexRangeForSelection( * sure that some charts will not be cut off at the edges when zoomed in to a range. */ export function getInclusiveSampleIndexRangeForSelection( - table: { time: Milliseconds[]; length: number }, + table: { + time: Milliseconds[] | Float64Array; + length: number; + }, rangeStart: number, rangeEnd: number ): [IndexIntoSamplesTable, IndexIntoSamplesTable] { @@ -2042,7 +2056,7 @@ export function getInclusiveSampleIndexRangeForSelection( } export function getInclusiveIndexRangeForSelection( - times: Milliseconds[], + times: Milliseconds[] | Float64Array, rangeStart: number, rangeEnd: number ): [IndexIntoSamplesTable, IndexIntoSamplesTable] { @@ -2776,6 +2790,48 @@ export function computeSamplesTableFromRawSamplesTable( }; } +export function computeJsAllocationsTableFromRawJsAllocationsTable( + raw: RawJsAllocationsTable +): JsAllocationsTable { + return { + time: Float64Array.from(raw.time), + className: raw.className, + typeName: raw.typeName, + coarseType: raw.coarseType, + weight: raw.weight, + weightType: raw.weightType, + inNursery: raw.inNursery, + stack: raw.stack, + length: raw.length, + }; +} + +export function computeNativeAllocationsTableFromRawNativeAllocationsTable( + raw: RawNativeAllocationsTable +): NativeAllocationsTable { + const time = Float64Array.from(raw.time); + if ('memoryAddress' in raw) { + return { + time, + weight: raw.weight, + weightType: raw.weightType, + stack: raw.stack, + argumentValues: raw.argumentValues, + memoryAddress: raw.memoryAddress, + threadId: raw.threadId, + length: raw.length, + }; + } + return { + time, + weight: raw.weight, + weightType: raw.weightType, + stack: raw.stack, + argumentValues: raw.argumentValues, + length: raw.length, + }; +} + /** * Create the derived Thread. */ @@ -2790,7 +2846,9 @@ export function createThreadFromDerivedTables( stringTable: StringTable, sources: SourceTable, tracedValuesBuffer: ArrayBuffer | undefined, - sourceLocationTable: SourceLocationTable + sourceLocationTable: SourceLocationTable, + jsAllocations: JsAllocationsTable | undefined, + nativeAllocations: NativeAllocationsTable | undefined ): Thread { const { processType, @@ -2807,8 +2865,6 @@ export function createThreadFromDerivedTables( isJsTracer, pid, tid, - jsAllocations, - nativeAllocations, markers, jsTracer, isPrivateBrowsing, @@ -2897,11 +2953,11 @@ export function updateThreadStacksByGeneratingNewStackColumns( newStackTable: StackTable, computeMappedStackColumn: ( oldStack: Array, - sampleTime: Array + sampleTime: Float64Array ) => Array, computeMappedSyncBacktraceStackColumn: ( oldStack: Array, - sampleTime: Array + sampleTime: Float64Array ) => Array, computeMappedMarkerDataColumn: ( markerData: Array @@ -4310,7 +4366,7 @@ export function nudgeReturnAddresses(profile: Profile): Profile { // Create the new frame table. // Frames that were observed both from the instruction pointer and from // stack walking have to be duplicated. - const newFrameTable = shallowCloneFrameTable(frameTable); + const newFrameTable = getRawFrameTableBuilderWithExistingContents(frameTable); // Iterate over all *return address* frames, i.e. all frames that were obtained // by stack walking. for (const [frame, address] of returnAddressFrames) { @@ -4393,7 +4449,7 @@ export function nudgeReturnAddresses(profile: Profile): Profile { const newShared: RawProfileSharedData = { ...profile.shared, - frameTable: newFrameTable, + frameTable: finishRawFrameTableBuilder(newFrameTable), stackTable: finishRawStackTableBuilder(newStackTable), }; @@ -4724,9 +4780,39 @@ export function computeTabToThreadIndexesMap( return tabToThreadIndexesMap; } +export function computeFrameTableFromRawFrameTable( + rawFrameTable: RawFrameTable +): FrameTable { + const address = + rawFrameTable.address instanceof Int32Array + ? rawFrameTable.address + : new Int32Array(rawFrameTable.address); + const inlineDepth = + rawFrameTable.inlineDepth instanceof Uint8Array + ? rawFrameTable.inlineDepth + : new Uint8Array(rawFrameTable.inlineDepth); + const func = + rawFrameTable.func instanceof Int32Array + ? rawFrameTable.func + : new Int32Array(rawFrameTable.func); + return { + address, + inlineDepth, + category: rawFrameTable.category, + subcategory: rawFrameTable.subcategory, + func, + nativeSymbol: rawFrameTable.nativeSymbol, + innerWindowID: rawFrameTable.innerWindowID, + line: rawFrameTable.line, + column: rawFrameTable.column, + originalLocation: rawFrameTable.originalLocation, + length: rawFrameTable.length, + }; +} + export function computeStackTableFromRawStackTable( rawStackTable: RawStackTable, - frameTable: FrameTable, + frameTable: RawFrameTable, categories: CategoryList | undefined, defaultCategory: IndexIntoCategoryList ): StackTable { diff --git a/src/profile-logic/source-map-symbolication.ts b/src/profile-logic/source-map-symbolication.ts index f4d5ebe4c6..2c013c5323 100644 --- a/src/profile-logic/source-map-symbolication.ts +++ b/src/profile-logic/source-map-symbolication.ts @@ -67,8 +67,9 @@ */ import { + finishRawFrameTableBuilder, shallowCloneFuncTable, - shallowCloneFrameTable, + getRawFrameTableBuilderWithExistingContents, shallowCloneSourceLocationTable, } from './data-structures'; import { StringTable } from '../utils/string-table'; @@ -92,7 +93,7 @@ import type { IndexIntoFuncTable, IndexIntoFrameTable, FuncTable, - FrameTable, + RawFrameTable, RawProfileSharedData, SourceLocationTable, SourceTable, @@ -132,7 +133,7 @@ type ParsedSource = { // main thread in applySourceMapSymbolicationResponse, which builds new // tables from the current shared state at apply time. export type SourceMapSymbolicationInput = { - frameTable: FrameTable; + frameTable: RawFrameTable; funcTable: FuncTable; sourceLocationTable: SourceLocationTable; sources: SourceTable; @@ -185,7 +186,7 @@ export function symbolicateWithSourceMaps( * candidates for line/column remapping. */ function _identifyToSymbolicate( - frameTable: FrameTable, + frameTable: RawFrameTable, funcTable: FuncTable, sources: SourceTable ): { @@ -949,7 +950,7 @@ export function applySourceMapSymbolicationResponse( response: SourceMapSymbolicationResponse ): { newFuncTable: FuncTable; - newFrameTable: FrameTable; + newFrameTable: RawFrameTable; newSourceLocationTable: SourceLocationTable; newSources: SourceTable; newStringArray: string[]; @@ -958,7 +959,7 @@ export function applySourceMapSymbolicationResponse( shared; const newFuncTable = shallowCloneFuncTable(funcTable); - const newFrameTable = shallowCloneFrameTable(frameTable); + const newFrameTable = getRawFrameTableBuilderWithExistingContents(frameTable); const newSourceLocationTable = shallowCloneSourceLocationTable(sourceLocationTable); const newSources = _shallowCloneSourceTable(sources); @@ -1042,7 +1043,7 @@ export function applySourceMapSymbolicationResponse( return { newFuncTable, - newFrameTable, + newFrameTable: finishRawFrameTableBuilder(newFrameTable), newSourceLocationTable, newSources, newStringArray, diff --git a/src/profile-logic/symbolication.ts b/src/profile-logic/symbolication.ts index 52a53d7c1a..a501c112b2 100644 --- a/src/profile-logic/symbolication.ts +++ b/src/profile-logic/symbolication.ts @@ -3,10 +3,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { getRawStackTableBuilder, + finishRawFrameTableBuilder, finishRawStackTableBuilder, shallowCloneFuncTable, shallowCloneNativeSymbolTable, - shallowCloneFrameTable, + getRawFrameTableBuilderWithExistingContents, } from './data-structures'; import { SymbolsNotFoundError } from './errors'; @@ -716,7 +717,7 @@ function _partiallyApplySymbolicationStep( // Integrate the new native symbol column into the frame table and make a // copy so that we can add new frames below. - const frameTable = shallowCloneFrameTable({ + const frameTable = getRawFrameTableBuilderWithExistingContents({ ...oldFrameTable, nativeSymbol: newFrameTableNativeSymbolsColumn, }); @@ -892,7 +893,7 @@ function _partiallyApplySymbolicationStep( const newShared = { ...shared, - frameTable, + frameTable: finishRawFrameTableBuilder(frameTable), funcTable, nativeSymbols, }; diff --git a/src/profile-logic/transforms.ts b/src/profile-logic/transforms.ts index 0dd6f2b7ff..57a96ed9d6 100644 --- a/src/profile-logic/transforms.ts +++ b/src/profile-logic/transforms.ts @@ -45,7 +45,6 @@ import type { MarkerIndex, MarkerSchemaByName, CategoryList, - Milliseconds, ProfileIndexTranslationMaps, } from 'firefox-profiler/types'; import type { CallNodeInfo } from 'firefox-profiler/profile-logic/call-node-info'; @@ -1876,7 +1875,7 @@ export function filterSamples( function computeFilteredStackColumn( originalStackColumn: Array, - timeColumn: Milliseconds[] + timeColumn: Float64Array ): Array { const newStackColumn = originalStackColumn.slice(); let sampleIndex = 0; diff --git a/src/profile-query/cpu-activity.ts b/src/profile-query/cpu-activity.ts index 79351ac47b..d1f6b0666d 100644 --- a/src/profile-query/cpu-activity.ts +++ b/src/profile-query/cpu-activity.ts @@ -69,7 +69,7 @@ function collectSliceSubtree( childrenStartPerParent: Array, interestingSliceIndexes: Set, nestingDepth: number, - time: number[], + time: Float64Array, result: CpuActivityEntry[], tsManager: TimestampManager ) { diff --git a/src/selectors/per-thread/thread.tsx b/src/selectors/per-thread/thread.tsx index 54966a55c7..f83961bbbe 100644 --- a/src/selectors/per-thread/thread.tsx +++ b/src/selectors/per-thread/thread.tsx @@ -27,7 +27,9 @@ import type { JsTracerTable, RawSamplesTable, SamplesTable, + RawNativeAllocationsTable, NativeAllocationsTable, + RawJsAllocationsTable, JsAllocationsTable, SamplesLikeTable, Selector, @@ -143,11 +145,25 @@ export function getBasicThreadSelectorsPerThread( ) : null ); - const getNativeAllocations: Selector = ( + const getRawNativeAllocations: Selector = ( state ) => getRawThread(state).nativeAllocations; - const getJsAllocations: Selector = (state) => + const getRawJsAllocations: Selector = (state) => getRawThread(state).jsAllocations; + const getNativeAllocations: Selector = + createSelector(getRawNativeAllocations, (raw) => + raw + ? ProfileData.computeNativeAllocationsTableFromRawNativeAllocationsTable( + raw + ) + : undefined + ); + const getJsAllocations: Selector = + createSelector(getRawJsAllocations, (raw) => + raw + ? ProfileData.computeJsAllocationsTableFromRawJsAllocationsTable(raw) + : undefined + ); const getThreadRange: Selector = (state) => // This function is already memoized in profile-data.js, so we don't need to // memoize it here with `createSelector`. @@ -183,8 +199,7 @@ export function getBasicThreadSelectorsPerThread( getRawThread, getSamplesTable, ProfileSelectors.getStackTable, - (state: State) => - ProfileSelectors.getRawProfileSharedData(state).frameTable, + ProfileSelectors.getFrameTable, ProfileSelectors.getFunctionsReservedFuncTable, (state: State) => ProfileSelectors.getRawProfileSharedData(state).nativeSymbols, @@ -195,6 +210,8 @@ export function getBasicThreadSelectorsPerThread( getTracedValuesBuffer, (state: State) => ProfileSelectors.getRawProfileSharedData(state).sourceLocationTable, + getJsAllocations, + getNativeAllocations, ProfileData.createThreadFromDerivedTables ); diff --git a/src/selectors/profile.ts b/src/selectors/profile.ts index 896ca26b27..9a2df2e36a 100644 --- a/src/selectors/profile.ts +++ b/src/selectors/profile.ts @@ -20,6 +20,7 @@ import { computeInnerWindowIDToTabMap, computeTabToThreadIndexesMap, computeStackTableFromRawStackTable, + computeFrameTableFromRawFrameTable, reserveFunctionsForCollapsedResources, computeSamplesTableFromRawSamplesTable, } from '../profile-logic/profile-data'; @@ -39,6 +40,7 @@ import type { Profile, RawProfileSharedData, StackTable, + FrameTable, CategoryList, IndexIntoCategoryList, RawThread, @@ -283,6 +285,11 @@ export const getStackTable: Selector = createSelector( computeStackTableFromRawStackTable ); +export const getFrameTable: Selector = createSelector( + (state: State) => getRawProfileSharedData(state).frameTable, + computeFrameTableFromRawFrameTable +); + export const getFuncTableWithReservedFunctions: Selector = createSelector( (state: State) => getRawProfileSharedData(state).funcTable, diff --git a/src/test/components/EmptyThreadIndicator.test.tsx b/src/test/components/EmptyThreadIndicator.test.tsx index d835738784..ca5b77e044 100644 --- a/src/test/components/EmptyThreadIndicator.test.tsx +++ b/src/test/components/EmptyThreadIndicator.test.tsx @@ -29,7 +29,7 @@ describe('EmptyThreadIndicator', function () { thread.processShutdownTime = 10; thread.registerTime = 3; thread.unregisterTime = 9; - thread.samples.time = [5, 6, 7]; + thread.samples.time = Float64Array.of(5, 6, 7); // Make it really easy to generate the component's props. function propsFromViewportRange(viewport: StartEndRange) { diff --git a/src/test/fixtures/profiles/call-nodes.ts b/src/test/fixtures/profiles/call-nodes.ts index 0ffed2dd52..8692daf1ab 100644 --- a/src/test/fixtures/profiles/call-nodes.ts +++ b/src/test/fixtures/profiles/call-nodes.ts @@ -1,7 +1,7 @@ /* 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/. */ -import type { FuncTable, FrameTable, Profile } from 'firefox-profiler/types'; +import type { FuncTable, RawFrameTable, Profile } from 'firefox-profiler/types'; import { getEmptyThread, @@ -74,7 +74,7 @@ export default function getProfile(): Profile { funcFFrame, ] = frameFuncs.map((_, i) => i); - const frameTable: FrameTable = { + const frameTable: RawFrameTable = { func: frameFuncs.map((stringIndex) => funcTable.name.indexOf(stringIndex)), address: Array(frameFuncs.length).fill(-1), inlineDepth: Array(frameFuncs.length).fill(0), diff --git a/src/test/fixtures/profiles/processed-profile.ts b/src/test/fixtures/profiles/processed-profile.ts index fea127bc5c..6e117bcf97 100644 --- a/src/test/fixtures/profiles/processed-profile.ts +++ b/src/test/fixtures/profiles/processed-profile.ts @@ -5,11 +5,19 @@ import { getEmptyProfile, getEmptyThread, getEmptyJsTracerTable, - getEmptyJsAllocationsTable, - getEmptyUnbalancedNativeAllocationsTable, - getEmptyBalancedNativeAllocationsTable, + getEmptyRawJsAllocationsTable, + getEmptyRawUnbalancedNativeAllocationsTable, + getEmptyRawBalancedNativeAllocationsTable, getRawStackTableBuilderWithExistingContents, + finishRawBalancedNativeAllocationsTableBuilder, + finishRawFrameTableBuilder, + finishRawJsAllocationsTableBuilder, + finishRawSamplesTableBuilder, + finishRawUnbalancedNativeAllocationsTableBuilder, + getRawSamplesTableBuilderFromExisting, finishRawStackTableBuilder, + getRawFrameTableBuilderWithExistingContents, + getRawSamplesTableBuilderWithEventDelay, } from '../../../profile-logic/data-structures'; import { mergeProfilesForDiffing } from '../../../profile-logic/merge-compare'; import { computeReferenceCPUDeltaPerMs } from '../../../profile-logic/cpu'; @@ -209,7 +217,7 @@ export function addMarkersToThreadWithCorrespondingSamples( // control the initial range. Because of that we need to add samples so that // the range includes these markers. Note that when a thread has no sample, // then the markers are used to compute the initial range. - const { samples } = thread; + const samples = getRawSamplesTableBuilderFromExisting(thread.samples); if (samples.length) { const firstMarkerTime = Math.min(...allTimes); const lastMarkerTime = Math.max(...allTimes); @@ -255,6 +263,7 @@ export function addMarkersToThreadWithCorrespondingSamples( samples.length++; } } + thread.samples = finishRawSamplesTableBuilder(samples); } export function getThreadWithMarkers( @@ -876,7 +885,7 @@ function _buildThreadFromTextOnlyStacks( ): RawThread { const thread = getEmptyThread(); - const { samples } = thread; + const samples = getRawSamplesTableBuilderWithEventDelay(); const stringTable = globalDataCollector.getStringTable(); const frameTable = globalDataCollector.getFrameTable(); @@ -1018,6 +1027,8 @@ function _buildThreadFromTextOnlyStacks( samples.time = sampleTimes; } + thread.samples = finishRawSamplesTableBuilder(samples); + return thread; } @@ -1501,13 +1512,13 @@ export function getCounterForThread( pid: thread.pid, mainThreadIndex, samples: { - time: sampleTimes.slice(), + time: Array.from(sampleTimes), // Create some arbitrary (positive integer) values for the number. number: config.hasCountNumber - ? sampleTimes.map((_, i) => Math.floor(50 * Math.sin(i) + 50)) + ? Array.from(sampleTimes, (_, i) => Math.floor(50 * Math.sin(i) + 50)) : undefined, // Create some arbitrary values for the count. - count: sampleTimes.map((_, i) => Math.sin(i)), + count: Array.from(sampleTimes, (_, i) => Math.sin(i)), length: thread.samples.length, }, display: deriveCounterDisplay(category, name), @@ -1522,7 +1533,7 @@ export function getCounterForThreadWithSamples( thread: RawThread, mainThreadIndex: ThreadIndex, samples: { - time?: number[]; + time?: number[] | Float64Array; number?: number[]; count?: number[]; length: number; @@ -1628,9 +1639,8 @@ export function getProfileWithJsAllocations() { I[lib:libI.so] `); - // Now add a JsAllocationsTable. - const jsAllocations = getEmptyJsAllocationsTable(); - profile.threads[0].jsAllocations = jsAllocations; + // Now add a RawJsAllocationsTable. + const jsAllocations = getEmptyRawJsAllocationsTable(); // The stack table is built sequentially, so we can assume that the stack indexes // match the func indexes. @@ -1657,6 +1667,9 @@ export function getProfileWithJsAllocations() { jsAllocations.length++; } + profile.threads[0].jsAllocations = + finishRawJsAllocationsTableBuilder(jsAllocations); + return { profile, funcNamesDict, funcNames }; } @@ -1708,9 +1721,8 @@ export function getProfileWithUnbalancedNativeAllocations() { ` ); - // Now add a NativeAllocationsTable. - const nativeAllocations = getEmptyUnbalancedNativeAllocationsTable(); - profile.threads[0].nativeAllocations = nativeAllocations; + // Now add a RawNativeAllocationsTable. + const nativeAllocations = getEmptyRawUnbalancedNativeAllocationsTable(); // The stack table is built sequentially, so we can assume that the stack indexes // match the func indexes. @@ -1738,6 +1750,9 @@ export function getProfileWithUnbalancedNativeAllocations() { nativeAllocations.length++; } + profile.threads[0].nativeAllocations = + finishRawUnbalancedNativeAllocationsTableBuilder(nativeAllocations); + return { profile, funcNamesDict }; } @@ -1776,10 +1791,9 @@ export function getProfileWithBalancedNativeAllocations() { ` ); - // Now add a NativeAllocationsTable. - const nativeAllocations = getEmptyBalancedNativeAllocationsTable(); + // Now add a RawNativeAllocationsTable. + const nativeAllocations = getEmptyRawBalancedNativeAllocationsTable(); const [thread] = profile.threads; - thread.nativeAllocations = nativeAllocations; const threadId = thread.tid; if (typeof threadId !== 'number') { throw new Error( @@ -1825,6 +1839,9 @@ export function getProfileWithBalancedNativeAllocations() { nativeAllocations.length++; } + thread.nativeAllocations = + finishRawBalancedNativeAllocationsTableBuilder(nativeAllocations); + return { profile, funcNamesDict }; } @@ -2013,7 +2030,7 @@ export function addInnerWindowIdToStacks( callNodesToDupe?: CallNodePath[] ) { const { stackTable, frameTable } = shared; - const { samples } = thread; + const samples = getRawSamplesTableBuilderFromExisting(thread.samples); const usedInnerWindowIDsSet = new Set(); for (const { innerWindowID, callNodes } of listOfOperations) { @@ -2043,30 +2060,38 @@ export function addInnerWindowIdToStacks( const stackTableBuilder = getRawStackTableBuilderWithExistingContents(stackTable); + const frameTableBuilder = + getRawFrameTableBuilderWithExistingContents(frameTable); for (const callNode of callNodesToDupe) { const stackIndex = getStackIndexForCallNodePath(shared, callNode); const foundFrameIndex = stackTable.frame[stackIndex]; // The found one comes from the first tab. - frameTable.innerWindowID[foundFrameIndex] = + frameTableBuilder.innerWindowID[foundFrameIndex] = listOfOperations[0].innerWindowID; // Clone this frame - const newFrameIndex = frameTable.length++; - frameTable.address.push(frameTable.address[foundFrameIndex]); - frameTable.inlineDepth.push(frameTable.inlineDepth[foundFrameIndex]); - frameTable.category.push(frameTable.category[foundFrameIndex]); - frameTable.subcategory.push(frameTable.subcategory[foundFrameIndex]); - frameTable.func.push(frameTable.func[foundFrameIndex]); - frameTable.nativeSymbol.push(frameTable.nativeSymbol[foundFrameIndex]); - frameTable.line.push(frameTable.line[foundFrameIndex]); - frameTable.column.push(frameTable.column[foundFrameIndex]); - frameTable.originalLocation.push( + const newFrameIndex = frameTableBuilder.length++; + frameTableBuilder.address.push(frameTable.address[foundFrameIndex]); + frameTableBuilder.inlineDepth.push( + frameTable.inlineDepth[foundFrameIndex] + ); + frameTableBuilder.category.push(frameTable.category[foundFrameIndex]); + frameTableBuilder.subcategory.push( + frameTable.subcategory[foundFrameIndex] + ); + frameTableBuilder.func.push(frameTable.func[foundFrameIndex]); + frameTableBuilder.nativeSymbol.push( + frameTable.nativeSymbol[foundFrameIndex] + ); + frameTableBuilder.line.push(frameTable.line[foundFrameIndex]); + frameTableBuilder.column.push(frameTable.column[foundFrameIndex]); + frameTableBuilder.originalLocation.push( frameTable.originalLocation[foundFrameIndex] ); // And that one comes from the second tab. - frameTable.innerWindowID.push(listOfOperations[1].innerWindowID); + frameTableBuilder.innerWindowID.push(listOfOperations[1].innerWindowID); // Clone the stack const newStackIndex = stackTableBuilder.length++; @@ -2079,6 +2104,7 @@ export function addInnerWindowIdToStacks( } shared.stackTable = finishRawStackTableBuilder(stackTableBuilder); + shared.frameTable = finishRawFrameTableBuilder(frameTableBuilder); const sampleTimes = ensureExists(samples.time); for (let sampleIndex = samples.length; sampleIndex >= 0; sampleIndex--) { @@ -2112,6 +2138,8 @@ export function addInnerWindowIdToStacks( } } + thread.samples = finishRawSamplesTableBuilder(samples); + if (usedInnerWindowIDsSet.size !== 0) { thread.usedInnerWindowIDs = Array.from(usedInnerWindowIDsSet); } diff --git a/src/test/fixtures/utils.ts b/src/test/fixtures/utils.ts index d91e76e8fa..83c68020cb 100644 --- a/src/test/fixtures/utils.ts +++ b/src/test/fixtures/utils.ts @@ -18,7 +18,10 @@ import { getOriginAnnotationForFunc, createThreadFromDerivedTables, computeStackTableFromRawStackTable, + computeFrameTableFromRawFrameTable, computeSamplesTableFromRawSamplesTable, + computeJsAllocationsTableFromRawJsAllocationsTable, + computeNativeAllocationsTableFromRawNativeAllocationsTable, } from 'firefox-profiler/profile-logic/profile-data'; import { getProfileWithDicts } from './profiles/processed-profile'; import { StringTable } from '../../utils/string-table'; @@ -162,18 +165,31 @@ export function computeThreadFromRawThread( const tracedValuesBuffer = rawThread.tracedValuesBuffer ? base64StringToBytes(rawThread.tracedValuesBuffer) : undefined; + const jsAllocations = rawThread.jsAllocations + ? computeJsAllocationsTableFromRawJsAllocationsTable( + rawThread.jsAllocations + ) + : undefined; + const nativeAllocations = rawThread.nativeAllocations + ? computeNativeAllocationsTableFromRawNativeAllocationsTable( + rawThread.nativeAllocations + ) + : undefined; + const frameTable = computeFrameTableFromRawFrameTable(shared.frameTable); return createThreadFromDerivedTables( rawThread, samples, stackTable, - shared.frameTable, + frameTable, shared.funcTable, shared.nativeSymbols, shared.resourceTable, stringTable, shared.sources, tracedValuesBuffer, - shared.sourceLocationTable + shared.sourceLocationTable, + jsAllocations, + nativeAllocations ); } diff --git a/src/test/integration/profiler-edit/__snapshots__/profiler-edit.test.ts.snap b/src/test/integration/profiler-edit/__snapshots__/profiler-edit.test.ts.snap index d186387a95..ddef611540 100644 --- a/src/test/integration/profiler-edit/__snapshots__/profiler-edit.test.ts.snap +++ b/src/test/integration/profiler-edit/__snapshots__/profiler-edit.test.ts.snap @@ -87,7 +87,7 @@ Object { "markerSchema": Array [], "oscpu": "macOS 14.6.1", "pausedRanges": Array [], - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "a.out", "sampleUnits": Object { @@ -1452,7 +1452,7 @@ Object { "markerSchema": Array [], "oscpu": "macOS 14.6.1", "pausedRanges": Array [], - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "a.out", "sampleUnits": Object { @@ -2817,7 +2817,7 @@ Object { "markerSchema": Array [], "oscpu": "macOS 14.6.1", "pausedRanges": Array [], - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "a.out", "sampleUnits": Object { @@ -4182,7 +4182,7 @@ Object { "markerSchema": Array [], "oscpu": "macOS 14.6.1", "pausedRanges": Array [], - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "a.out", "sampleUnits": Object { diff --git a/src/test/store/__snapshots__/profile-view.test.ts.snap b/src/test/store/__snapshots__/profile-view.test.ts.snap index 0479910d2b..75109d8fbf 100644 --- a/src/test/store/__snapshots__/profile-view.test.ts.snap +++ b/src/test/store/__snapshots__/profile-view.test.ts.snap @@ -423,7 +423,7 @@ Object { "oscpu": "", "physicalCPUs": 0, "platform": "", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Firefox", "sourceURL": "", @@ -443,7 +443,7 @@ Object { ], "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -476,7 +476,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -487,7 +487,7 @@ Object { 7, 8, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -912,6 +912,7 @@ Object { 55, 56, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -1055,7 +1056,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -1265,6 +1267,7 @@ Array [ 55, 56, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -1408,7 +1411,8 @@ Array [ "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -2396,7 +2400,7 @@ CallTree { 100, 100, ], - "time": Array [ + "time": Float64Array [ 4, 5, ], @@ -2410,7 +2414,7 @@ CallTree { "_thread": Object { "eTLD+1": undefined, "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -2443,7 +2447,7 @@ CallTree { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -2454,7 +2458,7 @@ CallTree { 7, 8, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -2684,7 +2688,7 @@ CallTree { 100, 100, ], - "time": Array [ + "time": Float64Array [ 3, 4, 5, @@ -2798,7 +2802,7 @@ exports[`snapshots of selectors/profile matches the last stored run of selectedT Object { "eTLD+1": undefined, "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -2831,7 +2835,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -2842,7 +2846,7 @@ Object { 7, 8, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -3072,7 +3076,7 @@ Object { 100, 100, ], - "time": Array [ + "time": Float64Array [ 3, 4, 5, @@ -3266,7 +3270,7 @@ exports[`snapshots of selectors/profile matches the last stored run of selectedT Object { "eTLD+1": undefined, "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -3299,7 +3303,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -3310,7 +3314,7 @@ Object { 7, 8, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -3530,7 +3534,7 @@ Object { 100, 100, ], - "time": Array [ + "time": Float64Array [ 4, 5, ], @@ -3640,7 +3644,7 @@ exports[`snapshots of selectors/profile matches the last stored run of selectedT Object { "eTLD+1": undefined, "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -3673,7 +3677,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -3684,7 +3688,7 @@ Object { 7, 8, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -3914,7 +3918,7 @@ Object { 100, 100, ], - "time": Array [ + "time": Float64Array [ 3, 4, 5, @@ -4026,7 +4030,7 @@ exports[`snapshots of selectors/profile matches the last stored run of selectedT Object { "eTLD+1": undefined, "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -4059,7 +4063,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -4070,7 +4074,7 @@ Object { 7, 8, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -4300,7 +4304,7 @@ Object { 100, 100, ], - "time": Array [ + "time": Float64Array [ 3, 4, 5, diff --git a/src/test/store/profile-view.test.ts b/src/test/store/profile-view.test.ts index 9fda33ec65..b89362fdd6 100644 --- a/src/test/store/profile-view.test.ts +++ b/src/test/store/profile-view.test.ts @@ -19,9 +19,10 @@ import { getThreadWithMarkers, } from '../fixtures/profiles/processed-profile'; import { + finishRawSamplesTableBuilder, getEmptyThread, getEmptyProfile, - getEmptySamplesTableWithEventDelay, + getRawSamplesTableBuilderWithEventDelay, } from '../../profile-logic/data-structures'; import { withAnalyticsMock } from '../fixtures/mocks/analytics'; import { getProfileWithNiceTracks } from '../fixtures/profiles/tracks'; @@ -53,11 +54,11 @@ import { checkBit } from '../../utils/bitset'; import type { TrackReference, Milliseconds, - RawThread, StartEndRange, Marker, MixedObject, CallNodePath, + RawThread, } from 'firefox-profiler/types'; describe('call node paths on implementation filter change', function () { @@ -3824,7 +3825,7 @@ describe('getProcessedEventDelays', function () { const profile = getEmptyProfile(); // Create event delay values. - const samples = getEmptySamplesTableWithEventDelay(); + const samples = getRawSamplesTableBuilderWithEventDelay(); if (eventDelay) { samples.eventDelay = eventDelay; } else { @@ -3842,7 +3843,9 @@ describe('getProcessedEventDelays', function () { .fill(0) .map((_, i) => i); samples.stack = Array(samples.length).fill(null); - profile.threads.push(getEmptyThread({ samples })); + profile.threads.push( + getEmptyThread({ samples: finishRawSamplesTableBuilder(samples) }) + ); const { dispatch, getState } = storeWithProfile(profile); diff --git a/src/test/store/receive-profile.test.ts b/src/test/store/receive-profile.test.ts index 5de663db0f..afc2309460 100644 --- a/src/test/store/receive-profile.test.ts +++ b/src/test/store/receive-profile.test.ts @@ -1611,7 +1611,6 @@ describe('actions/receive-profile', function () { const expectedThreads = [ expect.objectContaining({ - ...profile1.threads[0], pid: '0 from profile 1', tid: '0 from profile 1', isMainThread: true, diff --git a/src/test/store/useful-tabs.test.ts b/src/test/store/useful-tabs.test.ts index 2e770a2581..0d63df2759 100644 --- a/src/test/store/useful-tabs.test.ts +++ b/src/test/store/useful-tabs.test.ts @@ -13,7 +13,10 @@ import { getMergedProfileFromTextSamples, getProfileWithUnbalancedNativeAllocations, } from '../fixtures/profiles/processed-profile'; -import { getEmptySamplesTableWithEventDelay } from '../../profile-logic/data-structures'; +import { + finishRawSamplesTableBuilder, + getRawSamplesTableBuilderWithEventDelay, +} from '../../profile-logic/data-structures'; describe('getUsefulTabs', function () { it('hides the network chart and JS tracer when no data is in the thread', function () { @@ -79,7 +82,9 @@ describe('getUsefulTabs', function () { it('shows sample related tabs even when there are only allocation samples in the profile', function () { const { profile } = getProfileWithUnbalancedNativeAllocations(); for (const thread of profile.threads) { - thread.samples = getEmptySamplesTableWithEventDelay(); + thread.samples = finishRawSamplesTableBuilder( + getRawSamplesTableBuilderWithEventDelay() + ); } const { getState } = storeWithProfile(profile); expect(selectedThreadSelectors.getUsefulTabs(getState())).toEqual([ diff --git a/src/test/unit/__snapshots__/profile-conversion.test.ts.snap b/src/test/unit/__snapshots__/profile-conversion.test.ts.snap index 713bff2592..5620674b85 100644 --- a/src/test/unit/__snapshots__/profile-conversion.test.ts.snap +++ b/src/test/unit/__snapshots__/profile-conversion.test.ts.snap @@ -591,7 +591,7 @@ Object { "oscpu": undefined, "physicalCPUs": undefined, "platform": undefined, - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "ART Trace (Android)", "sampleUnits": undefined, @@ -613,7 +613,7 @@ Object { "profilingLog": Object {}, "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -8677,7 +8677,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -11365,7 +11365,7 @@ Object { 1493, 1494, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -83833,7 +83833,7 @@ Object { "oscpu": undefined, "physicalCPUs": undefined, "platform": undefined, - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "ART Trace (Android)", "sampleUnits": undefined, @@ -83855,7 +83855,7 @@ Object { "profilingLog": Object {}, "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -100097,7 +100097,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -105511,7 +105511,7 @@ Object { 2531, 2532, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -329278,7 +329278,7 @@ Object { "oscpu": "", "physicalCPUs": 0, "platform": "", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Chrome Trace", "profilingEndTime": 119159778.026, @@ -329293,7 +329293,7 @@ Object { "pages": Array [], "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -329377,7 +329377,7 @@ Object { 297, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -329405,7 +329405,7 @@ Object { 23, 24, ], - "inlineDepth": Array [], + "inlineDepth": Uint8Array [], "innerWindowID": Array [ 0, 0, @@ -333080,7 +333080,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -337250,7 +337251,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -337346,7 +337348,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -337388,7 +337391,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -337454,7 +337458,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -345146,7 +345151,7 @@ Object { 14, 14, ], - "time": Array [ + "time": Float64Array [ 119159290.82000001, 119159291.979, 119159292.559, @@ -346053,6 +346058,7 @@ Object { 119159770.15899245, 119159770.67499243, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -347288,7 +347294,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -351002,7 +351009,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -351044,7 +351052,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -351224,7 +351233,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -351404,7 +351414,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -351584,7 +351595,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -351746,7 +351758,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -359406,7 +359419,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -364122,7 +364136,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -364259,7 +364274,7 @@ Object { "oscpu": "", "physicalCPUs": 0, "platform": "", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Chrome Trace", "profilingEndTime": 119159778.026, @@ -364274,7 +364289,7 @@ Object { "pages": Array [], "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -364358,7 +364373,7 @@ Object { 297, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -364386,7 +364401,7 @@ Object { 23, 24, ], - "inlineDepth": Array [], + "inlineDepth": Uint8Array [], "innerWindowID": Array [ 0, 0, @@ -368061,7 +368076,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -372231,7 +372247,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -372327,7 +372344,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -372369,7 +372387,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -372435,7 +372454,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -380127,7 +380147,7 @@ Object { 14, 14, ], - "time": Array [ + "time": Float64Array [ 119159290.82000001, 119159291.979, 119159292.559, @@ -381034,6 +381054,7 @@ Object { 119159770.15899245, 119159770.67499243, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -382269,7 +382290,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -385983,7 +386005,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -386025,7 +386048,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -386205,7 +386229,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -386385,7 +386410,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -386565,7 +386591,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -386727,7 +386754,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -394387,7 +394415,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -399103,7 +399132,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -399219,7 +399249,7 @@ Object { "oscpu": "", "physicalCPUs": 0, "platform": "", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Chrome Trace", "profilingEndTime": 66155012.423, @@ -399234,7 +399264,7 @@ Object { "pages": Array [], "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -399381,7 +399411,7 @@ Object { 31, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -399430,7 +399460,7 @@ Object { 40, 20, ], - "inlineDepth": Array [], + "inlineDepth": Uint8Array [], "innerWindowID": Array [ 0, 0, @@ -401380,7 +401410,7 @@ Object { 20, 44, ], - "time": Array [ + "time": Float64Array [ 66148721.172, 66148734.519, 66148820.363, @@ -401402,6 +401432,7 @@ Object { 66148973.421000004, 66148976.957, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -401811,7 +401842,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -401927,7 +401959,7 @@ Object { "oscpu": "", "physicalCPUs": 0, "platform": "", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Chrome Trace", "sourceURL": "", @@ -401940,11 +401972,11 @@ Object { "pages": Array [], "shared": Object { "frameTable": Object { - "address": Array [], + "address": Int32Array [], "category": Array [], "column": Array [], - "func": Array [], - "inlineDepth": Array [], + "func": Int32Array [], + "inlineDepth": Uint8Array [], "innerWindowID": Array [], "length": 0, "line": Array [], @@ -402255,7 +402287,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -402303,7 +402336,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -402351,7 +402385,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -402399,7 +402434,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -403137,7 +403173,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -403185,7 +403222,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -403263,7 +403301,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -403335,7 +403374,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -403407,7 +403447,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -403479,7 +403520,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -403545,7 +403587,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -403587,7 +403630,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -403629,7 +403673,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -403670,7 +403715,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -403765,7 +403811,7 @@ Object { "oscpu": "", "physicalCPUs": 0, "platform": "", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Chrome Trace", "profilingEndTime": 355035987.653, @@ -403780,7 +403826,7 @@ Object { "pages": Array [], "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -404278,7 +404324,7 @@ Object { 25, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -404444,7 +404490,7 @@ Object { 115, 116, ], - "inlineDepth": Array [], + "inlineDepth": Uint8Array [], "innerWindowID": Array [ 0, 0, @@ -407523,7 +407569,7 @@ Object { 159, 163, ], - "time": Array [ + "time": Float64Array [ 355035818.698, 355035820.536, 355035821.623, @@ -407675,6 +407721,7 @@ Object { 355035985.6030004, 355035986.7690004, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -407776,7 +407823,7 @@ Object { "oscpu": "", "physicalCPUs": 0, "platform": "", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Chrome Trace", "sourceURL": "", @@ -407789,7 +407836,7 @@ Object { "pages": Array [], "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -408488,7 +408535,7 @@ Object { 7, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -408721,7 +408768,7 @@ Object { 4, 141, ], - "inlineDepth": Array [], + "inlineDepth": Uint8Array [], "innerWindowID": Array [ 0, 0, @@ -412382,7 +412429,7 @@ Object { 213, 223, ], - "time": Array [ + "time": Float64Array [ 13.291, 14.666, 15.916, @@ -412588,6 +412635,7 @@ Object { 265.99999999999994, 267.24999999999994, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -412790,7 +412838,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -413035,7 +413084,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -413304,7 +413354,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -413399,7 +413450,7 @@ Object { "oscpu": "", "physicalCPUs": 0, "platform": "", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Chrome Trace", "profilingEndTime": 66155012.423, @@ -413414,7 +413465,7 @@ Object { "pages": Array [], "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -413561,7 +413612,7 @@ Object { 31, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -413610,7 +413661,7 @@ Object { 40, 20, ], - "inlineDepth": Array [], + "inlineDepth": Uint8Array [], "innerWindowID": Array [ 0, 0, @@ -414472,7 +414523,7 @@ Object { 20, 44, ], - "time": Array [ + "time": Float64Array [ 66148721.172, 66148734.519, 66148820.363, @@ -414494,6 +414545,7 @@ Object { 66148973.421000004, 66148976.957, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -414544,7 +414596,7 @@ Object { "oscpu": undefined, "physicalCPUs": undefined, "platform": undefined, - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Firefox", "sampleUnits": undefined, @@ -414566,7 +414618,7 @@ Object { "profilingLog": Object {}, "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -415178,7 +415230,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -415382,7 +415434,7 @@ Object { 70, 71, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -418704,7 +418756,7 @@ Object { "oscpu": undefined, "physicalCPUs": undefined, "platform": undefined, - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Firefox", "sampleUnits": undefined, @@ -418726,7 +418778,7 @@ Object { "profilingLog": Object {}, "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -420562,7 +420614,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -421174,7 +421226,7 @@ Object { 608, 609, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -434833,7 +434885,7 @@ Object { "oscpu": undefined, "physicalCPUs": undefined, "platform": undefined, - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Firefox", "sampleUnits": undefined, @@ -434855,7 +434907,7 @@ Object { "profilingLog": Object {}, "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -435548,7 +435600,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -435779,7 +435831,7 @@ Object { 227, 228, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -441509,7 +441561,7 @@ Object { "oscpu": undefined, "physicalCPUs": undefined, "platform": undefined, - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Firefox", "sampleUnits": undefined, @@ -441531,7 +441583,7 @@ Object { "profilingLog": Object {}, "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -443943,7 +443995,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -444747,7 +444799,7 @@ Object { 641, 642, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -459410,7 +459462,7 @@ Object { "keepProfileThreadOrder": true, "markerSchema": Array [], "platform": "Android", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "com.example.sampleapplication", "sourceCodeIsNotOnSearchfox": true, @@ -459423,7 +459475,7 @@ Object { }, "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -466068,7 +466120,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -468283,7 +468335,7 @@ Object { 2211, 2212, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -517286,9 +517338,10 @@ Object { "stack": Array [ 7677, ], - "time": Array [ + "time": Float64Array [ 1870805.135585, ], + "timeDeltas": undefined, "weight": Array [ 0, ], @@ -517320,9 +517373,10 @@ Object { "stack": Array [ 7659, ], - "time": Array [ + "time": Float64Array [ 1870804.962151, ], + "timeDeltas": undefined, "weight": Array [ 0, ], @@ -517360,7 +517414,7 @@ Object { 7631, 7643, ], - "time": Array [ + "time": Float64Array [ 1870798.267391, 1870799.627152, 1870800.996407, @@ -517369,6 +517423,7 @@ Object { 1870803.710581, 1870804.590554, ], + "timeDeltas": undefined, "weight": Array [ 0.25, 0.25, @@ -518183,7 +518238,7 @@ Object { 6534, 6636, ], - "time": Array [ + "time": Float64Array [ 1869019.844661, 1869021.346745, 1869021.653273, @@ -518963,6 +519018,7 @@ Object { 1870049.837894, 1870991.999199, ], + "timeDeltas": undefined, "weight": Array [ 0.25, 0.25, @@ -519771,9 +519827,10 @@ Object { "stack": Array [ 7340, ], - "time": Array [ + "time": Float64Array [ 1870000.035016, ], + "timeDeltas": undefined, "weight": Array [ 0, ], @@ -519912,7 +519969,7 @@ Object { 7562, 7581, ], - "time": Array [ + "time": Float64Array [ 1869945.803221, 1869946.223152, 1869946.412204, @@ -520022,6 +520079,7 @@ Object { 1870036.504092, 1870036.959297, ], + "timeDeltas": undefined, "weight": Array [ 0, 0.25, @@ -520160,9 +520218,10 @@ Object { "stack": Array [ 5767, ], - "time": Array [ + "time": Float64Array [ 1869648.972568, ], + "timeDeltas": undefined, "weight": Array [ 0.25, ], @@ -520192,7 +520251,8 @@ Object { "samples": Object { "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": Array [], "weightType": "tracing-ms", }, @@ -520234,7 +520294,7 @@ Object { 7628, 2453, ], - "time": Array [ + "time": Float64Array [ 1869546.779819, 1869730.306137, 1869731.146345, @@ -520249,6 +520309,7 @@ Object { 1870093.309895, 1870093.456949, ], + "timeDeltas": undefined, "weight": Array [ 0, 0, @@ -520292,9 +520353,10 @@ Object { "stack": Array [ 7694, ], - "time": Array [ + "time": Float64Array [ 1870805.427766, ], + "timeDeltas": undefined, "weight": Array [ 0, ], @@ -520328,11 +520390,12 @@ Object { 6599, 6599, ], - "time": Array [ + "time": Float64Array [ 1869736.799492, 1869738.643145, 1870093.536446, ], + "timeDeltas": undefined, "weight": Array [ 0, 0, @@ -520373,7 +520436,7 @@ Object { 2453, 2453, ], - "time": Array [ + "time": Float64Array [ 1869305.603191, 1869546.886035, 1869548.80852, @@ -520383,6 +520446,7 @@ Object { 1869728.695827, 1869730.289393, ], + "timeDeltas": undefined, "weight": Array [ 0, 0, @@ -520474,7 +520538,7 @@ Object { 1661, 1557, ], - "time": Array [ + "time": Float64Array [ 1869183.119464, 1869183.741288, 1869189.374398, @@ -520530,6 +520594,7 @@ Object { 1870037.747567, 1870038.148022, ], + "timeDeltas": undefined, "weight": Array [ 0.25, 0, @@ -520732,7 +520797,7 @@ Object { 1214, 1240, ], - "time": Array [ + "time": Float64Array [ 1869035.496831, 1869038.067792, 1869053.166018, @@ -520853,6 +520918,7 @@ Object { 1869160.276578, 1869161.658844, ], + "timeDeltas": undefined, "weight": Array [ 0.25, 0.25, @@ -521140,7 +521206,7 @@ Object { 6134, 7626, ], - "time": Array [ + "time": Float64Array [ 1869021.184909, 1869021.561212, 1869034.289177, @@ -521281,6 +521347,7 @@ Object { 1870050.761256, 1870051.337287, ], + "timeDeltas": undefined, "weight": Array [ 0.25, 0.25, @@ -521502,7 +521569,7 @@ Object { "keepProfileThreadOrder": true, "markerSchema": Array [], "platform": "Android", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "com.example.sampleapplication", "sourceCodeIsNotOnSearchfox": true, @@ -521515,7 +521582,7 @@ Object { }, "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -527752,7 +527819,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -529831,7 +529898,7 @@ Object { 2075, 2076, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -583375,7 +583442,7 @@ Object { 10979, 9066, ], - "time": Array [ + "time": Float64Array [ 51497.504337, 51498.075568, 51520.688359, @@ -583436,6 +583503,7 @@ Object { 52106.846732, 52107.312522, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -583490,7 +583558,7 @@ Object { 10822, 7347, ], - "time": Array [ + "time": Float64Array [ 50935.231164, 51170.542439, 51344.969219, @@ -583518,6 +583586,7 @@ Object { 52060.860041, 52060.931061, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -583552,7 +583621,7 @@ Object { 8481, 7347, ], - "time": Array [ + "time": Float64Array [ 50897.993536, 50898.090764, 50935.283518, @@ -583560,6 +583629,7 @@ Object { 51352.208852, 51352.61108, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -583594,7 +583664,7 @@ Object { 10805, 8513, ], - "time": Array [ + "time": Float64Array [ 51353.409302, 52053.582956, 52054.429474, @@ -583602,6 +583672,7 @@ Object { 52055.368444, 52055.72538, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -583633,11 +583704,12 @@ Object { 4897, 4909, ], - "time": Array [ + "time": Float64Array [ 50616.91355, 50617.185082, 50617.222115, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -583670,12 +583742,13 @@ Object { 4866, 4941, ], - "time": Array [ + "time": Float64Array [ 50616.525095, 50616.786243, 50619.430528, 50619.540631, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -583705,9 +583778,10 @@ Object { "stack": Array [ 4926, ], - "time": Array [ + "time": Float64Array [ 50619.140291, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -583791,7 +583865,7 @@ Object { 4943, 4280, ], - "time": Array [ + "time": Float64Array [ 50496.703862, 50497.004734, 50497.283102, @@ -583848,6 +583922,7 @@ Object { 50619.847208, 50620.099211, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -583877,9 +583952,10 @@ Object { "stack": Array [ 7347, ], - "time": Array [ + "time": Float64Array [ 51352.685225, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -584584,7 +584660,7 @@ Object { 10619, 10654, ], - "time": Array [ + "time": Float64Array [ 51326.95693, 51332.074205, 51332.495676, @@ -585262,6 +585338,7 @@ Object { 52018.068497, 52019.552087, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -586563,7 +586640,7 @@ Object { 11003, 8496, ], - "time": Array [ + "time": Float64Array [ 50020.471113, 50020.490138, 50021.143985, @@ -587838,6 +587915,7 @@ Object { 52538.163985, 52538.225498, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -587927,7 +588005,7 @@ Object { "oscpu": "", "physicalCPUs": 0, "platform": "", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "target/debug/examples/work_log (dhat)", "sourceURL": "", @@ -587940,437 +588018,437 @@ Object { "pages": Array [], "shared": Object { "frameTable": Object { - "address": Array [ - -1, - -1, - 4434414523, - 4434380281, - 4434381997, - 4434340159, - 4434348176, - 4434348380, - 4434340956, - 4434340908, - 4434341004, - 4434378972, - 4434383623, - 4433768173, - 4433771704, - 4433869736, - 4433907427, - 4433860184, - 4433742924, - 4433707208, - 4433946914, - 4433764447, - 4433768748, - 4433907188, - 4433870895, - 4433815600, - 4433870407, - 4433859192, - 4433727438, - 4433705160, - 4433876308, - 4433787574, - 4433870773, - 4433860504, - 4433727790, - 4433705432, - 4433871619, - 4433807958, - 4433870549, - 4433859416, - 4433728494, - 4433705256, - 4433919000, - 4433773046, - 4433909157, - 4433859896, - 4433729022, - 4433704968, - 4433909731, - 4433810870, - 4433909301, - 4433690406, - 4433691566, - 4433892450, - 4433817678, - 4433581665, - 4433578169, - 4433933037, - 4433766287, - 4433768700, - 4433907284, - 4433669311, - 4433815552, - 4433668823, - 4433859736, - 4433728846, - 4433705112, - 4433674118, - 4433799222, - 4433669189, - 4433858808, - 4433729374, - 4433705480, - 4433670035, - 4433793398, - 4433669045, - 4433858712, - 4433727086, - 4433705720, - 4433918697, - 4435357725, - 4435357725, - 4435357725, - 4435357725, - 4435357725, - 4435357725, - 4435357725, - 4435516916, - 4435343797, - 4435343797, - 4435343797, - 4435343797, - 4435343797, - 4433577402, - 4433578253, - 4435335193, - 4435335193, - 4435335193, - 4435335193, - 4435335193, - 4435335193, - 4435335193, - 4433655678, - 4433613618, - 4433612853, - 4433577711, - 4433934793, - 4433875399, - 4433936988, - 4435372547, - 4435372547, - 4435372547, - 4435372547, - 4435372547, - 4435372547, - 4435372547, - 4435372547, - 4435372547, - 4435357280, - 4435357280, - 4433815847, - 4433936549, - 4433673815, - 4433932610, - 4435357056, - 4435357056, - 4435357056, - 4435357056, - 4435357056, - 4435357056, - 4435357056, - 4435357056, - 4435357056, - 4435357056, - 4435357056, - 4435357056, - 4433654538, - 4433612835, - 4433933476, - 4433613597, - 4434125051, - 4434104625, - 4434106255, - 4434105127, - 4434108174, - 4434099818, - 4434098492, - 4434098197, - 4434099068, - 4434135657, - 4434135353, - 4434101804, - 4434133186, - 4434121026, - 4434117512, - 4435473437, - 4434101625, - 4434074996, - 4434069158, - 4434075304, - 4434068856, - 4433815893, - 4433932226, - 4433674724, - 4433936110, - 4433947298, - 4434107048, - 4434104999, - 4434108254, - 4434099866, - 4434099572, - 4434128182, - 4434125664, - 4434120868, - 4434120956, - 4433614860, - 4433615607, - 4433615708, - 4433638093, - 4433643720, - 4433596840, - 4433655176, - 4433627732, - 4433623112, - 4433655937, - 4433632687, - 4433607592, - 4433616499, - 4433655080, - 4433631416, - 4433622616, - 4433604422, - 4433640585, - 4433599285, - 4433655128, - 4433624526, - 4433622824, - 4433599995, - 4433645099, - 4433598757, - 4433617170, - 4433622244, - 4433613973, - 4435447667, - 4435447667, - 4435447667, - 4435447667, - 4435447667, - 4435447667, - 4435447667, - 4435447667, - 4435447667, - 4435447667, - 4435447667, - 4435447667, - 4434148218, - 4435448212, - 4435448212, - 4434087285, - 4434074024, - 4434086536, - 4433815728, - 4433949042, - 4433946319, - 4433768978, - 4433850424, - 4433859688, - 4433726222, - 4433705864, - 4433876005, - 4433935232, - 4433949481, - 4433726398, - 4433705208, - 4433819813, - 4433781761, - 4433818693, - 4433860072, - 4433728142, - 4433705816, - 4433828929, - 4433778864, - 4433818901, - 4433860280, - 4433729198, - 4433705304, - 4433823555, - 4433805046, - 4433818837, - 4433860456, - 4433728318, - 4433705624, - 4433919303, - 4433948603, - 4433946403, - 4433771058, - 4433849848, - 4433859784, - 4433728670, - 4433705912, - 4433836977, - 4433775952, - 4433819045, - 4433946543, - 4433769810, - 4433850376, - 4433859576, - 4433726910, - 4433705672, - 4433823858, - 4433861497, - 4433796304, - 4433860661, - 4433858760, - 4433729726, - 4433705016, - 4433913481, - 4433813782, - 4433909013, - 4433860232, - 4433726574, - 4433705352, - 4433910034, - 4433861153, - 4433913750, - 4433914019, - 4434141931, - 4434147097, - 4434147741, - 4434140111, - 4433929880, - 4433688729, - 4433689109, - 4433816723, - 4433933915, - 4433934354, - 4433935671, - 4433948164, - 4433648904, - 4433647863, - 4433650174, - 4433607514, - 4433607291, - 4433656231, - 4433819469, - 4433862185, - 4434146400, - 4434146604, - 4434142812, - 4434142764, - 4434142860, - 4433999404, - 4433973292, - 4433972763, - 4433973243, - 4433968071, - 4433997012, - 4434001862, - 4434000938, - 4434000393, - 4433582481, - 4434003046, - 4434000609, - 4433962888, - 4433961639, - 4433963422, - 4433961210, - 4433960540, - 4433961097, - 4433970902, - 4433997295, - 4434002475, - 4434001324, - 4434099244, - 4433973088, - 4433971548, - 4435334870, - 4435334870, - 4435334870, - 4435334870, - 4435334870, - 4435334870, - 4435334870, - 4435334870, - 4435334870, - 4435334870, - 4433654735, - 4433612711, - 4433827905, - 4435358005, - 4435358005, - 4435358005, - 4435358005, - 4435358005, - 4435358005, - 4435358005, - 4435358005, - 4435358005, - 4435358005, - 4435358005, - 4433660741, - 4433663996, - 4433731851, - 4433737617, - 4433912977, - 4433860385, - 4433708661, - 4433706465, - 4433909412, - 4433875702, - 4433947725, - 4434084153, - 4434018698, - 4434018698, - 4433818089, - 4434005241, - 4433997138, - 4433930608, - 4433846007, - 4433894007, - 4433894247, - 4433815709, - 4433612772, - 4433827393, - 4433861841, - 4433576315, - 4433572249, - 4433573901, - 4433593039, - 4433592472, - 4433593710, - 4433593439, - 4433594183, - 4433584543, - 4433567363, - 4433584731, - 4433567295, - 4433576540, - 4433577809, - 4433816367, - 4433960859, - 4433967952, - 4433579108, - 4435357933, - 4435357933, - 4435357933, - 4435357933, - 4435357933, - 4435357933, - 4435357933, - 4435357933, - 4435357933, - 4435357933, - 4435357933, - 4435336372, - 4435336372, - 4435336372, - 4435336372, - 4435336372, - 4435336372, - 4435336372, - 4435336372, - 4435336372, - 4435336372, - 4435335008, - 4435335008, - 4435335008, - 4433926318, - 4433926497, - 4433816406, + "address": Int32Array [ + -1, + -1, + 139447227, + 139412985, + 139414701, + 139372863, + 139380880, + 139381084, + 139373660, + 139373612, + 139373708, + 139411676, + 139416327, + 138800877, + 138804408, + 138902440, + 138940131, + 138892888, + 138775628, + 138739912, + 138979618, + 138797151, + 138801452, + 138939892, + 138903599, + 138848304, + 138903111, + 138891896, + 138760142, + 138737864, + 138909012, + 138820278, + 138903477, + 138893208, + 138760494, + 138738136, + 138904323, + 138840662, + 138903253, + 138892120, + 138761198, + 138737960, + 138951704, + 138805750, + 138941861, + 138892600, + 138761726, + 138737672, + 138942435, + 138843574, + 138942005, + 138723110, + 138724270, + 138925154, + 138850382, + 138614369, + 138610873, + 138965741, + 138798991, + 138801404, + 138939988, + 138702015, + 138848256, + 138701527, + 138892440, + 138761550, + 138737816, + 138706822, + 138831926, + 138701893, + 138891512, + 138762078, + 138738184, + 138702739, + 138826102, + 138701749, + 138891416, + 138759790, + 138738424, + 138951401, + 140390429, + 140390429, + 140390429, + 140390429, + 140390429, + 140390429, + 140390429, + 140549620, + 140376501, + 140376501, + 140376501, + 140376501, + 140376501, + 138610106, + 138610957, + 140367897, + 140367897, + 140367897, + 140367897, + 140367897, + 140367897, + 140367897, + 138688382, + 138646322, + 138645557, + 138610415, + 138967497, + 138908103, + 138969692, + 140405251, + 140405251, + 140405251, + 140405251, + 140405251, + 140405251, + 140405251, + 140405251, + 140405251, + 140389984, + 140389984, + 138848551, + 138969253, + 138706519, + 138965314, + 140389760, + 140389760, + 140389760, + 140389760, + 140389760, + 140389760, + 140389760, + 140389760, + 140389760, + 140389760, + 140389760, + 140389760, + 138687242, + 138645539, + 138966180, + 138646301, + 139157755, + 139137329, + 139138959, + 139137831, + 139140878, + 139132522, + 139131196, + 139130901, + 139131772, + 139168361, + 139168057, + 139134508, + 139165890, + 139153730, + 139150216, + 140506141, + 139134329, + 139107700, + 139101862, + 139108008, + 139101560, + 138848597, + 138964930, + 138707428, + 138968814, + 138980002, + 139139752, + 139137703, + 139140958, + 139132570, + 139132276, + 139160886, + 139158368, + 139153572, + 139153660, + 138647564, + 138648311, + 138648412, + 138670797, + 138676424, + 138629544, + 138687880, + 138660436, + 138655816, + 138688641, + 138665391, + 138640296, + 138649203, + 138687784, + 138664120, + 138655320, + 138637126, + 138673289, + 138631989, + 138687832, + 138657230, + 138655528, + 138632699, + 138677803, + 138631461, + 138649874, + 138654948, + 138646677, + 140480371, + 140480371, + 140480371, + 140480371, + 140480371, + 140480371, + 140480371, + 140480371, + 140480371, + 140480371, + 140480371, + 140480371, + 139180922, + 140480916, + 140480916, + 139119989, + 139106728, + 139119240, + 138848432, + 138981746, + 138979023, + 138801682, + 138883128, + 138892392, + 138758926, + 138738568, + 138908709, + 138967936, + 138982185, + 138759102, + 138737912, + 138852517, + 138814465, + 138851397, + 138892776, + 138760846, + 138738520, + 138861633, + 138811568, + 138851605, + 138892984, + 138761902, + 138738008, + 138856259, + 138837750, + 138851541, + 138893160, + 138761022, + 138738328, + 138952007, + 138981307, + 138979107, + 138803762, + 138882552, + 138892488, + 138761374, + 138738616, + 138869681, + 138808656, + 138851749, + 138979247, + 138802514, + 138883080, + 138892280, + 138759614, + 138738376, + 138856562, + 138894201, + 138829008, + 138893365, + 138891464, + 138762430, + 138737720, + 138946185, + 138846486, + 138941717, + 138892936, + 138759278, + 138738056, + 138942738, + 138893857, + 138946454, + 138946723, + 139174635, + 139179801, + 139180445, + 139172815, + 138962584, + 138721433, + 138721813, + 138849427, + 138966619, + 138967058, + 138968375, + 138980868, + 138681608, + 138680567, + 138682878, + 138640218, + 138639995, + 138688935, + 138852173, + 138894889, + 139179104, + 139179308, + 139175516, + 139175468, + 139175564, + 139032108, + 139005996, + 139005467, + 139005947, + 139000775, + 139029716, + 139034566, + 139033642, + 139033097, + 138615185, + 139035750, + 139033313, + 138995592, + 138994343, + 138996126, + 138993914, + 138993244, + 138993801, + 139003606, + 139029999, + 139035179, + 139034028, + 139131948, + 139005792, + 139004252, + 140367574, + 140367574, + 140367574, + 140367574, + 140367574, + 140367574, + 140367574, + 140367574, + 140367574, + 140367574, + 138687439, + 138645415, + 138860609, + 140390709, + 140390709, + 140390709, + 140390709, + 140390709, + 140390709, + 140390709, + 140390709, + 140390709, + 140390709, + 140390709, + 138693445, + 138696700, + 138764555, + 138770321, + 138945681, + 138893089, + 138741365, + 138739169, + 138942116, + 138908406, + 138980429, + 139116857, + 139051402, + 139051402, + 138850793, + 139037945, + 139029842, + 138963312, + 138878711, + 138926711, + 138926951, + 138848413, + 138645476, + 138860097, + 138894545, + 138609019, + 138604953, + 138606605, + 138625743, + 138625176, + 138626414, + 138626143, + 138626887, + 138617247, + 138600067, + 138617435, + 138599999, + 138609244, + 138610513, + 138849071, + 138993563, + 139000656, + 138611812, + 140390637, + 140390637, + 140390637, + 140390637, + 140390637, + 140390637, + 140390637, + 140390637, + 140390637, + 140390637, + 140390637, + 140369076, + 140369076, + 140369076, + 140369076, + 140369076, + 140369076, + 140369076, + 140369076, + 140369076, + 140369076, + 140367712, + 140367712, + 140367712, + 138959022, + 138959201, + 138849110, ], "category": Array [ 0, @@ -589236,7 +589314,7 @@ Object { 9, 26, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -589668,7 +589746,7 @@ Object { 210, 212, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -595765,7 +595843,7 @@ Object { 360, 92, ], - "time": Array [ + "time": Float64Array [ 0, 0, 0, @@ -596005,7 +596083,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -596140,7 +596219,7 @@ Object { 360, 92, ], - "time": Array [ + "time": Float64Array [ 0, 0, 0, @@ -596380,7 +596459,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -596515,7 +596595,7 @@ Object { 360, 92, ], - "time": Array [ + "time": Float64Array [ 0, 0, 0, @@ -596755,7 +596835,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -596890,7 +596971,7 @@ Object { 360, 92, ], - "time": Array [ + "time": Float64Array [ 0, 0, 0, @@ -597130,7 +597211,8 @@ Object { "eventDelay": Array [], "length": 0, "stack": Array [], - "time": Array [], + "time": Float64Array [], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -597177,7 +597259,7 @@ Object { "oscpu": "", "physicalCPUs": 0, "platform": "", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Flamegraph", "sourceURL": "", @@ -597190,7 +597272,7 @@ Object { "pages": Array [], "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -597658,7 +597740,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -597814,7 +597896,7 @@ Object { 152, 153, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -752970,7 +753052,7 @@ Object { 192, 192, ], - "time": Array [ + "time": Float64Array [ 0, 1, 2, @@ -905336,6 +905418,7 @@ Object { 152362, 152363, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, @@ -905382,7 +905465,7 @@ Object { "oscpu": "", "physicalCPUs": 0, "platform": "", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Flamegraph", "sourceURL": "", @@ -905395,7 +905478,7 @@ Object { "pages": Array [], "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -905416,14 +905499,14 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, 3, 4, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -905622,7 +905705,7 @@ Object { 4, 4, ], - "time": Array [ + "time": Float64Array [ 0, 1, 2, @@ -905642,6 +905725,7 @@ Object { 16, 17, ], + "timeDeltas": undefined, "weight": null, "weightType": "samples", }, diff --git a/src/test/unit/__snapshots__/profile-upgrading.test.ts.snap b/src/test/unit/__snapshots__/profile-upgrading.test.ts.snap index 4b1a8867e6..66d77fe6cd 100644 --- a/src/test/unit/__snapshots__/profile-upgrading.test.ts.snap +++ b/src/test/unit/__snapshots__/profile-upgrading.test.ts.snap @@ -40,7 +40,7 @@ Object { "oscpu": undefined, "physicalCPUs": undefined, "platform": undefined, - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Firefox", "sampleUnits": undefined, @@ -62,7 +62,7 @@ Object { "profilingLog": Object {}, "shared": Object { "frameTable": Object { - "address": Array [ + "address": Int32Array [ -1, -1, -1, @@ -674,7 +674,7 @@ Object { null, null, ], - "func": Array [ + "func": Int32Array [ 0, 1, 2, @@ -878,7 +878,7 @@ Object { 70, 71, ], - "inlineDepth": Array [ + "inlineDepth": Uint8Array [ 0, 0, 0, @@ -7643,7 +7643,7 @@ Object { "misc": "rv:48.0", "oscpu": "Intel Mac OS X 10.11", "platform": "Macintosh", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Firefox", "stackwalk": 1, @@ -9019,7 +9019,7 @@ Object { "misc": "rv:48.0", "oscpu": "Intel Mac OS X 10.11", "platform": "Macintosh", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Firefox", "stackwalk": 1, @@ -10563,7 +10563,7 @@ Object { "misc": "rv:48.0", "oscpu": "Intel Mac OS X 10.11", "platform": "Macintosh", - "preprocessedProfileVersion": 66, + "preprocessedProfileVersion": 67, "processType": 0, "product": "Firefox", "stackwalk": 1, diff --git a/src/test/unit/activity-slice-tree.test.ts b/src/test/unit/activity-slice-tree.test.ts index 95af457973..91daea025b 100644 --- a/src/test/unit/activity-slice-tree.test.ts +++ b/src/test/unit/activity-slice-tree.test.ts @@ -5,7 +5,7 @@ import { getSlices, printSliceTree } from '../../utils/slice-tree'; function getSlicesEasy(threadCPUPercentage: number[]): string[] { - const time = threadCPUPercentage.map((_, i) => i); + const time = Float64Array.from(threadCPUPercentage, (_, i) => i); const cpuRatio = new Float64Array(threadCPUPercentage.map((p) => p / 100)); const slices = getSlices([0.05, 0.2, 0.4, 0.6, 0.8], cpuRatio, time); return printSliceTree(slices); @@ -46,7 +46,7 @@ describe('Activity slice tree', function () { { start: 0, end: 1, avg: 0.9, sum: 1000, parent: 0 }, ]; - expect(printSliceTree({ slices, time: [0, 1] })).toEqual([ + expect(printSliceTree({ slices, time: Float64Array.of(0, 1) })).toEqual([ '- 10% for 1.0ms (1 samples): 0.0ms - 1.0ms', ' - 90% for 1.0ms (1 samples): 0.0ms - 1.0ms', '- 20% for 1.0ms (1 samples): 0.0ms - 1.0ms', diff --git a/src/test/unit/combined-cpu.test.ts b/src/test/unit/combined-cpu.test.ts index 87fbc6501a..aa75cff535 100644 --- a/src/test/unit/combined-cpu.test.ts +++ b/src/test/unit/combined-cpu.test.ts @@ -10,7 +10,7 @@ function createSamplesTable(time: number[], cpuRatio: number[]): SamplesTable { const percentValues = cpuRatio.map((v) => Math.round(v * 100)); percentValues.push(0); return { - time, + time: Float64Array.from(time), threadCPUPercent: Uint8Array.from(percentValues), hasCPUDeltas: true, // Other required fields (stubbed for test purposes) @@ -35,7 +35,7 @@ describe('combineCPUDataFromThreads', function () { const result = combineCPUDataFromThreads(samples); expect(result).not.toBeNull(); - expect(result!.time).toEqual([0, 100, 200]); + expect(Array.from(result!.time)).toEqual([0, 100, 200]); expect(Array.from(result!.cpuRatio)).toEqual([0.0, 0.5, 0.8]); }); @@ -48,7 +48,7 @@ describe('combineCPUDataFromThreads', function () { const result = combineCPUDataFromThreads(samples); expect(result).not.toBeNull(); - expect(result!.time).toEqual([0, 100, 200]); + expect(Array.from(result!.time)).toEqual([0, 100, 200]); expect(Array.from(result!.cpuRatio)).toEqual([0, 0.9, 0.8]); }); @@ -62,7 +62,7 @@ describe('combineCPUDataFromThreads', function () { expect(result).not.toBeNull(); // Should have all unique time points - expect(result!.time).toEqual([0, 50, 100, 150, 200, 250]); + expect(Array.from(result!.time)).toEqual([0, 50, 100, 150, 200, 250]); // 0: thread1=bef, thread2=bef → 0.0 // 0- 50: thread1=0.5, thread2=bef → 0.5 @@ -87,7 +87,7 @@ describe('combineCPUDataFromThreads', function () { const result = combineCPUDataFromThreads(samples); expect(result).not.toBeNull(); - expect(result!.time).toEqual([0, 10, 20, 30, 40, 50]); + expect(Array.from(result!.time)).toEqual([0, 10, 20, 30, 40, 50]); // At times 0, 10, 20: only thread1 has samples // At times 30, 40, 50: thread1 has ended (30 > 20), only thread2 contributes diff --git a/src/test/unit/process-profile.test.ts b/src/test/unit/process-profile.test.ts index 11c3e63f05..945bfd78e6 100644 --- a/src/test/unit/process-profile.test.ts +++ b/src/test/unit/process-profile.test.ts @@ -284,12 +284,16 @@ describe('gecko counters processing', function () { expect(extractTime(childCounter)).toEqual(originalTime); expect( - computeTimeColumnForRawSamplesTable(processedCounters[0].samples) + Array.from( + computeTimeColumnForRawSamplesTable(processedCounters[0].samples) + ) ).toEqual(originalTime); // The subprocess times are offset when processed: expect( - computeTimeColumnForRawSamplesTable(processedCounters[1].samples) + Array.from( + computeTimeColumnForRawSamplesTable(processedCounters[1].samples) + ) ).toEqual(offsetTime); }); }); @@ -506,7 +510,7 @@ describe('js allocation processing', function () { } // Assert that the transformation makes sense. - expect(jsAllocations.time).toEqual([0, 1, 2]); + expect(jsAllocations.time).toEqual(new Float64Array([0, 1, 2])); expect(jsAllocations.weight).toEqual([3, 5, 7]); // All addressses should be nudged by 1 byte, because js allocation stack frames @@ -590,7 +594,7 @@ describe('native allocation processing', function () { } // Assert that the transformation makes sense. - expect(nativeAllocations.time).toEqual([0, 1, 2]); + expect(nativeAllocations.time).toEqual(new Float64Array([0, 1, 2])); expect(nativeAllocations.weight).toEqual([3, 5, 7]); expect(nativeAllocations.stack).toEqual([8, 9, null]); }); @@ -645,7 +649,7 @@ describe('gecko samples table processing', function () { hardcodedStackAfterProcessing ); const sampleTimes = computeTimeColumnForRawSamplesTable(processedSamples); - expect(sampleTimes.slice(0, 2)).toEqual(hardcodedTime); + expect(Array.from(sampleTimes.slice(0, 2))).toEqual(hardcodedTime); expect(ensureExists(processedSamples.eventDelay).slice(0, 2)).toEqual( hardcodedEventDelay ); diff --git a/src/test/unit/profile-data.test.ts b/src/test/unit/profile-data.test.ts index 7be0938fde..206e8a07b6 100644 --- a/src/test/unit/profile-data.test.ts +++ b/src/test/unit/profile-data.test.ts @@ -22,6 +22,7 @@ import { extractProfileFilterPageData, findAddressProofForFile, calculateFunctionSizeLowerBound, + computeFrameTableFromRawFrameTable, getNativeSymbolsForCallNode, getNativeSymbolInfo, computeTimeColumnForRawSamplesTable, @@ -1475,7 +1476,7 @@ describe('calculateFunctionSizeLowerBound', function () { const nativeSymbolIndex = nativeSymbolsDict.symSomeFunc; const functionSizeLowerBound = calculateFunctionSizeLowerBound( - shared.frameTable, + computeFrameTableFromRawFrameTable(shared.frameTable), 0x1000, nativeSymbolIndex ); @@ -1769,12 +1770,13 @@ describe('getNativeSymbolInfo', function () { const { shared } = profile; const stringTable = StringTable.withBackingArray(shared.stringArray); const { symSomeFunc, symOtherFunc } = nativeSymbolsDictPerThread[0]; + const frameTable = computeFrameTableFromRawFrameTable(shared.frameTable); expect( getNativeSymbolInfo( symSomeFunc, shared.nativeSymbols, - shared.frameTable, + frameTable, stringTable ) ).toEqual({ @@ -1788,7 +1790,7 @@ describe('getNativeSymbolInfo', function () { getNativeSymbolInfo( symOtherFunc, shared.nativeSymbols, - shared.frameTable, + frameTable, stringTable ) ).toEqual({ diff --git a/src/test/unit/profile-query/cpu-activity.test.ts b/src/test/unit/profile-query/cpu-activity.test.ts index 5d1b7f8dc0..9528d19ac4 100644 --- a/src/test/unit/profile-query/cpu-activity.test.ts +++ b/src/test/unit/profile-query/cpu-activity.test.ts @@ -12,7 +12,7 @@ describe('profile-query cpu activity', function () { { start: 1, end: 3, avg: 0.75, sum: 40, parent: 0 }, { start: 2, end: 3, avg: 1, sum: 20, parent: 1 }, ]; - const time = [0, 10, 20, 30, 40]; + const time = Float64Array.of(0, 10, 20, 30, 40); const tsManager = new TimestampManager({ start: 0, end: 40 }); const result = collectSliceTree({ slices, time }, tsManager); @@ -43,6 +43,8 @@ describe('profile-query cpu activity', function () { it('returns an empty list when there are no slices', function () { const tsManager = new TimestampManager({ start: 0, end: 10 }); - expect(collectSliceTree({ slices: [], time: [] }, tsManager)).toEqual([]); + expect( + collectSliceTree({ slices: [], time: new Float64Array() }, tsManager) + ).toEqual([]); }); }); diff --git a/src/test/unit/profile-tree.test.ts b/src/test/unit/profile-tree.test.ts index 566bedf105..90f8a59a91 100644 --- a/src/test/unit/profile-tree.test.ts +++ b/src/test/unit/profile-tree.test.ts @@ -13,6 +13,7 @@ import { } from '../../profile-logic/call-tree'; import { computeFlameGraphRows } from '../../profile-logic/flame-graph'; import { + computeFrameTableFromRawFrameTable, getCallNodeInfo, getInvertedCallNodeInfo, getOriginAnnotationForFunc, @@ -726,7 +727,7 @@ describe('origin annotation', function () { return getOriginAnnotationForFunc( funcNames.indexOf(funcName), null, - shared.frameTable, + computeFrameTableFromRawFrameTable(shared.frameTable), shared.funcTable, shared.resourceTable, stringTable, @@ -795,7 +796,7 @@ describe('getOriginAnnotationForFunc with originalLocation', function () { return getOriginAnnotationForFunc( 0, 0, - shared.frameTable, + computeFrameTableFromRawFrameTable(shared.frameTable), shared.funcTable, shared.resourceTable, stringTable, @@ -883,7 +884,7 @@ describe('getOriginalPositionForFrame', function () { getOriginalPositionForFrame( 0, 0, - shared.frameTable, + computeFrameTableFromRawFrameTable(shared.frameTable), shared.funcTable, shared.sourceLocationTable ) @@ -901,7 +902,7 @@ describe('getOriginalPositionForFrame', function () { getOriginalPositionForFrame( 0, 0, - shared.frameTable, + computeFrameTableFromRawFrameTable(shared.frameTable), shared.funcTable, shared.sourceLocationTable ) @@ -914,7 +915,7 @@ describe('getOriginalPositionForFrame', function () { getOriginalPositionForFrame( 0, 0, - shared.frameTable, + computeFrameTableFromRawFrameTable(shared.frameTable), shared.funcTable, shared.sourceLocationTable ) @@ -929,7 +930,7 @@ describe('getOriginalPositionForFrame', function () { getOriginalPositionForFrame( 0, 0, - shared.frameTable, + computeFrameTableFromRawFrameTable(shared.frameTable), shared.funcTable, shared.sourceLocationTable ) @@ -947,7 +948,7 @@ describe('getOriginalPositionForFrame', function () { getOriginalPositionForFrame( null, 0, - shared.frameTable, + computeFrameTableFromRawFrameTable(shared.frameTable), shared.funcTable, shared.sourceLocationTable ) @@ -966,7 +967,7 @@ describe('getOriginalPositionForFrame', function () { getOriginalPositionForFrame( 0, 0, - shared.frameTable, + computeFrameTableFromRawFrameTable(shared.frameTable), shared.funcTable, null ) diff --git a/src/types/actions.ts b/src/types/actions.ts index fdde883ad1..42dbae604c 100644 --- a/src/types/actions.ts +++ b/src/types/actions.ts @@ -15,7 +15,7 @@ import type { PageList, IndexIntoSourceTable, FuncTable, - FrameTable, + RawFrameTable, SourceLocationTable, SourceTable, } from './profile'; @@ -455,7 +455,7 @@ type ReceiveProfileAction = | { readonly type: 'BULK_SOURCE_MAP_SYMBOLICATION'; readonly newFuncTable: FuncTable; - readonly newFrameTable: FrameTable; + readonly newFrameTable: RawFrameTable; readonly newSourceLocationTable: SourceLocationTable; readonly newSources: SourceTable; readonly newStringArray: string[]; diff --git a/src/types/profile-derived.ts b/src/types/profile-derived.ts index 6568b3b209..f7d61057f6 100644 --- a/src/types/profile-derived.ts +++ b/src/types/profile-derived.ts @@ -7,10 +7,13 @@ import type { MarkerPayload, MarkerSchema } from './markers'; import type { ThreadIndex, Pid, + InnerWindowID, IndexIntoFuncTable, IndexIntoJsTracerEvents, IndexIntoCategoryList, + IndexIntoSubcategoryListForCategory, IndexIntoResourceTable, + IndexIntoNativeSymbolTable, IndexIntoLibs, CounterIndex, IndexIntoRawMarkerTable, @@ -19,10 +22,7 @@ import type { Tid, ProcessType, PausedRange, - JsAllocationsTable, - NativeAllocationsTable, RawMarkerTable, - FrameTable, FuncTable, ResourceTable, NativeSymbolTable, @@ -31,6 +31,7 @@ import type { WeightType, SourceTable, IndexIntoSourceTable, + IndexIntoSourceLocationTable, CounterDisplayConfig, SourceLocationTable, } from './profile'; @@ -130,7 +131,7 @@ export type SamplesTable = { // This is optional because older profiles didn't have that field. eventDelay?: Array; stack: Array; - time: Milliseconds[]; + time: Float64Array; // An optional weight array. If not present, then the weight is assumed to be 1. // See the WeightType type for more information. weight: null | number[]; @@ -165,7 +166,7 @@ export type SampleCategoriesAndSubcategories = { export type SamplesLikeTable = { stack: Array; - time: Milliseconds[]; + time: Float64Array; // An optional weight array. If not present, then the weight is assumed to be 1. // See the WeightType type for more information. weight: null | number[]; @@ -175,7 +176,7 @@ export type SamplesLikeTable = { }; export type CounterSamplesTable = { - time: Milliseconds[]; + time: Float64Array; // The number of times the Counter's "number" was changed since the previous sample. // This property was mandatory until the format version 42, it was made optional in 43. number?: number[]; @@ -185,6 +186,55 @@ export type CounterSamplesTable = { length: number; }; +/** + * The `JsAllocationsTable` type of the derived thread. + * + * Differs from `RawJsAllocationsTable` in that the `time` column is always a + * `Float64Array`. + */ +export type JsAllocationsTable = { + time: Float64Array; + className: string[]; + typeName: string[]; + coarseType: string[]; + weight: Bytes[]; + weightType: 'bytes'; + inNursery: boolean[]; + stack: Array; + length: number; +}; + +/** + * The `UnbalancedNativeAllocationsTable` type of the derived thread. + * + * Differs from `RawUnbalancedNativeAllocationsTable` in that the `time` column + * is always a `Float64Array`. + */ +export type UnbalancedNativeAllocationsTable = { + time: Float64Array; + weight: Bytes[]; + weightType: 'bytes'; + stack: Array; + argumentValues?: Array; + length: number; +}; + +/** + * The `BalancedNativeAllocationsTable` type of the derived thread. + */ +export type BalancedNativeAllocationsTable = + UnbalancedNativeAllocationsTable & { + memoryAddress: number[]; + threadId: number[]; + }; + +/** + * The `NativeAllocationsTable` type of the derived thread. + */ +export type NativeAllocationsTable = + | UnbalancedNativeAllocationsTable + | BalancedNativeAllocationsTable; + export type Counter = { name: string; category: string; @@ -235,6 +285,33 @@ export type StackTable = { subcategory: Uint8Array | Uint16Array; // represents a Map }; +/** + * The `FrameTable` type of the derived thread. + * + * Differs from `RawFrameTable` in that the following columns are always + * stored as typed arrays: `address` (`Int32Array`, with `-1` as the sentinel + * for missing addresses), `inlineDepth` (`Uint8Array`), and `func` + * (`Int32Array`). In `RawFrameTable`, these columns may be either regular + * arrays or typed arrays, since regular arrays are convenient during + * construction. + */ +export type FrameTable = { + // Differs from RawFrameTable: always Int32Array (-1 sentinel preserved). + address: Int32Array; + // Differs from RawFrameTable: always Uint8Array. + inlineDepth: Uint8Array; + category: (IndexIntoCategoryList | null)[]; + subcategory: (IndexIntoSubcategoryListForCategory | null)[]; + // Differs from RawFrameTable: always Int32Array. + func: Int32Array; + nativeSymbol: (IndexIntoNativeSymbolTable | null)[]; + innerWindowID: (InnerWindowID | null)[]; + line: (number | null)[]; + column: (number | null)[]; + originalLocation: Array; + length: number; +}; + /** * Similar to the StackTable, but based on functions rather than on frames. * diff --git a/src/types/profile.ts b/src/types/profile.ts index 8b470516e2..bbac5d671b 100644 --- a/src/types/profile.ts +++ b/src/types/profile.ts @@ -126,9 +126,9 @@ export type RawSamplesTable = { // This is optional because older profiles didn't have that field. eventDelay?: Array; stack: Array; - time?: Milliseconds[]; + time?: Milliseconds[] | Float64Array; // If the `time` column is not present, then the `timeDeltas` column must be present. - timeDeltas?: Milliseconds[]; + timeDeltas?: Milliseconds[] | Float64Array; argumentValues?: Array; // An optional weight array. If not present, then the weight is assumed to be 1. // See the WeightType type for more information. @@ -151,9 +151,11 @@ export type RawSamplesTable = { /** * JS allocations are recorded as a marker payload, but in profile processing they * are moved to the Thread. This allows them to be part of the stack processing pipeline. + * + * There is also a derived `JsAllocationsTable` type, see profile-derived.js. */ -export type JsAllocationsTable = { - time: Milliseconds[]; +export type RawJsAllocationsTable = { + time: Milliseconds[] | Float64Array; className: string[]; typeName: string[]; // Currently only 'JSObject' coarseType: string[]; // Currently only 'Object', @@ -170,8 +172,8 @@ export type JsAllocationsTable = { * This variant is the original version of the table, before the memory address * and threadId were added. */ -export type UnbalancedNativeAllocationsTable = { - time: Milliseconds[]; +export type RawUnbalancedNativeAllocationsTable = { + time: Milliseconds[] | Float64Array; // "weight" is used here rather than "bytes", so that this type can be // used as a SamplesLikeTable. weight: Bytes[]; @@ -184,8 +186,8 @@ export type UnbalancedNativeAllocationsTable = { /** * The memory address and thread ID were added later. */ -export type BalancedNativeAllocationsTable = - UnbalancedNativeAllocationsTable & { +export type RawBalancedNativeAllocationsTable = + RawUnbalancedNativeAllocationsTable & { memoryAddress: number[]; threadId: number[]; }; @@ -195,10 +197,12 @@ export type BalancedNativeAllocationsTable = * are moved to the Thread. This allows them to be part of the stack processing pipeline. * Currently they include native allocations and deallocations. However, both * of them are sampled independently, so they will be unbalanced if summed togther. + * + * There is also a derived `NativeAllocationsTable` type, see profile-derived.js. */ -export type NativeAllocationsTable = - | UnbalancedNativeAllocationsTable - | BalancedNativeAllocationsTable; +export type RawNativeAllocationsTable = + | RawUnbalancedNativeAllocationsTable + | RawBalancedNativeAllocationsTable; /** * Markers represent arbitrary events that happen within the browser. They have a @@ -229,7 +233,7 @@ export type RawMarkerTable = { * Frames contain the context information about the function execution at the moment in * time. The caller/callee relationship between frames is defined by the StackTable. */ -export type FrameTable = { +export type RawFrameTable = { // If this is a frame for native code, the address is the address of the frame's // assembly instruction, relative to the native library that contains it. // @@ -241,7 +245,9 @@ export type FrameTable = { // // The library which this address is relative to is given by the frame's nativeSymbol: // frame -> nativeSymbol -> lib. - address: Array
; + // + // Frames with no address use the sentinel value `-1`. + address: Array
| Int32Array; // The inline depth for this frame. If there is an inline stack at an address, // we create multiple frames with the same address, one for each depth. @@ -269,7 +275,7 @@ export type FrameTable = { // // The frames of an inline stack at an address all have the same address and the same // nativeSymbol, but each has a different func and line. - inlineDepth: number[]; + inlineDepth: number[] | Uint8Array; // The category of the frame. This is used to calculate the category of the stack nodes // which use this frame: @@ -286,7 +292,7 @@ export type FrameTable = { subcategory: (IndexIntoSubcategoryListForCategory | null)[]; // The frame's function. - func: IndexIntoFuncTable[]; + func: IndexIntoFuncTable[] | Int32Array; // The symbol index (referring into this thread's nativeSymbols table) corresponding // to symbol that covers the frame address of this frame. Only non-null for native @@ -530,8 +536,8 @@ export type JsTracerTable = { }; export type RawCounterSamplesTable = { - time?: Milliseconds[]; - timeDeltas?: Milliseconds[]; + time?: Milliseconds[] | Float64Array; + timeDeltas?: Milliseconds[] | Float64Array; // The number of times the Counter's "number" was changed since the previous sample. // This property was mandatory until the format version 42, it was made optional in 43. number?: number[]; @@ -764,8 +770,8 @@ export type RawThread = { pid: Pid; tid: Tid; samples: RawSamplesTable; - jsAllocations?: JsAllocationsTable; - nativeAllocations?: NativeAllocationsTable; + jsAllocations?: RawJsAllocationsTable; + nativeAllocations?: RawNativeAllocationsTable; markers: RawMarkerTable; jsTracer?: JsTracerTable; // If present and true, this thread was launched for a private browsing session only. @@ -1082,7 +1088,7 @@ export type SourceLocationTable = { export type RawProfileSharedData = { stackTable: RawStackTable; - frameTable: FrameTable; + frameTable: RawFrameTable; funcTable: FuncTable; resourceTable: ResourceTable; nativeSymbols: NativeSymbolTable; diff --git a/src/utils/number-series.ts b/src/utils/number-series.ts index e676a9faeb..5a3252e4cf 100644 --- a/src/utils/number-series.ts +++ b/src/utils/number-series.ts @@ -2,8 +2,10 @@ * 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/. */ -export function numberSeriesFromDeltas(deltas: number[]): number[] { - const values = new Array(deltas.length); +export function numberSeriesFromDeltas( + deltas: number[] | Float64Array +): Float64Array { + const values = new Float64Array(deltas.length); let prev = 0; for (let i = 0; i < deltas.length; i++) { const current = prev + deltas[i]; @@ -13,7 +15,9 @@ export function numberSeriesFromDeltas(deltas: number[]): number[] { return values; } -export function numberSeriesToDeltas(values: number[]): number[] { +export function numberSeriesToDeltas( + values: number[] | Float64Array +): number[] { const deltas = new Array(values.length); let prev = 0; for (let i = 0; i < values.length; i++) { diff --git a/src/utils/slice-tree.ts b/src/utils/slice-tree.ts index c2289b2b7b..c218a2eb80 100644 --- a/src/utils/slice-tree.ts +++ b/src/utils/slice-tree.ts @@ -13,7 +13,7 @@ export type Slice = { function addIndexIntervalsExceedingThreshold( threshold: number, cpuRatio: Float64Array, - time: number[], + time: Float64Array, items: Slice[], parent: number | null, startIndex: number = 0, @@ -74,13 +74,13 @@ function addIndexIntervalsExceedingThreshold( export type SliceTree = { slices: Slice[]; - time: number[]; + time: Float64Array; }; export function getSlices( thresholds: number[], cpuRatio: Float64Array, - time: number[], + time: Float64Array, startIndex: number = 0, endIndex: number = cpuRatio.length - 1 ): SliceTree { @@ -114,7 +114,7 @@ export function getSlices( return { slices, time }; } -function sliceToString(slice: Slice, time: number[]): string { +function sliceToString(slice: Slice, time: Float64Array): string { const { avg, start, end } = slice; const startTime = time[start]; const endTime = time[end]; @@ -130,7 +130,7 @@ function appendSliceSubtree( childrenStartPerParent: Array, interestingSliceIndexes: Set, nestingDepth: number, - time: number[], + time: Float64Array, s: string[] ) { for (let i = startIndex; i < slices.length; i++) {