From 6d876ba1597396a92bd88d0ab6f16d526eb30356 Mon Sep 17 00:00:00 2001 From: fatadel Date: Tue, 1 Sep 2026 13:13:24 +0200 Subject: [PATCH 1/2] Make marker styles serializable Marker styles use methods to resolve theme-dependent colors, which cannot be serialized as marker schema metadata. Store only color data in each style and resolve it when drawing timeline markers. --- src/components/timeline/Markers.tsx | 11 +-- src/profile-logic/marker-styles.ts | 122 +++++++++++----------------- src/types/markers.ts | 19 ++++- 3 files changed, 72 insertions(+), 80 deletions(-) diff --git a/src/components/timeline/Markers.tsx b/src/components/timeline/Markers.tsx index 536f3e4e2b..7bb3914d90 100644 --- a/src/components/timeline/Markers.tsx +++ b/src/components/timeline/Markers.tsx @@ -8,6 +8,7 @@ import { InView } from 'react-intersection-observer'; import { overlayFills, getMarkerStyle, + getMarkerStyleColor, } from 'firefox-profiler/profile-logic/marker-styles'; import { withSize } from 'firefox-profiler/components/shared/WithSize'; import { Tooltip } from 'firefox-profiler/components/tooltip/Tooltip'; @@ -155,7 +156,7 @@ class TimelineMarkersCanvas extends React.PureComponent { ) : Number.MAX_SAFE_INTEGER; const markerStyle = getMarkerStyle(marker); - ctx.fillStyle = markerStyle.getBackground(); + ctx.fillStyle = getMarkerStyleColor(markerStyle.background); if (markerStyle.squareCorners) { ctx.fillRect(pos, markerStyle.top, itemWidth, markerStyle.height); } else { @@ -168,12 +169,12 @@ class TimelineMarkersCanvas extends React.PureComponent { 1 / devicePixelRatio ); } - if (markerStyle.hasBorderLeft()) { - ctx.fillStyle = markerStyle.getBorderLeft(); + if (markerStyle.borderLeft !== null) { + ctx.fillStyle = getMarkerStyleColor(markerStyle.borderLeft); ctx.fillRect(pos, markerStyle.top, 1, markerStyle.height); } - if (markerStyle.hasBorderRight()) { - ctx.fillStyle = markerStyle.getBorderRight(); + if (markerStyle.borderRight !== null) { + ctx.fillStyle = getMarkerStyleColor(markerStyle.borderRight); ctx.fillRect( pos + itemWidth - 1, markerStyle.top, diff --git a/src/profile-logic/marker-styles.ts b/src/profile-logic/marker-styles.ts index c29eccd509..b00ae2139e 100644 --- a/src/profile-logic/marker-styles.ts +++ b/src/profile-logic/marker-styles.ts @@ -4,65 +4,36 @@ import * as colors from 'photon-colors'; -import type { CssPixels, Marker } from 'firefox-profiler/types'; +import type { + Marker, + MarkerSchemaStyle, + MarkerSchemaStyleColor, +} from 'firefox-profiler/types'; import { maybeLightDark } from '../utils/dark-mode'; -type MarkerStyle = { - readonly top: CssPixels; - readonly height: CssPixels; - readonly _background: string | [string, string]; - readonly getBackground: () => string; - readonly squareCorners: boolean; - readonly _borderLeft: null | string | [string, string]; - readonly hasBorderLeft: () => boolean; - readonly getBorderLeft: () => string; - readonly _borderRight: null | string | [string, string]; - readonly hasBorderRight: () => boolean; - readonly getBorderRight: () => string; -}; - -const defaultStyle: MarkerStyle = { +const defaultStyle: MarkerSchemaStyle = { top: 0, height: 6, - _background: ['black', colors.GREY_40], - getBackground: function () { - return maybeLightDark(this._background); - }, + background: ['black', colors.GREY_40], squareCorners: false, - _borderLeft: null, - hasBorderLeft: function () { - return this._borderLeft !== null; - }, - getBorderLeft: function () { - return maybeLightDark(this._borderLeft as string | [string, string]); - }, - _borderRight: null, - hasBorderRight: function () { - return this._borderRight !== null; - }, - getBorderRight: function () { - return maybeLightDark(this._borderRight as string | [string, string]); - }, + borderLeft: null, + borderRight: null, }; const gcStyle = { ...defaultStyle, top: 6, - _background: colors.ORANGE_50, + background: colors.ORANGE_50, }; const ccStyle = { ...gcStyle, // This is a paler orange to distinguish CC from GC. - _background: '#ffc600', + background: '#ffc600', }; -/** - * Get the marker style. Start off by looking at the marker name, then fallback to - * the marker type. - */ -export function getMarkerStyle(marker: Marker): MarkerStyle { +export function getMarkerStyle(marker: Marker): MarkerSchemaStyle { const { data, name } = marker; if (name in markerStyles) { return markerStyles[name]; @@ -70,20 +41,23 @@ export function getMarkerStyle(marker: Marker): MarkerStyle { if (data && data.type in markerStyles) { return markerStyles[data.type]; } - return markerStyles.default; + return defaultStyle; +} + +export function getMarkerStyleColor(color: MarkerSchemaStyleColor): string { + return maybeLightDark(color); } -const markerStyles: { readonly [styleName: string]: MarkerStyle } = { - default: defaultStyle, +const markerStyles: { readonly [styleName: string]: MarkerSchemaStyle } = { RefreshDriverTick: { ...defaultStyle, - _background: 'rgba(237, 237, 240, 0.05)', + background: 'rgba(237, 237, 240, 0.05)', height: 18, squareCorners: true, }, RD: { ...defaultStyle, - _background: 'rgba(237, 237, 240, 0.05)', + background: 'rgba(237, 237, 240, 0.05)', height: 18, squareCorners: true, }, @@ -91,97 +65,97 @@ const markerStyles: { readonly [styleName: string]: MarkerStyle } = { // here for backwards compatibility. Scripts: { ...defaultStyle, - _background: colors.ORANGE_70, + background: colors.ORANGE_70, top: 6, }, 'requestAnimationFrame callbacks': { ...defaultStyle, - _background: colors.ORANGE_70, + background: colors.ORANGE_70, top: 6, }, Styles: { ...defaultStyle, - _background: [colors.TEAL_50, colors.TEAL_70], + background: [colors.TEAL_50, colors.TEAL_70], top: 7, }, FireScrollEvent: { ...defaultStyle, - _background: colors.ORANGE_70, + background: colors.ORANGE_70, top: 7, }, Reflow: { ...defaultStyle, - _background: colors.BLUE_50, + background: colors.BLUE_50, top: 7, }, DispatchSynthMouseMove: { ...defaultStyle, - _background: colors.ORANGE_70, + background: colors.ORANGE_70, top: 8, }, DisplayList: { ...defaultStyle, - _background: colors.PURPLE_50, + background: colors.PURPLE_50, top: 9, }, LayerBuilding: { ...defaultStyle, - _background: colors.ORANGE_50, + background: colors.ORANGE_50, top: 9, }, Rasterize: { ...defaultStyle, - _background: [colors.GREEN_50, colors.GREEN_60], + background: [colors.GREEN_50, colors.GREEN_60], top: 10, }, ForwardTransaction: { ...defaultStyle, - _background: colors.RED_70, + background: colors.RED_70, top: 11, }, NotifyDidPaint: { ...defaultStyle, - _background: colors.GREY_40, + background: colors.GREY_40, top: 12, }, LayerTransaction: { ...defaultStyle, - _background: colors.RED_70, + background: colors.RED_70, }, Composite: { ...defaultStyle, - _background: colors.BLUE_50, + background: colors.BLUE_50, }, Vsync: { ...defaultStyle, - _background: 'rgb(255, 128, 0)', + background: 'rgb(255, 128, 0)', }, LayerContentGPU: { ...defaultStyle, - _background: 'rgba(0,200,0,0.5)', + background: 'rgba(0,200,0,0.5)', }, LayerCompositorGPU: { ...defaultStyle, - _background: 'rgba(0,200,0,0.5)', + background: 'rgba(0,200,0,0.5)', }, LayerOther: { ...defaultStyle, - _background: 'rgb(200,0,0)', + background: 'rgb(200,0,0)', }, Jank: { ...defaultStyle, - _background: ['hsl(347, 100%, 60%)', 'hsl(347, 75%, 40%)'], - _borderLeft: [colors.RED_50, colors.RED_70], - _borderRight: [colors.RED_50, colors.RED_70], + background: ['hsl(347, 100%, 60%)', 'hsl(347, 75%, 40%)'], + borderLeft: [colors.RED_50, colors.RED_70], + borderRight: [colors.RED_50, colors.RED_70], squareCorners: true, }, // BHR markers are displayed in the timeline only if jank markers are // unavailable. Let's style them like Jank markers. 'BHR-detected hang': { ...defaultStyle, - _background: ['hsl(347, 100%, 60%)', 'hsl(347, 75%, 40%)'], - _borderLeft: [colors.RED_50, colors.RED_70], - _borderRight: [colors.RED_50, colors.RED_70], + background: ['hsl(347, 100%, 60%)', 'hsl(347, 75%, 40%)'], + borderLeft: [colors.RED_50, colors.RED_70], + borderRight: [colors.RED_50, colors.RED_70], squareCorners: true, }, // Memory: @@ -208,27 +182,27 @@ const markerStyles: { readonly [styleName: string]: MarkerStyle } = { // IO: FileIO: { ...defaultStyle, - _background: colors.BLUE_50, + background: colors.BLUE_50, }, IPCOut: { ...defaultStyle, - _background: colors.BLUE_50, + background: colors.BLUE_50, top: 2, }, SyncIPCOut: { ...defaultStyle, - _background: colors.BLUE_70, + background: colors.BLUE_70, top: 6, }, IPCIn: { ...defaultStyle, - _background: colors.PURPLE_40, + background: colors.PURPLE_40, top: 13, }, SyncIPCIn: { ...defaultStyle, - _background: colors.PURPLE_70, + background: colors.PURPLE_70, top: 17, }, }; diff --git a/src/types/markers.ts b/src/types/markers.ts index 3dfcc65f10..98d1854fc3 100644 --- a/src/types/markers.ts +++ b/src/types/markers.ts @@ -2,7 +2,13 @@ * 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 { Milliseconds, Microseconds, Seconds, Bytes } from './units'; +import type { + Milliseconds, + Microseconds, + Seconds, + Bytes, + CssPixels, +} from './units'; import type { GeckoMarkerStack } from './gecko-profile'; import type { IndexIntoStackTable, @@ -128,6 +134,17 @@ export type MarkerGraph = { color?: GraphColor; }; +export type MarkerSchemaStyleColor = string | [string, string]; + +export type MarkerSchemaStyle = { + top: CssPixels; + height: CssPixels; + background: MarkerSchemaStyleColor; + squareCorners: boolean; + borderLeft: MarkerSchemaStyleColor | null; + borderRight: MarkerSchemaStyleColor | null; +}; + export type MarkerSchemaField = { // The property key of the marker data property that carries the field value. key: string; From 07edfc705b1de2bf7c7873ad33d033f87534dac1 Mon Sep 17 00:00:00 2001 From: fatadel Date: Tue, 1 Sep 2026 15:55:32 +0200 Subject: [PATCH 2/2] Move timeline marker styles into marker schemas Timeline rendering selects styles from a hardcoded table keyed by marker `data.type`. Putting the style in each schema removes that type-specific lookup and lets producers define marker appearance. --- docs-developer/CHANGELOG-formats.md | 4 + src/app-logic/constants.ts | 2 +- src/components/timeline/Markers.tsx | 43 +- src/profile-logic/gecko-profile-versioning.ts | 1 - src/profile-logic/import/chrome.ts | 3 + src/profile-logic/marker-schema.ts | 4 + src/profile-logic/marker-styles.ts | 22 +- src/profile-logic/process-profile.ts | 4 + .../processed-profile-versioning.ts | 6 + src/test/components/GlobalTrack.test.tsx | 2 + src/test/components/MarkerChart.test.tsx | 2 + .../components/TrackCustomMarker.test.tsx | 2 + src/test/fixtures/profiles/marker-schema.ts | 15 +- .../__snapshots__/profiler-edit.test.ts.snap | 8 +- .../__snapshots__/profile-view.test.ts.snap | 185 +++++- src/test/store/tracks.test.ts | 3 + .../profile-conversion.test.ts.snap | 36 +- .../profile-upgrading.test.ts.snap | 581 +++++++++++++++++- src/test/unit/marker-data.test.ts | 2 + src/test/unit/marker-schema.test.ts | 2 + src/test/unit/marker-styles.test.ts | 37 ++ src/test/unit/merge-compare.test.ts | 2 + src/test/unit/process-profile.test.ts | 29 + src/test/unit/profile-upgrading.test.ts | 30 + src/test/unit/sanitize.test.ts | 5 + src/types/gecko-profile.ts | 3 + src/types/markers.ts | 2 + 27 files changed, 988 insertions(+), 47 deletions(-) create mode 100644 src/test/unit/marker-styles.test.ts diff --git a/docs-developer/CHANGELOG-formats.md b/docs-developer/CHANGELOG-formats.md index dcbcb8f484..4ed2c5a31f 100644 --- a/docs-developer/CHANGELOG-formats.md +++ b/docs-developer/CHANGELOG-formats.md @@ -6,6 +6,10 @@ Note that this is not an exhaustive list. Processed profile format upgraders can ## Processed profile format +### Version 72 + +Marker schemas now include a `style` field that controls their appearance in timeline marker tracks. It specifies the marker's background, position, height, corner shape, and optional border colors. The upgrader derives styles for older profiles. + ### Version 71 The frame table (`profile.shared.frameTable`) representation changed in such a way that all its columns can now be typed arrays when using [JsonSlabs](https://github.com/mstange/json-slabs/) profiles. diff --git a/src/app-logic/constants.ts b/src/app-logic/constants.ts index e0f67bd2ff..034f51bdc5 100644 --- a/src/app-logic/constants.ts +++ b/src/app-logic/constants.ts @@ -12,7 +12,7 @@ export const GECKO_PROFILE_VERSION = 36; // 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 = 71; +export const PROCESSED_PROFILE_VERSION = 72; // 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/components/timeline/Markers.tsx b/src/components/timeline/Markers.tsx index 7bb3914d90..759b7329f8 100644 --- a/src/components/timeline/Markers.tsx +++ b/src/components/timeline/Markers.tsx @@ -10,12 +10,16 @@ import { getMarkerStyle, getMarkerStyleColor, } from 'firefox-profiler/profile-logic/marker-styles'; +import { getSchemaFromMarker } from 'firefox-profiler/profile-logic/marker-schema'; import { withSize } from 'firefox-profiler/components/shared/WithSize'; import { Tooltip } from 'firefox-profiler/components/tooltip/Tooltip'; import { TooltipMarker } from 'firefox-profiler/components/tooltip/Marker'; import { timeCode } from 'firefox-profiler/utils/time-code'; import explicitConnect from 'firefox-profiler/utils/connect'; -import { getPreviewSelectionIsBeingModified } from 'firefox-profiler/selectors/profile'; +import { + getMarkerSchemaByName, + getPreviewSelectionIsBeingModified, +} from 'firefox-profiler/selectors/profile'; import { getThreadSelectorsFromThreadsKey } from 'firefox-profiler/selectors/per-thread'; import { getSelectedThreadIndexes } from 'firefox-profiler/selectors/url-state'; import { changeRightClickedMarker } from 'firefox-profiler/actions/profile-view'; @@ -29,6 +33,7 @@ import type { Marker, MarkerIndex, MarkerDisplayLocation, + MarkerSchemaByName, ThreadsKey, } from 'firefox-profiler/types'; @@ -53,6 +58,7 @@ type CanvasProps = { readonly height: CssPixels; readonly getMarker: (param: MarkerIndex) => Marker; readonly markerIndexes: MarkerIndex[]; + readonly markerSchemaByName: MarkerSchemaByName; readonly hoveredMarker: Marker | null; readonly mouseDownMarker: Marker | null; readonly rightClickedMarker: Marker | null; @@ -110,8 +116,15 @@ class TimelineMarkersCanvas extends React.PureComponent { } drawCanvas(c: HTMLCanvasElement) { - const { rangeStart, rangeEnd, width, height, getMarker, markerIndexes } = - this.props; + const { + rangeStart, + rangeEnd, + width, + height, + getMarker, + markerIndexes, + markerSchemaByName, + } = this.props; if (height === 0 || width === 0) { // bail out early if the size isn't known yet. @@ -155,7 +168,8 @@ class TimelineMarkersCanvas extends React.PureComponent { MIN_MARKER_WIDTH / devicePixelRatio ) : Number.MAX_SAFE_INTEGER; - const markerStyle = getMarkerStyle(marker); + const markerSchema = getSchemaFromMarker(markerSchemaByName, marker.data); + const markerStyle = getMarkerStyle(marker.name, markerSchema); ctx.fillStyle = getMarkerStyleColor(markerStyle.background); if (markerStyle.squareCorners) { ctx.fillRect(pos, markerStyle.top, itemWidth, markerStyle.height); @@ -303,6 +317,7 @@ export type StateProps = { readonly additionalClassName?: string | null; readonly getMarker: (param: MarkerIndex) => Marker; readonly markerIndexes: MarkerIndex[]; + readonly markerSchemaByName: MarkerSchemaByName; readonly isSelected: boolean; readonly isModifyingSelection: boolean; readonly testId: string; @@ -333,8 +348,14 @@ class TimelineMarkers extends React.PureComponent { _hitTest(e: React.MouseEvent): MarkerIndex | null { const c = e.currentTarget; const r = c.getBoundingClientRect(); - const { width, rangeStart, rangeEnd, getMarker, markerIndexes } = - this.props; + const { + width, + rangeStart, + rangeEnd, + getMarker, + markerIndexes, + markerSchemaByName, + } = this.props; const x = e.pageX - r.left; const y = e.pageY - r.top; const rangeLength = rangeEnd - rangeStart; @@ -355,7 +376,8 @@ class TimelineMarkers extends React.PureComponent { continue; } - const markerStyle = getMarkerStyle(marker); + const markerSchema = getSchemaFromMarker(markerSchemaByName, marker.data); + const markerStyle = getMarkerStyle(marker.name, markerSchema); if (y >= markerStyle.top && y < markerStyle.top + markerStyle.height) { return markerIndex; @@ -492,6 +514,7 @@ class TimelineMarkers extends React.PureComponent { rangeEnd={this.props.rangeEnd} getMarker={this.props.getMarker} markerIndexes={this.props.markerIndexes} + markerSchemaByName={this.props.markerSchemaByName} hoveredMarker={hoveredMarker} mouseDownMarker={mouseDownMarker} rightClickedMarker={rightClickedMarker} @@ -540,6 +563,7 @@ export const TimelineMarkersJank = explicitConnect< return { getMarker: selectors.getMarkerGetter(state), + markerSchemaByName: getMarkerSchemaByName(state), // These don't use marker schema as they are derived. markerIndexes: selectors.getTimelineJankMarkerIndexes(state), isSelected: _getTimelineMarkersIsSelected(selectedThreads, threadsKey), @@ -570,6 +594,7 @@ export const TimelineMarkersOverview = explicitConnect< ? 'timelineMarkersGeckoMain' : null, getMarker: selectors.getMarkerGetter(state), + markerSchemaByName: getMarkerSchemaByName(state), markerIndexes: selectors.getTimelineOverviewMarkerIndexes(state), isSelected: _getTimelineMarkersIsSelected(selectedThreads, threadsKey), isModifyingSelection: getPreviewSelectionIsBeingModified(state), @@ -596,6 +621,7 @@ export const TimelineMarkersFileIo = explicitConnect< return { getMarker: selectors.getMarkerGetter(state), + markerSchemaByName: getMarkerSchemaByName(state), markerIndexes: selectors.getTimelineFileIoMarkerIndexes(state), isSelected: _getTimelineMarkersIsSelected(selectedThreads, threadsKey), isModifyingSelection: getPreviewSelectionIsBeingModified(state), @@ -622,6 +648,7 @@ export const TimelineMarkersMemory = explicitConnect< return { getMarker: selectors.getMarkerGetter(state), + markerSchemaByName: getMarkerSchemaByName(state), markerIndexes: selectors.getTimelineMemoryMarkerIndexes(state), isSelected: _getTimelineMarkersIsSelected(selectedThreads, threadsKey), isModifyingSelection: getPreviewSelectionIsBeingModified(state), @@ -649,6 +676,7 @@ export const TimelineMarkersIPC = explicitConnect< return { getMarker: selectors.getMarkerGetter(state), + markerSchemaByName: getMarkerSchemaByName(state), markerIndexes: selectors.getTimelineIPCMarkerIndexes(state), isSelected: _getTimelineMarkersIsSelected(selectedThreads, threadsKey), isModifyingSelection: getPreviewSelectionIsBeingModified(state), @@ -696,6 +724,7 @@ export const TimelineMarkersCounter = explicitConnect< return { getMarker: selectors.getMarkerGetter(state), + markerSchemaByName: getMarkerSchemaByName(state), markerIndexes: selectors.getTimelineMarkerIndexesBySchemaLocation( markerSchemaLocation diff --git a/src/profile-logic/gecko-profile-versioning.ts b/src/profile-logic/gecko-profile-versioning.ts index b14e769274..010513ce99 100644 --- a/src/profile-logic/gecko-profile-versioning.ts +++ b/src/profile-logic/gecko-profile-versioning.ts @@ -1578,7 +1578,6 @@ const _upgraders: { // marker schema. This bump is only here so that older frontends, which read // these two fields directly, get updated. }, - // If you add a new upgrader here, please document the change in // `docs-developer/CHANGELOG-formats.md`. }; diff --git a/src/profile-logic/import/chrome.ts b/src/profile-logic/import/chrome.ts index 06b723b68b..a0f87e664e 100644 --- a/src/profile-logic/import/chrome.ts +++ b/src/profile-logic/import/chrome.ts @@ -31,6 +31,7 @@ import { import { getTimeRangeForThread } from '../profile-data'; import { GlobalDataCollector } from '../global-data-collector'; +import { getMarkerSchemaStyleFallback } from '../marker-styles'; // Chrome Tracing Event Spec: // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview @@ -993,6 +994,7 @@ function extractMarkers( profile.meta.markerSchema = [ { name: 'EventDispatch', + style: getMarkerSchemaStyleFallback('EventDispatch'), chartLabel: '{marker.data.type2}', tooltipLabel: '{marker.data.type2} - EventDispatch', tableLabel: '{marker.data.type2}', @@ -1091,6 +1093,7 @@ function extractMarkers( // generates Source markers, ParseDeclarationOrFunctionDefinition markers, // and similar compiler events with file paths or location details. name: 'EventWithDetail', + style: getMarkerSchemaStyleFallback('EventWithDetail'), chartLabel: '{marker.data.detail}', tooltipLabel: '{marker.name}: {marker.data.detail}', tableLabel: '{marker.data.detail}', diff --git a/src/profile-logic/marker-schema.ts b/src/profile-logic/marker-schema.ts index 90a81d4333..096f780d07 100644 --- a/src/profile-logic/marker-schema.ts +++ b/src/profile-logic/marker-schema.ts @@ -28,6 +28,7 @@ import type { Pid, } from 'firefox-profiler/types'; import type { StringTable } from '../utils/string-table'; +import { getMarkerSchemaStyleFallback } from './marker-styles'; /** * The marker schema comes from Gecko, and is embedded in the profile. However, @@ -37,6 +38,7 @@ import type { StringTable } from '../utils/string-table'; export const markerSchemaFrontEndOnly: MarkerSchema[] = [ { name: 'Jank', + style: getMarkerSchemaStyleFallback('Jank'), display: ['marker-table', 'marker-chart'], tooltipLabel: 'Jank – event processing delay', tableLabel: 'Event processing delay', @@ -51,6 +53,7 @@ export const markerSchemaFrontEndOnly: MarkerSchema[] = [ // for IPC, the Gecko ones get overwritten by this definition. { name: 'IPC', + style: getMarkerSchemaStyleFallback('IPC'), tooltipLabel: 'IPC — {marker.data.niceDirection}', tableLabel: '{marker.data.messageType} — {marker.data.niceDirection}', chartLabel: '{marker.data.messageType}', @@ -68,6 +71,7 @@ export const markerSchemaFrontEndOnly: MarkerSchema[] = [ // `display` property is used to decide where to display these markers, and // we need it to hide them from the marker chart. name: 'Network', + style: getMarkerSchemaStyleFallback('Network'), display: ['marker-table', 'marker-chart', 'timeline-network'], chartLabel: '{marker.data.URI}', fields: [ diff --git a/src/profile-logic/marker-styles.ts b/src/profile-logic/marker-styles.ts index b00ae2139e..9436a34459 100644 --- a/src/profile-logic/marker-styles.ts +++ b/src/profile-logic/marker-styles.ts @@ -5,7 +5,7 @@ import * as colors from 'photon-colors'; import type { - Marker, + MarkerSchema, MarkerSchemaStyle, MarkerSchemaStyleColor, } from 'firefox-profiler/types'; @@ -33,21 +33,23 @@ const ccStyle = { background: '#ffc600', }; -export function getMarkerStyle(marker: Marker): MarkerSchemaStyle { - const { data, name } = marker; - if (name in markerStyles) { - return markerStyles[name]; - } - if (data && data.type in markerStyles) { - return markerStyles[data.type]; - } - return defaultStyle; +export function getMarkerStyle( + markerName: string, + markerSchema: MarkerSchema | null +): MarkerSchemaStyle { + return markerStyles[markerName] ?? markerSchema?.style ?? defaultStyle; } export function getMarkerStyleColor(color: MarkerSchemaStyleColor): string { return maybeLightDark(color); } +export function getMarkerSchemaStyleFallback( + schemaName: string +): MarkerSchemaStyle { + return markerStyles[schemaName] ?? defaultStyle; +} + const markerStyles: { readonly [styleName: string]: MarkerSchemaStyle } = { RefreshDriverTick: { ...defaultStyle, diff --git a/src/profile-logic/process-profile.ts b/src/profile-logic/process-profile.ts index 8be48440cb..46c729989c 100644 --- a/src/profile-logic/process-profile.ts +++ b/src/profile-logic/process-profile.ts @@ -124,6 +124,7 @@ import type { CounterDisplayConfig, RawProfileSharedData, } from 'firefox-profiler/types'; +import { getMarkerSchemaStyleFallback } from './marker-styles'; import { FrameFlag } from 'firefox-profiler/types'; import { decompress, isGzip } from 'firefox-profiler/utils/gz'; import { jsonEncodeObjectWithTypedArraysAsRegularArrays } from 'firefox-profiler/utils/json-with-typed-arrays'; @@ -1685,6 +1686,7 @@ function _convertGeckoMarkerSchema( display, data, graphs, + style, colorField, isStackBased, } = markerSchema; @@ -1731,6 +1733,7 @@ function _convertGeckoMarkerSchema( fields, description, graphs, + style: style ?? getMarkerSchemaStyleFallback(name), colorField, isStackBased, }; @@ -2628,6 +2631,7 @@ export function processVisualMetrics( // Add progress markers for every visual progress change for more fine grained information. const progressMarkerSchema: MarkerSchema = { name: 'VisualMetricProgress', + style: getMarkerSchemaStyleFallback('VisualMetricProgress'), tableLabel: '{marker.name} — {marker.data.percentage}', display: ['marker-chart', 'marker-table'], fields: [ diff --git a/src/profile-logic/processed-profile-versioning.ts b/src/profile-logic/processed-profile-versioning.ts index c009bd052d..93efdd51b3 100644 --- a/src/profile-logic/processed-profile-versioning.ts +++ b/src/profile-logic/processed-profile-versioning.ts @@ -20,6 +20,7 @@ import { timeCode } from '../utils/time-code'; import { PROCESSED_PROFILE_VERSION } from '../app-logic/constants'; import { ProfileVersionError } from './errors'; import type { Profile } from 'firefox-profiler/types'; +import { getMarkerSchemaStyleFallback } from './marker-styles'; export type ProfileUpgradeInfo = { v60?: ProfileV60UpgradeInfo; @@ -3433,6 +3434,11 @@ const _upgraders: { frameTable.address = new Uint32Array(frameTable.address); } }, + [72]: (profile: any) => { + for (const schema of profile.meta.markerSchema) { + schema.style ??= getMarkerSchemaStyleFallback(schema.name); + } + }, // If you add a new upgrader here, please document the change in // `docs-developer/CHANGELOG-formats.md`. }; diff --git a/src/test/components/GlobalTrack.test.tsx b/src/test/components/GlobalTrack.test.tsx index 1f73373e8a..b5ee0ec024 100644 --- a/src/test/components/GlobalTrack.test.tsx +++ b/src/test/components/GlobalTrack.test.tsx @@ -32,6 +32,7 @@ import { autoMockElementSize } from '../fixtures/mocks/element-size'; import { mockRaf } from '../fixtures/mocks/request-animation-frame'; import { autoMockIntersectionObserver } from '../fixtures/mocks/intersection-observer'; import { selectedThreadSelectors } from '../../selectors/per-thread'; +import { getMarkerSchemaStyleFallback } from '../../profile-logic/marker-styles'; describe('timeline/GlobalTrack', function () { autoMockCanvasContext(); @@ -272,6 +273,7 @@ describe('timeline/GlobalTrack', function () { profile.meta.markerSchema = [ { name: 'task', + style: getMarkerSchemaStyleFallback('task'), display: ['timeline-overview'], fields: [], }, diff --git a/src/test/components/MarkerChart.test.tsx b/src/test/components/MarkerChart.test.tsx index d789a8f5e6..27db823ce4 100644 --- a/src/test/components/MarkerChart.test.tsx +++ b/src/test/components/MarkerChart.test.tsx @@ -51,6 +51,7 @@ import { } from '../fixtures/utils'; import { mockRaf } from '../fixtures/mocks/request-animation-frame'; import { autoMockElementSize } from '../fixtures/mocks/element-size'; +import { getMarkerSchemaStyleFallback } from '../../profile-logic/marker-styles'; import type { CssPixels, Profile } from 'firefox-profiler/types'; @@ -807,6 +808,7 @@ describe('MarkerChart', function () { profile.meta.markerSchema = [ { name: 'Test', + style: getMarkerSchemaStyleFallback('Test'), display: ['marker-chart', 'marker-table'], fields: [ { key: 'status', label: 'Status', format: 'string' }, diff --git a/src/test/components/TrackCustomMarker.test.tsx b/src/test/components/TrackCustomMarker.test.tsx index 65185e65f9..170c7edcb9 100644 --- a/src/test/components/TrackCustomMarker.test.tsx +++ b/src/test/components/TrackCustomMarker.test.tsx @@ -37,6 +37,7 @@ import { triggerIntersectionObservers, } from '../fixtures/mocks/intersection-observer'; import { triggerResizeObservers } from '../fixtures/mocks/resize-observer'; +import { getMarkerSchemaStyleFallback } from '../../profile-logic/marker-styles'; // The following constants determine the size of the drawn graph. const SAMPLE_COUNT = 8; @@ -62,6 +63,7 @@ function setup( const thread = profile.threads[threadIndex]; profile.meta.markerSchema.push({ name: 'Marker', + style: getMarkerSchemaStyleFallback('Marker'), display: ['marker-chart', 'marker-table', 'timeline-memory'], fields: [ { key: 'first', label: 'first', format: 'integer' }, diff --git a/src/test/fixtures/profiles/marker-schema.ts b/src/test/fixtures/profiles/marker-schema.ts index 00dc94843b..ddfe0ffff8 100644 --- a/src/test/fixtures/profiles/marker-schema.ts +++ b/src/test/fixtures/profiles/marker-schema.ts @@ -2,8 +2,9 @@ * 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 { MarkerSchema } from 'firefox-profiler/types'; +import { getMarkerSchemaStyleFallback } from '../../../profile-logic/marker-styles'; -export const markerSchemaForTests: MarkerSchema[] = [ +const markerSchemasWithoutStyle: Array> = [ { name: 'GCMajor', display: ['marker-chart', 'marker-table', 'timeline-memory'], @@ -193,3 +194,15 @@ export const markerSchemaForTests: MarkerSchema[] = [ ], }, ]; + +function getMarkerSchemaWithStyle( + schema: Omit +): MarkerSchema { + return { + ...schema, + style: getMarkerSchemaStyleFallback(schema.name), + }; +} + +export const markerSchemaForTests: MarkerSchema[] = + markerSchemasWithoutStyle.map(getMarkerSchemaWithStyle); 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 27af272e13..cfec2157bc 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": 71, + "preprocessedProfileVersion": 72, "processType": 0, "product": "a.out", "sampleUnits": Object { @@ -1488,7 +1488,7 @@ Object { "markerSchema": Array [], "oscpu": "macOS 14.6.1", "pausedRanges": Array [], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "processType": 0, "product": "a.out", "sampleUnits": Object { @@ -2889,7 +2889,7 @@ Object { "markerSchema": Array [], "oscpu": "macOS 14.6.1", "pausedRanges": Array [], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "processType": 0, "product": "a.out", "sampleUnits": Object { @@ -4290,7 +4290,7 @@ Object { "markerSchema": Array [], "oscpu": "macOS 14.6.1", "pausedRanges": Array [], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "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 92fd2e39d8..b431b97f49 100644 --- a/src/test/store/__snapshots__/profile-view.test.ts.snap +++ b/src/test/store/__snapshots__/profile-view.test.ts.snap @@ -88,6 +88,14 @@ Object { ], "fields": Array [], "name": "GCMajor", + "style": Object { + "background": "#ff9400", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": true, + "top": 0, + }, }, Object { "display": Array [ @@ -97,6 +105,14 @@ Object { ], "fields": Array [], "name": "GCMinor", + "style": Object { + "background": "#ff9400", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 6, + }, }, Object { "display": Array [ @@ -106,6 +122,14 @@ Object { ], "fields": Array [], "name": "GCSlice", + "style": Object { + "background": "#ff9400", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 6, + }, }, Object { "display": Array [ @@ -115,6 +139,14 @@ Object { ], "fields": Array [], "name": "CC", + "style": Object { + "background": "#ffc600", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": true, + "top": 0, + }, "tooltipLabel": "Cycle Collect", }, Object { @@ -140,6 +172,14 @@ Object { }, ], "name": "FileIO", + "style": Object { + "background": "#0a84ff", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -159,6 +199,17 @@ Object { }, ], "name": "MediaSample", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -194,6 +245,17 @@ Object { }, ], "name": "Styles", + "style": Object { + "background": Array [ + "#00feff", + "#008ea4", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 7, + }, }, Object { "display": Array [ @@ -223,6 +285,17 @@ Object { }, ], "name": "PreferenceRead", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "chartLabel": "{marker.data.name}", @@ -244,6 +317,17 @@ Object { }, ], "name": "UserTiming", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.data.name}", "tooltipLabel": "{marker.data.name}", }, @@ -261,6 +345,17 @@ Object { }, ], "name": "Text", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.name} — {marker.data.name}", }, Object { @@ -290,6 +385,17 @@ Object { }, ], "name": "Log", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "({marker.data.module}) {marker.data.name}", }, Object { @@ -312,6 +418,17 @@ Object { }, ], "name": "DOMEvent", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.data.eventType}", "tooltipLabel": "{marker.data.eventType} — DOMEvent", }, @@ -329,6 +446,17 @@ Object { }, ], "name": "tracing", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -344,6 +472,17 @@ Object { }, ], "name": "Layout", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "chartLabel": "{marker.data.messageType}", @@ -375,6 +514,17 @@ Object { }, ], "name": "IPC", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.name} — {marker.data.messageType} — {marker.data.niceDirection}", "tooltipLabel": "IPC — {marker.data.niceDirection}", }, @@ -386,6 +536,17 @@ Object { ], "fields": Array [], "name": "VisibleInTimelineOverview", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -406,6 +567,17 @@ Object { }, ], "name": "StringTesting", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -422,13 +594,24 @@ Object { }, ], "name": "MarkerWithHiddenField", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, ], "misc": "", "oscpu": "", "physicalCPUs": 0, "platform": "", - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "processType": 0, "product": "Firefox", "sourceURL": "", diff --git a/src/test/store/tracks.test.ts b/src/test/store/tracks.test.ts index 4a128f35be..e5cb18b56f 100644 --- a/src/test/store/tracks.test.ts +++ b/src/test/store/tracks.test.ts @@ -33,6 +33,7 @@ import { isolateProcessMainThread, } from '../../actions/profile-view'; import type { MarkerSchema } from 'firefox-profiler/types'; +import { getMarkerSchemaStyleFallback } from '../../profile-logic/marker-styles'; describe('ordering and hiding', function () { function init(profile = getProfileWithNiceTracks()) { @@ -137,6 +138,7 @@ describe('ordering and hiding', function () { const extraMarkerSchemas: MarkerSchema[] = [ { name: 'Marker', + style: getMarkerSchemaStyleFallback('Marker'), display: ['marker-chart', 'marker-table', 'timeline-memory'], fields: [{ key: 'first', label: 'first', format: 'integer' }], graphs: [ @@ -148,6 +150,7 @@ describe('ordering and hiding', function () { }, { name: 'NoGraphMarker', + style: getMarkerSchemaStyleFallback('NoGraphMarker'), display: ['marker-chart', 'marker-table'], fields: [{ key: 'first', label: 'first', format: 'integer' }], // An empty array should behave just as if the property isn't present. diff --git a/src/test/unit/__snapshots__/profile-conversion.test.ts.snap b/src/test/unit/__snapshots__/profile-conversion.test.ts.snap index 46f5bf9b8e..3bffbb2edf 100644 --- a/src/test/unit/__snapshots__/profile-conversion.test.ts.snap +++ b/src/test/unit/__snapshots__/profile-conversion.test.ts.snap @@ -42,7 +42,7 @@ Object { "RefreshDriverTick", "Network", ], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "ART Trace (Android)", "symbolicated": true, "version": 36, @@ -1022,7 +1022,7 @@ Object { "RefreshDriverTick", "Network", ], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "ART Trace (Android)", "symbolicated": true, "version": 36, @@ -2305,7 +2305,7 @@ Object { "markerSchemaNames": Array [ "EventDispatch", ], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "Chrome Trace", "symbolicated": true, "version": 36, @@ -2697,7 +2697,7 @@ Object { "markerSchemaNames": Array [ "EventDispatch", ], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "Chrome Trace", "symbolicated": true, "version": 36, @@ -3086,7 +3086,7 @@ Object { "markerSchemaNames": Array [ "EventDispatch", ], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "Chrome Trace", "symbolicated": true, "version": 36, @@ -3187,7 +3187,7 @@ Object { "markerSchemaNames": Array [ "EventDispatch", ], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "Chrome Trace", "symbolicated": true, "version": 36, @@ -3540,7 +3540,7 @@ Object { "markerSchemaNames": Array [ "EventDispatch", ], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "Chrome Trace", "symbolicated": true, "version": 36, @@ -3605,7 +3605,7 @@ Object { "markerSchemaNames": Array [ "EventDispatch", ], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "Chrome Trace", "symbolicated": true, "version": 36, @@ -3759,7 +3759,7 @@ Object { "markerSchemaNames": Array [ "EventDispatch", ], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "Chrome Trace", "symbolicated": true, "version": 36, @@ -3817,7 +3817,7 @@ Object { "importedFrom": undefined, "interval": 1, "markerSchemaNames": Array [], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "Firefox", "symbolicated": true, "version": 36, @@ -4207,7 +4207,7 @@ Object { "importedFrom": undefined, "interval": 1, "markerSchemaNames": Array [], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "Firefox", "symbolicated": true, "version": 36, @@ -4265,7 +4265,7 @@ Object { "importedFrom": undefined, "interval": 1, "markerSchemaNames": Array [], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "Firefox", "symbolicated": true, "version": 36, @@ -4323,7 +4323,7 @@ Object { "importedFrom": undefined, "interval": 1, "markerSchemaNames": Array [], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "Firefox", "symbolicated": true, "version": 36, @@ -4643,7 +4643,7 @@ Object { "importedFrom": "Simpleperf", "interval": 0, "markerSchemaNames": Array [], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "com.example.sampleapplication", "symbolicated": undefined, "version": 30, @@ -5019,7 +5019,7 @@ Object { "importedFrom": "Simpleperf", "interval": 0, "markerSchemaNames": Array [], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "com.example.sampleapplication", "symbolicated": undefined, "version": 30, @@ -5319,7 +5319,7 @@ Object { "importedFrom": "dhat", "interval": 1, "markerSchemaNames": Array [], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "target/debug/examples/work_log (dhat)", "symbolicated": true, "version": 36, @@ -5452,7 +5452,7 @@ Object { "importedFrom": undefined, "interval": 1, "markerSchemaNames": Array [], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "Flamegraph", "symbolicated": true, "version": 36, @@ -5510,7 +5510,7 @@ Object { "importedFrom": undefined, "interval": 1, "markerSchemaNames": Array [], - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "product": "Flamegraph", "symbolicated": true, "version": 36, diff --git a/src/test/unit/__snapshots__/profile-upgrading.test.ts.snap b/src/test/unit/__snapshots__/profile-upgrading.test.ts.snap index 4d039c9117..9c77d8b47b 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": 71, + "preprocessedProfileVersion": 72, "processType": 0, "product": "Firefox", "sampleUnits": undefined, @@ -7497,6 +7497,14 @@ Object { ], "fields": Array [], "name": "GCMajor", + "style": Object { + "background": "#ff9400", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": true, + "top": 0, + }, }, Object { "display": Array [ @@ -7506,6 +7514,14 @@ Object { ], "fields": Array [], "name": "GCMinor", + "style": Object { + "background": "#ff9400", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 6, + }, }, Object { "display": Array [ @@ -7515,6 +7531,14 @@ Object { ], "fields": Array [], "name": "GCSlice", + "style": Object { + "background": "#ff9400", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 6, + }, }, Object { "display": Array [ @@ -7524,6 +7548,14 @@ Object { ], "fields": Array [], "name": "CC", + "style": Object { + "background": "#ffc600", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": true, + "top": 0, + }, "tooltipLabel": "Cycle Collect", }, Object { @@ -7554,6 +7586,14 @@ Object { }, ], "name": "FileIO", + "style": Object { + "background": "#0a84ff", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -7573,6 +7613,17 @@ Object { }, ], "name": "MediaSample", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -7608,6 +7659,17 @@ Object { }, ], "name": "Styles", + "style": Object { + "background": Array [ + "#00feff", + "#008ea4", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 7, + }, }, Object { "display": Array [ @@ -7637,6 +7699,17 @@ Object { }, ], "name": "PreferenceRead", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "chartLabel": "{marker.data.name}", @@ -7653,6 +7726,17 @@ Object { }, ], "name": "UserTiming", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.data.name}", "tooltipLabel": "{marker.data.name}", }, @@ -7670,6 +7754,17 @@ Object { }, ], "name": "Text", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.name} — {marker.data.name}", }, Object { @@ -7689,6 +7784,17 @@ Object { }, ], "name": "Log", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "({marker.data.module}) {marker.data.name}", }, Object { @@ -7711,6 +7817,17 @@ Object { }, ], "name": "DOMEvent", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.data.eventType}", "tooltipLabel": "{marker.data.eventType} — DOMEvent", }, @@ -7728,6 +7845,17 @@ Object { }, ], "name": "Paint", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -7743,6 +7871,17 @@ Object { }, ], "name": "Navigation", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -7758,6 +7897,17 @@ Object { }, ], "name": "Layout", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "chartLabel": "{marker.data.messageType}", @@ -7789,6 +7939,17 @@ Object { }, ], "name": "IPC", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.name} — {marker.data.messageType} — {marker.data.niceDirection}", "tooltipLabel": "IPC — {marker.data.niceDirection}", }, @@ -7806,6 +7967,14 @@ Object { }, ], "name": "RefreshDriverTick", + "style": Object { + "background": "rgba(237, 237, 240, 0.05)", + "borderLeft": null, + "borderRight": null, + "height": 18, + "squareCorners": true, + "top": 0, + }, }, Object { "display": Array [ @@ -7814,6 +7983,17 @@ Object { ], "fields": Array [], "name": "Network", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -7829,12 +8009,23 @@ Object { }, ], "name": "tracing", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, ], "misc": "rv:48.0", "oscpu": "Intel Mac OS X 10.11", "platform": "Macintosh", - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "processType": 0, "product": "Firefox", "stackwalk": 1, @@ -8892,6 +9083,14 @@ Object { ], "fields": Array [], "name": "GCMajor", + "style": Object { + "background": "#ff9400", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": true, + "top": 0, + }, }, Object { "display": Array [ @@ -8901,6 +9100,14 @@ Object { ], "fields": Array [], "name": "GCMinor", + "style": Object { + "background": "#ff9400", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 6, + }, }, Object { "display": Array [ @@ -8910,6 +9117,14 @@ Object { ], "fields": Array [], "name": "GCSlice", + "style": Object { + "background": "#ff9400", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 6, + }, }, Object { "display": Array [ @@ -8919,6 +9134,14 @@ Object { ], "fields": Array [], "name": "CC", + "style": Object { + "background": "#ffc600", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": true, + "top": 0, + }, "tooltipLabel": "Cycle Collect", }, Object { @@ -8949,6 +9172,14 @@ Object { }, ], "name": "FileIO", + "style": Object { + "background": "#0a84ff", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -8968,6 +9199,17 @@ Object { }, ], "name": "MediaSample", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -9003,6 +9245,17 @@ Object { }, ], "name": "Styles", + "style": Object { + "background": Array [ + "#00feff", + "#008ea4", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 7, + }, }, Object { "display": Array [ @@ -9032,6 +9285,17 @@ Object { }, ], "name": "PreferenceRead", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "chartLabel": "{marker.data.name}", @@ -9048,6 +9312,17 @@ Object { }, ], "name": "UserTiming", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.data.name}", "tooltipLabel": "{marker.data.name}", }, @@ -9065,6 +9340,17 @@ Object { }, ], "name": "Text", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.name} — {marker.data.name}", }, Object { @@ -9084,6 +9370,17 @@ Object { }, ], "name": "Log", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "({marker.data.module}) {marker.data.name}", }, Object { @@ -9106,6 +9403,17 @@ Object { }, ], "name": "DOMEvent", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.data.eventType}", "tooltipLabel": "{marker.data.eventType} — DOMEvent", }, @@ -9123,6 +9431,17 @@ Object { }, ], "name": "Paint", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -9138,6 +9457,17 @@ Object { }, ], "name": "Navigation", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -9153,6 +9483,17 @@ Object { }, ], "name": "Layout", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "chartLabel": "{marker.data.messageType}", @@ -9184,6 +9525,17 @@ Object { }, ], "name": "IPC", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.name} — {marker.data.messageType} — {marker.data.niceDirection}", "tooltipLabel": "IPC — {marker.data.niceDirection}", }, @@ -9201,6 +9553,14 @@ Object { }, ], "name": "RefreshDriverTick", + "style": Object { + "background": "rgba(237, 237, 240, 0.05)", + "borderLeft": null, + "borderRight": null, + "height": 18, + "squareCorners": true, + "top": 0, + }, }, Object { "display": Array [ @@ -9209,6 +9569,17 @@ Object { ], "fields": Array [], "name": "Network", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -9224,12 +9595,23 @@ Object { }, ], "name": "tracing", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, ], "misc": "rv:48.0", "oscpu": "Intel Mac OS X 10.11", "platform": "Macintosh", - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "processType": 0, "product": "Firefox", "stackwalk": 1, @@ -10457,6 +10839,14 @@ Object { ], "fields": Array [], "name": "GCMajor", + "style": Object { + "background": "#ff9400", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": true, + "top": 0, + }, }, Object { "display": Array [ @@ -10466,6 +10856,14 @@ Object { ], "fields": Array [], "name": "GCMinor", + "style": Object { + "background": "#ff9400", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 6, + }, }, Object { "display": Array [ @@ -10475,6 +10873,14 @@ Object { ], "fields": Array [], "name": "GCSlice", + "style": Object { + "background": "#ff9400", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 6, + }, }, Object { "display": Array [ @@ -10484,6 +10890,14 @@ Object { ], "fields": Array [], "name": "CC", + "style": Object { + "background": "#ffc600", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": true, + "top": 0, + }, "tooltipLabel": "Cycle Collect", }, Object { @@ -10514,6 +10928,14 @@ Object { }, ], "name": "FileIO", + "style": Object { + "background": "#0a84ff", + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -10533,6 +10955,17 @@ Object { }, ], "name": "MediaSample", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -10568,6 +11001,17 @@ Object { }, ], "name": "Styles", + "style": Object { + "background": Array [ + "#00feff", + "#008ea4", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 7, + }, }, Object { "display": Array [ @@ -10597,6 +11041,17 @@ Object { }, ], "name": "PreferenceRead", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "chartLabel": "{marker.data.name}", @@ -10613,6 +11068,17 @@ Object { }, ], "name": "UserTiming", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.data.name}", "tooltipLabel": "{marker.data.name}", }, @@ -10630,6 +11096,17 @@ Object { }, ], "name": "Text", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.name} — {marker.data.name}", }, Object { @@ -10649,6 +11126,17 @@ Object { }, ], "name": "Log", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "({marker.data.module}) {marker.data.name}", }, Object { @@ -10671,6 +11159,17 @@ Object { }, ], "name": "DOMEvent", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.data.eventType}", "tooltipLabel": "{marker.data.eventType} — DOMEvent", }, @@ -10688,6 +11187,17 @@ Object { }, ], "name": "Paint", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -10703,6 +11213,17 @@ Object { }, ], "name": "Navigation", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -10718,6 +11239,17 @@ Object { }, ], "name": "Layout", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "chartLabel": "{marker.data.messageType}", @@ -10749,6 +11281,17 @@ Object { }, ], "name": "IPC", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, "tableLabel": "{marker.name} — {marker.data.messageType} — {marker.data.niceDirection}", "tooltipLabel": "IPC — {marker.data.niceDirection}", }, @@ -10766,6 +11309,14 @@ Object { }, ], "name": "RefreshDriverTick", + "style": Object { + "background": "rgba(237, 237, 240, 0.05)", + "borderLeft": null, + "borderRight": null, + "height": 18, + "squareCorners": true, + "top": 0, + }, }, Object { "display": Array [ @@ -10774,6 +11325,17 @@ Object { ], "fields": Array [], "name": "Network", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, Object { "display": Array [ @@ -10789,12 +11351,23 @@ Object { }, ], "name": "tracing", + "style": Object { + "background": Array [ + "black", + "#b1b1b3", + ], + "borderLeft": null, + "borderRight": null, + "height": 6, + "squareCorners": false, + "top": 0, + }, }, ], "misc": "rv:48.0", "oscpu": "Intel Mac OS X 10.11", "platform": "Macintosh", - "preprocessedProfileVersion": 71, + "preprocessedProfileVersion": 72, "processType": 0, "product": "Firefox", "stackwalk": 1, diff --git a/src/test/unit/marker-data.test.ts b/src/test/unit/marker-data.test.ts index 9a5d06beff..9d15e92b0c 100644 --- a/src/test/unit/marker-data.test.ts +++ b/src/test/unit/marker-data.test.ts @@ -36,6 +36,7 @@ import { } from '../fixtures/profiles/processed-profile'; import { storeWithProfile } from '../fixtures/stores'; import { getEmptySharedData } from '../../profile-logic/data-structures'; +import { getMarkerSchemaStyleFallback } from '../../profile-logic/marker-styles'; import type { IndexIntoRawMarkerTable, @@ -1407,6 +1408,7 @@ describe('formatLogStatement', function () { function logSchema(messageFormat: MarkerFormatType): MarkerSchema { return { name: 'Log', + style: getMarkerSchemaStyleFallback('Log'), display: ['marker-chart', 'marker-table'], fields: [ { key: 'level', label: 'Level', format: 'unique-string' }, diff --git a/src/test/unit/marker-schema.test.ts b/src/test/unit/marker-schema.test.ts index 31f7ed8dd2..ff6c8c19c4 100644 --- a/src/test/unit/marker-schema.test.ts +++ b/src/test/unit/marker-schema.test.ts @@ -19,6 +19,7 @@ import { getMarkerSchema } from '../../selectors/profile'; import { getProfileFromTextSamples } from '../fixtures/profiles/processed-profile'; import { markerSchemaForTests } from '../fixtures/profiles/marker-schema'; import { StringTable } from '../../utils/string-table'; +import { getMarkerSchemaStyleFallback } from '../../profile-logic/marker-styles'; /** * Generally, higher level type of testing is preferred to detailed unit tests of @@ -47,6 +48,7 @@ describe('marker schema labels', function () { const schema = { name: 'TestDefinedMarker', + style: getMarkerSchemaStyleFallback('TestDefinedMarker'), display: [], fields: schemaFields, }; diff --git a/src/test/unit/marker-styles.test.ts b/src/test/unit/marker-styles.test.ts new file mode 100644 index 0000000000..23e6e3cbf0 --- /dev/null +++ b/src/test/unit/marker-styles.test.ts @@ -0,0 +1,37 @@ +/* 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 { getMarkerStyle } from '../../profile-logic/marker-styles'; +import type { MarkerSchema, MarkerSchemaStyle } from 'firefox-profiler/types'; + +describe('getMarkerStyle', function () { + const schemaStyle: MarkerSchemaStyle = { + top: 3, + height: 9, + background: 'pink', + squareCorners: true, + borderLeft: null, + borderRight: 'purple', + }; + const markerSchema: MarkerSchema = { + name: 'CustomMarker', + display: ['timeline-overview'], + fields: [], + style: schemaStyle, + }; + + it('uses the schema style for markers without a name override', function () { + expect(getMarkerStyle('Dynamic marker name', markerSchema)).toBe( + schemaStyle + ); + }); + + it('keeps marker name overrides ahead of the schema style', function () { + expect(getMarkerStyle('Reflow', markerSchema)).toMatchObject({ + top: 7, + height: 6, + squareCorners: false, + }); + }); +}); diff --git a/src/test/unit/merge-compare.test.ts b/src/test/unit/merge-compare.test.ts index f565e08bc2..9d46f22cae 100644 --- a/src/test/unit/merge-compare.test.ts +++ b/src/test/unit/merge-compare.test.ts @@ -27,6 +27,7 @@ import { getThreadSelectors, selectedThreadSelectors, } from '../../selectors/per-thread'; +import { getMarkerSchemaStyleFallback } from '../../profile-logic/marker-styles'; describe('mergeProfilesForDiffing function', function () { it('merges the various tables properly in the diffing profile', function () { @@ -779,6 +780,7 @@ describe('mergeThreads function', function () { const { profile, stringTable } = getProfileFromTextSamples(`A`, `B`); profile.meta.markerSchema.push({ name: 'testSchemaWithUniqueUrlField', + style: getMarkerSchemaStyleFallback('testSchemaWithUniqueUrlField'), display: [], fields: [{ key: 'fieldWithUniqueString', format: 'unique-string' }], }); diff --git a/src/test/unit/process-profile.test.ts b/src/test/unit/process-profile.test.ts index 6bd72e94d1..7613db7293 100644 --- a/src/test/unit/process-profile.test.ts +++ b/src/test/unit/process-profile.test.ts @@ -22,6 +22,7 @@ import { getVisualMetrics, } from '../fixtures/profiles/gecko-profile'; import { ensureExists } from '../../utils/types'; +import { getMarkerSchemaStyleFallback } from '../../profile-logic/marker-styles'; import type { JsAllocationPayload_Gecko, NativeAllocationPayload_Gecko, @@ -1111,6 +1112,19 @@ describe('Marker schema conversion', function () { { key: 'color', label: 'Color', format: 'string' }, ], colorField: 'color', + }, + { + name: 'TestMarkerWithStyle', + display: ['timeline-overview'], + data: [], + style: { + top: 2, + height: 8, + background: ['blue', 'lightblue'], + squareCorners: true, + borderLeft: 'navy', + borderRight: null, + }, } ); @@ -1128,6 +1142,9 @@ describe('Marker schema conversion', function () { expect(schemaMinimal?.colorField).toBeUndefined(); expect(schemaMinimal?.graphs).toBeUndefined(); expect(schemaMinimal?.isStackBased).toBeUndefined(); + expect(schemaMinimal?.style).toEqual( + getMarkerSchemaStyleFallback('TestMarkerMinimal') + ); // Test labels are preserved const schemaWithLabels = processedProfile.meta.markerSchema.find( @@ -1153,5 +1170,17 @@ describe('Marker schema conversion', function () { ); expect(schemaWithColor).toBeDefined(); expect(schemaWithColor?.colorField).toBe('color'); + + const schemaWithStyle = processedProfile.meta.markerSchema.find( + (s) => s.name === 'TestMarkerWithStyle' + ); + expect(schemaWithStyle?.style).toEqual({ + top: 2, + height: 8, + background: ['blue', 'lightblue'], + squareCorners: true, + borderLeft: 'navy', + borderRight: null, + }); }); }); diff --git a/src/test/unit/profile-upgrading.test.ts b/src/test/unit/profile-upgrading.test.ts index 50a7d6ceaa..4943adb1b6 100644 --- a/src/test/unit/profile-upgrading.test.ts +++ b/src/test/unit/profile-upgrading.test.ts @@ -7,6 +7,8 @@ import { serializeProfileToJsonString, } from '../../profile-logic/process-profile'; import { upgradeGeckoProfileToCurrentVersion } from '../../profile-logic/gecko-profile-versioning'; +import { attemptToUpgradeProcessedProfileThroughMutation } from '../../profile-logic/processed-profile-versioning'; +import { getMarkerSchemaStyleFallback } from '../../profile-logic/marker-styles'; import { GECKO_PROFILE_VERSION, PROCESSED_PROFILE_VERSION, @@ -134,6 +136,34 @@ describe('upgrading processed profiles', function () { require('../fixtures/upgrades/processed-3.json') ); }); + + it('adds required marker styles while preserving existing styles', function () { + const existingStyle = { + top: 2, + height: 8, + background: 'pink', + squareCorners: true, + borderLeft: null, + borderRight: null, + }; + const profile: any = { + meta: { + preprocessedProfileVersion: 71, + markerSchema: [ + { name: 'GCMajor' }, + { name: 'Custom', style: existingStyle }, + ], + }, + threads: [], + }; + + attemptToUpgradeProcessedProfileThroughMutation(profile, {}); + + expect(profile.meta.markerSchema[0].style).toEqual( + getMarkerSchemaStyleFallback('GCMajor') + ); + expect(profile.meta.markerSchema[1].style).toBe(existingStyle); + }); }); describe('importing perf profile', function () { diff --git a/src/test/unit/sanitize.test.ts b/src/test/unit/sanitize.test.ts index 9af63ef369..9f3f169300 100644 --- a/src/test/unit/sanitize.test.ts +++ b/src/test/unit/sanitize.test.ts @@ -33,6 +33,7 @@ import { import { ValueSummaryReader } from 'devtools-reps'; import { StringTable } from 'firefox-profiler/utils/string-table'; import { FrameFlag } from 'firefox-profiler/types'; +import { getMarkerSchemaStyleFallback } from '../../profile-logic/marker-styles'; import type { MarkerSchemaByName, RawThread, @@ -85,6 +86,7 @@ describe('sanitizePII', function () { const markerSchemaByName: MarkerSchemaByName = { FileIO: { name: 'FileIO', + style: getMarkerSchemaStyleFallback('FileIO'), display: ['marker-chart', 'marker-table', 'timeline-fileio'], fields: [ { @@ -111,6 +113,7 @@ describe('sanitizePII', function () { }, Url: { name: 'Url', + style: getMarkerSchemaStyleFallback('Url'), tableLabel: '{marker.name} - {marker.data.url}', display: ['marker-chart', 'marker-table'], fields: [ @@ -122,6 +125,7 @@ describe('sanitizePII', function () { }, HostResolver: { name: 'HostResolver', + style: getMarkerSchemaStyleFallback('HostResolver'), tableLabel: '{marker.name} - {marker.data.host}', display: ['marker-chart', 'marker-table'], fields: [ @@ -169,6 +173,7 @@ describe('sanitizePII', function () { const uniqueStringTextSchema: MarkerSchemaByName = { Text: { name: 'Text', + style: getMarkerSchemaStyleFallback('Text'), tableLabel: '{marker.name} — {marker.data.name}', display: ['marker-chart', 'marker-table'], fields: [{ key: 'name', label: 'Details', format: 'unique-string' }], diff --git a/src/types/gecko-profile.ts b/src/types/gecko-profile.ts index af50ef66dd..6d099329a7 100644 --- a/src/types/gecko-profile.ts +++ b/src/types/gecko-profile.ts @@ -19,6 +19,7 @@ import type { MarkerDisplayLocation, MarkerFormatType, MarkerGraph, + MarkerSchemaStyle, } from './markers'; import type { Milliseconds, Nanoseconds, MemoryOffset, Bytes } from './units'; @@ -396,6 +397,8 @@ export type GeckoMetaMarkerSchema = { // if present, give the marker its own local track graphs?: Array; + style?: MarkerSchemaStyle; + // If present, specifies the key of a marker field that contains the marker's color. // The field should contain one of the GraphColor values. // This allows individual markers to have different colors based on their data. diff --git a/src/types/markers.ts b/src/types/markers.ts index 98d1854fc3..3160824e77 100644 --- a/src/types/markers.ts +++ b/src/types/markers.ts @@ -187,6 +187,8 @@ export type MarkerSchema = { // Not all listed fields have to be present on every marker (they're all optional). fields: MarkerSchemaField[]; + style: MarkerSchemaStyle; + // An optional description for markers of this type. // Will be displayed to the user. description?: string;