Hi all:
How much performance do you lose when using Smalltalk at: #ClassName instead of direct referencing the class? Small suggestion to OA*: It would help a lot if you could load a package (from .pac or STS), and instead of ignoring the methods that don't compile (because of a reference to an non-existent global/class, for example), the system loads them anyway, and flag it somehow. And thereafter when you load the missing global, the non-compiled method re-compiles itself and fixes the missing reference(s). It will help a lot when porting something that uses a diferent packaging strategy (such as VW parcels/bundles), allowing you to load everything, and then repackage properly. *I recall this was requested during the D6 beta phase Regards, -- Esteban. |
Esteban A. Maringolo escribió:
> Hi all: > > How much performance do you lose when using Smalltalk at: #ClassName > instead of direct referencing the class? Answering myself... Smalltalk at: is about 10% slower than direct class reference. Regards, -- Esteban. |
Esteban,
> > How much performance do you lose when using Smalltalk at: #ClassName > > instead of direct referencing the class? > > Answering myself... Smalltalk at: is about 10% slower than direct class > reference. That doesn't sound right. On this 1.5 GHz machine, evaluating: Cursor takes around 4 nanoseconds; evaluating: Smalltalk at: #Cursor takes around 1 microsecond. It's around 250 times slower ;-) Of course, that is meaningless without knowing what the evaluation is part of. In practise it would be silly to put: Smalltalk at: #Cursor into the middle of a loop so tight that 1 usec made a difference to the overall execution speed -- for exactly the same reason as it would be silly to put anArray at: someFixedNumber into such a loop. You'd naturally pull the constant-valued expression out of the loop, and so the difference between: Cursor and: Smalltalk at: #Cursor would be irrelevant. -- chris |
In reply to this post by Esteban A. Maringolo
Esteban,
> It would help a lot if you could load a package (from .pac or STS), > and instead of ignoring the methods that don't compile (because of a > reference to an non-existent global/class, for example), the system > loads them anyway, and flag it somehow. > And thereafter when you load the missing global, the non-compiled > method re-compiles itself and fixes the missing reference(s). This is something that I'm starting to want too, although in may case what I want is the ability to define methods /of/ classes which don't exist -- which would have a very similar implementation, I'd imagine. For me it's a packaging issue. I have quite often recently found myself in a position where some package adds some feature to some other package. Logically that feature should /also/ be added to some third package, but that would create an undesirable dependency. Alternatively, I could split the problematic package into two, which would remove the unwanted part of the dependency, but at the cost of fragmenting what /should/ be a coherent whole. Here's an example from my published code. I have a package 'CU Stream Extensions' which adds things like #nextFLOAT and #nextQWORD (plus big-endian equivalents) to the standard Streams -- that is one coherent unit of functionality. I also have a package 'CU Abstract Streams' which provides a base from which to derive custom stream implementations -- also one coherent unit of functionality. But, and this is the problem, where does the abstract equivalent of #nextQWORD go ? If I put it into 'CU Abstract Streams' then I'm scrambling the package boundaries. If I put it into 'CU Stream Extensions' then I'm creating an unwanted dependency. If I split 'CU Stream Extensions' then -- at best -- that's inconvenient. That is only one example, I have several more. I don't know whether the feature would be useful enough to justify the extra complication and development time, that's for OA to decide, but I /do/ know that if it did exist then I'd have used it several times already. -- chris |
In reply to this post by Chris Uppal-3
Chris Uppal escribió:
> Esteban, > >>> How much performance do you lose when using Smalltalk at: #ClassName >>> instead of direct referencing the class? >> Answering myself... Smalltalk at: is about 10% slower than direct class >> reference. > > That doesn't sound right. On this 1.5 GHz machine, evaluating: > Cursor > takes around 4 nanoseconds; evaluating: > Smalltalk at: #Cursor > takes around 1 microsecond. It's around 250 times slower ;-) Uhm... it's odd. I ran the following expressions on a 1.7GHz centrino and obtained the results in comments: Time microsecondsToRun: [ 1000 timesRepeat: [SwazooURI]] "30 µs" Time microsecondsToRun: [ 1000 timesRepeat: [Smalltalk at: #SwazooURI]]. "1131 µs" Time microsecondsToRun: [ 1000 timesRepeat: [SwazooURI fromString: '/']] "24569 µs" Time microsecondsToRun: [ 1000 timesRepeat: [(Smalltalk at: #SwazooURI) fromString: '/']] "32511 µs" Time microsecondsToRun: [ 10000 timesRepeat: [SwazooURI fromString: '/']] "268055 µs" Time microsecondsToRun: [ 10000 timesRepeat: [(Smalltalk at: #SwazooURI) fromString: '/'] ] "304880 µs" Then if you add repetitions of 10^5 or more, the results of indirect access are about 25% slower than direct reference. Best regards, ps: how do you measure nanoseconds? -- Esteban. |
Esteban,
[me:] > > [...] On this 1.5 GHz machine, evaluating: > > Cursor > > takes around 4 nanoseconds; evaluating: > > Smalltalk at: #Cursor > > takes around 1 microsecond. It's around 250 times slower ;-) > > Uhm... it's odd. > I ran the following expressions on a 1.7GHz centrino and obtained the > results in comments: > > Time microsecondsToRun: [ > 1000 timesRepeat: [SwazooURI]] "30 µs" OK, around 3 nanoseconds each (or less since some of that will be loop overhead). > Time microsecondsToRun: [ > 1000 timesRepeat: [Smalltalk at: #SwazooURI]]. "1131 µs" Around 1 usec each. Pretty similar to my figures. > Time microsecondsToRun: [ > 1000 timesRepeat: [SwazooURI fromString: '/']] "24569 µs" So the fromString: but is taking the bulk of the time -- around 25 usecs each. > Time microsecondsToRun: [ > 1000 timesRepeat: [(Smalltalk at: #SwazooURI) fromString: '/']] "32511 µs" But that is odd. You'd expect it to take around 26 usecs each time, but it's taking rather longer than that. If it /was/ behaving as expected then it this case would be about 5% slower, but it's actually more like 30%. I don't know why. I tried the same thing on my machine (actually slightly different because my version of Swazoo doesn't have the class-side method). I get: [SwazooURI new parseURI: '/'] 26.5 usecs [(Smalltalk at: #SwazooURI) new parseURI: '/'] 29.2 usecs [Smalltalk at: #SwazooURI] 1.36 (+/-0.05) usecs [SwazooURI] 4.0 (+/-0.3) nanosecs So I'm seeing the same effect but not nearly as extreme (10% slower for that expression when the raw figures would lead me to expect 5%). I took a look at the bytecode for the various blocks, but it seems there's no difference between: [SwazooURI new parseURI: '/'] [(Smalltalk at: #SwazooURI) new parseURI: '/'] which isn't just a parallel of the difference between: [Smalltalk at: #SwazooURI] [SwazooURI] Possibly there is an optimisation in the VM for methods which return a constant, and that is available only for the last form, so it shows up as being unrepresentatively cheap -- but I haven't been able to find any real evidence to support that. > ps: how do you measure nanoseconds? With the little timing framework I have used for years and years. It's on my website: 'CU Expression Timer' under 'Experiments'. -- chris |
Free forum by Nabble | Edit this page |