Skip to content

Commit

Permalink
Merge pull request #3867 from canonical/daemon-cpu-disk-usage
Browse files Browse the repository at this point in the history
get available CPUs and RAM from daemon when launching a new instance in GUI
  • Loading branch information
ricab authored Jan 16, 2025
2 parents 7f63e39 + 96f5187 commit cbcb5e7
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 46 deletions.
2 changes: 2 additions & 0 deletions include/multipass/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class Platform : public Singleton<Platform>
virtual QString default_privileged_mounts() const;
virtual bool is_image_url_supported() const;
[[nodiscard]] virtual std::string bridge_nomenclature() const;
virtual int get_cpus() const;
virtual long long get_total_ram() const;
};

QString interpret_setting(const QString& key, const QString& val);
Expand Down
4 changes: 4 additions & 0 deletions src/client/gui/lib/providers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ final daemonAvailableProvider = Provider((ref) {
return false;
});

final daemonInfoProvider = FutureProvider((ref) {
return ref.watch(grpcClientProvider).daemonInfo();
});

class AllVmInfosNotifier extends Notifier<List<DetailedInfoItem>> {
@override
List<DetailedInfoItem> build() {
Expand Down
21 changes: 13 additions & 8 deletions src/client/gui/lib/vm_details/cpus_slider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:system_info2/system_info2.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class CpusSlider extends StatefulWidget {
import '../providers.dart';

class CpusSlider extends ConsumerStatefulWidget {
final int? initialValue;
final FormFieldSetter<int> onSaved;

Expand All @@ -15,14 +17,12 @@ class CpusSlider extends StatefulWidget {
});

@override
State<CpusSlider> createState() => _CpusSliderState();
ConsumerState<CpusSlider> createState() => _CpusSliderState();
}

class _CpusSliderState extends State<CpusSlider> {
static final cores = SysInfo.cores.length;

class _CpusSliderState extends ConsumerState<CpusSlider> {
final min = 1;
late final max = math.max(widget.initialValue ?? 0, cores);

late final controller = TextEditingController(
text: widget.initialValue?.toString(),
);
Expand Down Expand Up @@ -57,6 +57,11 @@ class _CpusSliderState extends State<CpusSlider> {

@override
Widget build(BuildContext context) {
final daemonInfo = ref.watch(daemonInfoProvider);
final cores = daemonInfo.valueOrNull?.cpus ?? min;
final max = math.max(widget.initialValue ?? min, cores);
final divisions = math.max(1, max - min); // Ensure at least 1 division

final textField = TextField(
controller: controller,
focusNode: focusNode,
Expand All @@ -78,7 +83,7 @@ class _CpusSliderState extends State<CpusSlider> {
Slider(
min: min.toDouble(),
max: max.toDouble(),
divisions: max - min,
divisions: divisions,
value: (field.value ?? min).toDouble(),
onChanged: (value) {
final intValue = value.toInt();
Expand Down
12 changes: 3 additions & 9 deletions src/client/gui/lib/vm_details/disk_slider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,12 @@ import '../tooltip.dart';
import 'mapping_slider.dart';
import 'memory_slider.dart';

final diskSizeProvider = FutureProvider((ref) {
return ref
.watch(grpcClientProvider)
.daemonInfo()
.then((r) => r.availableSpace.toInt());
});

class DiskSlider extends ConsumerWidget {
final int? initialValue;
final int min;
final FormFieldSetter<int> onSaved;

DiskSlider({
const DiskSlider({
super.key,
int? min,
this.initialValue,
Expand All @@ -29,7 +22,8 @@ class DiskSlider extends ConsumerWidget {

@override
Widget build(BuildContext context, WidgetRef ref) {
final disk = ref.watch(diskSizeProvider).valueOrNull ?? min;
final daemonInfo = ref.watch(daemonInfoProvider);
final disk = daemonInfo.valueOrNull?.availableSpace.toInt() ?? min;
final max = math.max(initialValue ?? 0, disk);
final enabled = min != max;

Expand Down
21 changes: 13 additions & 8 deletions src/client/gui/lib/vm_details/ram_slider.dart
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:system_info2/system_info2.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../providers.dart';
import 'mapping_slider.dart';
import 'memory_slider.dart';

class RamSlider extends StatelessWidget {
static final ram = SysInfo.getTotalPhysicalMemory();

class RamSlider extends ConsumerWidget {
final int? initialValue;
final int min;
final FormFieldSetter<int> onSaved;

const RamSlider({
super.key,
int? min,
this.initialValue,
required this.onSaved,
});
}) : min = min ?? 512.mebi;

@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
final daemonInfo = ref.watch(daemonInfoProvider);
final ram = daemonInfo.valueOrNull?.memory.toInt() ?? min;
final max = math.max(initialValue ?? min, ram);

return MemorySlider(
label: 'Memory',
initialValue: initialValue,
min: 512.mebi,
max: math.max(initialValue ?? 0, ram),
min: min,
max: max,
sysMax: ram,
onSaved: onSaved,
);
Expand Down
17 changes: 0 additions & 17 deletions src/client/gui/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -268,14 +268,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.0"
globbing:
dependency: transitive
description:
name: globbing
sha256: "4f89cfaf6fa74c9c1740a96259da06bd45411ede56744e28017cc534a12b6e2d"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
google_identity_services_web:
dependency: transitive
description:
Expand Down Expand Up @@ -698,15 +690,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.3.0+3"
system_info2:
dependency: "direct main"
description:
path: "."
ref: "4.0.0+mp"
resolved-ref: ea5fac0e3a03db72276d946f6ca9abc9939e737a
url: "https://github.com/andrei-toterman/system_info.git"
source: git
version: "4.0.0"
term_glyph:
dependency: transitive
description:
Expand Down
4 changes: 0 additions & 4 deletions src/client/gui/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ dependencies:
rxdart: ^0.28.0
shared_preferences: ^2.3.2
synchronized: ^3.3.0+3
system_info2:
git:
url: https://github.com/andrei-toterman/system_info.git
ref: 4.0.0+mp
tray_menu:
git:
url: https://github.com/andrei-toterman/tray_menu.git
Expand Down
3 changes: 3 additions & 0 deletions src/daemon/daemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2789,6 +2789,9 @@ try // clang-format on
QStorageInfo storage_info{config->data_directory};
response.set_available_space(storage_info.bytesTotal());

response.set_cpus(MP_PLATFORM.get_cpus());
response.set_memory(MP_PLATFORM.get_total_ram());

server->Write(response);
status_promise->set_value(grpc::Status{});
}
Expand Down
10 changes: 10 additions & 0 deletions src/platform/platform_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,13 @@ std::function<int()> mp::platform::make_quit_watchdog()
return sig;
};
}

int mp::platform::Platform::get_cpus() const
{
return sysconf(_SC_NPROCESSORS_ONLN);
}

long long mp::platform::Platform::get_total_ram() const
{
return static_cast<long long>(sysconf(_SC_PHYS_PAGES)) * sysconf(_SC_PAGESIZE);
}
2 changes: 2 additions & 0 deletions src/rpc/multipass.proto
Original file line number Diff line number Diff line change
Expand Up @@ -547,4 +547,6 @@ message DaemonInfoRequest {
message DaemonInfoReply {
string log_line = 1;
uint64 available_space = 2;
uint32 cpus = 3;
uint64 memory = 4;
}
12 changes: 12 additions & 0 deletions tests/unix/test_platform_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,15 @@ TEST_F(TestPlatformUnix, multipassStorageLocationNotSetReturnsEmpty)

EXPECT_TRUE(storage_path.isEmpty());
}

TEST_F(TestPlatformUnix, get_cpus_returns_greater_than_zero)
{
// On any real system, there should be at least 1 CPU
EXPECT_GT(MP_PLATFORM.get_cpus(), 0);
}

TEST_F(TestPlatformUnix, get_total_ram_returns_greater_than_zero)
{
// On any real system, there should be some RAM
EXPECT_GT(MP_PLATFORM.get_total_ram(), 0LL);
}

0 comments on commit cbcb5e7

Please sign in to comment.