Skip to content

Conversation

@niaow
Copy link
Member

@niaow niaow commented May 30, 2020

This works right now, but there are some pieces here and there which are sub-optimal or have limited support. This is mostly a proof of concept that I hacked together tonight.

@niaow niaow force-pushed the altsched branch 2 times, most recently from 82294f6 to da83522 Compare May 30, 2020 04:09
@niaow
Copy link
Member Author

niaow commented May 30, 2020

@aykevl Is this design more of what you were looking for, rather than the other scheduler design?

Copy link
Member

@aykevl aykevl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still need to look at this properly (and I intend to do so very soon), but I quickly skimmed through the code.

@niaow
Copy link
Member Author

niaow commented Jun 5, 2020

I don't want to scope-creep this PR any further, so I would suggest adding support for other boards in separate PRs after this is merged, because otherwise we would basically have to test every board to merge this.

@niaow niaow requested a review from aykevl June 5, 2020 01:23
@niaow niaow added this to the v0.14 milestone Jun 6, 2020
@deadprogram
Copy link
Member

@jaddr2line please resolve merge conflict.

@niaow
Copy link
Member Author

niaow commented Jun 9, 2020

Rebased.

@niaow
Copy link
Member Author

niaow commented Jun 13, 2020

Rebased again after the go mod tidy.

Copy link
Member

@aykevl aykevl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have taken a bit more in-depth look, I need to look at the write barrier next.

Sorry, lots of things going on right now in my life so don't have as much time as I would hope.

Sidenote (semi-related): the functionality I'm most waiting for is some sort of simple condition variable that one goroutine can wait on and an interrupt can signal. That's what is needed by the vast majority of hardware, for example to queue a DMA SPI transfer and wait for it to finish. Or, in my case, wait for a BLE operation to complete (in the nrf SoftDevice) while another goroutine is allowed to run. Right now I just wait for it to complete, which is a waste:

// Wait for the next advertisement packet to arrive.
// TODO: use some sort of condition variable once the scheduler supports
// them.
arm.Asm("wfe")
if gotScanReport.Get() == 0 {
	// Spurious event. Continue waiting.
	continue
}
gotScanReport.Set(0)

Of course, that should happen after this PR is merged (which lays the foundation for more interrupt <-> goroutine communication).

@aykevl
Copy link
Member

aykevl commented Jun 14, 2020

I think the write barrier system is solid. I am however not sure whether disabling interrupts in the GC is ever a good idea. Even the possibility of it happening may be a problem for real time applications, while endless GC loops seem rather unlikely to me (except for really badly designed interrupt handlers). I'm inclined to say it's better to risk unbounded GC than to disable interrupts in the GC.

I'll think a bit about the best strategy.

@aykevl
Copy link
Member

aykevl commented Jun 14, 2020

Actually, it seems to me that every heap pointer move would be a task pointer move from some arbitrary location (for example the blocked list in a channel) to the runqueue. Therefore it might be enough to scan the runqueue with interrupts disabled, or rather (after the heap has been scanned) do something like this:

while True:
  task = nil
  disable interrupts
    for t in runqueue:
      if t not marked:
        task = t
        break
  enable interrupts
  if task == nil:
    break # finished scanning
  scan task

Maybe we have already discussed this, but I don't see an obvious flaw here. The advantage here is that the number of goroutines is limited, especially on bare metal systems it may be just a few or only one. Certainly iterating through the runqueue will be much more predictable than rescanning the entire heap.

@niaow
Copy link
Member Author

niaow commented Jun 14, 2020

@aykevl I have removed the write barrier with a pattern like what you suggested.

@niaow
Copy link
Member Author

niaow commented Jun 14, 2020

Alright, this should finally be done!

@deadprogram
Copy link
Member

I am doing some testing with this PR now...

@deadprogram
Copy link
Member

So this PR currently causes the ItsyBitsy-M4 SAMD51 board to become unresponsive. I could recover by using the manual bootloader and then flashing code from the previous version...

@niaow
Copy link
Member Author

niaow commented Jun 15, 2020

Unresposive when running what?

@deadprogram
Copy link
Member

Once flashed, the MCU "locks up" and even the USB CDC code no longer works. The IRQ that is uses to detect the USB CDC is no longer called, so the MCU no longer goes into bootloader when switching to 1200 baud.

@deadprogram
Copy link
Member

When I was finally able to get GDB to connect (had a bad solder joint on my connector) here is the stack trace I was able to obtain:

(gdb) continue                                                                                                                                                               
Continuing.                                                                                                                                                                  
^C                                                                                                                                                                           
Program received signal SIGTRAP, Trace/breakpoint trap.                                                                                                                      
runtime.timerSleep (ticks=<optimized out>) at /home/ron/.gvm/pkgsets/go1.14.2/global/src/github.com/tinygo-org/tinygo/src/runtime/runtime_atsamd51.go:290                    
290             for timerWakeup.Get() == 0 {                                                                                                                                 
(gdb) bt                                                                                                                                                                     
#0  runtime.timerSleep (ticks=<optimized out>) at /home/ron/.gvm/pkgsets/go1.14.2/global/src/github.com/tinygo-org/tinygo/src/runtime/runtime_atsamd51.go:290                
#1  0x0000655c in runtime.sleepTicks (d=16384) at /home/ron/.gvm/pkgsets/go1.14.2/global/src/github.com/tinygo-org/tinygo/src/runtime/runtime_atsamd51.go:252                
#2  0x00006530 in runtime.scheduler () at /home/ron/.gvm/pkgsets/go1.14.2/global/src/github.com/tinygo-org/tinygo/src/runtime/scheduler.go:153                               
#3  0x00006456 in runtime.run () at /home/ron/.gvm/pkgsets/go1.14.2/global/src/github.com/tinygo-org/tinygo/src/runtime/scheduler_any.go:24                                  
#4  0x00006254 in Reset_Handler () at /home/ron/.gvm/pkgsets/go1.14.2/global/src/github.com/tinygo-org/tinygo/src/runtime/runtime_atsamd51.go:20

I discovered that the same problem of MCU locks up even on blinky1 exists on the nrf52840 when I accidentally flashed my Circuit Playground Bluefruit with code from this branch. Oops!

@deadprogram
Copy link
Member

The issue I reported regarding M4 processors was corrected by #1182 which has now been merged into dev. @jaddr2line if you rebase dev into this branch then all the tests should pass now.

@niaow
Copy link
Member Author

niaow commented Jun 21, 2020

Rebased.

@aykevl
Copy link
Member

aykevl commented Jun 23, 2020

I did a size comparison before and after this PR:

  • Somehow amd64 is affected by this: code size is usually increased a bit. I did not expect that to happen. Not a big problem but it might be a symptom of something.
  • Similarly, WebAssembly outputs tend to be a bit larger.
  • As expected, code size is increased a little bit for most baremetal targets (usually around 150-200 bytes). I think this increase is worth the extra functionality it provides.

@niaow
Copy link
Member Author

niaow commented Jun 23, 2020

Somehow amd64 is affected by this: code size is usually increased a bit.

This probably has to do with the GC changes.

@aykevl
Copy link
Member

aykevl commented Jun 23, 2020

Right, that makes sense. For amd64 I don't really care but for wasm it's a bit unfortunate that it adds extra overhead for something that doesn't happen on WebAssembly.

@niaow
Copy link
Member Author

niaow commented Jun 23, 2020

I have now put parts of the conservative collector behind the baremetal build tag, and they will only build if the scheduler is enabled

The test failure is completely unrelated, and is an instance of #1185

@deadprogram
Copy link
Member

@jaddr2line if you rebase against dev the tests should pass now due to 1ad6953

@niaow
Copy link
Member Author

niaow commented Jun 24, 2020

Rebased.

Copy link
Member

@aykevl aykevl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did another size comparison. The last commit (to reduce size) did not have an effect on amd64 but did reduce code size on wasm. Still there is a small (much more acceptable) size increase on wasm. Interestingly, it did sometimes reduce .bss size by 4 bytes on baremetal targets.

Size results (for diffing):
https://gist.github.com/aykevl/ea54c616224e5f8af55545cef7387d77

This is ready to go from my POV. @deadprogram any last comments before merging?

(some thoughts below inline, probably not worth changing)


// Push a task onto the queue.
func (q *Queue) Push(t *Task) {
i := interrupt.Disable()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be more efficient to put all these locks where the queue/stack are used.

if baremetal && hasScheduler {
// Channel operations in interrupts may move task pointers around while we are marking.
// Therefore we need to scan the runqueue seperately.
var markedTaskQueue task.Queue
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was hoping you could just go through the runqueue instead of (essentially) rewriting it, but it seems fine. And perhaps safer.

@deadprogram
Copy link
Member

From my POV this PR is ready to go. The small comments made by @aykevl are either not worth changing, or can be looked at for future refinements.

Now merging, incredible work again from @jaddr2line thank you!! 🍰 🎆

@deadprogram deadprogram merged commit e8c84d2 into tinygo-org:dev Jul 4, 2020
@niaow niaow modified the milestones: v0.15, v0.14 Jul 4, 2020
@aykevl aykevl mentioned this pull request Jul 4, 2020
7 tasks
@aykevl aykevl mentioned this pull request Feb 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants