[squeak-dev] The Inbox: Morphic-ct.1540.mcz

Thiede, Christoph Christoph.Thiede at student.hpi.uni-potsdam.de
Mon Sep 23 17:10:17 UTC 2019


Thanks for your thoughts!


Well, I already did some benchmarks, but I find it hard to achieve objective results:


cleanUp := [
    TransformationMorph allSubInstancesDo: [:m | m submorphs ifEmpty: [m delete]].
    5 timesRepeat: [Smalltalk garbageCollect]].


Morph rememberProvenance: false.
cleanUp value.
[TransformationMorph new] bench." '526,000 per second. 1.9 microseconds per run.'"

"Test 2"
Morph rememberProvenance: true.
cleanUp value.
[TransformationMorph new] bench." '118,000 per second. 8.44 microseconds per run.'"


Morph rememberProvenance: false.
cleanUp value.
[TransformationMorph new openInWorld] bench." '3,790 per second. 264 microseconds per run.'"

Morph rememberProvenance: true.
cleanUp value.
[TransformationMorph new openInWorld] bench." '3,690 per second. 271 microseconds per run.'"


Could we say: the overhead nearly disappears when compared to the costs of actually opening a morph?

How could I measure the memory load appropriately?


> -1 to keeping track of the #creatorStack because compiled methods can outdate in a long-running image

See Tools-ct.894, you actually could browse the outdated methods, but I agree this is of very rare benefit. I changed the code to store MethodReferences instead, but if my benchmark code is not erroneous, this nearly doubled the time for test 2 (15.9 ms/run).


> Still ... what if we would use PasteUpMorph >> addedMorph:? How would those stacks look like? What's the user requirements here? Something in the world or more a debugging tool at the level of halos?


My main intention was to allow users for finding out where a morph was created. Where is the code that is responsible for showing this Debugger window? What methods create the docking bar morph? How is the window close box created? If we only record where it was added to world, we are missing any information about how exactly it was created, not to mention information for any submorphs.


> Morph keepTrackOfCreationDuring: someBlock.

+1 :-)

So you mean all I need to update is the class-side of Morph?


Best,

Christoph

________________________________
Von: Squeak-dev <squeak-dev-bounces at lists.squeakfoundation.org> im Auftrag von Taeumel, Marcel
Gesendet: Montag, 23. September 2019 17:12 Uhr
An: Alan Grimes via Squeak-dev
Betreff: Re: [squeak-dev] The Inbox: Morphic-ct.1540.mcz

Hmm... this feature has quite an impact on Morph creation time and the overall memory footprint, right? Did you benchmark that somehow?

>From a first impression, I would say:

-1 to keeping track of the #creatorStack because compiled methods can outdate in a long-running image
+1 to keeping track of the #officialCreator because that could help setting a breakpoint at the right place

Still ... what if we would use PasteUpMorph >> addedMorph:? How would those stacks look like? What's the user requirements here? Something in the world or more a debugging tool at the level of halos?

Maybe there could be a way to keep track of morph creation explicitely?

Morph keepTrackOfCreationDuring: someBlock.

Even with a preference, adding such a thing to Morph >> #initialize requires actual benchmarks to asses the performance and memory overhead.

Just my two cents. :-)

Best,
Marcel

Am 23.09.2019 16:47:29 schrieb Thiede, Christoph <christoph.thiede at student.hpi.uni-potsdam.de>:

How do you like that?

[cid:b635a64a-7981-444c-af79-70188915420b]

Can you notice a real performance impact when activating the preference? What is on Raspi?


Best,

Christoph

________________________________
Von: Squeak-dev <squeak-dev-bounces at lists.squeakfoundation.org> im Auftrag von commits at source.squeak.org <commits at source.squeak.org>
Gesendet: Montag, 23. September 2019 16:44:39
An: squeak-dev at lists.squeakfoundation.org
Betreff: [squeak-dev] The Inbox: Morphic-ct.1540.mcz

A new version of Morphic was added to project The Inbox:
http://source.squeak.org/inbox/Morphic-ct.1540.mcz

==================== Summary ====================

Name: Morphic-ct.1540
Author: ct
Time: 23 September 2019, 4:44:32.818523 pm
UUID: 064f7940-90ea-1646-a6f5-6c0a82c06e91
Ancestors: Morphic-mt.1539

Proposal: Remember & explore provenance of any morph.

Sure, this is a performance regression (that's why it's turned off by default), but when you are debugging, I could tell you of so many cases in which this can be a useful utility. Looking at #browseCreatorMethod, we can also use this to allow beginners for quickly browsing the <example> method that created a morph.

=============== Diff against Morphic-mt.1539 ===============

Item was changed:
  Object subclass: #Morph
         instanceVariableNames: 'bounds owner submorphs fullBounds color extension'
+        classVariableNames: 'HaloForAll IndicateKeyboardFocus MetaMenuForAll PreferredCornerRadius RememberProvenance UseSoftDropShadow'
-        classVariableNames: 'HaloForAll IndicateKeyboardFocus MetaMenuForAll PreferredCornerRadius UseSoftDropShadow'
         poolDictionaries: ''
         category: 'Morphic-Kernel'!

  !Morph commentStamp: 'klc 3/14/2017 11:30' prior: 0!
  A Morph (from the Greek "shape" or "form") is an interactive graphical object. General information on the Morphic system can be found at http://wiki.squeak.org/squeak/30.

  Morphs exist in a tree, rooted at a World (generally a PasteUpMorph). The morphs owned by a morph are its submorphs. Morphs are drawn recursively; if a Morph has no owner it never gets drawn. To hide a Morph and its submorphs, set its #visible property to false using the #visible: method.

  The World (screen) coordinate system is used for most coordinates, but can be changed if there is a TransformMorph somewhere in the owner chain.

  My instance variables have accessor methods (e.g., #bounds, #bounds:). Most users should use the accessor methods instead of using the instance variables directly.

  Structure:
  instance var   Type                     Description
  bounds                         Rectangle                A Rectangle indicating my position and a size that will enclose                                                                  me.
  owner                  Morph             My parent Morph, or nil for the top-level Morph, which is a
                                 or nil                  world, typically a PasteUpMorph.
  submorphs              Array                    My child Morphs.
  fullBounds             Rectangle                A Rectangle minimally enclosing me and my submorphs.
  color                  Color                    My primary color. Subclasses can use this in different ways.
  extension              MorphExtension Allows extra properties to be stored without adding a
                                 or nil                           storage burden to all morphs.

  By default, Morphs do not position their submorphs. Morphs may position their submorphs directly or use a LayoutPolicy to automatically control their submorph positioning.

  Although Morph has some support for BorderStyle, most users should use BorderedMorph if they want borders.!

Item was added:
+ ----- Method: Morph class>>rememberProvenance (in category 'preferences') -----
+ rememberProvenance
+
+        <preference: 'Remember provenance of each morph'
+                categoryList: #(Morphic)
+                description: 'If enabled, each morph will contain a debug item to view its creator stack. This allows you to explore its provenance later. May affect performance.'
+                type: #Boolean>
+        ^ RememberProvenance ifNil: [false]!

Item was added:
+ ----- Method: Morph class>>rememberProvenance: (in category 'preferences') -----
+ rememberProvenance: aBoolean
+
+        RememberProvenance := aBoolean.!

Item was added:
+ ----- Method: Morph>>browseCreatorMethod (in category 'debug and other') -----
+ browseCreatorMethod
+
+        ^ (self valueOfProperty: #officialCreator) browse!

Item was changed:
  ----- Method: Morph>>buildDebugMenu: (in category 'debug and other') -----
  buildDebugMenu: aHand
         "Answer a debugging menu for the receiver.  The hand argument is seemingly historical and plays no role presently"

         | aMenu aPlayer |
         aMenu := MenuMorph new defaultTarget: self.
         aMenu addStayUpItem.
         (self hasProperty: #errorOnDraw) ifTrue:
                 [aMenu add: 'start drawing again' translated action: #resumeAfterDrawError.
                 aMenu addLine].
         (self hasProperty: #errorOnStep) ifTrue:
                 [aMenu add: 'start stepping again' translated action: #resumeAfterStepError.
                 aMenu addLine].

         aMenu add: 'inspect morph' translated action: #inspectInMorphic:.
         aMenu add: 'inspect owner chain' translated action: #inspectOwnerChain.
         Smalltalk isMorphic ifFalse:
                 [aMenu add: 'inspect morph (in MVC)' translated action: #inspect].

         self isMorphicModel ifTrue:
                 [aMenu add: 'inspect model' translated target: self model action: #inspect;
                         add: 'explore model' translated target: self model action: #explore].
         (aPlayer := self player) ifNotNil:
                 [aMenu add: 'inspect player' translated target: aPlayer action: #inspect].

       aMenu add: 'explore morph' translated target: self selector: #exploreInMorphic:.

         aMenu addLine.
         aPlayer ifNotNil:
                 [ aMenu add: 'viewer for Player' translated target: self player action: #beViewed.
         aMenu balloonTextForLastItem: 'Opens a viewer on my Player -- this is the same thing you get if you click on the cyan "View" halo handle' translated ].

         aMenu add: 'viewer for Morph' translated target: self action: #viewMorphDirectly.
         aMenu balloonTextForLastItem: 'Opens a Viewer on this Morph, rather than on its Player' translated.
         aMenu addLine.

         aPlayer ifNotNil:
                 [aPlayer class isUniClass ifTrue: [
                         aMenu add: 'browse player class' translated target: aPlayer selector: #haveFullProtocolBrowsedShowingSelector: argumentList: #(nil)]].
         aMenu add: 'browse morph class' translated target: self selector: #browseHierarchy.
+        self isMorphicModel
-        (self isMorphicModel)
                 ifTrue: [aMenu
                                 add: 'browse model class'
                                 target: self model
                                 selector: #browseHierarchy].
+        (self valueOfProperty: #officialCreator ifAbsent: [nil]) ifNotNil: [
+                aMenu add: 'browse creator method' action: #browseCreatorMethod].
+        (self hasProperty: #creatorStack) ifTrue: [
+                aMenu add: 'explore creator stack' action: #exploreCreatorStack].
         aMenu addLine.

         self addViewingItemsTo: aMenu.
         aMenu
                 add: 'make own subclass' translated action: #subclassMorph;
                 add: 'save morph in file' translated  action: #saveOnFile;
                 addLine;
                 add: 'call #tempCommand' translated action: #tempCommand;
                 add: 'define #tempCommand' translated action: #defineTempCommand;
                 addLine;

                 add: 'control-menu...' translated target: self selector: #invokeMetaMenu:;
                 add: 'edit balloon help' translated action: #editBalloonHelpText.

         ^ aMenu!

Item was added:
+ ----- Method: Morph>>exploreCreatorStack (in category 'debug and other') -----
+ exploreCreatorStack
+
+        ^ (self valueOfProperty: #creatorStack) explore!

Item was changed:
  ----- Method: Morph>>initialize (in category 'initialization') -----
  initialize
         "initialize the state of the receiver"
         owner := nil.
         submorphs := Array empty.
         bounds := self defaultBounds.
+        color := self defaultColor.
+        self class rememberProvenance ifTrue: [
+                | creatorStack |
+                creatorStack := thisContext home stack collect: #method.
+                self setProperty: #creatorStack toValue: creatorStack.
+                creatorStack
+                        detect: [:method | method hasPragma: #example]
+                        ifFound: [:method | self setProperty: #officialCreator toValue: method]].!
-        color := self defaultColor!


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20190923/dc14ea6d/attachment.html>


More information about the Squeak-dev mailing list