I think we could simplify the logic by simply putting the default behavior here. Something like
```
// Use all cores available, up to user-specified limit
val realCores = Runtime.getRuntime.availableProcessors()
val numCores = math.min(realCores, conf.getInt("spark.cores.max", realCores))
val backend = new LocalBackend(scheduler, numCores)
```

This would allow us to avoid changing much in LocalBackend.