Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4d2f20b
🔃 Daily sync: main -> l10n (April 9, 2025)
Apr 9, 2025
f167639
Update all Yarn dependencies (2025-04-09) (#5416)
depfu[bot] Apr 15, 2025
8066616
Update stylelint-config-standard 37.0.0 → 38.0.0 (major) (#5427)
depfu[bot] Apr 15, 2025
962ddeb
Bump koa from 2.15.4 to 2.16.1 (#5417)
dependabot[bot] Apr 15, 2025
939d4b4
Pontoon/Firefox Profiler: Update Chinese (China) (zh-CN)
mozilla-pontoon Apr 16, 2025
4d905ac
🔃 Daily sync: main -> l10n (April 16, 2025)
Apr 16, 2025
4765ae2
Update all Yarn dependencies (2025-04-16) (#5430)
depfu[bot] Apr 16, 2025
33ba08d
🔃 Daily sync: main -> l10n (April 17, 2025)
Apr 17, 2025
3adc86c
⬆️ Update @fluent/bundle to version 0.19.1 (#5433)
depfu[bot] Apr 24, 2025
7042f82
🔃 Daily sync: main -> l10n (April 25, 2025)
Apr 25, 2025
29767e0
Update all Yarn dependencies (2025-04-28) (#5435)
depfu[bot] Apr 28, 2025
8b83c7a
Bump http-proxy-middleware from 2.0.7 to 2.0.9 (#5436)
dependabot[bot] Apr 28, 2025
fe06a6c
🔃 Daily sync: main -> l10n (April 29, 2025)
Apr 29, 2025
513b720
Pontoon/Firefox Profiler: Update Kabyle (kab)
mozilla-pontoon May 4, 2025
e8fc1b1
Pontoon/Firefox Profiler: Update Kabyle (kab)
mozilla-pontoon May 4, 2025
fbc7d79
⬆️ Update glob to version 11.0.2 (#5441)
depfu[bot] May 7, 2025
89f2541
🔃 Daily sync: main -> l10n (May 8, 2025)
May 8, 2025
54f9d12
Relax the check about chrome profiles (#5439)
julienw May 12, 2025
49a35e8
Do not fail when the input isn't valid UTF-8 (#5426)
julienw May 12, 2025
cfbabf5
Update all Yarn dependencies (2025-05-12)
depfu[bot] May 12, 2025
08a6bbb
Update the test expectation after the update of the dependency @tgwf/co2
julienw May 12, 2025
cffa1ce
Update all Yarn dependencies (2025-05-12) (#5449)
julienw May 12, 2025
28595b7
Add the marker field types "flow-id" and "terminating-flow-id" to the…
mstange May 12, 2025
6465128
Use the right allocations call tree when an allocations summary is se…
julienw May 12, 2025
062cc5d
Add a test to ensure the stack chart works with other call tree summa…
julienw May 12, 2025
1eb69be
🔃 Daily sync: main -> l10n (May 13, 2025)
May 13, 2025
98ba4aa
Update npm-run-all2 7.0.2 → 8.0.1 (major) (#5457)
depfu[bot] May 13, 2025
723b514
Fix the wrong length computation in Timeline.test (#5455)
julienw May 13, 2025
6ba90a6
Retain platform-specific timestamp field that are being added in bug …
mstange May 13, 2025
70c96fd
🔃 Daily sync: main -> l10n (May 14, 2025)
May 14, 2025
f780ba9
Merge branch 'main' into 5327-fix-stack-chart-with-allocations
julienw May 15, 2025
53111e0
Use the right allocations call tree when an allocations summary is se…
julienw May 15, 2025
5018c30
Update all Yarn dependencies (2025-05-14) (#5459)
depfu[bot] May 15, 2025
1bdf301
Do not use a link to display the sourceURL if it's not a proper URL (…
julienw May 15, 2025
b82356c
Merge branch 'main' into l10n
julienw May 15, 2025
223a11c
🔃 Sync: l10n -> main (May 15, 2025) (#5460)
julienw May 15, 2025
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
9 changes: 9 additions & 0 deletions locales/kab/app.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ Home--additional-content-title = Sali imuɣna yellan
Home--additional-content-content = Tzemreḍ <strong>ad tzuɣreḍ syen sers</strong> afaylu n umaɣnu da i usali-ines, neɣ:
Home--compare-recordings-info = Tzemreḍ daɣen ad tsenmehleḍ iseklasen. <a>Ldi agrudem n usnemhel.</a>
Home--your-recent-uploaded-recordings-title = Iseklasen-ik·im i d-yulin melmi kan
Home--install-chrome-extension = Sbedd aseɣẓan n Chrome

## IdleSearchField
## The component that is used for all the search inputs in the application.
Expand Down Expand Up @@ -259,6 +260,7 @@ MenuButtons--index--profile-info-uploaded-label = Yuli-d:
MenuButtons--index--profile-info-uploaded-actions = Kkes
MenuButtons--index--metaInfo-subtitle = Talɣut n umaɣnu
MenuButtons--metaInfo--symbols = Izamulen:
MenuButtons--metaInfo--main-memory = Takatut tagejdant:
MenuButtons--index--show-moreInfo-button = Sken ugar
MenuButtons--index--hide-moreInfo-button = Sken drus
MenuButtons--metaInfo--profiling-started = Asekles yebda:
Expand Down Expand Up @@ -360,6 +362,8 @@ NumberFormat--short-date = { SHORTDATE($date) }

## Profile Name Button

ProfileName--edit-profile-name-button =
.title = Ẓreg isem n umaɣnu

## Profile Delete Button

Expand Down Expand Up @@ -541,6 +545,11 @@ TransformNavigator--merge-function = Smezdi: { $item }
# Variables:
# $item (String) - Name of the function that transform applied to.
TransformNavigator--drop-function = Sers: { $item }
# "Collapse recursion" transform.
# See: https://profiler.firefox.com/docs/#/./guide-filtering-call-trees?id=collapse
# Variables:
# $item (String) - Name of the function that transform applied to.
TransformNavigator--collapse-recursion = Fneẓ asniles: { $item }

## "Bottom box" - a view which contains the source view and the assembly view,
## at the bottom of the profiler UI
Expand Down
9 changes: 5 additions & 4 deletions locales/zh-CN/app.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ Home--your-recent-uploaded-recordings-title = 您最近上传的记录
# documentation to use these tools.
Home--load-files-from-other-tools2 = { -profiler-brand-name } 也可以从其他分析器导入记录,例如 <perf>Linux perf</perf>、<simpleperf>Android SimplePerf</simpleperf>、Chrome 性能面板、<androidstudio>Android Studio</androidstudio>,支持直接导入 <dhat>dhat</dhat>、<traceevent>Google 的 Trace Event</traceevent> 格式保存的分析记录。<write>点此了解如何编写您自己的导入程序</write>。
Home--install-chrome-extension = 安装 Chrome 扩展
Home--chrome-extension-instructions = 使用 <a>Chrome 版 { -profiler-brand-name } 扩展</a>,在 Chrome 中捕获性能分析记录,并通过 { -profiler-brand-name } 分析。可到 Chrome 应用商店安装扩展。
Home--chrome-extension-instructions = 使用 <a>Chrome 版 { -profiler-brand-name } 扩展</a>,在 Chrome 中捕捉性能分析记录,并通过 { -profiler-brand-name } 分析。可到 Chrome 应用商店安装扩展。
Home--chrome-extension-recording-instructions = 安装后,即可使用扩展的工具栏图标和快捷键来开始或停止分析,也可以导出分析记录并在此处加载以进行详细分析。

## IdleSearchField
Expand Down Expand Up @@ -405,9 +405,10 @@ MenuButtons--index--hide-moreInfo-button = 显示更少
# $physicalCPUs (Number), $logicalCPUs (Number) - Number of Physical and Logical CPU Cores
MenuButtons--metaInfo--physical-and-logical-cpu =
{ $physicalCPUs ->
*[other] 物理核心 × { $physicalCPUs }
}、{ $logicalCPUs ->
*[other] 逻辑核心 × { $logicalCPUs }
*[other]
{ $logicalCPUs ->
*[other] 物理核心 × { $physicalCPUs }、逻辑核心 × { $logicalCPUs }
}
}
# This string is used when we only have the information about the number of
# physical CPU cores.
Expand Down
54 changes: 27 additions & 27 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,33 +67,33 @@
"@codemirror/lang-rust": "^6.0.1",
"@codemirror/language": "^6.11.0",
"@codemirror/state": "^6.5.2",
"@codemirror/view": "^6.36.4",
"@codemirror/view": "^6.36.7",
"@firefox-devtools/react-contextmenu": "^5.2.2",
"@fluent/bundle": "^0.18.0",
"@fluent/bundle": "^0.19.1",
"@fluent/langneg": "^0.7.0",
"@fluent/react": "^0.15.2",
"@lezer/highlight": "^1.2.1",
"@tgwf/co2": "^0.16.6",
"@tgwf/co2": "^0.16.7",
"array-move": "^3.0.1",
"array-range": "^1.0.1",
"clamp": "^1.0.1",
"classnames": "^2.5.1",
"common-tags": "^1.8.2",
"copy-to-clipboard": "^3.3.3",
"core-js": "^3.41.0",
"core-js": "^3.42.0",
"escape-string-regexp": "^4.0.0",
"gecko-profiler-demangle": "^0.3.3",
"idb": "^8.0.2",
"jszip": "^3.10.1",
"long": "^5.3.1",
"long": "^5.3.2",
"memoize-immutable": "^3.0.0",
"memoize-one": "^6.0.0",
"minimist": "^1.2.8",
"mixedtuplemap": "^1.0.0",
"namedtuplemap": "^1.0.0",
"photon-colors": "^3.3.2",
"protobufjs": "^7.4.0",
"query-string": "^9.1.1",
"protobufjs": "^7.5.0",
"query-string": "^9.1.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-intersection-observer": "^9.16.0",
Expand All @@ -109,24 +109,24 @@
"workbox-window": "^7.3.0"
},
"devDependencies": {
"@babel/cli": "^7.27.0",
"@babel/core": "^7.26.10",
"@babel/eslint-parser": "^7.26.10",
"@babel/eslint-plugin": "^7.26.10",
"@babel/cli": "^7.27.2",
"@babel/core": "^7.27.1",
"@babel/eslint-parser": "^7.27.1",
"@babel/eslint-plugin": "^7.27.1",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/preset-env": "^7.26.9",
"@babel/preset-flow": "^7.25.9",
"@babel/preset-react": "^7.26.3",
"@babel/preset-env": "^7.27.2",
"@babel/preset-flow": "^7.27.1",
"@babel/preset-react": "^7.27.1",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0",
"@testing-library/react": "^16.3.0",
"alex": "^11.0.1",
"autoprefixer": "^10.4.21",
"babel-jest": "^29.7.0",
"babel-loader": "^10.0.0",
"babel-plugin-module-resolver": "^5.0.2",
"browserslist": "^4.24.4",
"caniuse-lite": "^1.0.30001699",
"browserslist": "^4.24.5",
"caniuse-lite": "^1.0.30001715",
"circular-dependency-plugin": "^5.2.1",
"codecov": "^3.8.3",
"copy-webpack-plugin": "^13.0.0",
Expand All @@ -135,45 +135,45 @@
"cssnano": "^7.0.6",
"devtools-license-check": "^0.9.0",
"eslint": "^8.57.1",
"eslint-config-prettier": "^10.1.1",
"eslint-config-prettier": "^10.1.2",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-flowtype": "^8.0.3",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-jest-dom": "^5.5.0",
"eslint-plugin-jest-formatting": "^3.1.0",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-testing-library": "^7.1.1",
"espree": "^10.3.0",
"fake-indexeddb": "^6.0.0",
"fetch-mock-jest": "^1.5.1",
"file-loader": "^6.2.0",
"flow-bin": "^0.96.0",
"glob": "^10.4.5",
"glob": "^11.0.2",
"html-webpack-plugin": "^5.6.3",
"husky": "^4.3.8",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-extended": "^4.0.2",
"json-loader": "^0.5.7",
"local-web-server": "^5.4.0",
"lockfile-lint": "^4.14.0",
"lockfile-lint": "^4.14.1",
"mkdirp": "^3.0.1",
"node-fetch": "^2.6.11",
"npm-run-all2": "^7.0.2",
"open": "^10.1.0",
"npm-run-all2": "^8.0.1",
"open": "^10.1.1",
"postcss": "^8.5.3",
"postcss-loader": "^8.1.1",
"prettier": "^3.5.3",
"raw-loader": "^4.0.2",
"rimraf": "^5.0.10",
"style-loader": "^4.0.0",
"stylelint": "^16.15.0",
"stylelint": "^16.19.1",
"stylelint-config-idiomatic-order": "^10.0.0",
"stylelint-config-standard": "^37.0.0",
"webpack": "^5.98.0",
"stylelint-config-standard": "^38.0.0",
"webpack": "^5.99.8",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.0",
"webpack-dev-server": "^5.2.1",
"workbox-webpack-plugin": "^7.3.0",
"yargs": "^17.7.2"
},
Expand Down
2 changes: 1 addition & 1 deletion src/components/app/MenuButtons/MetaInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ class MetaInfoPanelImpl extends React.PureComponent<Props, State> {
Build ID:
</Localized>
</span>
{meta.sourceURL ? (
{meta.sourceURL && /^https?:\/\//i.test(meta.sourceURL) ? (
<a
href={meta.sourceURL}
title={meta.sourceURL}
Expand Down
12 changes: 5 additions & 7 deletions src/profile-logic/import/chrome.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,14 +215,12 @@ export function attemptToConvertChromeProfile(

if (Array.isArray(json)) {
// Chrome profiles come as a list of events.
const event: mixed = json[0];
// Lightly check that some properties exist that are in the TracingEvent.
const firstEvents = json.slice(0, 5);
// Lightly check that the first items look like a TracingEvent.
if (
event &&
typeof event === 'object' &&
'ph' in event &&
'cat' in event &&
'args' in event
firstEvents.every(
(event) => event && typeof event === 'object' && 'ph' in event
)
) {
events = coerce<mixed[], TracingEventUnion[]>(json);
}
Expand Down
7 changes: 6 additions & 1 deletion src/profile-logic/marker-schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,12 @@ export function computeStringIndexMarkerFieldsByDataType(
const { name, fields } = schema;
const stringIndexFields = [];
for (const field of fields) {
if (field.format === 'unique-string' && field.key) {
if (
(field.format === 'unique-string' ||
field.format === 'flow-id' ||
field.format === 'terminating-flow-id') &&
field.key
) {
stringIndexFields.push(field.key);
}
}
Expand Down
8 changes: 7 additions & 1 deletion src/profile-logic/process-profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -1697,6 +1697,12 @@ export function processGeckoProfile(geckoProfile: GeckoProfile): Profile {
const meta: ProfileMeta = {
interval: geckoProfile.meta.interval,
startTime: geckoProfile.meta.startTime,
startTimeAsClockMonotonicNanosecondsSinceBoot:
geckoProfile.meta.startTimeAsClockMonotonicNanosecondsSinceBoot,
startTimeAsMachAbsoluteTimeNanoseconds:
geckoProfile.meta.startTimeAsMachAbsoluteTimeNanoseconds,
startTimeAsQueryPerformanceCounterValue:
geckoProfile.meta.startTimeAsQueryPerformanceCounterValue,
abi: geckoProfile.meta.abi,
extensions: extensions,
misc: geckoProfile.meta.misc,
Expand Down Expand Up @@ -1896,7 +1902,7 @@ export async function unserializeProfileOfArbitraryFormat(
arbitraryFormat = convertSimpleperfTraceProfile(arrayBuffer);
} else {
try {
const textDecoder = new TextDecoder('utf-8', { fatal: true });
const textDecoder = new TextDecoder();
arbitraryFormat = await textDecoder.decode(arrayBuffer);
} catch (e) {
console.error('Source exception:', e);
Expand Down
28 changes: 14 additions & 14 deletions src/selectors/per-thread/stack-sample.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,36 +230,36 @@ export function getStackAndSampleSelectorsPerThread(
)
);

const _getPreviewFilteredCtssSampleIndexToNonInvertedCallNodeIndex: Selector<
const _getSampleIndexToNonInvertedCallNodeIndexForPreviewFilteredCtssThread: Selector<
Array<IndexIntoCallNodeTable | null>,
> = createSelector(
(state) => threadSelectors.getPreviewFilteredCtssSamples(state).stack,
(state) => getCallNodeInfo(state).getStackIndexToNonInvertedCallNodeIndex(),
ProfileData.getSampleIndexToCallNodeIndex
);

const _getSampleIndexToNonInvertedCallNodeIndexForFilteredCtssThread: Selector<
Array<IndexIntoCallNodeTable | null>,
> = createSelector(
(state) => threadSelectors.getFilteredCtssSamples(state).stack,
(state) => getCallNodeInfo(state).getStackIndexToNonInvertedCallNodeIndex(),
ProfileData.getSampleIndexToCallNodeIndex
);

const getSampleIndexToNonInvertedCallNodeIndexForFilteredThread: Selector<
Array<IndexIntoCallNodeTable | null>,
> = createSelector(
(state) => threadSelectors.getFilteredThread(state).samples.stack,
(state) => getCallNodeInfo(state).getStackIndexToNonInvertedCallNodeIndex(),
(filteredThreadSampleStacks, stackIndexToNonInvertedCallNodeIndex) =>
ProfileData.getSampleIndexToCallNodeIndex(
filteredThreadSampleStacks,
stackIndexToNonInvertedCallNodeIndex
)
ProfileData.getSampleIndexToCallNodeIndex
);

const _getSampleIndexToNonInvertedCallNodeIndexForTabFilteredThread: Selector<
Array<IndexIntoCallNodeTable | null>,
> = createSelector(
(state) => threadSelectors.getTabFilteredThread(state).samples.stack,
(state) => getCallNodeInfo(state).getStackIndexToNonInvertedCallNodeIndex(),
(tabFilteredThreadSampleStacks, stackIndexToNonInvertedCallNodeIndex) =>
ProfileData.getSampleIndexToCallNodeIndex(
tabFilteredThreadSampleStacks,
stackIndexToNonInvertedCallNodeIndex
)
ProfileData.getSampleIndexToCallNodeIndex
);

const getSamplesSelectedStatesInFilteredThread: Selector<
Expand Down Expand Up @@ -313,7 +313,7 @@ export function getStackAndSampleSelectorsPerThread(
const getCallNodeSelfAndSummary: Selector<CallNodeSelfAndSummary> =
createSelector(
threadSelectors.getPreviewFilteredCtssSamples,
_getPreviewFilteredCtssSampleIndexToNonInvertedCallNodeIndex,
_getSampleIndexToNonInvertedCallNodeIndexForPreviewFilteredCtssThread,
getCallNodeInfo,
(samples, sampleIndexToCallNodeIndex, callNodeInfo) => {
return CallTree.computeCallNodeSelfAndSummary(
Expand Down Expand Up @@ -362,7 +362,7 @@ export function getStackAndSampleSelectorsPerThread(
const getTracedTiming: Selector<CallTree.CallTreeTimings | null> =
createSelector(
threadSelectors.getPreviewFilteredCtssSamples,
_getPreviewFilteredCtssSampleIndexToNonInvertedCallNodeIndex,
_getSampleIndexToNonInvertedCallNodeIndexForPreviewFilteredCtssThread,
getCallNodeInfo,
ProfileSelectors.getProfileInterval,
(samples, sampleIndexToCallNodeIndex, callNodeInfo, interval) => {
Expand Down Expand Up @@ -403,7 +403,7 @@ export function getStackAndSampleSelectorsPerThread(
const getStackTimingByDepth: Selector<StackTiming.StackTimingByDepth> =
createSelector(
threadSelectors.getFilteredCtssSamples,
getSampleIndexToNonInvertedCallNodeIndexForFilteredThread, // Bug! #5327
_getSampleIndexToNonInvertedCallNodeIndexForFilteredCtssThread,
getCallNodeInfo,
getFilteredCallNodeMaxDepthPlusOne,
ProfileSelectors.getProfileInterval,
Expand Down
44 changes: 43 additions & 1 deletion src/test/components/MenuButtons.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import { MenuButtons } from 'firefox-profiler/components/app/MenuButtons';
import { CurrentProfileUploadedInformationLoader } from 'firefox-profiler/components/app/CurrentProfileUploadedInformationLoader';

import { stateFromLocation } from 'firefox-profiler/app-logic/url-handling';
import { processGeckoProfile } from 'firefox-profiler/profile-logic/process-profile';
import {
processGeckoProfile,
unserializeProfileOfArbitraryFormat,
} from 'firefox-profiler/profile-logic/process-profile';
import {
persistUploadedProfileInformationToDb,
retrieveUploadedProfileInformationFromDb,
Expand Down Expand Up @@ -612,6 +615,45 @@ describe('app/MenuButtons', function () {
expect(moreInfoPart).toMatchSnapshot();
});

it('Does display a link for the build if there is a URL', async () => {
const { profile } = getProfileFromTextSamples('A');
profile.meta.sourceURL =
'https://hg.mozilla.org/mozilla-central/rev/6be6a06991d7a2123d4b51f4ce384c6bce92f859';
const buildID = '20250402094810';
profile.meta.appBuildID = buildID;

const unserializedProfile =
await unserializeProfileOfArbitraryFormat(profile);
const { displayMetaInfoPanel } =
await setupForMetaInfoPanel(unserializedProfile);
await displayMetaInfoPanel();

const buildIdElement = ensureExists(
screen.getByText(/Build ID:/).nextSibling
);
expect(buildIdElement).toBeInstanceOf(HTMLAnchorElement);
expect(buildIdElement).toHaveTextContent(buildID);
expect((buildIdElement: any).href).toBe(profile.meta.sourceURL);
});

it('does not display a link for the build ID if there is no URL', async () => {
const { profile } = getProfileFromTextSamples('A');
profile.meta.sourceURL = 'unknown';
const buildID = '20250402094810';
profile.meta.appBuildID = buildID;
const unserializedProfile =
await unserializeProfileOfArbitraryFormat(profile);
const { displayMetaInfoPanel } =
await setupForMetaInfoPanel(unserializedProfile);
await displayMetaInfoPanel();

const buildIdElement = ensureExists(
screen.getByText(/Build ID:/).nextSibling
);
expect(buildIdElement).toBeInstanceOf(Text);
expect(buildIdElement).toHaveTextContent(buildID);
});

describe('deleting a profile', () => {
const FAKE_HASH = 'FAKE_HASH';
const FAKE_PROFILE_DATA = {
Expand Down
Loading