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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs-developer/CHANGELOG-formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ Note that this is not an exhaustive list. Processed profile format upgraders can

## Processed profile format

### Version 65

The stack table's `frame` column (stored at `profile.shared.stackTable.frame`) can now optionally be stored as an `Int32Array`, for profiles loaded from [JsonSlabs](https://github.com/mstange/json-slabs/) files (.jslb, .jslb.gz). Regular JS / JSON arrays are still accepted.

### Version 64

A new `SourceLocationTable` has been added to `profile.shared.sourceLocationTable`. It holds the original (pre-compilation) source positions produced by source map symbolication, paired with the generated `line`/`column` already on `FrameTable`.
Expand Down
2 changes: 1 addition & 1 deletion src/app-logic/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = 64;
export const PROCESSED_PROFILE_VERSION = 65;

// The following are the margin sizes for the left and right of the timeline. Independent
// components need to share these values.
Expand Down
33 changes: 31 additions & 2 deletions src/profile-logic/data-structures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import type {
CallNodeTable,
SourceTable,
SourceLocationTable,
IndexIntoFrameTable,
IndexIntoStackTable,
} from 'firefox-profiler/types';

/**
Expand All @@ -47,7 +49,13 @@ export function getEmptySamplesTable(): RawSamplesTable {
};
}

export function getEmptyRawStackTable(): RawStackTable {
export type RawStackTableBuilder = {
frame: IndexIntoFrameTable[];
prefix: Array<IndexIntoStackTable | null>;
length: number;
};

export function getRawStackTableBuilder(): RawStackTableBuilder {
return {
// Important!
// If modifying this structure, please update all callers of this function to ensure
Expand All @@ -59,6 +67,27 @@ export function getEmptyRawStackTable(): RawStackTable {
};
}

export function getRawStackTableBuilderWithExistingContents(
existing: RawStackTable
): RawStackTableBuilder {
return {
frame: [...existing.frame],
prefix: [...existing.prefix],
length: existing.length,
};
}

export function finishRawStackTableBuilder(
builder: RawStackTableBuilder
): RawStackTable {
const { frame, prefix, length } = builder;
return {
frame: new Int32Array(frame),
prefix,
length,
};
}

/**
* Returns an empty samples table with eventDelay field instead of responsiveness.
* eventDelay is a new field and it replaced responsiveness. We should still
Expand Down Expand Up @@ -393,7 +422,7 @@ export function getEmptyThread(overrides?: Partial<RawThread>): RawThread {

export function getEmptySharedData(): RawProfileSharedData {
return {
stackTable: getEmptyRawStackTable(),
stackTable: finishRawStackTableBuilder(getRawStackTableBuilder()),
frameTable: getEmptyFrameTable(),
funcTable: getEmptyFuncTable(),
resourceTable: getEmptyResourceTable(),
Expand Down
13 changes: 7 additions & 6 deletions src/profile-logic/global-data-collector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

import { StringTable } from '../utils/string-table';
import {
finishRawStackTableBuilder,
getEmptyFrameTable,
getEmptyFuncTable,
getEmptyNativeSymbolTable,
getEmptyRawStackTable,
getEmptyResourceTable,
getEmptySourceTable,
getEmptySourceLocationTable,
getRawStackTableBuilder,
} from './data-structures';

import type {
Expand All @@ -22,7 +23,6 @@ import type {
RawProfileSharedData,
SourceTable,
FrameTable,
RawStackTable,
FuncTable,
ResourceTable,
NativeSymbolTable,
Expand All @@ -34,6 +34,7 @@ import type {
Bytes,
} from 'firefox-profiler/types';
import { ResourceType } from 'firefox-profiler/types';
import type { RawStackTableBuilder } from './data-structures';

/**
* GlobalDataCollector collects data which is global in the processed profile
Expand All @@ -50,7 +51,7 @@ export class GlobalDataCollector {
_stringTable: StringTable = StringTable.withBackingArray(this._stringArray);
_sources: SourceTable = getEmptySourceTable();
_frameTable: FrameTable = getEmptyFrameTable();
_stackTable: RawStackTable = getEmptyRawStackTable();
_stackTableBuilder: RawStackTableBuilder = getRawStackTableBuilder();
_funcTable: FuncTable = getEmptyFuncTable();
_resourceTable: ResourceTable = getEmptyResourceTable();
_nativeSymbols: NativeSymbolTable = getEmptyNativeSymbolTable();
Expand Down Expand Up @@ -302,15 +303,15 @@ export class GlobalDataCollector {
return this._frameTable;
}

getStackTable(): RawStackTable {
return this._stackTable;
getStackTableBuilder(): RawStackTableBuilder {
return this._stackTableBuilder;
}

// Package up all de-duplicated global tables so that they can be embedded in
// the profile.
finish(): { libs: Lib[]; shared: RawProfileSharedData } {
const shared: RawProfileSharedData = {
stackTable: this._stackTable,
stackTable: finishRawStackTableBuilder(this._stackTableBuilder),
frameTable: this._frameTable,
funcTable: this._funcTable,
resourceTable: this._resourceTable,
Expand Down
2 changes: 1 addition & 1 deletion src/profile-logic/import/chrome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ async function processTracingEvents(
const stringTable = globalDataCollector.getStringTable();

const frameTable = globalDataCollector.getFrameTable();
const stackTable = globalDataCollector.getStackTable();
const stackTable = globalDataCollector.getStackTableBuilder();

let profileEvents: (ProfileEvent | CpuProfileEvent)[] = (eventsByName.get(
'Profile'
Expand Down
2 changes: 1 addition & 1 deletion src/profile-logic/import/dhat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ export function attemptToConvertDhat(json: unknown): Profile | null {
profile.meta.product = dhat.cmd + ' (dhat)';
profile.meta.importedFrom = `dhat`;
const globalDataCollector = new GlobalDataCollector();
const stackTable = globalDataCollector.getStackTable();
const stackTable = globalDataCollector.getStackTableBuilder();
const frameTable = globalDataCollector.getFrameTable();
const stringTable = globalDataCollector.getStringTable();

Expand Down
2 changes: 1 addition & 1 deletion src/profile-logic/import/flame-graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export function convertFlameGraphProfile(profileText: string): Profile {
});

const frameTable = globalDataCollector.getFrameTable();
const stackTable = globalDataCollector.getStackTable();
const stackTable = globalDataCollector.getStackTableBuilder();
const { samples } = thread;

// Maps to deduplicate stacks, frames, and functions.
Expand Down
8 changes: 5 additions & 3 deletions src/profile-logic/import/simpleperf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ import {
getEmptyFuncTable,
getEmptyResourceTable,
getEmptyFrameTable,
getEmptyRawStackTable,
getRawStackTableBuilder,
finishRawStackTableBuilder,
type RawStackTableBuilder,
getEmptySamplesTable,
getEmptyRawMarkerTable,
getEmptyNativeSymbolTable,
Expand Down Expand Up @@ -189,15 +191,15 @@ class FirefoxFrameTable {
class FirefoxSampleTable {
strings: StringTable;

stackTable: RawStackTable = getEmptyRawStackTable();
stackTable: RawStackTableBuilder = getRawStackTableBuilder();
stackMap: Map<string, IndexIntoStackTable> = new Map();

constructor(strings: StringTable) {
this.strings = strings;
}

toJson(): RawStackTable {
return this.stackTable;
return finishRawStackTableBuilder(this.stackTable);
}

findOrAddStack(
Expand Down
10 changes: 9 additions & 1 deletion src/profile-logic/js-tracer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import {
getEmptySamplesTableWithEventDelay,
getEmptyRawMarkerTable,
finishRawStackTableBuilder,
getRawStackTableBuilderWithExistingContents,
} from './data-structures';
import { StringTable } from '../utils/string-table';
import { ensureExists } from '../utils/types';
Expand Down Expand Up @@ -512,7 +514,10 @@ export function convertJsTracerToThreadWithoutSamples(
samples,
};

const { funcTable, frameTable, stackTable } = shared;
const { funcTable, frameTable } = shared;
const stackTable = getRawStackTableBuilderWithExistingContents(
shared.stackTable
);

// Keep a stack of js tracer events, and end timings, that will be used to find
// the stack prefixes. Once a JS tracer event starts past another event end, the
Expand Down Expand Up @@ -620,6 +625,9 @@ export function convertJsTracerToThreadWithoutSamples(
unmatchedEventEnds[unmatchedIndex] = end;
}

// Write the augmented stackTable back to the shared data.
shared.stackTable = finishRawStackTableBuilder(stackTable);

return { thread, stackMap };
}

Expand Down
10 changes: 7 additions & 3 deletions src/profile-logic/merge-compare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
getEmptyNativeSymbolTable,
getEmptyFrameTable,
getEmptyFuncTable,
getEmptyRawStackTable,
getRawStackTableBuilder,
finishRawStackTableBuilder,
getEmptyRawMarkerTable,
getEmptySamplesTableWithEventDelay,
shallowCloneRawMarkerTable,
Expand Down Expand Up @@ -1117,7 +1118,7 @@ function mergeStackTables(
translationMapsForFrames: TranslationMapForFrames[]
): { stackTable: RawStackTable; translationMaps: TranslationMapForStacks[] } {
const translationMaps: TranslationMapForStacks[] = [];
const newStackTable = getEmptyRawStackTable();
const newStackTable = getRawStackTableBuilder();

profiles.forEach((profile, profileIndex) => {
const { stackTable } = profile.shared;
Expand All @@ -1143,7 +1144,10 @@ function mergeStackTables(
translationMaps.push(oldStackToNewStackPlusOne);
});

return { stackTable: newStackTable, translationMaps };
return {
stackTable: finishRawStackTableBuilder(newStackTable),
translationMaps,
};
}

/**
Expand Down
9 changes: 5 additions & 4 deletions src/profile-logic/process-profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
getEmptyRawMarkerTable,
getEmptyJsAllocationsTable,
getEmptyUnbalancedNativeAllocationsTable,
type RawStackTableBuilder,
} from './data-structures';
import { immutableUpdate, ensureExists } from '../utils/types';
import { verifyMagic, SIMPLEPERF as SIMPLEPERF_MAGIC } from '../utils/magic';
Expand Down Expand Up @@ -53,7 +54,6 @@ import type {
FrameTable,
RawCounterSamplesTable,
RawSamplesTable,
RawStackTable,
RawMarkerTable,
LibMapping,
IndexIntoStackTable,
Expand Down Expand Up @@ -107,6 +107,7 @@ import type {
CounterDisplayConfig,
} from 'firefox-profiler/types';
import { decompress, isGzip } from 'firefox-profiler/utils/gz';
import { jsonEncodeObjectWithTypedArraysAsRegularArrays } from 'firefox-profiler/utils/json-with-typed-arrays';

type RegExpResult = null | string[];
/**
Expand Down Expand Up @@ -548,7 +549,7 @@ function _processFrameTable(
*/
function _processStackTable(
geckoStackTable: GeckoStackStruct,
sharedStackTable: RawStackTable,
sharedStackTable: RawStackTableBuilder,
frameIndexOffset: IndexIntoFrameTable
): IndexIntoStackTable {
const stackIndexOffset = sharedStackTable.length;
Expand Down Expand Up @@ -1336,7 +1337,7 @@ function _processThread(
);
const stackIndexOffset = _processStackTable(
geckoStackTable,
globalDataCollector.getStackTable(),
globalDataCollector.getStackTableBuilder(),
frameIndexOffset
);

Expand Down Expand Up @@ -2056,7 +2057,7 @@ export function processGeckoProfile(geckoProfile: GeckoProfile): Profile {
* Take a processed profile and convert it to a string.
*/
export function serializeProfileToJsonString(profile: Profile): string {
return JSON.stringify(profile);
return jsonEncodeObjectWithTypedArraysAsRegularArrays(profile);
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/profile-logic/processed-profile-versioning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3255,6 +3255,11 @@ const _upgraders: {
};
sources.content = new Array(sources.length).fill(null);
},
[65]: (_profile: any) => {
// The type of `profile.shared.stackTable.frame` was changed from
// `IndexIntoFrameTable[]` to `IndexIntoFrameTable[] | Int32Array<ArrayBuffer>`.
// All valid v64 profiles are valid v65 profiles, so no upgrader is needed.
},
// If you add a new upgrader here, please document the change in
// `docs-developer/CHANGELOG-formats.md`.
};
Expand Down
Loading
Loading