Hi guys. We were discussing yesterday with Marcus about the following.... I remember a problem we have in Pharo because of changing "foo == nil" to "foo isNil" in some important places like Process/Delay/Semaphore. Such change introduces a suspension point, where if I understand correctly, the scheduler can switch to another process only during method sends. #== is optimized with a special bytecode and there is no message send. Sending #isNil is a message sent, and hence we introduce a suspension point. In 99% of the cases this is not a problem. But I can imagine that there are places (mostly those related to Process/Delay/Semaphore) where this changes can be very very bad. To do some experiments, I want to remove the bytecode for #== but of course, I think I will have all these problems. And there are more. Marcus told me that some optimizations done by the compiler end up sending #==. And I also remember some code he told me (I think it was #allObjectsDo:) that would never finish because of the block closure objects creation. So...what about making the necessity of NOT sending a message or NOT introducing a suspension point more explicit? first we should have the support for that and second know each place where we need them. The most basic thing I can think of is doing something like: (ParseNode classVarNamed: 'StdSelectors') at: #== put: #bytecodedEqualEqual. Compiler recompileAll. And put a nice comment why one may want to use #optimizedEqualEqual. But again, in which places should I change #== for #bytecodedEqualEqual Any thought or idea about them is really appreciated. Thanks -- Mariano http://marianopeck.wordpress.com |
I would properly comment the places where this "ATOMIC" operation is really used. Nicolas 2011/8/11 Mariano Martinez Peck <[hidden email]>: > > Hi guys. We were discussing yesterday with Marcus about the following.... > > I remember a problem we have in Pharo because of changing "foo == nil" to "foo isNil" in some important places like Process/Delay/Semaphore. Such change introduces a suspension point, where if I understand correctly, the scheduler can switch to another process only during method sends. #== is optimized with a special bytecode and there is no message send. Sending #isNil is a message sent, and hence we introduce a suspension point. In 99% of the cases this is not a problem. But I can imagine that there are places (mostly those related to Process/Delay/Semaphore) where this changes can be very very bad. > > > To do some experiments, I want to remove the bytecode for #== but of course, I think I will have all these problems. And there are more. Marcus told me that some optimizations done by the compiler end up sending #==. And I also remember some code he told me (I think it was #allObjectsDo:) that would never finish because of the block closure objects creation. > > So...what about making the necessity of NOT sending a message or NOT introducing a suspension point more explicit? first we should have the support for that and second know each place where we need them. > > The most basic thing I can think of is doing something like: > > (ParseNode classVarNamed: 'StdSelectors') at: #== put: #bytecodedEqualEqual. > Compiler recompileAll. > > And put a nice comment why one may want to use #optimizedEqualEqual. But again, in which places should I change #== for #bytecodedEqualEqual > > > Any thought or idea about them is really appreciated. > > Thanks > > > -- > Mariano > http://marianopeck.wordpress.com > > > |
On 11 August 2011 13:17, Nicolas Cellier <[hidden email]> wrote: > > I would properly comment the places where this "ATOMIC" operation is > really used. Like in AtomicQueueItem>>makeCircular? :) I also remember discussion that some precautions in code to not insert suspension point(s) in ProcessorScheduler/Process/or Semaphore.. but i forgot which one exactly. Is it LinkedList>>removeLink:? > Nicolas > > 2011/8/11 Mariano Martinez Peck <[hidden email]>: >> >> Hi guys. We were discussing yesterday with Marcus about the following.... >> >> I remember a problem we have in Pharo because of changing "foo == nil" to "foo isNil" in some important places like Process/Delay/Semaphore. Such change introduces a suspension point, where if I understand correctly, the scheduler can switch to another process only during method sends. #== is optimized with a special bytecode and there is no message send. Sending #isNil is a message sent, and hence we introduce a suspension point. In 99% of the cases this is not a problem. But I can imagine that there are places (mostly those related to Process/Delay/Semaphore) where this changes can be very very bad. >> >> >> To do some experiments, I want to remove the bytecode for #== but of course, I think I will have all these problems. And there are more. Marcus told me that some optimizations done by the compiler end up sending #==. And I also remember some code he told me (I think it was #allObjectsDo:) that would never finish because of the block closure objects creation. >> >> So...what about making the necessity of NOT sending a message or NOT introducing a suspension point more explicit? first we should have the support for that and second know each place where we need them. >> >> The most basic thing I can think of is doing something like: >> >> (ParseNode classVarNamed: 'StdSelectors') at: #== put: #bytecodedEqualEqual. >> Compiler recompileAll. >> >> And put a nice comment why one may want to use #optimizedEqualEqual. But again, in which places should I change #== for #bytecodedEqualEqual >> >> >> Any thought or idea about them is really appreciated. >> >> Thanks >> >> >> -- >> Mariano >> http://marianopeck.wordpress.com >> >> >> > -- Best regards, Igor Stasenko AKA sig. |
On Aug 11, 2011, at 2:11 37PM, Igor Stasenko wrote:
So suspension points in remove:ifAbsent (as written now) and removeLink: are ok. Not in removeLink:ifAbsent: though. Used to be: link := self linkOf: aLinkOrObject ifAbsent: [^aBlock value]. self removeLink: link. ^aLinkOrObject Because, well, I didn't think you'd ever get in a situation where : 1) two processes would try to remove the same link 2) first of them suspends after link assignment 3) second carries through, and actually removes link 4) first calls removeLink: , and default block raising error is triggered when link is not found. Cheers, Henry |
On 11 August 2011 14:28, Henrik Johansen <[hidden email]> wrote: > > > On Aug 11, 2011, at 2:11 37PM, Igor Stasenko wrote: > > On 11 August 2011 13:17, Nicolas Cellier > <[hidden email]> wrote: > > I would properly comment the places where this "ATOMIC" operation is > > really used. > > Like in > AtomicQueueItem>>makeCircular? :) > > > I also remember discussion that some precautions in code to not insert > suspension point(s) in ProcessorScheduler/Process/or Semaphore.. > but i forgot which one exactly. > Is it LinkedList>>removeLink:? > > http://code.google.com/p/pharo/issues/detail?id=3498 > So suspension points in remove:ifAbsent (as written now) and removeLink: are ok. > Not in removeLink:ifAbsent: though. > Used to be: > link := self linkOf: aLinkOrObject ifAbsent: [^aBlock value]. > self removeLink: link. > ^aLinkOrObject i don't like this code, because it iterating list twice, first to find a link, and second time to remove it. I don't think it is a big secret that removing an element from linked list could be done using single iteration :) > Because, well, I didn't think you'd ever get in a situation where : > 1) two processes would try to remove the same link > 2) first of them suspends after link assignment > 3) second carries through, and actually removes link > 4) first calls removeLink: , and default block raising error is triggered when link is not found. > Cheers, > Henry > -- Best regards, Igor Stasenko AKA sig. |
On Aug 11, 2011, at 2:59 56PM, Igor Stasenko wrote: > > On 11 August 2011 14:28, Henrik Johansen <[hidden email]> wrote: >> >> >> On Aug 11, 2011, at 2:11 37PM, Igor Stasenko wrote: >> >> On 11 August 2011 13:17, Nicolas Cellier >> <[hidden email]> wrote: >> >> I would properly comment the places where this "ATOMIC" operation is >> >> really used. >> >> Like in >> AtomicQueueItem>>makeCircular? :) >> >> >> I also remember discussion that some precautions in code to not insert >> suspension point(s) in ProcessorScheduler/Process/or Semaphore.. >> but i forgot which one exactly. >> Is it LinkedList>>removeLink:? >> >> http://code.google.com/p/pharo/issues/detail?id=3498 >> So suspension points in remove:ifAbsent (as written now) and removeLink: are ok. >> Not in removeLink:ifAbsent: though. >> Used to be: >> link := self linkOf: aLinkOrObject ifAbsent: [^aBlock value]. >> self removeLink: link. >> ^aLinkOrObject > > i don't like this code, because it iterating list twice, first to find a link, > and second time to remove it. > > I don't think it is a big secret that removing an element from linked > list could be done using single iteration :) You really only need to iterate to find the correct one if passed a non-link. So the following is probably better: linkOf: anObject ifAbsent: errorBlock anObject asLink == anObject ifTrue: [^anObject]. self linksDo: [:el | el value = anObject ifTrue: [^ el]]. ^ errorBlock value Then ll := LinkedList new. link := ll addFirst: 5. ll remove: link ifAbsent: [self halt] works without halting as well :) Cheers, Henry |
In reply to this post by Nicolas Cellier
One idea marcus mentioned was to have an explicit bytecode for suspension point. I think that explicit semantics and behavior is always better. Marcus is also thinking about expression or method tagging that the compiler could take into account to generate this specific bytecode. Stef > > I would properly comment the places where this "ATOMIC" operation is > really used. > > Nicolas > > 2011/8/11 Mariano Martinez Peck <[hidden email]>: >> >> Hi guys. We were discussing yesterday with Marcus about the following.... >> >> I remember a problem we have in Pharo because of changing "foo == nil" to "foo isNil" in some important places like Process/Delay/Semaphore. Such change introduces a suspension point, where if I understand correctly, the scheduler can switch to another process only during method sends. #== is optimized with a special bytecode and there is no message send. Sending #isNil is a message sent, and hence we introduce a suspension point. In 99% of the cases this is not a problem. But I can imagine that there are places (mostly those related to Process/Delay/Semaphore) where this changes can be very very bad. >> >> >> To do some experiments, I want to remove the bytecode for #== but of course, I think I will have all these problems. And there are more. Marcus told me that some optimizations done by the compiler end up sending #==. And I also remember some code he told me (I think it was #allObjectsDo:) that would never finish because of the block closure objects creation. >> >> So...what about making the necessity of NOT sending a message or NOT introducing a suspension point more explicit? first we should have the support for that and second know each place where we need them. >> >> The most basic thing I can think of is doing something like: >> >> (ParseNode classVarNamed: 'StdSelectors') at: #== put: #bytecodedEqualEqual. >> Compiler recompileAll. >> >> And put a nice comment why one may want to use #optimizedEqualEqual. But again, in which places should I change #== for #bytecodedEqualEqual >> >> >> Any thought or idea about them is really appreciated. >> >> Thanks >> >> >> -- >> Mariano >> http://marianopeck.wordpress.com >> >> >> |
In reply to this post by Nicolas Cellier
> I would properly comment the places where this "ATOMIC" operation is > really used. Yeah, whatever is done behind the scenes (an explicit instruction for the suspension point, etc.), I think it's also important to document what's going on at the source level. -C -- Craig Latta www.netjam.org/resume +31 6 2757 7177 + 1 415 287 3547 |
In reply to this post by stephane ducasse-2
On 11 August 2011 16:28, stephane ducasse <[hidden email]> wrote: > > One idea marcus mentioned was to have an explicit bytecode for suspension point. > I think that explicit semantics and behavior is always better. > > Marcus is also thinking about expression or method tagging that the compiler could take into account > to generate this specific bytecode. > We're discussed this today. My own point that we should design our algorithms to never rely on some specific scheduling semantics, but always assume that an interrupt could happen at any moment, or more in general: two or more processes could run in parallel. Because if you won't let baby to start walking and running (and of course there are 90% risk of falling down at the beginning), by tying it tightly in baby carriage, one have zero chances to learn how to walk without falling down. > Stef > > >> >> I would properly comment the places where this "ATOMIC" operation is >> really used. >> >> Nicolas >> >> 2011/8/11 Mariano Martinez Peck <[hidden email]>: >>> >>> Hi guys. We were discussing yesterday with Marcus about the following.... >>> >>> I remember a problem we have in Pharo because of changing "foo == nil" to "foo isNil" in some important places like Process/Delay/Semaphore. Such change introduces a suspension point, where if I understand correctly, the scheduler can switch to another process only during method sends. #== is optimized with a special bytecode and there is no message send. Sending #isNil is a message sent, and hence we introduce a suspension point. In 99% of the cases this is not a problem. But I can imagine that there are places (mostly those related to Process/Delay/Semaphore) where this changes can be very very bad. >>> >>> >>> To do some experiments, I want to remove the bytecode for #== but of course, I think I will have all these problems. And there are more. Marcus told me that some optimizations done by the compiler end up sending #==. And I also remember some code he told me (I think it was #allObjectsDo:) that would never finish because of the block closure objects creation. >>> >>> So...what about making the necessity of NOT sending a message or NOT introducing a suspension point more explicit? first we should have the support for that and second know each place where we need them. >>> >>> The most basic thing I can think of is doing something like: >>> >>> (ParseNode classVarNamed: 'StdSelectors') at: #== put: #bytecodedEqualEqual. >>> Compiler recompileAll. >>> >>> And put a nice comment why one may want to use #optimizedEqualEqual. But again, in which places should I change #== for #bytecodedEqualEqual >>> >>> >>> Any thought or idea about them is really appreciated. >>> >>> Thanks >>> >>> >>> -- >>> Mariano >>> http://marianopeck.wordpress.com >>> >>> >>> > > -- Best regards, Igor Stasenko AKA sig. |
On Aug 11, 2011, at 5:10 PM, Igor Stasenko wrote: > > On 11 August 2011 16:28, stephane ducasse <[hidden email]> wrote: >> >> One idea marcus mentioned was to have an explicit bytecode for suspension point. >> I think that explicit semantics and behavior is always better. >> >> Marcus is also thinking about expression or method tagging that the compiler could take into account >> to generate this specific bytecode. >> > > We're discussed this today. > My own point that we should design our algorithms to never rely on > some specific scheduling semantics, > but always assume that an interrupt could happen at any moment, or > more in general: > two or more processes could run in parallel. > > Because if you won't let baby to start walking and running (and of > course there are 90% risk of falling down at the beginning), > by tying it tightly in baby carriage, one have zero chances to learn > how to walk without falling down. yes this us my favorite solution :) > > >> Stef >> >> >>> >>> I would properly comment the places where this "ATOMIC" operation is >>> really used. >>> >>> Nicolas >>> >>> 2011/8/11 Mariano Martinez Peck <[hidden email]>: >>>> >>>> Hi guys. We were discussing yesterday with Marcus about the following.... >>>> >>>> I remember a problem we have in Pharo because of changing "foo == nil" to "foo isNil" in some important places like Process/Delay/Semaphore. Such change introduces a suspension point, where if I understand correctly, the scheduler can switch to another process only during method sends. #== is optimized with a special bytecode and there is no message send. Sending #isNil is a message sent, and hence we introduce a suspension point. In 99% of the cases this is not a problem. But I can imagine that there are places (mostly those related to Process/Delay/Semaphore) where this changes can be very very bad. >>>> >>>> >>>> To do some experiments, I want to remove the bytecode for #== but of course, I think I will have all these problems. And there are more. Marcus told me that some optimizations done by the compiler end up sending #==. And I also remember some code he told me (I think it was #allObjectsDo:) that would never finish because of the block closure objects creation. >>>> >>>> So...what about making the necessity of NOT sending a message or NOT introducing a suspension point more explicit? first we should have the support for that and second know each place where we need them. >>>> >>>> The most basic thing I can think of is doing something like: >>>> >>>> (ParseNode classVarNamed: 'StdSelectors') at: #== put: #bytecodedEqualEqual. >>>> Compiler recompileAll. >>>> >>>> And put a nice comment why one may want to use #optimizedEqualEqual. But again, in which places should I change #== for #bytecodedEqualEqual >>>> >>>> >>>> Any thought or idea about them is really appreciated. >>>> >>>> Thanks >>>> >>>> >>>> -- >>>> Mariano >>>> http://marianopeck.wordpress.com >>>> >>>> >>>> >> >> > > > > -- > Best regards, > Igor Stasenko AKA sig. |
In reply to this post by stephane ducasse-2
On Thu, 11 Aug 2011, stephane ducasse wrote: > > One idea marcus mentioned was to have an explicit bytecode for suspension point. > I think that explicit semantics and behavior is always better. What's the point of having a bytecode for suspension points? Since the goal is to avoid suspension points, the best solution is to use pragmas that the compiler takes into account. It can either be global for the given method or it can specify some selectors which should be optimized to avoid suspension points. Here's an example for the per selector version: critical: mutuallyExcludedBlock ifLocked: alternativeBlock "Evaluate mutuallyExcludedBlock only if the receiver is not currently in the process of running the critical: message. If the receiver is, then evaluate alternativeBlock and return." "See the comment of #critical: for the explanation how this pattern works before changing the code." | caught | <useByteCodesFor: #(== ifTrue:ifFalse: -)> caught := false. ^[ "We're using #== here instead of #=, because it won't introduce a suspension point, while #= may do that." excessSignals == 0 ifTrue: [ alternativeBlock value ] ifFalse: [ excessSignals := excessSignals - 1. caught := true. mutuallyExcludedBlock value ] ] ensure: [ caught ifTrue: [ self signal ] ] Levente > > Marcus is also thinking about expression or method tagging that the compiler could take into account > to generate this specific bytecode. > > Stef > > >> >> I would properly comment the places where this "ATOMIC" operation is >> really used. >> >> Nicolas >> >> 2011/8/11 Mariano Martinez Peck <[hidden email]>: >>> >>> Hi guys. We were discussing yesterday with Marcus about the following.... >>> >>> I remember a problem we have in Pharo because of changing "foo == nil" to "foo isNil" in some important places like Process/Delay/Semaphore. Such change introduces a suspension point, where if I understand correctly, the scheduler can switch to another process only during method sends. #== is optimized with a special bytecode and there is no message send. Sending #isNil is a message sent, and hence we introduce a suspension point. In 99% of the cases this is not a problem. But I can imagine that there are places (mostly those related to Process/Delay/Semaphore) where this changes can be very very bad. >>> >>> >>> To do some experiments, I want to remove the bytecode for #== but of course, I think I will have all these problems. And there are more. Marcus told me that some optimizations done by the compiler end up sending #==. And I also remember some code he told me (I think it was #allObjectsDo:) that would never finish because of the block closure objects creation. >>> >>> So...what about making the necessity of NOT sending a message or NOT introducing a suspension point more explicit? first we should have the support for that and second know each place where we need them. >>> >>> The most basic thing I can think of is doing something like: >>> >>> (ParseNode classVarNamed: 'StdSelectors') at: #== put: #bytecodedEqualEqual. >>> Compiler recompileAll. >>> >>> And put a nice comment why one may want to use #optimizedEqualEqual. But again, in which places should I change #== for #bytecodedEqualEqual >>> >>> >>> Any thought or idea about them is really appreciated. >>> >>> Thanks >>> >>> >>> -- >>> Mariano >>> http://marianopeck.wordpress.com >>> >>> >>> > > |
Free forum by Nabble | Edit this page |