A new version of Compiler was added to project The Inbox:
http://source.squeak.org/inbox/Compiler-mt.456.mcz ==================== Summary ==================== Name: Compiler-mt.456 Author: mt Time: 2 February 2021, 11:06:33.099178 am UUID: 0558759c-0bf7-e946-8a65-c673c49d6c8f Ancestors: Compiler-mt.455 Forgot to remove old method. Sorry for the noise. =============== Diff against Compiler-mt.455 =============== Item was removed: - ----- Method: Parser>>noContextSwitch (in category 'pragmas - code evaluation') ----- - noContextSwitch - "By adding this pragma to a method, it will not be preempt the current process on method activation if a higher-priority process is runnable. Any numbered primitive without side effects will do here." - <pragmaParser> - - "Note that primitive 123 once was primitiveValueUninteruptibly but is no longer in use." - self addPragma: (Pragma keyword: #primitive: arguments: #(123)). - - self advance. - ^ true! |
Hi all! I would like to merge <noContextSwitchOnActivation> into Trunk. But I still need a nice test case. Should be independent from the JIT. Maybe a simple setter? foobar: value <noContextSwitchOnActivation> instVar := value ... [ test instVar should be 42 already ] forkAt: current + 1. self foobar: 42. ?? Best, Marcel
|
Ha! Tricky. I figured that #forkAt: will immediately run the process if its priority is higher than the current one: x := 0. [ x := 1 ] forkAt: 41. y := x == 1. "true :-)" However, I have no idea why the following happens: x := 0. [ [ x := 1 ] forkAt: 41 ] valueUnpreemptively. y := x == 1. "false :-(" Or this: x := 0. [ [ x := 1 ] forkAt: 41 ] valueUnpreemptively. Transcript showln: 'foo'. y := x == 1. "false :-(" I would expect that "Transcript showln: 'foo'" entails many suspension points. The following, however, works for me: x := 0. [ [ x := 1 ] forkAt: 41 ] valueUnpreemptively. ActiveWorld imageForm asMorph. y := x == 1. "true :-)" In any case, I have not yet found a way to test <noContextSwitchOnActivation>. Best, Marcel
|
Also, taking a closer look at #valueUnpreemptively, which I now use to schedule that higher-priority process in a test: [ [ result := value == 10 ] forkAt: 41 ] valueUnpreemptively. self setValue. self assert: result. Here is the problem: "result" is still undefined. That means that there is no suspension point when invoking #setValue. At least not my VM. setValue value := 10. What would be a good implementation for #setValue to benefit from <noContextSwitchOnActivation>? Best, Marcel
|
In reply to this post by marcel.taeumel
> However, I have no idea why the following happens:
> > x := 0. > [ [ x := 1 ] forkAt: 41 ] valueUnpreemptively. > y := x == 1. "false :-(" > > > Or this: > > x := 0. > [ [ x := 1 ] forkAt: 41 ] valueUnpreemptively. > Transcript showln: 'foo'. > y := x == 1. "false :-(" The reason is the #yield primitive 167 - it doesn't reflect the change of priority as done in #valueUnpreemptively... Try to remove the primitive from #yield and then it works ok Regards, Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html
^[^ Jaromir
|
> Try to remove the primitive from #yield and then it works ok Yes, removing the primitive form #yield will introduce one (or more) suspension points because of the (rather complex) fallback implementation. Yet, I cannot do that in a test. :-) Best, Marcel
|
> Yet, I cannot do that in a test. :-) Hypothetically, you could use a mock environment and subclass ProcessorScheduler. But this would get too complex for a single test ...
Do we have a good framework for such mocking experiments in Squeak? :-)
self mock: #Processor with: MockProcessorWithoutYield new during: [
self doYourTestLogic].
or also:
self
mock: Processor class >> #yield
with: (Processor class >> #yield) decompile withoutPrimitiveNode generate
during: [
...].
Best,
Christoph
Von: Squeak-dev <[hidden email]> im Auftrag von Taeumel, Marcel
Gesendet: Dienstag, 2. Februar 2021 14:22:34 An: squeak-dev Betreff: Re: [squeak-dev] The Inbox: Compiler-mt.456.mcz
> Try to remove the primitive from #yield and then it works ok
Yes, removing the primitive form #yield will introduce one (or more) suspension points because of the (rather complex) fallback implementation. Yet, I cannot do that in a test. :-)
Best,
Marcel
Carpe Squeak!
|
In reply to this post by marcel.taeumel
> > Try to remove the primitive from #yield and then it works ok
> > Yes, removing the primitive form #yield will introduce one (or more) > suspension points because of the (rather complex) fallback implementation. > Yet, I cannot do that in a test. :-) Now I'm confused - it looks to me either yield primitive 167 or #valueUnpreemptively behave incorrectly because your example x := 0. [ [ x := 1 ] forkAt: 41 ] valueUnpreemptively. y := x == 1. should definitely return true. In case yield primitive works as intended, #valueUnpreemptively should change (replace Processor yield line to digest the change of priority) or vice versa - or am I missing something? J. -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html
^[^ Jaromir
|
> Now I'm confused - it looks to me either yield primitive 167 or #valueUnpreemptively behave incorrectly Hmm... I think that "Processor yield" should not only schedule the next runnable process at the same priority but also serve as a "classic" suspension point and consider higher-priority processes first. Not sure whether this is "by design" or actually a bug... most of the time, you would not need "Processor yield" to also look for interrupts. There are typically enough other suspension points. Hmmmm... Best, Marcel
|
> Not sure whether this is "by design" or actually a bug... most of the time,
you would not need "Processor yield" to also look for interrupts. There are typically enough other suspension points. Hmmmm... Aaah, I guess I know what you mean - looking at the valueUnpreemptively method the Processor yield was meant to let the same priority preempted processes a chance to run but here we have a higher priority process scheduled and yield doesn't look there. And when you change `activeProcess priority: oldPriority` just like this there's a higher priority process scheduled while a lower priority process running! Funny, I thought that can't happen :D valueUnpreemptively | activeProcess oldPriority result | activeProcess := Processor activeProcess. oldPriority := activeProcess priority. activeProcess priority: Processor highestPriority. result := self ensure: [activeProcess priority: oldPriority]. "Yield after restoring priority to give the preempted processes a chance to run" Processor yield. "<-- replace by: [activeProcess resume] fork. activeProcess suspend." ^result I wanted to suggest replacing the yield as above but it may be a more general issue... J -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html
^[^ Jaromir
|
> looking at the valueUnpreemptively > method the Processor yield was meant to let the same priority preempted > processes a chance to run Not quite. If you are at 40 and get boosted up to 80, there can be preempted processes at any other priority in between. I would expect that "Processor yield" accounts for that. Other processes running at 40 do not matter because we have cooperative schedulding at each priority. Best, Marcel
|
> If you are at 40 and get boosted up to 80, there can be preempted processes
at any other priority in between. I would expect that "Processor yield" accounts for that. Well, in that case #yield probably doesn't do that considering #yield's comment: "Give other Processes at the *current priority* a chance to run." J -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html
^[^ Jaromir
|
Actually, I'd place the problem in Process>>#priority: method - it should
make sure that if the active process downgrades it's priority below an existing runnable process, the active process will automatically be preempted - something like this (works for your examples): Process>>priority: anInteger "Set the receiver's priority to anInteger." (anInteger >= Processor lowestPriority and:[anInteger <= Processor highestPriority]) ifTrue: [ priority := anInteger. (self isActiveProcess and: [anInteger < Processor nextReadyProcess priority]) ifTrue: [ [self resume] fork. self suspend ] ] ifFalse: [self error: 'Invalid priority: ', anInteger printString] And then the #yield primitive can remain as it is :) J -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html
^[^ Jaromir
|
If you modify #priority behavior as per my previous message the
#valueUnpreemptively can be simplified: valueUnpreemptively | activeProcess oldPriority | activeProcess := Processor activeProcess. oldPriority := activeProcess priority. activeProcess priority: Processor highestPriority. ^self ensure: [activeProcess priority: oldPriority]. -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html
^[^ Jaromir
|
Hi Marcel,
same problem here: x := 0. [ [ x := 1 ] forkAt: 41 ] valueAt: 42. y := x == 1. "false :-(" And the same solution: fix Process>>priority: and simplify #valueAt: method. Regards, Jaromir BlockClosure>>valueAt: blockPriority "Evaluate the receiver (block), with another priority as the actual one and restore it afterwards. The caller should be careful with using higher priorities." | activeProcess result outsidePriority | activeProcess := Processor activeProcess. outsidePriority := activeProcess priority. activeProcess priority: blockPriority. result := self ensure: [activeProcess priority: outsidePriority]. * "Yield after restoring lower priority to give the preempted processes a chance to run." blockPriority > outsidePriority ifTrue: [Processor yield].* / "this part doesn't work and can be removed"/ ^ result -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html
^[^ Jaromir
|
In reply to this post by marcel.taeumel
>
> > Hi all! > > I would like to merge <noContextSwitchOnActivation> into Trunk. But I > still need a nice test case. Should be independent from the JIT. Maybe a > simple setter? > > foobar: value > <noContextSwitchOnActivation> > instVar := value > > ... > > [ test instVar should be 42 already ] forkAt: current + 1. > self foobar: 42. > > ?? > Hi Marcel, is it even possible to test #valueNoContextSwitch? I'm trying to understand what would that require: you'd like to catch a higher priority process trying to interrupt (preempt) a block activation between the #valueNoContextSwitch send and the first context switching point inside the block - right? Like a non-primitive send etc. So it's a very short period of time you're targeting before the first switching point. I was thinking along the lines of: x := 0. [1 milliSecond wait. x := x+1000000] forkAt:41. [[x:=x+1. x<1000000] whileTrue] valueNoContextSwitch. x but x returns e.g. 1084476 meaning whileTrue must be a context switching point (because it's a backward jump?) and 1 millisecond is a desperately long period... My question - is this at least the right understanding? If yes, could you think of any time consuming operations that would not contain any switching points? To get past the 1 msec? I'm really curious. Thanks! ----- ^[^ Jaromir -- Sent from: http://forum.world.st/Squeak-Dev-f45488.html
^[^ Jaromir
|
Free forum by Nabble | Edit this page |