[botanist] Allow specifying number of CPU and memory for QEMU

Provide a default which is selected based on the underlying machine.

Change-Id: I260d23749f7afcc1031240f19ae1c9ecada55978
diff --git a/cmd/botanist/qemu.go b/cmd/botanist/qemu.go
index a76a5b2..3208168 100644
--- a/cmd/botanist/qemu.go
+++ b/cmd/botanist/qemu.go
@@ -8,10 +8,12 @@
 	"context"
 	"flag"
 	"fmt"
+	"runtime"
 
 	"fuchsia.googlesource.com/tools/botanist/target"
 	"fuchsia.googlesource.com/tools/build"
 	"fuchsia.googlesource.com/tools/logger"
+	"fuchsia.googlesource.com/tools/memory"
 	"fuchsia.googlesource.com/tools/secrets"
 	"github.com/google/subcommands"
 )
@@ -42,6 +44,12 @@
 
 	// EnableKVM dictates whether to enable KVM.
 	enableKVM bool
+
+	// CPU is the number of processors to emulate.
+	cpu int
+
+	// Memory is the amount of memory (in MB) to provide.
+	memory int
 }
 
 func (*QEMUCommand) Name() string {
@@ -57,12 +65,15 @@
 }
 
 func (cmd *QEMUCommand) SetFlags(f *flag.FlagSet) {
+	totalMB := int(memory.Total()) / (1024 * 1024)
 	f.StringVar(&cmd.imageManifest, "images", "", "path to an image manifest")
 	f.StringVar(&cmd.qemuBinDir, "qemu-dir", "", "")
 	f.StringVar(&cmd.minFSImage, "minfs", "", "path to minFS image")
 	f.StringVar(&cmd.minFSBlkDevPCIAddr, "pci-addr", "06.0", "minFS block device PCI address")
 	f.StringVar(&cmd.targetArch, "arch", "", "target architecture (x64 or arm64)")
 	f.BoolVar(&cmd.enableKVM, "use-kvm", false, "whether to enable KVM")
+	f.IntVar(&cmd.cpu, "cpu", runtime.NumCPU(), "number of processors to emulate")
+	f.IntVar(&cmd.memory, "memory", totalMB, "amount of memory (in MB) to provide")
 }
 
 func (cmd *QEMUCommand) execute(ctx context.Context, cmdlineArgs []string) error {
@@ -77,8 +88,8 @@
 
 	// TODO: pass this directly from a file.
 	config := target.QEMUConfig{
-		CPU:    4,
-		Memory: 4096,
+		CPU:    cmd.cpu,
+		Memory: cmd.memory,
 		Path:   cmd.qemuBinDir,
 		Target: cmd.targetArch,
 		KVM:    cmd.enableKVM,
diff --git a/memory/memory.go b/memory/memory.go
new file mode 100644
index 0000000..4ca44da
--- /dev/null
+++ b/memory/memory.go
@@ -0,0 +1,10 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package memory
+
+// Total returns the total amount of memory on the system.
+func Total() uint64 {
+	return total()
+}
diff --git a/memory/memory_darwin.go b/memory/memory_darwin.go
new file mode 100644
index 0000000..fea8bdf
--- /dev/null
+++ b/memory/memory_darwin.go
@@ -0,0 +1,17 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package memory
+
+import (
+	"golang.org/x/sys/unix"
+)
+
+func total() uint64 {
+	memsize, err := unix.SysctlUint64("hw.memsize")
+	if err != nil {
+		return 0
+	}
+	return memsize
+}
diff --git a/memory/memory_linux.go b/memory/memory_linux.go
new file mode 100644
index 0000000..4aa74f8
--- /dev/null
+++ b/memory/memory_linux.go
@@ -0,0 +1,18 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package memory
+
+import (
+	"syscall"
+)
+
+func total() uint64 {
+	info := &syscall.Sysinfo_t{}
+	err := syscall.Sysinfo(info)
+	if err != nil {
+		return 0
+	}
+	return uint64(info.Totalram) * uint64(info.Unit)
+}
diff --git a/memory/memory_test.go b/memory/memory_test.go
new file mode 100644
index 0000000..10abeb2
--- /dev/null
+++ b/memory/memory_test.go
@@ -0,0 +1,15 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package memory
+
+import (
+	"testing"
+)
+
+func TestNonZero(t *testing.T) {
+	if Total() == 0 {
+		t.Fatal("Total returned 0")
+	}
+}