34
Iulian Dragos @jaguarul Rethinking the debugger

Rethinking the debugger

Embed Size (px)

DESCRIPTION

New abstractions for concurrency make writing programs easier by moving away from threads and locks, but debugging such programs becomes harder. The call-stack, an essential tool in understanding why and how control flow reached a certain point in the program, loses meaning when inspected in traditional debuggers. Futures, actors or iteratees make code easier to write and reason about, and in this talk I'll show a simple solution to make them easier to debug. The tool I present integrates well with the Eclipse plugin for Scala, and shows how a "reactive debugger" might look like.

Citation preview

Page 1: Rethinking the debugger

Iulian Dragos @jaguarul

Rethinking the debugger

Page 2: Rethinking the debugger

Overview

• Async Debugger

• Scala IDE for Eclipse 4.0

Page 3: Rethinking the debugger

Reactive applications

• Different parts of the application run in different logical threads

• ..the programmer must ensure correct coordination and communication

Page 4: Rethinking the debugger
Page 5: Rethinking the debugger
Page 6: Rethinking the debugger

Concurrency

• Threads and Locks are replaced by

• Futures

• Actors

• parallel collections (fork-join frameworks)

Page 7: Rethinking the debugger

Concurrency

• non-blocking

• often leads to callbacks

• flow of execution is not flow of program text

Page 8: Rethinking the debugger

Futures

val fTweets = Future { getAllTweets(user) } ! // also a future val nrOfTweets = fTweets.map(ts => ts.size) ! nrOfTweets onSuccess { println }

Execution continues without

waiting for all tweets

Futures can be chained

Callback for successful completion

Page 9: Rethinking the debugger

How do we debug asynchronous programs?

Page 10: Rethinking the debugger

Detective work

• go from undesirable effects back to causes

• attempt a fix

• repeat

Page 11: Rethinking the debugger

The Call Stack

java.lang.Exception at test.FuturesTest$$anonfun$simpleUse$1$$anonfun$2$$anonfun$apply$1.apply$mcI$sp(Futur.. at test.FuturesTest$$anonfun$simpleUse$1$$anonfun$2$$anonfun$apply$1.apply(FuturesTest.sca.. at test.FuturesTest$$anonfun$simpleUse$1$$anonfun$2$$anonfun$apply$1.apply(FuturesTest.sca.. at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24) at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24) at scala.concurrent.impl.ExecutionContextImpl$$anon$3.exec(ExecutionContextImpl.scala:107) at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

Futures use a thread pool for execution!

Page 12: Rethinking the debugger

The Problem

• The call-stack used to record the flow of control of sequential programs

• futures (and actors) execute each computation step on a different thread

• on a mostly uninteresting call stack

Page 13: Rethinking the debugger

Can we recover the async stack?

Record call stack when a future is created

Page 14: Rethinking the debugger

Under the hood

• Intercept Future instantiation

• Save stack contents (all of it)

• Resume

• When a breakpoint is hit

• check async stacks store

• (overhead is comparable to conditional breakpoint)

Page 15: Rethinking the debugger

Chrome does it

Visual Studio does it, too

Page 16: Rethinking the debugger

Debugging Actors

Page 17: Rethinking the debugger

Debugging Actors

• Can we find out where a message was sent?

• what was the state at that point?

• IT’S THE SAME THING!

Page 18: Rethinking the debugger

Not just futures

• message sends (Akka, Scala actors)

• Play iteratees

• any composable asynchronous structure

• user-defined/data-flow debugging

Page 19: Rethinking the debugger

Debugging Actors

• Message-send is like an asynchronous method call

• “I’d really like to step-into that message send”

Page 20: Rethinking the debugger

Step-with-a-bang

• resume execution until the next message sent is received by an actor

• the receiving actor might run on a different thread

• other messages might be exchanged in the meantime

Page 21: Rethinking the debugger

Demo Time!

Page 22: Rethinking the debugger

More tools

• Exception breakpoint: break on dead letters

• Logical Structure of an actor

• parent

• current sender

• supervisor strategy

Page 23: Rethinking the debugger

Future

• user-extensible points-of-interest

• filter collected data (by package, frame)

Page 24: Rethinking the debugger

Summary

Call Stack

Step Into

Exception breakpoint

Logical Structure

Async stack

Step-Message

Break on Dead Letters

Actor details

Page 25: Rethinking the debugger

Scala IDE for Eclipse 4.0 preview and roadmap

Page 26: Rethinking the debugger

Lithium release (4.0)

quiescence type-checking

quick fixes (implement abstract member)

multiple Scala version support

name hashing

stable API for plugins

Page 27: Rethinking the debugger

Community steps up

Page 28: Rethinking the debugger

4.0 community

Evaluate expression

Debugger improvements

Refactoring (extract..)

UI cleanups

wizards, hovers

completions

Page 29: Rethinking the debugger

Quiescence Typing

3.0.x 4.0.0-M2

Page 30: Rethinking the debugger

Multiple Scala Version support

• Starting with Scala 2.11.0 and IDE 4.0-M2

• Presentation compiler works in (2.10) compatibility mode

• The build compiler is 2.10

• Can have multiple Scala versions in the same workspace

Page 31: Rethinking the debugger

What next?

Page 32: Rethinking the debugger

Sbt-server

• Delegate build to an Sbt (shared) process

• Directly import Sbt project

• Run any task

• Launch/debug Play apps

Page 33: Rethinking the debugger

GSoC project

• extensible IDE

• use Scala snippets to plug into the IDE

• Save Actions

• Debug Object rendering

• Auto-edits

Page 34: Rethinking the debugger

Contribute!