Okay, I'm still feeling quite new to Smalltalk, so I'm looking for
advice here (and hopefully not "omg, never use globals!"). :-) When dealing with functionality that is "global", it would be nice if all code could access it with as little work as possible. The exact context I'm dealing with this in is OpenGL. Right now, I have an OpenGLLibrary, which is a singleton instance, of course, and a OpenGLView class has a class variable 'gl'. This gets initialized something like this: OpenGLView>>initialize gl ifNil: [ gl := OpenGLLibrary open ]. "other init stuff here" Now all my views can call OpenGL code just fine, it works, I'm happy. The problem is that there will be [potentially] lots of classes that need to call OpenGL functions. Consider a Vector class that wants to call glVertex3f, or a Matrix class that wants to call glMultMatrixf. Even being a singleton, I'd consider it a real pain if every instance of all these classes has to point to the singleton instance of OpenGLLibrary in order to call a function. Now, I could always just not have an instance in all these classes, but instead use OpenGLLibrary>>current to access the singleton (I suppose). But this is going to result in unnecessary message passing in performance critical code. Is it possible to just make a "gl" global variable that all my other objects can use? By the same token, is there a more common (and better) solution to this problem? Jeff M. |
Jeff,
> Okay, I'm still feeling quite new to Smalltalk, so I'm looking for > advice here (and hopefully not "omg, never use globals!"). :-) Well.... > Now, I could always just not have an instance in all these classes, but > instead use OpenGLLibrary>>current to access the singleton (I suppose). > But this is going to result in unnecessary message passing in > performance critical code. Message passing is very efficient and the small number of extra message sends involved, when compared to the total number of message sends, should be insignificant (but see below). All the Dolphin base image libraries use the singleton #default method and, to be honest, I wouldn't really consider doing it any other way. Just make your OpenGLLibrary a subclass of ExternalLibrary and use OpenGLLibrary>>default to access the library instance. If performance is *really* that critical then you can override the class side #default method (see PermanentLibrary and ScintillaLibrary for a couple of examples) but you will then have to make sure the Library is opened and closed yourself. FWIW, you _can_ use globals in Smalltalk. Evaluate Smalltalk at: #GL put: WinMMLibrary default to create a global object named GL that contains an open instance of WinMMLibrary. You can then send it messages from anywhere .... GL timeGetTime but, "omg, never use globals!" ;=) -- Ian Use the Reply-To address to contact me (limited validity). Mail sent to the From address is ignored. |
In reply to this post by Jeff M.
Thanks for the reply. I mixed up Current and #default, thanks for the
correction. :-) I appeciate the options mentioned. I'll have to do some timings, but if the message passing is as fast as you suggest, then perhaps this isn't as big a deal as I think it is. I'd just like to get it right the first time before having to go back through a lot of code.... As for the "omg, never use globals!", I just didn't want an academic response to the question. There is nothing inherently wrong with globals: it's just another tool available, and if it is part of the best solution, use 'em. ;-) Thanks again! I'll take a closer look at PermanentLibrary and see if there is anything there that might help me. Jeff M. |
> I appeciate the options mentioned. I'll have to do some timings, but if
> the message passing is as fast as you suggest, then perhaps this isn't > as big a deal as I think it is. I'd just like to get it right the first > time before having to go back through a lot of code.... Just in case you don't know the tool already, you can use Ian's great profiler to find out where the time goes. best regards martin |
In reply to this post by Jeff M.
Jeff,
> I'll have to do some timings, but if > the message passing is as fast as you suggest, then perhaps this isn't > as big a deal as I think it is. .... I think you'll find that the compiler knows about methods that just return an instVar and optimizes them so that they don't need a full method evaluation. The interpreter can just answer the contents of the instVar without having to evaluate any code. That's why the debugger doesn't step into simple accessor methods - there's no code to step through. -- Ian Use the Reply-To address to contact me (limited validity). Mail sent to the From address is ignored. |
In reply to this post by Martin Rubi
Does someone have a link to this tool?
Jeff M. |
In reply to this post by Jeff M.
Past experience has taught me to never just "trust the compiler". :-)
However, if I find through equal experience that Dolphin does a fine job of optimizations, there's another great reason for me to purchase sooner rather than later. Jeff M. |
In reply to this post by Jeff M.
Jeff,
> Does someone have a link to this tool? It's on of the goodies available from my web site. http://www.idb.me.uk Like the rest of the goodies it's getting a bit long in the tooth now and could do with a rewrite. I should say that it's not particularly good for timing low level operations[1], for that I would still use the tried and trusted Time>>millisecondsToRun . [1] Dolphin only generates interrupts at certain times (entry and exit from a method send) so the profiler, which uses the VM interrupts to take samples, struggles when a method doesn't contain any/many message sends. -- Ian Use the Reply-To address to contact me (limited validity). Mail sent to the From address is ignored. |
In reply to this post by Jeff M.
"Jeff M." <[hidden email]> wrote in message
news:[hidden email]... > Okay, I'm still feeling quite new to Smalltalk, so I'm looking for > advice here (and hopefully not "omg, never use globals!"). :-) > > When dealing with functionality that is "global", it would be nice if > all code could access it with as little work as possible. The exact > context I'm dealing with this in is OpenGL. Right now, I have an > OpenGLLibrary, which is a singleton instance, of course, and a > OpenGLView class has a class variable 'gl'. This gets initialized > something like this: > > OpenGLView>>initialize > gl ifNil: [ gl := OpenGLLibrary open ]. > "other init stuff here" > > Now all my views can call OpenGL code just fine, it works, I'm happy. > The problem is that there will be [potentially] lots of classes that > need to call OpenGL functions. Consider a Vector class that wants to > call glVertex3f, or a Matrix class that wants to call glMultMatrixf. > Even being a singleton, I'd consider it a real pain if every instance > of all these classes has to point to the singleton instance of > OpenGLLibrary in order to call a function. > > Now, I could always just not have an instance in all these classes, but > instead use OpenGLLibrary>>current to access the singleton (I suppose). > But this is going to result in unnecessary message passing in > performance critical code. > The normal thing to do would be to use 'OpenGLLibrary default' rather than hold onto the instance. The level of indirection is useful in allowing the library to be re-opened on demand on image restart. In D6 you can hold an instance, since the default instance is always re-used (so you won't end up referencing a stale instance on restart), but at some point you need to cause that instance to be re-initialised. Sending #default to the library class will do that. If it is really performance critical you can make OpenGLLibrary be a subclass of PermanentLibrary. This means that it is explicitly opened on image start, rather than lazily. This cuts the cost of accessing the default instance substantially, since a method activation is not needed. You can time the relative performance by comparing: 1) Time microsecondsToRun: [10000 timesRepeat: [AdvApiLibrary default]] 2) Time microsecondsToRun: [10000 timesRepeat: [KernelLibrary default]] I think you will find that the latter runs about 5x faster than the former, and in fact if one eliminates the loop overhead the permanent library access is about 7.5x faster. YMMV. > Is it possible to just make a "gl" global variable that all my other > objects can use? By the same token, is there a more common (and better) > solution to this problem? Yes, although I don't think you will need to. The overhead of a "partial" message send to get the default instance of a permanent library will probably be insignificant in relation to the cost of most external calls. Bear in mind that the whole Dolphin base image is built using 'XXXLibrary default'. Regards Blair |
In reply to this post by Jeff M.
Jeff,
> Okay, I'm still feeling quite new to Smalltalk, so I'm looking for > advice here (and hopefully not "omg, never use globals!"). :-) Unlikely to get that advice -- Smalltalk makes /very heavy/ use of globals, whenever you use a class name you are refering to a global variable ;-) > Is it possible to just make a "gl" global variable that all my other > objects can use? By the same token, is there a more common (and better) > solution to this problem? You've already been given the right answers to this. I just wanted to add a note that if you did want to use this kind of achitecture, you should ensure that your system hooks the #onStartup event triggered off SessionManager current, and uses that to clear or reset the value of the global. -- chris |
In reply to this post by Blair McGlashan-4
> If it is really performance critical you can make OpenGLLibrary
> be a subclass of PermanentLibrary. This means that it is > explicitly opened on image start, rather than lazily. Can I ask how the image does this? Is it just a hard-coded feature of Dolphin somewhere internally (ie, for i = 1 to num_subclasses do load)? Or is this some feature I can leverage elsewhere in my code (I'm assuming through the #onStartup that others have mentioned)? Thanks again. I must say, as usenet groups go, this is one of the best I've come across. :-) Jeff M. |
Jeff,
> Can I ask how the image does this? Is it just a hard-coded feature of > Dolphin somewhere internally (ie, for i = 1 to num_subclasses do load)? > Or is this some feature I can leverage elsewhere in my code (I'm > assuming through the #onStartup that others have mentioned)? ExternalLibrary is a bit of a special case as it needs to be started very early on in the startup process. Because of this it is hard coded into the startup sequence. Most other code, both in the base image and in any additions that have been installed, will use Dolphin's event mechanism to receive a notification that the image has been started. The SessionManager triggers a number of events (#sessionStarted, #sessionStopped etc) at appropriate times and these can be used to instigate appropriate actions. As an example look at the Chat class. When you open a Chat window the #createSchematicWiring method tells the SessionManager that, in future, it wants to be informed when the session starts and names a method, #onStartup, that should be called. If you exit and save the image with the Chat window open then the next time you start Dolphin the #onStartup method will be invoked to ensure a stable startup state. Note that there are other ways you can achieve initialization when the image is restarted, overriding various methods in the SessionManager hierarchy for example. -- Ian Use the Reply-To address to contact me (limited validity). Mail sent to the From address is ignored. |
Free forum by Nabble | Edit this page |