();
+ for (let sampleIndex = 0; sampleIndex < samples.length; sampleIndex++) {
+ const stack = samples.stack[sampleIndex];
+ if (stack === null) {
+ continue;
+ }
+ const callNodeFrame = callNodeFramePerStack[stack];
+ if (callNodeFrame === -1) {
+ // This sample does not contribute to the call node's total. Ignore.
+ continue;
+ }
+
+ const nativeSymbol = frameTable.nativeSymbol[callNodeFrame];
+ if (nativeSymbol === null) {
+ continue;
+ }
+
+ const sampleWeight =
+ samples.weight !== null ? samples.weight[sampleIndex] : 1;
+ totalPerNativeSymbol.set(
+ nativeSymbol,
+ (totalPerNativeSymbol.get(nativeSymbol) ?? 0) + sampleWeight
+ );
+ }
+
+ return totalPerNativeSymbol;
}
/**
diff --git a/src/test/components/TrackBandwidth.test.tsx b/src/test/components/TrackBandwidth.test.tsx
index 3f208ec09e..b8109c8693 100644
--- a/src/test/components/TrackBandwidth.test.tsx
+++ b/src/test/components/TrackBandwidth.test.tsx
@@ -164,7 +164,7 @@ describe('TrackBandwidth', function () {
screen.getByText('Transfer speed for this sample:')
).toBeInTheDocument();
expect(screen.getByText(/speed/).nextSibling).toHaveTextContent(
- '4.66GB\u2069 per second'
+ '5.00GB\u2069 per second'
);
expect(
@@ -176,14 +176,14 @@ describe('TrackBandwidth', function () {
screen.getByText('Data transferred up to this time:')
).toBeInTheDocument();
expect(screen.getByText(/transferred up to/).nextSibling).toHaveTextContent(
- /6.86MB\u2069 \(\u2068\d+(\.\d+)?\u2069 g CO₂e\)/
+ /7.19MB\u2069 \(\u2068\d+(\.\d+)?\u2069 g CO₂e\)/
);
expect(
screen.getByText('Data transferred in the visible range:')
).toBeInTheDocument();
expect(screen.getByText(/visible range/).nextSibling).toHaveTextContent(
- /7.97MB\u2069 \(\u2068\d+(\.\d+)?\u2069 g CO₂e\)/
+ /8.35MB\u2069 \(\u2068\d+(\.\d+)?\u2069 g CO₂e\)/
);
});
@@ -224,13 +224,13 @@ describe('TrackBandwidth', function () {
moveMouseAtCounter(3, 0);
// Note: Fluent adds isolation characters \u2068 and \u2069 around variables.
expect(screen.getByText(/speed/).nextSibling).toHaveTextContent(
- '95.4MB\u2069 per second'
+ '100MB\u2069 per second'
);
expect(screen.getByText(/visible range:/).nextSibling).toHaveTextContent(
- /7.97MB\u2069 \(\u2068\d+(\.\d+)?\u2069 g CO₂e\)/
+ /8.35MB\u2069 \(\u2068\d+(\.\d+)?\u2069 g CO₂e\)/
);
expect(
screen.getByText(/current selection:/).nextSibling
- ).toHaveTextContent(/4.77MB\u2069 \(\u2068\d+(\.\d+)?\u2069 g CO₂e\)/);
+ ).toHaveTextContent(/5.00MB\u2069 \(\u2068\d+(\.\d+)?\u2069 g CO₂e\)/);
});
});
diff --git a/src/test/components/__snapshots__/TooltipMarker.test.tsx.snap b/src/test/components/__snapshots__/TooltipMarker.test.tsx.snap
index 0b2b81311d..011f064231 100644
--- a/src/test/components/__snapshots__/TooltipMarker.test.tsx.snap
+++ b/src/test/components/__snapshots__/TooltipMarker.test.tsx.snap
@@ -342,7 +342,7 @@ exports[`TooltipMarker renders properly network markers where content type is bl
Requested bytes
:
- 45.9KB
+ 47.0KB
@@ -538,7 +538,7 @@ exports[`TooltipMarker renders properly network markers where content type is mi
Requested bytes
:
- 45.9KB
+ 47.0KB
@@ -744,7 +744,7 @@ exports[`TooltipMarker renders properly network markers with a preconnect part 2
Requested bytes
:
- 45.9KB
+ 47.0KB
@@ -1014,7 +1014,7 @@ exports[`TooltipMarker renders properly network markers with a preconnect part c
Requested bytes
:
- 45.9KB
+ 47.0KB
@@ -1210,7 +1210,7 @@ exports[`TooltipMarker renders properly normal network markers 1`] = `
Requested bytes
:
- 45.9KB
+ 47.0KB
@@ -3216,14 +3216,14 @@ exports[`TooltipMarker renders tooltips for various markers: GCMajor-16.5 1`] =
GC heap size (pre - post)
:
- 46.1MB - 36.3MB
+ 48.4MB - 38.1MB
Malloc heap size (pre - post)
:
- 23.1MB - 12.1MB
+ 24.2MB - 12.7MB
@@ -3362,7 +3362,7 @@ exports[`TooltipMarker renders tooltips for various markers: GCMinor-15.5 1`] =
Bytes tenured
:
- 1.30MB / 1.97MB (66%)
+ 1.37MB / 2.06MB (66%)
@@ -3376,7 +3376,7 @@ exports[`TooltipMarker renders tooltips for various markers: GCMinor-15.5 1`] =
Bytes used
:
- 1.97MB / 16.0MB (12%)
+ 2.06MB / 16.8MB (12%)
@@ -3397,7 +3397,7 @@ exports[`TooltipMarker renders tooltips for various markers: GCMinor-15.5 1`] =
Tenured allocation rate
:
- 181MB/s
+ 190MB/s
@@ -3501,7 +3501,7 @@ exports[`TooltipMarker renders tooltips for various markers: GCSlice-17.5 1`] =
Trigger (amt/trig)
:
- 266MB / 245MB
+ 279MB / 257MB
diff --git a/src/test/unit/format-numbers.test.ts b/src/test/unit/format-numbers.test.ts
index a6c47fbd08..19a0795245 100644
--- a/src/test/unit/format-numbers.test.ts
+++ b/src/test/unit/format-numbers.test.ts
@@ -28,27 +28,27 @@ describe('formatGigaBytes', () => {
});
it('returns large values without fractional digits by default', () => {
- expect(formatGigaBytes(1234567890123)).toBe('1,150GB');
+ expect(formatGigaBytes(1234567890123)).toBe('1,235GB');
});
it('returns values with 2 fractional digits by default', () => {
- expect(formatGigaBytes(1234567890)).toBe('1.15GB');
+ expect(formatGigaBytes(1234567890)).toBe('1.23GB');
});
it('can return values with byte precision', () => {
- expect(formatGigaBytes(1234567890, 3, 2, 1)).toBe('1GB 153MB 384KB 722B');
+ expect(formatGigaBytes(1234567890, 3, 2, 1)).toBe('1GB 234MB 567KB 890B');
});
it('can return values with kilobyte precision', () => {
- expect(formatGigaBytes(1234567890, 3, 2, 1024)).toBe('1GB 153MB 385KB');
+ expect(formatGigaBytes(1234567890, 3, 2, 1000)).toBe('1GB 234MB 568KB');
});
it('can return values with megabyte precision', () => {
- expect(formatGigaBytes(1234567890, 3, 2, 1024 ** 2)).toBe('1GB 153MB');
+ expect(formatGigaBytes(1234567890, 3, 2, 1000 ** 2)).toBe('1GB 235MB');
});
it('can return values with gigabyte precision', () => {
- expect(formatGigaBytes(1234567890, 3, 2, 1024 ** 3)).toBe('1GB');
+ expect(formatGigaBytes(1234567890, 3, 2, 1000 ** 3)).toBe('1GB');
});
});
@@ -58,23 +58,23 @@ describe('formatMegaBytes', () => {
});
it('returns large values without fractional digits by default', () => {
- expect(formatMegaBytes(1234567890)).toBe('1,177MB');
+ expect(formatMegaBytes(1234567890)).toBe('1,235MB');
});
it('returns values with 2 fractional digits by default', () => {
- expect(formatMegaBytes(1234567)).toBe('1.18MB');
+ expect(formatMegaBytes(1234567)).toBe('1.23MB');
});
it('can return values with byte precision', () => {
- expect(formatMegaBytes(1234567, 3, 2, 1)).toBe('1MB 181KB 647B');
+ expect(formatMegaBytes(1234567, 3, 2, 1)).toBe('1MB 234KB 567B');
});
it('can return values with kilobyte precision', () => {
- expect(formatMegaBytes(1234567, 3, 2, 1024)).toBe('1MB 182KB');
+ expect(formatMegaBytes(1234567, 3, 2, 1000)).toBe('1MB 235KB');
});
it('can return values with megabyte precision', () => {
- expect(formatMegaBytes(1234567, 3, 2, 1024 ** 2)).toBe('1MB');
+ expect(formatMegaBytes(1234567, 3, 2, 1000 ** 2)).toBe('1MB');
});
});
@@ -84,19 +84,19 @@ describe('formatKiloBytes', () => {
});
it('returns large values without fractional digits by default', () => {
- expect(formatKiloBytes(1234567)).toBe('1,206KB');
+ expect(formatKiloBytes(1234567)).toBe('1,235KB');
});
it('returns values with 2 fractional digits by default', () => {
- expect(formatKiloBytes(1234)).toBe('1.21KB');
+ expect(formatKiloBytes(1234)).toBe('1.23KB');
});
it('can return values with byte precision', () => {
- expect(formatKiloBytes(1234, 3, 2, 1)).toBe('1KB 210B');
+ expect(formatKiloBytes(1234, 3, 2, 1)).toBe('1KB 234B');
});
it('can return values with kilobyte precision', () => {
- expect(formatKiloBytes(1234, 3, 2, 1024)).toBe('1KB');
+ expect(formatKiloBytes(1234, 3, 2, 1000)).toBe('1KB');
});
});
@@ -110,40 +110,53 @@ describe('formatBytes', () => {
});
it('can return values with the kilobyte unit', () => {
- expect(formatBytes(12345)).toBe('12.1KB');
+ expect(formatBytes(12345)).toBe('12.3KB');
});
it('can return values with the megabyte unit', () => {
- expect(formatBytes(1234567)).toBe('1.18MB');
+ expect(formatBytes(1234567)).toBe('1.23MB');
});
it('can return values with the gigabyte unit', () => {
- expect(formatBytes(1234567890)).toBe('1.15GB');
+ expect(formatBytes(1234567890)).toBe('1.23GB');
});
it('can return values with byte precision', () => {
- expect(formatBytes(12345, 3, 2, 1)).toBe('12KB 57B');
+ expect(formatBytes(12345, 3, 2, 1)).toBe('12KB 345B');
});
it('can return values with kilobyte precision', () => {
- expect(formatBytes(12345, 3, 2, 1024)).toBe('12KB');
+ expect(formatBytes(12345, 3, 2, 1000)).toBe('12KB');
});
});
describe('findRoundBytesValueGreaterOrEqualTo', () => {
- const expectedValues = [0, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000];
-
- it('rounds small bytes values using base 10 round value', () => {
+ const expectedValues = [
+ // minValue, expected
+ // minValue <= 1000
+ [0, 0],
+ [3, 5],
+ [63, 100],
+ [511, 1000],
+ [1000, 2000],
+
+ // 1000 < minValue <= 1000^4
+ [2047, 4000],
+ [9999, 16000],
+ [123456, 128000],
+ [999999, 1000000],
+ [1_234_567, 2_000_000],
+ [1_234_567_891, 2_000_000_000],
+
+ // minValue > 1000^4
+ [1_234_567_891_234, 2_000_000_000_000],
+ [1_234_567_891_234_567, 2_000_000_000_000_000],
+ ];
+
+ it('correctly rounds bytes values using base 10 round value', () => {
for (let i = 0; i < expectedValues.length; ++i) {
- expect(findRoundBytesValueGreaterOrEqualTo(2 ** i - 1)).toBe(
- expectedValues[i]
- );
- }
- });
-
- it('rounds large bytes values using base 2 round value', () => {
- for (let i = expectedValues.length; i < 40; ++i) {
- expect(findRoundBytesValueGreaterOrEqualTo(2 ** i - 1)).toBe(2 ** i);
+ const [input, expected] = expectedValues[i];
+ expect(findRoundBytesValueGreaterOrEqualTo(input)).toBe(expected);
}
});
});
diff --git a/src/test/unit/marker-schema.test.ts b/src/test/unit/marker-schema.test.ts
index 5291f5b8c4..1fd6a8da0c 100644
--- a/src/test/unit/marker-schema.test.ts
+++ b/src/test/unit/marker-schema.test.ts
@@ -357,9 +357,9 @@ describe('marker schema formatting', function () {
"bytes - 0B",
"bytes - 10B",
"bytes - 12B",
- "bytes - 121KB",
- "bytes - 118MB",
- "bytes - 115GB",
+ "bytes - 123KB",
+ "bytes - 123MB",
+ "bytes - 123GB",
"bytes - 0.000B",
"integer - 0",
"integer - 10",
diff --git a/src/test/unit/profile-data.test.ts b/src/test/unit/profile-data.test.ts
index 96b85e6d94..e28ce2de6d 100644
--- a/src/test/unit/profile-data.test.ts
+++ b/src/test/unit/profile-data.test.ts
@@ -26,6 +26,7 @@ import {
getNativeSymbolInfo,
computeTimeColumnForRawSamplesTable,
getCallNodeFramePerStack,
+ getTotalNativeSymbolTimingsForCallNode,
} from '../../profile-logic/profile-data';
import { resourceTypes } from '../../profile-logic/data-structures';
import {
@@ -60,6 +61,8 @@ import type {
RawProfileSharedData,
IndexIntoFrameTable,
IndexIntoSourceTable,
+ IndexIntoCategoryList,
+ IndexIntoNativeSymbolTable,
} from 'firefox-profiler/types';
describe('string-table', function () {
@@ -1481,7 +1484,7 @@ describe('getNativeSymbolsForCallNode', function () {
);
expect(
getNativeSymbolsForCallNode(callNodeFramePerStackAB, thread.frameTable)
- ).toEqual([symB]);
+ ).toEqual(new Set([symB]));
const callNodeFramePerStackABC = getCallNodeFramePerStack(
ensureExists(abc),
@@ -1490,7 +1493,7 @@ describe('getNativeSymbolsForCallNode', function () {
);
expect(
getNativeSymbolsForCallNode(callNodeFramePerStackABC, thread.frameTable)
- ).toEqual([symB]);
+ ).toEqual(new Set([symB]));
});
it('finds multiple symbols', function () {
@@ -1531,13 +1534,195 @@ describe('getNativeSymbolsForCallNode', function () {
thread.stackTable
);
expect(
- new Set(
- getNativeSymbolsForCallNode(callNodeFramePerStackC, thread.frameTable)
- )
+ getNativeSymbolsForCallNode(callNodeFramePerStackC, thread.frameTable)
).toEqual(new Set([symB, symD]));
});
});
+describe('getTotalNativeSymbolTimingsForCallNode', function () {
+ function getTimings(
+ thread: Thread,
+ callNodePath: CallNodePath,
+ defaultCategory: IndexIntoCategoryList,
+ isInverted: boolean
+ ): Map {
+ const { stackTable, frameTable, funcTable, samples } = thread;
+ const nonInvertedCallNodeInfo = getCallNodeInfo(
+ stackTable,
+ frameTable,
+ defaultCategory
+ );
+ const callNodeInfo = isInverted
+ ? getInvertedCallNodeInfo(
+ nonInvertedCallNodeInfo,
+ defaultCategory,
+ funcTable.length
+ )
+ : nonInvertedCallNodeInfo;
+ const callNodeIndex = ensureExists(
+ callNodeInfo.getCallNodeIndexFromPath(callNodePath),
+ 'invalid call node path'
+ );
+ const callNodeFramePerStack = getCallNodeFramePerStack(
+ callNodeIndex,
+ callNodeInfo,
+ stackTable
+ );
+ return getTotalNativeSymbolTimingsForCallNode(
+ samples,
+ callNodeFramePerStack,
+ frameTable
+ );
+ }
+
+ it('passes a basic test', function () {
+ const {
+ derivedThreads,
+ funcNamesDictPerThread,
+ nativeSymbolsDictPerThread,
+ defaultCategory,
+ } = getProfileFromTextSamples(`
+ A[lib:file][sym:Asym:20:]
+ B[lib:file][sym:Bsym:30:]
+ `);
+ const [{ A, B }] = funcNamesDictPerThread;
+ const [{ Asym, Bsym }] = nativeSymbolsDictPerThread;
+ const [thread] = derivedThreads;
+
+ // Compute the timings for the root call node.
+ // One total hit at symbol Asym.
+ const timingsRoot = getTimings(thread, [A], defaultCategory, false);
+ expect(timingsRoot.get(Asym)).toBe(1);
+ expect(timingsRoot.size).toBe(1); // no other hits
+
+ // Compute the timings for the child call node.
+ // One total hit at symbol Bsym.
+ const timingsChild = getTimings(thread, [A, B], defaultCategory, false);
+ expect(timingsChild.get(Bsym)).toBe(1);
+ expect(timingsChild.size).toBe(1); // no other hits
+ });
+
+ it('passes a basic test with recursion', function () {
+ const {
+ derivedThreads,
+ funcNamesDictPerThread,
+ nativeSymbolsDictPerThread,
+ defaultCategory,
+ } = getProfileFromTextSamples(`
+ A[lib:file][sym:Asym:20:]
+ B[lib:file][sym:Bsym:30:]
+ A[lib:file][sym:A2sym:40:]
+ `);
+
+ const [{ A, B }] = funcNamesDictPerThread;
+ const [{ Asym, A2sym }] = nativeSymbolsDictPerThread;
+ const [thread] = derivedThreads;
+
+ // Compute the timings for the root call node.
+ // One total hit at symbol Asym.
+ const timingsRoot = getTimings(thread, [A], defaultCategory, false);
+ expect(timingsRoot.get(Asym)).toBe(1);
+ expect(timingsRoot.size).toBe(1); // no other hits
+
+ // Compute the timings for the leaf call node.
+ // One total hit at symbol A2sym.
+ // In particular, we shouldn't record a hit for symbol Asym, even though
+ // the frame in Asym is also in A. But it's in the wrong call node.
+ const timingsChild = getTimings(thread, [A, B, A], defaultCategory, false);
+ expect(timingsChild.get(A2sym)).toBe(1);
+ expect(timingsChild.size).toBe(1); // no other hits
+ });
+
+ it('passes a test where the same function is called via different call paths', function () {
+ const {
+ derivedThreads,
+ funcNamesDictPerThread,
+ nativeSymbolsDictPerThread,
+ defaultCategory,
+ } = getProfileFromTextSamples(`
+ A[lib:one][sym:Asym:20:] A[lib:one][sym:Asym:20:] A[lib:one][sym:Asym:20:]
+ B[lib:one][sym:Bsym:30:] D[lib:one][sym:Dsym:40:] B[lib:one][sym:Bsym:30:]
+ C[lib:two][sym:Csym:10:] C[lib:two][sym:C2sym:50:] C[lib:two][sym:C3sym:60:]
+ D[lib:one][sym:Dsym:40:]
+ `);
+
+ const [{ A, B, C }] = funcNamesDictPerThread;
+ const [{ Csym, C3sym }] = nativeSymbolsDictPerThread;
+ const [thread] = derivedThreads;
+
+ const timingsABC = getTimings(thread, [A, B, C], defaultCategory, false);
+ expect(timingsABC.get(Csym)).toBe(1);
+ expect(timingsABC.get(C3sym)).toBe(1);
+ expect(timingsABC.size).toBe(2); // no other hits
+ });
+
+ it('passes a test with an inverted thread', function () {
+ const {
+ derivedThreads,
+ funcNamesDictPerThread,
+ nativeSymbolsDictPerThread,
+ defaultCategory,
+ } = getProfileFromTextSamples(`
+ A[lib:one][sym:Asym:20:] A[lib:one][sym:Asym:20:] A[lib:one][sym:Asym:20:]
+ B[lib:one][sym:Bsym:30:] D[lib:one][sym:Dsym:40:] B[lib:one][sym:Bsym:30:]
+ D[lib:one][sym:Dsym:40:] D[lib:one][sym:D2sym:50:] C[lib:two][sym:Csym:10:]
+ D[lib:one][sym:Dsym:40:]
+ `);
+
+ const [{ C, D }] = funcNamesDictPerThread;
+ const [{ Csym, Dsym, D2sym }] = nativeSymbolsDictPerThread;
+ const [thread] = derivedThreads;
+ // For the root D of the inverted tree, we have 3 native symbol hits.
+ const timingsD = getTimings(thread, [D], defaultCategory, true);
+ expect(timingsD.get(Dsym)).toBe(2);
+ expect(timingsD.get(D2sym)).toBe(1);
+ expect(timingsD.size).toBe(2); // no other hits
+
+ // For the C call node which is a child (direct caller) of D, we have
+ // one hit at symbol Csym.
+ const timingsDC = getTimings(thread, [D, C], defaultCategory, true);
+ expect(timingsDC.get(Csym)).toBe(1);
+ expect(timingsDC.size).toBe(1); // no other hits
+ });
+
+ it('passes a test where a function is present in two different native symbols', function () {
+ // The funky part here is that the targeted call node has frames from two different native
+ // symbols: Two from native symbol Bsym, and one from native symbol Asym. That's
+ // because B is present both as its own native symbol (separate outer function)
+ // and as an inlined call from A. In other words, C has been inlined both into
+ // a standalone B and also into another copy of B which was inlined into A.
+ //
+ // This means that, if the user double clicks call node [A, B, C], there are two
+ // different symbols for which we may want to display the assembly code, and we
+ // should compute how much time is spent in each.
+ const {
+ derivedThreads,
+ funcNamesDictPerThread,
+ nativeSymbolsDictPerThread,
+ defaultCategory,
+ } = getProfileFromTextSamples(`
+ A[lib:one][sym:Asym:20:] A[lib:one][sym:Asym:20:] A[lib:one][sym:Asym:20:] A[lib:one][sym:Asym:20:]
+ B[lib:one][sym:Bsym:30:] B[lib:one][sym:Asym:20:][inl:1] B[lib:one][sym:Bsym:30:] E[lib:one][sym:Esym:30:]
+ C[lib:one][sym:Bsym:30:][inl:1] C[lib:one][sym:Asym:20:][inl:2] C[lib:one][sym:Bsym:30:]
+ D[lib:one][sym:Dsym:40:]
+ `);
+
+ const [{ A, B, C }] = funcNamesDictPerThread;
+ const [{ Asym, Bsym }] = nativeSymbolsDictPerThread;
+ const [thread] = derivedThreads;
+
+ const timingsABCForBsym = getTimings(
+ thread,
+ [A, B, C],
+ defaultCategory,
+ false
+ );
+ expect(timingsABCForBsym.get(Asym)).toBe(1);
+ expect(timingsABCForBsym.get(Bsym)).toBe(2);
+ expect(timingsABCForBsym.size).toBe(2); // no other hits
+ });
+});
+
describe('getNativeSymbolInfo', function () {
it('calculates the correct native symbol info', function () {
const { profile, nativeSymbolsDictPerThread } = getProfileFromTextSamples(`
diff --git a/src/test/unit/window-console.test.ts b/src/test/unit/window-console.test.ts
index d2e1d84847..82c939f7c3 100644
--- a/src/test/unit/window-console.test.ts
+++ b/src/test/unit/window-console.test.ts
@@ -79,6 +79,39 @@ describe('console-accessible values on the window object', function () {
`);
});
+ it('can extract gecko logs with log level already in module', function () {
+ const profile = getProfileWithMarkers([
+ [
+ 'LogMessages',
+ 170,
+ null,
+ {
+ type: 'Log',
+ module: 'D/nsHttp',
+ name: 'ParentChannelListener::ParentChannelListener [this=7fb5e19b98d0, next=7fb5f48f2320]',
+ },
+ ],
+ [
+ 'LogMessages',
+ 190,
+ null,
+ {
+ type: 'Log',
+ name: 'nsJARChannel::nsJARChannel [this=0x87f1ec80]\n',
+ module: 'D/nsJarProtocol',
+ },
+ ],
+ ]);
+ const store = storeWithProfile(profile);
+ const target: MixedObject = {};
+ addDataToWindowObject(store.getState, store.dispatch, target);
+ const result = (target as any).extractGeckoLogs();
+ expect(result).toBe(stripIndent`
+ 1970-01-01 00:00:00.170000000 UTC - [Unknown Process 0: Empty]: D/nsHttp ParentChannelListener::ParentChannelListener [this=7fb5e19b98d0, next=7fb5f48f2320]
+ 1970-01-01 00:00:00.190000000 UTC - [Unknown Process 0: Empty]: D/nsJarProtocol nsJARChannel::nsJARChannel [this=0x87f1ec80]
+ `);
+ });
+
describe('totalMarkerDuration', function () {
function setup(): ExtraPropertiesOnWindowForConsole {
jest.spyOn(console, 'log').mockImplementation(() => {});
diff --git a/src/utils/colors.ts b/src/utils/colors.ts
index 98c8be73e0..1fc7bd19ce 100644
--- a/src/utils/colors.ts
+++ b/src/utils/colors.ts
@@ -101,6 +101,10 @@ const DEFAULT_STYLE: ColorStyles = {
gravity: 0,
};
+// Colors based on photon colors.
+export const PURPLE_55 = '#8a00eb';
+export const YELLOW_65 = '#be9b00';
+
const PSEUDO_TRANSPARENT_STYLE: ColorStyles = {
...DEFAULT_STYLE,
_selectedFillStyle: [GREY_30, GREY_70],
@@ -170,15 +174,15 @@ const STYLE_MAP: { [key: string]: ColorStyles } = {
},
green: {
...DEFAULT_STYLE,
- _selectedFillStyle: [GREEN_60, GREEN_80],
- _unselectedFillStyle: [GREEN_60 + '60', GREEN_80 + '60'],
+ _selectedFillStyle: [GREEN_60, GREEN_70],
+ _unselectedFillStyle: [GREEN_60 + '60', GREEN_70 + '60'],
_selectedTextColor: '#fff',
gravity: 4,
},
purple: {
...DEFAULT_STYLE,
- _selectedFillStyle: [PURPLE_70, PURPLE_60],
- _unselectedFillStyle: [PURPLE_70 + '60', PURPLE_60 + '60'],
+ _selectedFillStyle: [PURPLE_70, PURPLE_55],
+ _unselectedFillStyle: [PURPLE_70 + '60', PURPLE_55 + '70'],
_selectedTextColor: '#fff',
gravity: 5,
},
@@ -187,9 +191,9 @@ const STYLE_MAP: { [key: string]: ColorStyles } = {
_selectedFillStyle: [
// This yellow has more contrast than YELLOW_50.
'#ffe129',
- YELLOW_70,
+ YELLOW_65,
],
- _unselectedFillStyle: [YELLOW_50 + '70', YELLOW_60 + '70'],
+ _unselectedFillStyle: [YELLOW_50 + '70', YELLOW_65 + '85'],
_selectedTextColor: ['#000', GREY_20],
gravity: 6,
},
diff --git a/src/utils/format-numbers.ts b/src/utils/format-numbers.ts
index 77ecb185a7..7592599a16 100644
--- a/src/utils/format-numbers.ts
+++ b/src/utils/format-numbers.ts
@@ -180,7 +180,7 @@ export function formatGigaBytes(
maxFractionalDigits: number = 2,
precision: number = Infinity
): string {
- const bytesPerGigabyte = 1024 ** 3;
+ const bytesPerGigabyte = 1000 ** 3;
if (precision === Infinity) {
return (
formatNumber(
@@ -210,7 +210,7 @@ export function formatMegaBytes(
maxFractionalDigits: number = 2,
precision: number = Infinity
): string {
- const bytesPerMegabyte = 1024 ** 2;
+ const bytesPerMegabyte = 1000 ** 2;
if (precision === Infinity) {
return (
formatNumber(
@@ -240,7 +240,7 @@ export function formatKiloBytes(
maxFractionalDigits: number = 2,
precision: number = Infinity
): string {
- const bytesPerKilobyte = 1024;
+ const bytesPerKilobyte = 1000;
if (precision === Infinity) {
return (
formatNumber(
@@ -274,14 +274,14 @@ export function formatBytes(
// Use singles up to 10,000. I think 9,360B looks nicer than 9.36KB.
// We use "0" for significantDigits because bytes will always be integers.
return formatNumber(bytes, 0) + 'B';
- } else if (bytes < 1024 ** 2) {
+ } else if (bytes < 1000 ** 2) {
return formatKiloBytes(
bytes,
significantDigits,
maxFractionalDigits,
precision
);
- } else if (bytes < 1024 ** 3) {
+ } else if (bytes < 1000 ** 3) {
return formatMegaBytes(
bytes,
significantDigits,
@@ -542,10 +542,10 @@ function _findRoundValueGreaterOrEqualTo(minValue: number): number {
export function findRoundBytesValueGreaterOrEqualTo(minValue: number): number {
// Special case KB, MB, GB.
- if (minValue > 1024 && minValue <= 1024 ** 4) {
+ if (minValue > 1000 && minValue <= 1000 ** 4) {
for (const power of [1, 2, 3]) {
for (const value of [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]) {
- const number = value * 1024 ** power;
+ const number = value * 1000 ** power;
if (minValue <= number) {
return number;
}
diff --git a/src/utils/window-console.ts b/src/utils/window-console.ts
index 12ad179482..0beb4651fd 100644
--- a/src/utils/window-console.ts
+++ b/src/utils/window-console.ts
@@ -323,8 +323,12 @@ export function addDataToWindowObject(
) {
const strTimestamp = d2s(profile.meta.startTime + markerStartTime);
const processName = thread.processName ?? 'Unknown Process';
- // TODO: lying about the log level as it's not available yet in the markers
- const statement = `${strTimestamp} - [${processName} ${thread.pid}: ${thread.name}]: D/${(data as any).module} ${(data as any).name.trim()}`;
+
+ // The log module may contain the log level for profiles captured after bug 1995503.
+ // If the log module does not contain /, we fake it to D/module
+ const logModule = (data as any).module;
+ const prefix = logModule.includes('/') ? '' : 'D/';
+ const statement = `${strTimestamp} - [${processName} ${thread.pid}: ${thread.name}]: ${prefix}${logModule} ${(data as any).name.trim()}`;
logs.push(statement);
}
}