Skip to content

Commit a79df7f

Browse files
authored
Infer some categories on old processed profiles based on function names (Merge PR #1248)
2 parents b6af3f7 + 9bb4fd8 commit a79df7f

1 file changed

Lines changed: 110 additions & 18 deletions

File tree

src/profile-logic/processed-profile-versioning.js

Lines changed: 110 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,14 @@ const _upgraders = {
536536
// Old category list:
537537
// https://searchfox.org/mozilla-central/rev/5a744713370ec47969595e369fd5125f123e6d24/js/public/ProfilingStack.h#193-201
538538
// New category list:
539-
// [To be inserted once the Gecko change lands in mozilla-central]
539+
// https://searchfox.org/mozilla-central/rev/04b9cbbc2be2137a37e158a5ebaf9c7bef2364f9/js/public/ProfilingStack.h#193-200
540+
//
541+
// In addition to adding the meta category values, this upgrader attempts to deduce
542+
// a frame's category from a set of known function names. This helps the UI visualize
543+
// category-only views when that information is completely lacking. This is a
544+
// "best guess" approach, that may not get the information completely correct.
545+
// This list can safely be updated in the future, if needed, to help better refine
546+
// the categories.
540547
profile.meta.categories = [
541548
{
542549
name: 'Idle',
@@ -571,26 +578,111 @@ const _upgraders = {
571578
color: 'lightblue',
572579
},
573580
];
581+
const IDLE = 0;
582+
const OTHER = 1;
583+
const JS = 2;
584+
const LAYOUT = 3;
585+
const GRAPHICS = 4;
586+
const DOM = 5;
587+
const GCCC = 6;
588+
const NETWORK = 7;
574589
const oldCategoryToNewCategory = {
575-
[1 << 4 /* OTHER */]: 1 /* Other */,
576-
[1 << 5 /* CSS */]: 3 /* Layout */,
577-
[1 << 6 /* JS */]: 2 /* JavaScript */,
578-
[1 << 7 /* GC */]: 6 /* GC / CC */,
579-
[1 << 8 /* CC */]: 6 /* GC / CC */,
580-
[1 << 9 /* NETWORK */]: 7 /* Network */,
581-
[1 << 10 /* GRAPHICS */]: 4 /* Graphics */,
582-
[1 << 11 /* STORAGE */]: 1 /* Other */,
583-
[1 << 12 /* EVENTS */]: 1 /* Other */,
590+
[1 << 4 /* OTHER */]: OTHER,
591+
[1 << 5 /* CSS */]: LAYOUT,
592+
[1 << 6 /* JS */]: JS,
593+
[1 << 7 /* GC */]: GCCC,
594+
[1 << 8 /* CC */]: GCCC,
595+
[1 << 9 /* NETWORK */]: NETWORK,
596+
[1 << 10 /* GRAPHICS */]: GRAPHICS,
597+
[1 << 11 /* STORAGE */]: OTHER,
598+
[1 << 12 /* EVENTS */]: OTHER,
584599
};
600+
// This is the list of function names that are used to map to categories.
601+
const exactMatches = new Map([
602+
[
603+
'-[GeckoNSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]',
604+
IDLE,
605+
],
606+
['base::MessagePumpDefault::Run(base::MessagePump::Delegate*)', IDLE],
607+
['mozilla::widget::WinUtils::WaitForMessage(unsigned long)', IDLE],
608+
[
609+
'mozilla::ThreadEventQueue<mozilla::PrioritizedEventQueue<mozilla::LabeledEventQueue> >::GetEvent(bool,mozilla::EventPriority *)',
610+
IDLE,
611+
],
612+
[
613+
'mozilla::ThreadEventQueue<mozilla::PrioritizedEventQueue<mozilla::EventQueue> >::GetEvent(bool,mozilla::EventPriority *)',
614+
IDLE,
615+
],
616+
[
617+
'mozilla::ThreadEventQueue<mozilla::EventQueue>::GetEvent(bool,mozilla::EventPriority *)',
618+
IDLE,
619+
],
620+
[
621+
'mozilla::layers::PaintThread::AsyncPaintContents(mozilla::layers::CompositorBridgeChild *,mozilla::layers::CapturedPaintState *,bool (*)(mozilla::layers::CapturedPaintState *))',
622+
GRAPHICS,
623+
],
624+
['PresShell::DoFlushPendingNotifications InterruptibleLayout', LAYOUT],
625+
['nsRefreshDriver::Tick', LAYOUT],
626+
['nsLayoutUtils::GetFrameForPoint', LAYOUT],
627+
['nsAppShell::ProcessGeckoEvents', OTHER],
628+
['PollWrapper(_GPollFD*, unsigned int, int)', IDLE],
629+
['mozilla::image::DecodePoolImpl::PopWorkLocked(bool)', IDLE],
630+
[
631+
'nsCCUncollectableMarker::Observe(nsISupports*, char const*, char16_t const*)',
632+
GCCC,
633+
],
634+
['g_main_context_dispatch', OTHER],
635+
['nsContentSink::StartLayout(bool)', LAYOUT],
636+
]);
637+
638+
const upToFirstSpaceMatches = new Map([
639+
['PresShell::DoFlushPendingNotifications', LAYOUT],
640+
['PresShell::DoReflow', LAYOUT],
641+
]);
642+
643+
function truncateAtFirstSpace(s: string): string {
644+
const spacePos = s.indexOf(' ');
645+
return spacePos === -1 ? s : s.substr(0, spacePos);
646+
}
647+
648+
function getCategoryForFuncName(funcName: string): number | void {
649+
const exactMatch = exactMatches.get(funcName);
650+
if (exactMatch !== undefined) {
651+
return exactMatch;
652+
}
653+
654+
const truncatedMatch = upToFirstSpaceMatches.get(
655+
truncateAtFirstSpace(funcName)
656+
);
657+
return truncatedMatch;
658+
}
659+
660+
const domCallRegex = /^(get |set )?\w+(\.\w+| constructor)$/;
661+
662+
// Go through all of the threads and their frames and attempt to deduce
663+
// the categories by looking at the function names.
585664
for (const thread of profile.threads) {
586-
for (let i = 0; i < thread.frameTable.length; i++) {
587-
const oldCategory = thread.frameTable.category[i];
588-
if (oldCategory !== null) {
589-
const newCategory =
590-
oldCategory in oldCategoryToNewCategory
591-
? oldCategoryToNewCategory[oldCategory]
592-
: 1 /* Other */;
593-
thread.frameTable.category[i] = newCategory;
665+
const { frameTable, funcTable, stringArray } = thread;
666+
const stringTable = new UniqueStringArray(stringArray);
667+
for (let i = 0; i < frameTable.length; i++) {
668+
const funcIndex = frameTable.func[i];
669+
const funcName = stringTable.getString(funcTable.name[funcIndex]);
670+
const categoryBasedOnFuncName = getCategoryForFuncName(funcName);
671+
if (categoryBasedOnFuncName !== undefined) {
672+
frameTable.category[i] = categoryBasedOnFuncName;
673+
} else {
674+
const oldCategory = frameTable.category[i];
675+
if (oldCategory !== null) {
676+
if (!funcTable.isJS[funcIndex] && domCallRegex.test(funcName)) {
677+
frameTable.category[i] = DOM;
678+
} else {
679+
const newCategory =
680+
oldCategory in oldCategoryToNewCategory
681+
? oldCategoryToNewCategory[oldCategory]
682+
: 1 /* Other */;
683+
frameTable.category[i] = newCategory;
684+
}
685+
}
594686
}
595687
}
596688
}

0 commit comments

Comments
 (0)