@@ -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 = / ^ ( g e t | s e t ) ? \w + ( \. \w + | c o n s t r u c t o r ) $ / ;
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