phetsims / joist

Joist is the main framework for PhET Interactive Simulations. Joist creates and displays the simulation content, home screen, navigation bar, About dialog, enables switching between tabs, and other framework-related features.
http://scenerystack.org/
MIT License
9 stars 6 forks source link

Add phet.joist.sim.toggleFuzz() #981

Closed samreid closed 2 months ago

samreid commented 2 months ago

As part of https://github.com/phetsims/density-buoyancy-common/issues/168, we would like to add tooling to help clear out some noise from the memory profiling, to make it easier to discover and solve problems.

Toggling fuzz to false using this methodology should reset each screen, go back to the same screen, and potentially clear out pools.

samreid commented 2 months ago
```diff Subject: [PATCH] Add ?launchCounter, see https://github.com/phetsims/joist/issues/980 --- Index: phet-core/js/Pool.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/phet-core/js/Pool.ts b/phet-core/js/Pool.ts --- a/phet-core/js/Pool.ts (revision ea48154177030cb76708413ecd61a0fe9b05fa5c) +++ b/phet-core/js/Pool.ts (date 1725389069247) @@ -90,6 +90,7 @@ assert && assert( options.maxSize >= 0 ); assert && assert( options.initialSize >= 0 ); + options.maxSize = 0; this._maxPoolSize = options.maxSize; // There is a madness to this craziness. We'd want to use the method noted at @@ -159,7 +160,7 @@ public set maxPoolSize( value: number ) { assert && assert( value === Number.POSITIVE_INFINITY || ( Number.isInteger( value ) && value >= 0 ), 'maxPoolSize should be a non-negative integer or infinity' ); - this._maxPoolSize = value; + this._maxPoolSize = 0; } /** Index: phet-core/js/Poolable.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/phet-core/js/Poolable.ts b/phet-core/js/Poolable.ts --- a/phet-core/js/Poolable.ts (revision ea48154177030cb76708413ecd61a0fe9b05fa5c) +++ b/phet-core/js/Poolable.ts (date 1725389069233) @@ -78,6 +78,8 @@ // The actual array we store things in. Always push/pop. const pool: InstanceType[] = []; + options.maxSize = 0; + let maxPoolSize = options.maxSize; // There is a madness to this craziness. We'd want to use the method noted at @@ -144,7 +146,7 @@ set maxPoolSize( value: number ) { assert && assert( value === Number.POSITIVE_INFINITY || ( Number.isInteger( value ) && value >= 0 ), 'maxPoolSize should be a non-negative integer or infinity' ); - maxPoolSize = value; + maxPoolSize = 0; }, /** Index: joist/js/Sim.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/joist/js/Sim.ts b/joist/js/Sim.ts --- a/joist/js/Sim.ts (revision 7e15861a2f95583a127cdca8f937d6a300e66fe0) +++ b/joist/js/Sim.ts (date 1725392826254) @@ -70,9 +70,10 @@ import Combination from '../../dot/js/Combination.js'; import Permutation from '../../dot/js/Permutation.js'; import ArrayIO from '../../tandem/js/types/ArrayIO.js'; -import { Locale } from './i18n/localeProperty.js'; +import localeProperty, { Locale } from './i18n/localeProperty.js'; import isSettingPhetioStateProperty from '../../tandem/js/isSettingPhetioStateProperty.js'; import StringIO from '../../tandem/js/types/StringIO.js'; +import ResetAllButton from '../../scenery-phet/js/buttons/ResetAllButton.js'; import dotRandom from '../../dot/js/dotRandom.js'; import launchCounter from './launchCounter.js'; @@ -229,7 +230,7 @@ // list of nodes that are "modal" and hence block input with the barrierRectangle. Used by modal dialogs // and the PhetMenu - private modalNodeStack = createObservableArray(); + private readonly modalNodeStack = createObservableArray(); // (joist-internal) Semi-transparent black barrier used to block input events when a dialog (or other popup) // is present, and fade out the background. @@ -1137,6 +1138,50 @@ } return info; } + + /** + * For memory profiling, run phet.joist.sim.toggleFuzz() to toggle fuzzing. This will reset all screens and select the + * first screen. This can help get back to a similar circumstance for memory profiling. + * Invoke this from the dev tools like so: + * + * phet.joist.sim.toggleFuzz() + */ + public toggleFuzz(): void { + const wasFuzzing = phet.chipper.queryParameters.fuzz; + phet.chipper.queryParameters.fuzz = !wasFuzzing; + if ( wasFuzzing ) { + + // iterate over ScreenViews and reset them + this.screens.forEach( screen => { + + // find all reset all buttons in that screen view + const visit = ( node: Node ) => { + if ( node instanceof ResetAllButton ) { + + // @ts-expect-error hack to access protected method + node.pushButtonModel.fire(); + } + else { + node.children.forEach( child => visit( child ) ); + } + }; + + visit( screen.view ); + } ); + + this.selectedScreenProperty.value = this.simScreens[ 0 ]; + + localeProperty.reset(); + this.preferencesModel.reset(); + + while ( this.modalNodeStack.length > 0 ) { + const topPopup = this.modalNodeStack[ this.modalNodeStack.length - 1 ]; + this.hidePopup( topPopup, true ); + } + + // TODO: https://github.com/phetsims/joist/issues/981 can we clear out the pools? + } + } } type LayoutNode = Node & { Index: joist/js/preferences/PreferencesModel.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/joist/js/preferences/PreferencesModel.ts b/joist/js/preferences/PreferencesModel.ts --- a/joist/js/preferences/PreferencesModel.ts (revision 7e15861a2f95583a127cdca8f937d6a300e66fe0) +++ b/joist/js/preferences/PreferencesModel.ts (date 1725394220760) @@ -482,6 +482,27 @@ this.supportsAudioPreferences(); } + public reset(): void { + + this.visualModel.interactiveHighlightsEnabledProperty.reset(); + this.visualModel.colorProfileProperty.reset(); + + this.audioModel.audioEnabledProperty.reset(); + this.audioModel.soundEnabledProperty.reset(); + this.audioModel.extraSoundEnabledProperty.reset(); + this.audioModel.voicingEnabledProperty.reset(); + this.audioModel.voicingMainWindowVoicingEnabledProperty.reset(); + this.audioModel.voicingObjectResponsesEnabledProperty.reset(); + this.audioModel.voicingContextResponsesEnabledProperty.reset(); + this.audioModel.voicingHintResponsesEnabledProperty.reset(); + this.audioModel.voicePitchProperty.reset(); + this.audioModel.voiceRateProperty.reset(); + this.audioModel.voiceProperty.reset(); + this.audioModel.toolbarEnabledProperty.reset(); + + this.inputModel.gestureControlsEnabledProperty.reset(); + } + public static PreferencesModelIO = new IOType( 'PreferencesModelIO', { valueType: PreferencesModel,
samreid commented 2 months ago

@jonathanolson indicated that this tooling may mask some kinds of memory leaks. It also doesn't get rid of as much noise as I would like. Therefore, I recommend closing this without committing it to main. Next time anyone is doing memory testing, if they (or I) want something like this, we can reopen.